Tiecode Plugin Development
Plugin development documentation for Tiecode IDE / QiStudio (host package name
com.tiecode.develop). The official name of Tiecode Studio is QiStudio (a new generation open engineering platform, the first mobile app to implement the OSGi standard, extending the engineering development environment through 'micro-components/plugins'). Content source: Decompiledstudio-api-1.0-preview5.jar(com.rapid.api.*) + reverse-engineered source code of over a dozen real plugins (Go, Scala, Kotlin, Linux, AAR, LibGDX, No-install run, etc.).
Official Resources and Repositories (Important)
Official Gitee Repositories
| Repository | Description |
|---|---|
| MobileIPE-Plugin-DevManual | Official plugin development tutorial (QiStudio micro-components). Includes QiStudio核心体系介绍.md, Rapid框架介绍.md, plugin/扩展点介绍.md, plugin/插件清单配置.md, plugin/注册你的微组件——插件.md |
| TiecodeCompiler-Public | Tiecode Compiler (Cross-platform version) product release repository. Includes docs/ (compiler usage/grammar/packaging/platform integration docs), headers/tiec/ (C API + C++ wrapper headers), prebuilt/ (CLI + android/windows/linux/ohos/wasm dynamic libraries), stdlibs/ (Android/CXX/Web basic libraries) |
| QiStudio-PluginSamples | Official plugin sample projects (19+ examples: dependency injection, editor animation/rainbow brackets, floating log window, HTML project manager, network requests, icon extensions, Javac9 toolchain, syntax highlighting, custom themes, Application lifecycle, project components, various menus, tool pages, settings pages, etc.) |
The official API jar is named
qistudio-api-<version>.jar(thestudio-api-1.0-preview5.jardecompiled in this skill is its host-side SDK). QQ Community: 1016399857.
Community Reference Implementations (GitHub)
Set of real plugin source code (single repo, multiple directories, containing 8 complete compilable plugins) accompanying this skill:
https://github.com/boboyr/tiecode-plugin
| Directory | Plugin | Demonstrated Capabilities |
|---|---|---|
go语言工程插件/ | Go language engineering (Console+SDL3) | Dual templates + LSP(gopls) completions + TextMate highlighting + Toolchain + Run configuration + File tree virtual nodes |
结绳安卓工程aar构建插件/ | AAR/JAR building | Reuse host compiler chain + NameGenerator Chinese output |
结绳免安装运行插件/ | No-install runner | Reuse host tasks + Plugin-based loading of uninstalled APKs |
libgdx游戏编辑器插件/ | LibGDX visual editor | Designer + Editor code area menu + New scene classes |
scala安卓工程插件/ | Scala Android engineering | Full sbt build chain + 'Tiecode Plugin Project' template + Build/Debug plugins |
结绳Linux工程插件/ | Tiecode Linux-SDL3 | GCC toolchain + SDL3 + Task chains |
外部kotlin文件注解插件/ | External Kotlin file annotations | Tiecode Compiler API: CompilerPlugin + AnnotationProcessor + Kotlin completions |
BasicLanguages-lang参考/ | Official basic languages | CSML/JSON/Markdown/XML/Properties syntax highlighting reference |
0. Core Concepts and Overall Architecture
Tiecode is a modular IDE host. Plugins are distributed as .rmx files. A .rmx is essentially an APK: AndroidManifest.xml + classes.dex + META-INF/program.json.
The host discovers plugin capabilities through extension points declared in program.json, rather than relying on manifest <application> or the four major components.
0.1 Three Key Packages
| Package | Role |
|---|---|
com.rapid.api.* | Plugin SDK (main subject of this document). Engineering, Language, Tasks, Structure, Pages, UI, Networking, etc. |
com.rapid.framework.* | Framework layer: VFS (Virtual File System), Service/Data/Event Keys, program/plugin container |
com.tiecode.compiler.* | Tiecode Compiler (AST / Symbol Table / Toolchain completer/processor) – host-side, plugins generally only use its toolchain subpackage |
0.2 Extension Points (extension array in program.json)
Full structure of META-INF/program.json:
{
"id": "com.goproject.plugin",
"name": "Go语言工程插件",
"engine": "plugin",
"description": "...",
"versionCode": 4,
"versionName": "1.3",
"minSupport": 1,
"vendor": { "name": "boboyr", "email": "", "url": "#" },
"extension": [
{ "point": "application", "class": "com.goproject.plugin.MyApplication" },
{ "point": "project.manager", "class": "com.goproject.plugin.project.GoProjectManager" },
{ "point": "project.language", "class": "com.goproject.plugin.lang.GoLanguageFactory",
"scope": { "unit": "project", "identifiers": "sample.go" } },
{ "point": "domain.menu", "class": "com.goproject.plugin.Gomodmenu" }
]
}
minSupport Field Description (Minimum Supported Host Version)
minSupport is an integer indicating the minimum Tiecode version required by the plugin. Different versions have different values:
| Tiecode Version | minSupport | Description |
|---|---|---|
| Tiecode 4.6 | 1 | Plugins for 4.6 should use "minSupport": 1 |
| Tiecode 4.7 | 2 | Plugins for 4.7 should use "minSupport": 2 |
That is: when developing for 4.6, set
minSupportto1; when upgrading to 4.7 (or developing for 4.7), set it to2. The specific rules mapping values to host versions are official; just fill in according to the target host version when developing.
Confirmed complete list of extension points (point field):
| Extension Point | Class to Implement/Extend | Role | Source Plugin |
|---|---|---|---|
application | AndroidPlugin | Plugin entry point, onInit/activate/onUninstall | Go/Scala/AAR/No-install |
project.manager | ProjectManager (commonly CodeProjectManager) | Register a project type | Go/Scala/Linux |
project.language | LanguageFactory | Register a language (highlighting + associated file extensions), can have scope | Go/Scala |
project.language.engine | LanguageEngine | Register a language engine (container for completions/diagnostics providers) | Tiecode Console Plugin |
project.toolchain | Tool subclass (e.g., SunJdk8Compiler) | Register a build toolchain | JavaCompiler8 |
project.component | ComponentIntegrator/ComponentFactory | Mount components when opening a project (run configurations/first-run popups/hooks) | Linux/Kotlin/AAR/No-install |
project.file.creationOption | PSObjectCreationOption | 'New File' menu item in file tree | Kotlin/LibGDX |
project.file.openWithEditor | PSObjectOpeningOption | File 'Open With' options | Kotlin |
project.event.fileUi | ProjectFileUiEvent | File tree UI events (e.g., binding icons) | Kotlin |
domain.menu | BaseDomainMenuAction/menu action | Top-level menu items | Go |
domain.menu.editor.code | Code editor area menu | LibGDX | |
platform.settingsBuilder | SettingsBuilder | Add new sub-pages to settings | Scala Android |
project.file.creationOption | — | — | — |
Note:
scope.identifiersis used to restrict a language/component to a specific project typeId (e.g.,sample.go). Some extension point classes can beNone(placeholder).
1. Plugin Entry Point: application Extension Point
import com.rapid.framework.program.android.app.AndroidPlugin;
import com.rapid.framework.program.android.DvmPluginDescriptor;
import com.rapid.api.Platform;
import com.rapid.api.framework.project.toolchain.ToolchainService;
import com.rapid.api.framework.project.ProjectServiceKeys;
public class MyApplication extends AndroidPlugin {
@Override
public void onInit(DvmPluginDescriptor descriptor) {
// Register a custom build toolchain (example: Go compiler)
ToolchainService service = Platform.getService(ProjectServiceKeys.TOOLCHAIN);
service.setTool(GoCompileApiKeys.Gocompile, new BaseGoCompiler());
}
@Override
public void activate() {
// Executed once when the plugin is activated (often for hooks, listeners, assembling compilation plugins)
}
@Override
public void onUninstall() {
// Clean up: terminate child processes (e.g., gopls), disconnect LSP
}
}
Key API (com.rapid.api.Platform):
Platform.getService(Key<T>)— Get a host service (e.g.,ProjectServiceKeys.TOOLCHAIN)Platform.getProject()— Get the currently open project objectPlatform.getApplicationContext()— Get the host Context
2. Project Type: project.manager Extension Point
A plugin registers a 'project type' (e.g., Go语言工程, Tiecode Android Project) via ProjectManager.
2.1 Manager Skeleton
public class GoProjectManager extends CodeProjectManager<GoProject> {
public final static String TYPE = "Go语言工程"; // Display name
public final static String IDENTIFIER = "sample.go"; // typeId, stored in project.json
public GoProjectManager() {
super();
this.fileManager = new GoFileManager(); // Optional: custom file manager (bind icons, etc.)
// ① File open methods (by extension)
fileManager.addPSObjectOpeningOption(DefaultOpeningOption.INSTANCE, ".go", ".mod");
// ② File tree node expansion methods (virtual 'External Libraries' node)
fileManager.addPSObjectExpansionCase(new ExternalLibrariesExpansionCase(), MARKER);
// ③ New file menu items
fileManager.addPSObjectCreationOption(new GoFileCreationOption());
// ④ Language engine and language factory
languageManager.registerEngine("go", GoLanguageEngine.getInstance());
languageManager.registerLanguageFactory(new GoLanguageFactory());
languageManager.registerOperatorProvider(GoLanguage.ID, new GoOperatorProvider());
// ⑤ Project creation templates
addTemplate(new GoConsoleTemplate());
addTemplate(new GoSdl3Template());
}
@Override public String getIdentifier() { return IDENTIFIER; }
@Override public TypeDescription getTypeDescription() {
Drawable d = ContextUtils.getDrawable(AndroidPlugins.getContext(this), R.drawable.golang);
return new TypeDescription(TYPE, TypeDescription.APPLICATION, d);
}
@Override public GoProject newProject() { return new GoProject(); }
@Override public boolean isProjectDir(File file) { return false; }
}
ProjectManager interface methods (from javap):
String getIdentifier();
TypeDescription getTypeDescription(); // Name + Type + Icon
List<Template<T>> getTemplates();
void addTemplate(Template<T>);
ProjectFileManager<T> getFileManager();
T newProject();
void load(T, LoadingPresentation);
boolean isProjectDir(File); // Determine if a directory is of this project type
String backup(T); void delete(T);
TypeDescription type constants: APPLICATION / CONSOLE / LIBRARY.
3. Project Object and Pipeline Assembly: CodeProject.prepare()
Each project type corresponds to a Project subclass. prepare() is called by the host when opening a project. At this point, template files have been written, and you can assemble task chains, run configurations, and components based on the directory contents.
public class GoProject extends CodeProject {
@Override
public void prepare() {
if (GoProjectKind.isSdl3(getProjectDir())) {
Task buildLibmain = new BuildLibmainTask();
Task publishLib = new PublishLibTask();
addTask(buildLibmain);
addTask(publishLib);
publishLib.dependsOn(buildLibmain); // Task dependency
addRunConfiguration(new GoSdl3RunConfiguration());
} else {
addTask(new CompilerGoTask());
addTask(new RunGoTask());
addRunConfiguration(new GoStartRunConfig());
addRunConfiguration(new ElfRunConfig());
}
}
@Override public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
}
Key methods of CodeProject (extends BaseProject):
void prepare();
TaskContainer getTasks(); TaskExecutor getTaskExecutor();
void addTask(Task); void setTasks(Iterable<Task>);
void addRunConfiguration(RunConfiguration); // CodeProject only
ProjectVariant getVariant(); void setVariant(ProjectVariant);
Logger getLogger(); void setLogger(Logger);
String getName();
File getProjectDir(); File getChildFile(String); // Resolve a relative project path to a File
void recycle();
ProjectVariant values: DEBUG / RELEASE / UNDEFINED.
Tip (from Go plugin): In
prepare(), you can write marker files (e.g.,External Libraries) to the project to retroactively add capabilities to existing old projects without needing to recreate them.
4. Project Templates: BaseTemplate
Templates determine the options available in the 'New Project' dialog and which files to write upon creation.
public class GoConsoleTemplate extends BaseTemplate<GoProject> {
@Override public String getName() { return "Console Project"; }
@Override public Drawable getPicture() { return null; } // Template preview image, can be null
@Override public String getDefaultProjectName() { return "MyGoConsoleProject"; }
@Override public Form getForm() { return new Form(); } // Can add input fields
@Override public void create(GoProject project, Form form,
Project.OnProjectCreateListener listener) {
try {
File file = project.getChildFile("src/main.go");
String html = AssetUtils.readAsset(AndroidPlugins.getContext(this), "sample/main.go");
html = html.replace("${project_name}", project.getName());
FileUtils.writeFile(html, file); // Write to project directory
FileUtils.writeFile("module main\ngo 1.26.0", project.getChildFile("src/go.mod"));
listener.onSuccess(); // Success callback
} catch (IOException e) {
listener.onFail("Failed to write default files"); // Failure callback
}
}
}
Template<T> interface methods:
String getName();
Drawable getPicture();
String getDefaultProjectName();
Form getForm(); // com.rapid.framework.data.form.Form, can addInput(new FormInput(...))
void create(T, Form, OnProjectCreateListener); // OnProjectCreateListener.onSuccess()/onFail(msg)
Resources in Templates: Place template files in app/src/main/assets/<name>, and read/extract them using
AssetUtils.readAsset / AssetUtils.unZipAssetsFolder(context, zipName, destDir).
(The SDL3 project template, for example, uses the gosdl3_template.zip in assets which is extracted entirely to the project directory.)
5. Build Tasks and Toolchains: BaseTask + ToolchainService
5.1 Task BaseTask
public class CompilerGoTask extends BaseTask {
@Override public void execute() throws TaskInterruptError {
File output = new File(Platform.getProject().getProjectDir() + "/output");
if (!output.exists()) output.mkdirs();
GoCompile a = Platform.getService(ProjectServiceKeys.TOOLCHAIN)
.getTool(GoCompileApiKeys.Gocompile);
if (!a.isInstalled(ctx)) { logger.info("Installing toolchain..."); a.install(ctx); }
GoCompileParams p = new GoCompileParams();
p.inputFiles = FileUtils.getGofile(srcDir);
p.outputPath = output.getPath();
p.options = new String[]{"build", "-o"};
a.compile(p, new CompileOnExecutionCallback());
}
// Must override: default BaseTask.prepare throws UnsupportedOperationException;
// also, logger/variant fields must be assigned here, otherwise logger.info in execute() will NPE.
@Override public void prepare(Project project, ProjectVariant variant, Logger logger) {
this.logger = logger;
this.variant = variant;
Os.setenv("GOROOT", goRoot, false); // Set environment variables (android.system.Os)
}
@Override public String getId() { return "compileWithGo"; } // Referenced by run configuration's getTaskId()
@Override public String getName() { return "Compile to target platform"; }
}
Task interface (from javap):
String getId(); String getName();
void prepare(Project, ProjectVariant, Logger); // Note: default throws exception, must override
void execute() throws TaskInterruptError;
TaskState getState();
void interrupt();
void dependsOn(Task...); void dependsOn(List<Task>);
Task getDependencyTask(String); Task getDependencyTaskByName(String);
String getIntermediatePath(); String getIntermediatePath(String);
String getOutputPath(); String getOutputPath(String);
File getGeneratedDir();
Pitfall (from Go plugin comments): If
loggeris not assigned in the task, usinglogger.infoinexecute()will cause an NPE and fail immediately, so the toolchain installation will never execute.
5.2 Toolchain Tool + Installable
public interface Tool { /* Built-in keys: ANDROID_SDK/AAPT/AAPT2/D8/R8/DX/PROGUARD/
MANIFEST_MERGER/APK_SIGNER/JAVA_SDK/JAVA_COMPILER, etc. */ }
public interface Installable {
boolean isInstalled(Context);
void install(Context) throws IOException;
}
- Register a custom toolchain in
application.onInit()usingToolchainService.setTool(customKey, impl). - Built-in Android toolchain keys are all in the
Toolinterface (you can directly usePlatform.getService(TOOLCHAIN).getTool(Tool.AAPT2)). - To reuse the host's compiler chain (as done by the AAR plugin / No-install plugin): do not bundle the compiler yourself; instead, use
getDependencyTaskByName("compileWithTiecodec")to get the host task and add a dependency, or directly reusegetTaskId().
6. Run Configurations: RunConfiguration / TaskRunConfiguration
Add executable items to the project's 'Run' menu. The most commonly used is TaskRunConfiguration: specify a task ID, and the onResult callback is triggered upon successful execution.
public class GoStartRunConfig extends TaskRunConfiguration {
public Project getProject() { return Platform.getProject(); }
public String getTaskId() { return "RunWithGo"; } // Associated task ID
public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
public String getName() { return "Run"; }
@Override
public void onResult(TaskResult result) {
if (result.getTaskState() == TaskState.SUCCESS) {
// Launch the generated executable
getProject().getLogger().info("Run successful");
}
}
}
RunConfiguration interface (from javap):
String getName();
Project getProject();
ProjectVariant getVariant();
void run(); // Called when the user clicks the run button
void interrupt();
void onResult(TaskResult); // Callback after task chain execution
TaskResult getResult();
Tip: In the Linux plugin,
TaskRunConfigurationis used to run SDL3 programs after a GCC compilation completes. In the AAR plugin, a customRunConfigurationis used to write the build product path intoproject.json.
7. Language Features: LSP Completions + TextMate Highlighting + Tokenizer
7.1 LanguageEngine Architecture
LanguageEngine is a container for CompletionProvider, DiagnosticsProvider, TokenSet, etc.
public class GoLanguageEngine extends LanguageEngine {
private static GoLanguageEngine instance = new GoLanguageEngine();
public static GoLanguageEngine getInstance() { return instance; }
private GoLanguageEngine() {
// 1. Create a source file/class path tokenizer
addTokenSet(GoTokenSets.IMPORT_PATH);
addTokenSet(GoTokenSets.PACKAGE);
// 2. Register LSP completion provider (gopls)
addCompletionProvider(new GoLspCompletionProvider());
// 3. Register diagnostics provider (optional, e.g., import error checking)
addResourceResolver(new GoResourceResolver());
}
}
7.2 TextMate Grammar-Based Highlighting (.tmLanguage.json)
Reference: BasicLanguages-lang official sample. Parse the JSON grammar file into a StringMap grammar:
public class GoLanguageFactory extends LanguageFactoryBase {
@Override public void init() {
// Load textmate grammar from assets
String grammarJson = AssetUtils.readAsset(context, "textmate/go.json");
grammar = new TextMateProcessTokenGrammar();
grammar.load(grammarJson); // Parse JSON grammar
}
@Override public TextMateProcessTokenGrammar getGrammar() { return grammar; }
}
The official BasicLanguages-lang sample uses TextMateProcessTokenGrammar directly. Community plugins also support:
TokenProcessorchain: parse token nodes intoOperatorProvider: Provide an operator list (used for auto-pairing, indent guides)CompletionProviderbased onCharacterIndicesCompletionProvider: static keyword completion
7.3 LSP Client
Core classes for LSP support in the Go plugin:
import com.rapid.api.feature.lsp.*;
public class GoLspCompletionProvider extends LspCompletionProvider {
@Override protected LspServer createServer() {
return new GoLspServer();
}
}
public class GoLspServer extends LspServer {
private Process lspProcess;
@Override protected void start() throws IOException {
// Start gopls subprocess
lspProcess = new ProcessBuilder("gopls", "-mode=stdio")
.directory(getProjectDir())
.start();
super.setInputStream(lspProcess.getInputStream());
super.setOutputStream(lspProcess.getOutputStream());
}
@Override protected void stop() {
if (lspProcess != null) lspProcess.destroy();
}
// Override initialize to pass workspace folders, capabilities, etc.
@Override protected InitializeResult initialize() {
// Set LSP init params: rootUri, capabilities, etc.
return super.initialize();
}
}
Note: LSP support requires the plugin to manage the lifecycle of the LSP subprocess. The clean-up logic (stopping gopls) must be placed in
onUninstall()ofAndroidPlugin.
8. File Tree: Virtual Nodes (PSObject/ExpansionCase/CreationOption/OpeningOption)
8.1 Virtual Nodes (ExpansionCase)
Add a virtual node like 'External Libraries' below the project root, with the actual subtree being dynamically generated by querying the file system or a package manager:
public class ExternalLibrariesExpansionCase implements PSObjectExpansionCase {
// Referenced in fileManager.addPSObjectExpansionCase() with MARKER constant
@Override public List<? extends PSObject> computeChildren(@NotNull PSObject parent) {
List<PSObject> children = new ArrayList<>();
File libDir = new File(parent.getFile(), "lib");
if (libDir.exists()) {
for (File jar : libDir.listFiles((dir, name) -> name.endsWith(".jar"))) {
children.add(new PSObjectFile(jar)); // Each jar as a file node under the virtual folder
}
}
return children;
}
@Override public String getName() { return "External Libraries"; }
@Override public Icon getIcon() { return Icon.CLASSPATH; }
}
8.2 New File Menu (CreationOption)
public class GoFileCreationOption implements PSObjectCreationOption {
@Override public List<String> getSupportedExtensions() {
return Arrays.asList(".go", ".mod");
}
@Override public List<String> getFileTemplates() {
return Arrays.asList("main.go", "util.go");
}
@Override public boolean isAvailable(@NotNull PSObject context) {
return context instanceof PSODirectory; // Only show in directories
}
@Override public void execute(@NotNull PSObject context, @Nullable String template) {
// Create a new .go file in the target directory
File newFile = new File(context.getFile(), "new_file.go");
FileUtils.writeFile("package main\n", newFile);
}
}
8.3 Opening Options (OpeningOption)
Control how a file is opened in an editor (e.g., double-click on .mod opens text editor, not the design view):
public class ModOpeningOption implements PSObjectOpeningOption {
@Override public boolean canOpen(@NotNull PSObject psObject) {
return psObject.getFile().getName().endsWith(".mod");
}
@Override public void open(@NotNull PSObject psObject) {
// Open in the default text editor
Platform.getEditorManager().openTextEditor(psObject.getFile());
}
}
9. Menus: domain.menu Extension Point
Add top-level menu items to the IDE's main menu bar:
public class GoMenuAction extends BaseDomainMenuAction {
@Override public String getName() { return "Go"; }
@Override public Icon getIcon() { return Icon.TOOLS; }
@Override public List<BaseDomainMenuAction> getChildMenus() {
return Arrays.asList(
new BaseDomainMenuAction("Run go.mod", e -> {
Platform.getProject().getTaskExecutor().execute("go-mod-tidy");
}),
new BaseDomainMenuAction("Open Gopath", e -> {
Platform.getEditorManager().openFile(new File(System.getenv("GOPATH")));
})
);
}
}
The domain.menu.editor.code extension point allows adding menus to the editor's code area (e.g., right-click to run a single test).
10. Settings Pages: platform.settingsBuilder Extension Point
Add a new settings page to the IDE settings dialog:
public class GoSettingsBuilder extends SettingsBuilder {
@Override public String getName() { return "Go"; }
@Override public Icon getIcon() { return Icon.SETTINGS; }
@Override public View createView(LayoutInflater inflater, ViewGroup parent) {
// Inflate your custom settings layout
View view = inflater.inflate(R.layout.settings_go, parent, false);
// Initialize UI components (edit texts, switches)
return view;
}
@Override public void save() {
// Save settings to SharedPreferences or project.json
}
}
11. Packaging and Distribution: .rmx File Structure
A complete .rmx file is an APK with the following structure:
META-INF/
program.json # Extension point declarations (required)
MANIFEST.MF # Standard JAR manifest (optional)
SIGN.RSA / SIGN.SF # Signature (standard APK signing)
res/ # Resources (icons, layouts, strings)
drawable-xxxhdpi/
plugin_icon.png
lib/
arm64-v8a/
libnative.so # Native libraries (if any)
classes.dex # Compiled plugin code
AndroidManifest.xml # Minimal manifest (optional, can be empty)
Naming convention: File name should be com.yourdomain.pluginname_1.0.rmx. Place it in the plugins/ directory of Tiecode Studio on the device, or install it through the plugin market.
12. Summary of Common Patterns and Pitfalls
| Pattern | Example | Description |
|---|---|---|
| Reuse host compiler | AAR plugin | Call getDependencyTaskByName("compileWithTiecodec") instead of bundling your own compiler |
| Task dependencies | Go plugin | publishLib.dependsOn(buildLibmain) to ensure build order |
| Abort on failure | Go plugin | Use TaskInterruptError to abort the task chain, preventing the run configuration from executing |
| Environment setup | Go plugin | Os.setenv("GOROOT", ...) in Task.prepare() |
| LSP lifecycle | Go plugin | Destroy the LSP subprocess in AndroidPlugin.onUninstall() |
| Retroactive capabilities | Go plugin | Write marker files in CodeProject.prepare() for existing projects |
| Prevent NPE | All tasks | Must override prepare() and assign this.logger = logger, otherwise execute() will crash |
Translator's note: The original Chinese skill contains a
program.jsonsnippet with"name": "go语言工程插件"and"vendor": { "name": "boboyr", ... }. While most code examples are in English, these few strings were translated to maintain consistency with the target locale. The project identifiersample.gowas kept unchanged as per the instruction to preserve code and identifiers.