deveco-harness 0.1.1-test.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,71 +1,71 @@
1
- # deveco-harness
2
-
3
- <p align="center">
4
- <a href="README.md">简体中文</a> · English
5
- </p>
6
-
7
- OpenCode plugin for DevEco and HarmonyOS development workflows.
8
-
9
- ## What It Adds
10
-
11
- - **Agents**: DevEco Code-style `build` and `plan` overrides, plus any custom agents from `deveco-harness.jsonc`.
12
- - **Tools**: DevEco Code-compatible names (`arkts_knowledge_search`, `build_project`, `start_app`, `hdc_log`, `switch_cwd`, `check_ets_files`, `plan_write`, UI verification tools through MCP bridge).
13
- - **Skills**: migrated DevEco Code skills (`arkts-error-fixes`, `arkts-grammar-standards`, `arkts-runtime-fix`, `arkui-knowledge`, `deveco-create-project`) injected through OpenCode `skills.paths`.
14
-
15
- ## Installation
16
-
17
- ### Via DevEco CLI (recommended)
18
-
19
- ```bash
20
- deveco plugin deveco-harness
21
- ```
22
-
23
- Global install:
24
-
25
- ```bash
26
- deveco plugin deveco-harness --global
27
- ```
28
-
29
- ### Local development
30
-
31
- Build this package first:
32
-
33
- ```bash
34
- bun install
35
- bun run build
36
- ```
37
-
38
- Then add it to OpenCode config:
39
-
40
- ```jsonc
41
- {
42
- "plugin": ["file:///absolute/path/to/deveco-harness"]
43
- }
44
- ```
45
-
46
- For this workspace on Windows, the local plugin path is:
47
-
48
- ```jsonc
49
- {
50
- "plugin": ["file:///c:/DiskF/gitcode/oc_omo/deveco-harness"]
51
- }
52
- ```
53
-
54
- ## Configuration
55
-
56
- Create `deveco-harness.jsonc` in one of these locations:
57
-
58
- - `~/.config/opencode/deveco-harness.jsonc`
59
- - `<project>/deveco-harness.jsonc`
60
- - `<project>/.opencode/deveco-harness.jsonc`
61
-
62
- See `deveco-harness.example.jsonc` for all supported options.
63
-
64
- ## Architecture
65
-
66
- This follows the OpenCode plugin architecture used by `oh-my-openagent`:
67
-
68
- 1. `src/index.ts` default-exports a `PluginModule`.
69
- 2. `src/create-plugin-module.ts` builds the `server()` plugin and returns hooks.
70
- 3. `config` hook overrides OpenCode `build` / `plan` agents and injects skill paths.
71
- 4. `tool` hook exposes DevEco CLI tools.
1
+ # deveco-harness
2
+
3
+ <p align="center">
4
+ <a href="README.md">简体中文</a> · English
5
+ </p>
6
+
7
+ OpenCode plugin for DevEco and HarmonyOS development workflows.
8
+
9
+ ## What It Adds
10
+
11
+ - **Agents**: DevEco Code-style `build` and `plan` overrides, plus any custom agents from `deveco-harness.jsonc`.
12
+ - **Tools**: DevEco Code-compatible names (`build_project`, `start_app`, `hdc_log`, `switch_cwd`, `arkts_check`, `plan_write`).
13
+ - **Skills**: migrated DevEco Code skills (`arkts-error-fixes`, `arkts-grammar-standards`, `arkts-runtime-fix`, `arkui-knowledge`, `deveco-create-project`) injected through OpenCode `skills.paths`.
14
+
15
+ ## Installation
16
+
17
+ ### Via DevEco CLI (recommended)
18
+
19
+ ```bash
20
+ deveco plugin deveco-harness
21
+ ```
22
+
23
+ Global install:
24
+
25
+ ```bash
26
+ deveco plugin deveco-harness --global
27
+ ```
28
+
29
+ ### Local development
30
+
31
+ Build this package first:
32
+
33
+ ```bash
34
+ bun install
35
+ bun run build
36
+ ```
37
+
38
+ Then add it to OpenCode config:
39
+
40
+ ```jsonc
41
+ {
42
+ "plugin": ["file:///absolute/path/to/deveco-harness"]
43
+ }
44
+ ```
45
+
46
+ For this workspace on Windows, the local plugin path is:
47
+
48
+ ```jsonc
49
+ {
50
+ "plugin": ["file:///c:/DiskF/gitcode/oc_omo/deveco-harness"]
51
+ }
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ Create `deveco-harness.jsonc` in one of these locations:
57
+
58
+ - `~/.config/opencode/deveco-harness.jsonc`
59
+ - `<project>/deveco-harness.jsonc`
60
+ - `<project>/.opencode/deveco-harness.jsonc`
61
+
62
+ See `deveco-harness.example.jsonc` for all supported options.
63
+
64
+ ## Architecture
65
+
66
+ This follows the OpenCode plugin architecture used by `oh-my-openagent`:
67
+
68
+ 1. `src/index.ts` default-exports a `PluginModule`.
69
+ 2. `src/create-plugin-module.ts` builds the `server()` plugin and returns hooks.
70
+ 3. `config` hook overrides OpenCode `build` / `plan` agents and injects skill paths.
71
+ 4. `tool` hook exposes DevEco CLI tools.
package/README.md CHANGED
@@ -1,71 +1,71 @@
1
- # DEVECO-HARNESS
2
-
3
- <p align="center">
4
- <a href="README.en.md">English</a> · 简体中文
5
- </p>
6
-
7
- 面向 DevEco 与 HarmonyOS 开发工作流的 OpenCode 插件。
8
-
9
- ## 功能概览
10
-
11
- - **Agents**:覆盖 DevEco Code 风格的 `build` 与 `plan`,并支持通过 `deveco-harness.jsonc` 自定义 Agent。
12
- - **Tools**:兼容 DevEco Code 工具名(`arkts_knowledge_search`、`build_project`、`start_app`、`hdc_log`、`switch_cwd`、`check_ets_files`、`plan_write`,以及通过 MCP bridge 提供的 UI 验证工具)。
13
- - **Skills**:迁移自 DevEco Code 的 Skills(`arkts-error-fixes`、`arkts-grammar-standards`、`arkts-runtime-fix`、`arkui-knowledge`、`deveco-create-project`),通过 OpenCode `skills.paths` 注入。
14
-
15
- ## 安装
16
-
17
- ### 通过 DevEco CLI 安装(推荐)
18
-
19
- ```bash
20
- deveco plugin deveco-harness
21
- ```
22
-
23
- 全局安装:
24
-
25
- ```bash
26
- deveco plugin deveco-harness --global
27
- ```
28
-
29
- ### 本地开发
30
-
31
- 先构建本包:
32
-
33
- ```bash
34
- bun install
35
- bun run build
36
- ```
37
-
38
- 然后在 OpenCode 配置中添加插件:
39
-
40
- ```jsonc
41
- {
42
- "plugin": ["file:///absolute/path/to/deveco-harness"]
43
- }
44
- ```
45
-
46
- 在本工作区(Windows)的本地插件路径示例:
47
-
48
- ```jsonc
49
- {
50
- "plugin": ["file:///c:/DiskF/gitcode/oc_omo/deveco-harness"]
51
- }
52
- ```
53
-
54
- ## 配置
55
-
56
- 在以下任一位置创建 `deveco-harness.jsonc`:
57
-
58
- - `~/.config/opencode/deveco-harness.jsonc`
59
- - `<project>/deveco-harness.jsonc`
60
- - `<project>/.opencode/deveco-harness.jsonc`
61
-
62
- 完整配置项见 `deveco-harness.example.jsonc`。
63
-
64
- ## 架构
65
-
66
- 遵循 `oh-my-openagent` 使用的 OpenCode 插件架构:
67
-
68
- 1. `src/index.ts` 默认导出 `PluginModule`。
69
- 2. `src/create-plugin-module.ts` 构建 `server()` 插件并返回 hooks。
70
- 3. `config` hook 覆盖 OpenCode 的 `build` / `plan` Agent,并注入 skill 路径。
71
- 4. `tool` hook 暴露 DevEco CLI 工具。
1
+ # DEVECO-HARNESS
2
+
3
+ <p align="center">
4
+ <a href="README.en.md">English</a> · 简体中文
5
+ </p>
6
+
7
+ 面向 DevEco 与 HarmonyOS 开发工作流的 OpenCode 插件。
8
+
9
+ ## 功能概览
10
+
11
+ - **Agents**:覆盖 DevEco Code 风格的 `build` 与 `plan`,并支持通过 `deveco-harness.jsonc` 自定义 Agent。
12
+ - **Tools**:兼容 DevEco Code 工具名(`build_project`、`start_app`、`hdc_log`、`switch_cwd`、`arkts_check`、`plan_write`)。
13
+ - **Skills**:迁移自 DevEco Code 的 Skills(`arkts-error-fixes`、`arkts-grammar-standards`、`arkts-runtime-fix`、`arkui-knowledge`、`deveco-create-project`),通过 OpenCode `skills.paths` 注入。
14
+
15
+ ## 安装
16
+
17
+ ### 通过 DevEco CLI 安装(推荐)
18
+
19
+ ```bash
20
+ deveco plugin deveco-harness
21
+ ```
22
+
23
+ 全局安装:
24
+
25
+ ```bash
26
+ deveco plugin deveco-harness --global
27
+ ```
28
+
29
+ ### 本地开发
30
+
31
+ 先构建本包:
32
+
33
+ ```bash
34
+ bun install
35
+ bun run build
36
+ ```
37
+
38
+ 然后在 OpenCode 配置中添加插件:
39
+
40
+ ```jsonc
41
+ {
42
+ "plugin": ["file:///absolute/path/to/deveco-harness"]
43
+ }
44
+ ```
45
+
46
+ 在本工作区(Windows)的本地插件路径示例:
47
+
48
+ ```jsonc
49
+ {
50
+ "plugin": ["file:///c:/DiskF/gitcode/oc_omo/deveco-harness"]
51
+ }
52
+ ```
53
+
54
+ ## 配置
55
+
56
+ 在以下任一位置创建 `deveco-harness.jsonc`:
57
+
58
+ - `~/.config/opencode/deveco-harness.jsonc`
59
+ - `<project>/deveco-harness.jsonc`
60
+ - `<project>/.opencode/deveco-harness.jsonc`
61
+
62
+ 完整配置项见 `deveco-harness.example.jsonc`。
63
+
64
+ ## 架构
65
+
66
+ 遵循 `oh-my-openagent` 使用的 OpenCode 插件架构:
67
+
68
+ 1. `src/index.ts` 默认导出 `PluginModule`。
69
+ 2. `src/create-plugin-module.ts` 构建 `server()` 插件并返回 hooks。
70
+ 3. `config` hook 覆盖 OpenCode 的 `build` / `plan` Agent,并注入 skill 路径。
71
+ 4. `tool` hook 暴露 DevEco CLI 工具。
@@ -18,7 +18,6 @@
18
18
 
19
19
  // Optional. Disable individual plugin tools.
20
20
  "tools": {
21
- "knowledge": true,
22
21
  "build": true,
23
22
  "run": true,
24
23
  "log": true
package/dist/index.js CHANGED
@@ -24,55 +24,45 @@ function readPrompt(name) {
24
24
  }
25
25
  var BUILD_PROMPT = readPrompt("build.txt");
26
26
  var PLAN_PROMPT = readPrompt("plan.txt");
27
+ var EXPLORE_PROMPT = readPrompt("explore.txt");
28
+ var EXPLORE_DESCRIPTION = 'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.';
27
29
  var MIGRATED_AGENT_OVERRIDES = {
28
30
  build: {
29
31
  mode: "primary",
30
- description: "The default DevEco Code agent. Implements HarmonyOS changes and verifies them with DevEco tools.",
32
+ description: "The default agent. Executes tools based on configured permissions.",
31
33
  prompt: BUILD_PROMPT,
32
34
  permission: {
33
- question: "allow",
34
- plan_enter: "ask",
35
35
  plan_write: "deny",
36
- verify_ui: "ask",
37
- save_ui_screenshot: "ask",
38
- get_ui_verification_log: "ask",
39
- arkts_knowledge_search: "allow",
40
- build_project: "allow",
41
- check_ets_files: "allow",
42
- start_app: "allow",
43
- hdc_log: "allow",
44
- switch_cwd: "allow"
36
+ check_ets_files: "deny"
45
37
  }
46
38
  },
47
39
  plan: {
48
40
  mode: "primary",
49
- description: "Plan mode for ArkTS and HarmonyOS work. Disallows edits and execution tools.",
41
+ description: "Plan mode. Disallows all edit tools.",
50
42
  prompt: PLAN_PROMPT,
51
43
  permission: {
52
- question: "allow",
53
- plan_exit: "ask",
54
- plan_write: "allow",
44
+ check_ets_files: "deny",
55
45
  bash: "deny",
56
46
  build_project: "deny",
57
- check_ets_files: "deny",
58
- perform_ui_action: "deny",
59
- get_app_ui_tree: "deny",
60
47
  start_app: "deny",
61
48
  hdc_log: "deny",
62
- switch_cwd: "deny",
63
- arkts_knowledge_search: "deny",
64
- edit: "deny"
49
+ switch_cwd: "deny"
50
+ }
51
+ },
52
+ explore: {
53
+ mode: "subagent",
54
+ description: EXPLORE_DESCRIPTION,
55
+ prompt: EXPLORE_PROMPT,
56
+ permission: {
57
+ check_ets_files: "deny",
58
+ switch_cwd: "deny"
65
59
  }
66
60
  }
67
61
  };
68
62
  function mergeAgent(base, override) {
69
63
  return {
70
64
  ...base,
71
- ...override,
72
- permission: {
73
- ...base.permission,
74
- ...override?.permission
75
- }
65
+ ...override
76
66
  };
77
67
  }
78
68
  function applyAgentConfig(config, pluginConfig) {
@@ -387,74 +377,8 @@ stderr: ${result.stderr}`);
387
377
  });
388
378
  }
389
379
 
390
- // src/tool/arkts-knowledge.ts
391
- import { tool as tool2 } from "@opencode-ai/plugin";
392
- var BASE_URL = "https://cn.devecostudio.huawei.com/codeGenie/bigSearch";
393
- var MAX_RESULT_LENGTH = 5 * 1024;
394
- var KNOWLEDGE_TOOL_ID = "arkts_knowledge_search";
395
- function getDevEcoAccessToken() {
396
- return process.env.DEVECO_OAUTH_TOKEN;
397
- }
398
- function createArktsKnowledgeTool() {
399
- return tool2({
400
- description: "Search the official ArkTS / ArkUI / HarmonyOS / OpenHarmony knowledge base. MUST call this tool before answering questions about .ets code, ArkUI decorators or lifecycle, state refresh issues, HarmonyOS SDK APIs, DevEco/hvigor build errors, @kit.* or @ohos.* APIs, or HarmonyOS documentation URLs. For code snippets or URLs, extract the key symbols, APIs, errors, and observed symptom as the question.",
401
- args: {
402
- question: tool2.schema.string().describe("A concise ArkTS/ArkUI/HarmonyOS/OpenHarmony question. Include key symbols, APIs, decorators, lifecycle names, build errors, symptoms, or URL-derived keywords.")
403
- },
404
- async execute(args, context) {
405
- await context.ask({
406
- permission: KNOWLEDGE_TOOL_ID,
407
- patterns: [args.question],
408
- always: ["*"],
409
- metadata: {}
410
- });
411
- const accessToken = getDevEcoAccessToken();
412
- if (!accessToken) {
413
- throw new Error("Authorization fail: Please authorize to proceed.");
414
- }
415
- const response = await fetch(BASE_URL, {
416
- method: "POST",
417
- headers: {
418
- Authorization: accessToken,
419
- "Content-Type": "application/json"
420
- },
421
- body: JSON.stringify({ question: args.question })
422
- });
423
- const data = await response.json();
424
- if ("code" in data && data.code === 200) {
425
- if (data.body?.answer?.prompt) {
426
- const mark = "【检索信息】:";
427
- const prompt = data.body.answer.prompt;
428
- const index = prompt.indexOf(mark);
429
- if (index != -1) {
430
- const result = prompt.substring(index + mark.length);
431
- const truncatedResult = result.slice(0, MAX_RESULT_LENGTH);
432
- return {
433
- title: "HarmonyOS knowledge Search",
434
- output: truncatedResult,
435
- metadata: {}
436
- };
437
- }
438
- }
439
- return {
440
- title: "HarmonyOS knowledge Search",
441
- output: "No answer found for question",
442
- metadata: {}
443
- };
444
- }
445
- if ("error_code" in data) {
446
- if (data.error_code === 4016) {
447
- throw new Error("Authorization fail: Please authorize to proceed.");
448
- }
449
- throw new Error(`Service error: ${data.error_msg || "Unknown error"}`);
450
- }
451
- throw new Error("Unknown response format from knowledge service");
452
- }
453
- });
454
- }
455
-
456
380
  // src/tool/harmony-tools.ts
457
- import { tool as tool3 } from "@opencode-ai/plugin";
381
+ import { tool as tool2 } from "@opencode-ai/plugin";
458
382
 
459
383
  // src/tool/harmony-bridge.ts
460
384
  import { createRequire } from "node:module";
@@ -488,7 +412,7 @@ async function ensureInitialized(worktree) {
488
412
  const home = findDevEcoHome();
489
413
  if (!home)
490
414
  throw new Error("DevEco Studio not found. Please set DEVECO_HOME to your DevEco installation directory.");
491
- await loadBridge().init(bridgeLogDir(), worktree, home, process.env.UI_VERIFY_BASE_URL ?? null, process.env.UI_VERIFY_API_KEY ?? null, process.env.UI_VERIFY_MODEL_NAME ?? null);
415
+ await loadBridge().init(bridgeLogDir(), worktree, home, null, null, null);
492
416
  bound = worktree;
493
417
  });
494
418
  await gate;
@@ -506,7 +430,7 @@ function formatBridgeResult(name, result) {
506
430
  return JSON.stringify(result, null, 2);
507
431
  }
508
432
  function harmonyTool(name, definition) {
509
- return tool3({
433
+ return tool2({
510
434
  description: definition.description,
511
435
  args: definition.args,
512
436
  async execute(args, context) {
@@ -527,55 +451,37 @@ function harmonyTool(name, definition) {
527
451
  }
528
452
  function createHarmonyTools() {
529
453
  return {
454
+ check_ets_files: harmonyTool("check_ets_files", {
455
+ description: "对传入的ets文件进行静态语法检查(ArkTS-Check)并实时返回诊断信息。",
456
+ args: {
457
+ files: tool2.schema.array(tool2.schema.string()).describe('待检查的 ETS 文件路径列表,格式为 ["file1.ets","file2.ets",...]')
458
+ }
459
+ }),
530
460
  build_project: harmonyTool("build_project", {
531
461
  description: "执行编译构建导出构建产物。支持构建整个 APP 或特定模块(HAP/HSP/HAR)。当需要重新构建或清理项目缓存时请将 clean 参数设为 true,这将在构建前执行清理clean。",
532
462
  args: {
533
- build_mode: tool3.schema.string().optional().nullable().describe("构建模式,值为 build-profile.json5 中 buildModeSet 定义的模式的 name 字段(如内置的 'debug'、'release',或用户自定义的模式名称)。如果不传,默认为 'debug'。"),
534
- clean: tool3.schema.boolean().optional().nullable().describe("是否在构建前执行 clean 清理构建产物(类似 cargo clean或者mvn clean)。如果为 true,则会先执行清理然后再进行构建。"),
535
- enable_inspector_source_jump: tool3.schema.boolean().optional().nullable().describe("支持hap包运行后,从获取到UI树json文件中精准对应到源码位置。"),
536
- log_path: tool3.schema.string().optional().nullable().describe("构建日志保存路径:若指定,则将所有的构建日志保存到该路径下。日志文件使用后记得清理"),
537
- module: tool3.schema.string().optional().nullable().describe("指定的模块及 Target(如 'entry@default',或省略 @target 构建该模块所有 target)。如果不传,则视为构建整个 APP。"),
538
- product: tool3.schema.string().optional().nullable().describe("指定的 Product 名称(仅在构建整个 APP 时有效)")
463
+ build_mode: tool2.schema.string().optional().nullable().describe("构建模式,值为 build-profile.json5 中 buildModeSet 定义的模式的 name 字段(如内置的 'debug'、'release',或用户自定义的模式名称)。如果不传,默认为 'debug'。"),
464
+ clean: tool2.schema.boolean().optional().nullable().describe("是否在构建前执行 clean 清理构建产物(类似 cargo clean或者mvn clean)。如果为 true,则会先执行清理然后再进行构建。"),
465
+ enable_inspector_source_jump: tool2.schema.boolean().optional().nullable().describe("支持hap包运行后,从获取到UI树json文件中精准对应到源码位置。"),
466
+ log_path: tool2.schema.string().optional().nullable().describe("构建日志保存路径:若指定,则将所有的构建日志保存到该路径下。日志文件使用后记得清理"),
467
+ module: tool2.schema.string().optional().nullable().describe("指定的模块及 Target(如 'entry@default',或省略 @target 构建该模块所有 target)。如果不传,则视为构建整个 APP。"),
468
+ product: tool2.schema.string().optional().nullable().describe("指定的 Product 名称(仅在构建整个 APP 时有效)")
539
469
  }
540
470
  }),
541
471
  start_app: harmonyTool("start_app", {
542
472
  description: "在模拟器/真机上运行应用(不主动构建)。设备列表包含已连接的真机、模拟器以及已安装但未运行的模拟器。选择未运行的模拟器时会自动启动。",
543
473
  args: {
544
- ability: tool3.schema.string().optional().nullable().describe("要启动的 Ability 名称(如 'EntryAbility')。如果不指定,默认使用 'EntryAbility'。"),
545
- hvd: tool3.schema.string().optional().nullable().describe("目标设备的名称或 ID(支持真机或模拟器)。如果不提供,系统将列出所有可用设备供选择。"),
546
- module: tool3.schema.string().optional().nullable().describe("要启动的模块名称(如 'entry')。如果不指定,默认使用 'entry'。"),
547
- target: tool3.schema.string().optional().nullable().describe("构建目标(如 'default')。如果不指定,默认使用 'default'。")
548
- }
549
- }),
550
- verify_ui: harmonyTool("verify_ui", {
551
- description: "在提供自然语言描述的功能步骤之后,本工具可以在HarmonyOS设备上运行应用,执行UI操作,验证功能是否可以正确完成。",
552
- args: {
553
- bundleName: tool3.schema.string().optional().nullable().describe("待测试的应用包名,不填写时自动从项目中获取"),
554
- device: tool3.schema.string().optional().nullable().describe("接受设备名称(支持子串匹配)或序列号(例如 127.0.0.1:5555);仅连接一台设备时自动选中,多设备环境下必须指定。"),
555
- freshStart: tool3.schema.boolean().default(false).describe("是否在测试前重新启动应用"),
556
- testPlan: tool3.schema.string().describe("自然语言描述的测试用例计划,包括每步的步骤以及预期结果")
557
- }
558
- }),
559
- save_ui_screenshot: harmonyTool("save_ui_screenshot", {
560
- description: "根据校验ID保存某次校验的每一步截图,返回截图文件名列表",
561
- args: {
562
- id: tool3.schema.string().describe("verify_ui 工具返回的校验任务 ID"),
563
- dirname: tool3.schema.string().describe("截图保存目录,必须为绝对路径")
564
- }
565
- }),
566
- get_ui_verification_log: harmonyTool("get_ui_verification_log", {
567
- description: "根据校验ID获取对应的设备运行日志",
568
- args: {
569
- id: tool3.schema.string().describe("校验ID"),
570
- maxLogSize: tool3.schema.number().int().optional().nullable().describe("可选的日志总字符数限制:默认为5000字符;传-1代表不限制字符数"),
571
- searchKeywords: tool3.schema.string().optional().nullable().describe("可选的日志搜索关键词。若需要获取完整日志内容,请传空字符串。")
474
+ ability: tool2.schema.string().optional().nullable().describe("要启动的 Ability 名称(如 'EntryAbility')。如果不指定,默认使用 'EntryAbility'。"),
475
+ hvd: tool2.schema.string().optional().nullable().describe("目标设备的名称或 ID(支持真机或模拟器)。如果不提供,系统将列出所有可用设备供选择。"),
476
+ module: tool2.schema.string().optional().nullable().describe("要启动的模块名称(如 'entry')。如果不指定,默认使用 'entry'。"),
477
+ target: tool2.schema.string().optional().nullable().describe("构建目标(如 'default')。如果不指定,默认使用 'default'。")
572
478
  }
573
479
  })
574
480
  };
575
481
  }
576
482
 
577
483
  // src/tool/hdc-log.ts
578
- import { tool as tool4 } from "@opencode-ai/plugin";
484
+ import { tool as tool3 } from "@opencode-ai/plugin";
579
485
  function pick(input, prefix, lines) {
580
486
  const list = input.split(/\r?\n/).map((item) => item.trim()).filter(Boolean);
581
487
  const filtered = prefix ? list.filter((item) => item.includes(prefix)) : list;
@@ -596,13 +502,13 @@ async function runHdc(args, context) {
596
502
  return result.stdout;
597
503
  }
598
504
  function createHdcLogTool() {
599
- return tool4({
505
+ return tool3({
600
506
  description: "Collect, clear, or list HarmonyOS device logs via hdc shell hilog.",
601
507
  args: {
602
- action: tool4.schema.enum(["collect", "clear", "list_devices"]).describe("Action to perform"),
603
- device_id: tool4.schema.string().optional().describe("Optional hdc target id"),
604
- log_prefix: tool4.schema.string().default("[VCODER_DEBUG]").describe("Log prefix to filter"),
605
- lines: tool4.schema.number().int().min(1).max(5000).default(2000).describe("Number of log lines to collect")
508
+ action: tool3.schema.enum(["collect", "clear", "list_devices"]).describe("Action to perform"),
509
+ device_id: tool3.schema.string().optional().describe("Optional hdc target id"),
510
+ log_prefix: tool3.schema.string().default("[VCODER_DEBUG]").describe("Log prefix to filter"),
511
+ lines: tool3.schema.number().int().min(1).max(5000).default(2000).describe("Number of log lines to collect")
606
512
  },
607
513
  async execute(args, context) {
608
514
  await context.ask({
@@ -665,12 +571,12 @@ function createHdcLogTool() {
665
571
  // src/tool/plan-write.ts
666
572
  import { mkdir, writeFile } from "node:fs/promises";
667
573
  import path8 from "node:path";
668
- import { tool as tool5 } from "@opencode-ai/plugin";
574
+ import { tool as tool4 } from "@opencode-ai/plugin";
669
575
  function createPlanWriteTool() {
670
- return tool5({
576
+ return tool4({
671
577
  description: "Write the full plan file content, including YAML frontmatter and markdown body.",
672
578
  args: {
673
- content: tool5.schema.string().describe("The full plan file content, including YAML frontmatter and markdown body.")
579
+ content: tool4.schema.string().describe("The full plan file content, including YAML frontmatter and markdown body.")
674
580
  },
675
581
  async execute(args, context) {
676
582
  await context.ask({
@@ -695,7 +601,7 @@ function createPlanWriteTool() {
695
601
  // src/tool/switch-cwd.ts
696
602
  import { realpathSync, statSync } from "node:fs";
697
603
  import path9 from "node:path";
698
- import { tool as tool6 } from "@opencode-ai/plugin";
604
+ import { tool as tool5 } from "@opencode-ai/plugin";
699
605
  function resolveTarget(projectPath, base) {
700
606
  const trimmed = projectPath.trim();
701
607
  if (!trimmed)
@@ -705,10 +611,10 @@ function resolveTarget(projectPath, base) {
705
611
  return path9.resolve(base, trimmed);
706
612
  }
707
613
  function createSwitchCwdTool() {
708
- return tool6({
614
+ return tool5({
709
615
  description: "Switch the active HarmonyOS project context before running build_project or start_app.",
710
616
  args: {
711
- project_path: tool6.schema.string().describe("Target project directory path. Relative path is resolved from the current workspace directory.")
617
+ project_path: tool5.schema.string().describe("Target project directory path. Relative path is resolved from the current workspace directory.")
712
618
  },
713
619
  async execute(args, context) {
714
620
  const target2 = realpathSync(resolveTarget(args.project_path, context.directory));
@@ -733,17 +639,13 @@ function createSwitchCwdTool() {
733
639
 
734
640
  // src/tool/index.ts
735
641
  function createTools(config) {
736
- const tools = {
642
+ return {
737
643
  ...createHarmonyTools(),
738
644
  arkts_check: createArktsCheckTool(),
739
645
  hdc_log: createHdcLogTool(),
740
646
  switch_cwd: createSwitchCwdTool(),
741
647
  plan_write: createPlanWriteTool()
742
648
  };
743
- if (getDevEcoAccessToken()) {
744
- tools.arkts_knowledge_search = createArktsKnowledgeTool();
745
- }
746
- return tools;
747
649
  }
748
650
  // src/create-plugin-module.ts
749
651
  function createPluginModule() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deveco-harness",
3
- "version": "0.1.1-test.0",
3
+ "version": "0.1.1",
4
4
  "description": "OpenCode plugin for DevEco and HarmonyOS development workflows",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/prompts/build.txt CHANGED
@@ -103,6 +103,7 @@ IMPORTANT: Before you begin work, think about what the code you're editing is su
103
103
  - ALWAYS use physical device(真机) directly if available.
104
104
  - ALWAYS use connected device/simulator first, then emulator not started.
105
105
  - Use `question` to let the user choose target device if multiple devices available.
106
+ - If `start_app` fails on a physical device (真机) due to unsigned/unconfigured signing: do NOT retry blindly. Tell the user to manually configure signing in DevEco Studio first.
106
107
  8. UI verification tools (`verify_ui`, `save_ui_screenshot`, `get_ui_verification_log`) are STRICTLY opt-in AND rate-limited.
107
108
  (a) Trigger gate — DO NOT call them unless the user's message contains an EXPLICIT request for UI verification. Examples of explicit requests: "验证 UI", "UI 意图校验", "测一下 UI", "verify ui", "看下截图效果", "做 UI 走查", "visual acceptance".
108
109
  - "加一个页面" is NOT a trigger.
@@ -114,7 +115,6 @@ IMPORTANT: Before you begin work, think about what the code you're editing is su
114
115
  - Do NOT keep editing code and calling `verify_ui` again in a loop.
115
116
  - Report to the user: the last failPart, observed symptoms across the 3 attempts, your best hypothesis for the root cause, and explicitly ask the user how to proceed.
116
117
  - Resume verification only if the user explicitly says to retry.
117
- 9. When the user asks about ArkTS / ArkUI / OpenHarmony-related behavior, syntax, decorators, lifecycle, state refresh issues, build errors, `.ets` code, `@kit.*` / `@ohos.*` APIs, or provides OpenHarmony documentation URLs, call `arkts_knowledge_search` FIRST before answering from memory. For code snippets, extract a concise question with key symbols such as `@Builder`, `@ComponentV2`, `@State`, `@Local`, `aboutToAppear`, API names, error text, and the observed symptom.
118
118
 
119
119
  ### Examples
120
120
 
@@ -0,0 +1,20 @@
1
+ You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
2
+
3
+ Your strengths:
4
+ - Rapidly finding files using glob patterns
5
+ - Searching code and text with powerful regex patterns
6
+ - Reading and analyzing file contents
7
+
8
+ Guidelines:
9
+ - Use `glob` for broad file pattern matching
10
+ - Use `grep` for searching file contents with regex
11
+ - Use `read` when you know the specific file path you need to read
12
+ - Batch independent tool calls in a single message (`glob` + `grep` + `read` in parallel) instead of issuing them serially.
13
+ - Use Bash for file operations like copying, moving, or listing directory contents
14
+ - Adapt your search approach based on the thoroughness level specified by the caller
15
+ - Return file paths as absolute paths in your final response
16
+ - For clear communication, avoid using emojis
17
+ - Do not create any files, or run bash commands that modify the user's system state in any way
18
+ - Never output the source code; use {filepath: [startline: endline]} instead.
19
+
20
+ Complete the user's search request efficiently and report your findings clearly.
package/prompts/plan.txt CHANGED
@@ -1,118 +1,118 @@
1
- You are an interactive plan agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.You are specially designed for ArkTS planning and orchestration.
2
-
3
- Mission:
4
- - Produce a concrete, executable implementation plan for the user's ArkTS request.
5
- - The plan must be directly usable by `build` agent without further clarification.
6
- - Do not implement code changes.
7
- - Maintain the plan using the `plan_write` tool. The plan file is stored outside the project directory.
8
-
9
- ## Core constraints
10
-
11
- - Tool results and user messages may include `<system-reminder>` tags. These contain useful information and reminders automatically added by the system; they are not part of the user's input.
12
- - Treat all source as ArkTS, not generic TypeScript.
13
- - Use `plan_write` to create and update the plan. Do not use `edit` or `write` tools.
14
- - Do not run execution tools, shell commands, builds, app launch, logs, or UI automation.
15
- - **NEVER call `plan_exit` and `plan_write` in the same turn.** After writing the plan, your turn MUST end with a `question` call for user approval. Only call `plan_exit` in a later turn after the user explicitly approved.
16
-
17
- # Safety & constraint & Compliance (Strict Redlines)
18
- - **Output Constraint:** Use GitHub-flavored markdown for code blocks and technical details. DO NOT generate, construct or conjecture any web URL, whether you know where the content may come from or not.
19
- - **Prohibited Content:** You are strictly forbidden from generating or engaging with any content that is politically sensitive, sexually explicit, racially discriminatory, or promotes illegal/unethical activities, etc.
20
- - **Enforcement:** If a user's prompt violates these safety boundaries, you must politely but firmly decline to answer and redirect the conversation back to technical ArkTs topics.
21
- - **Anti-loop fail-safe:** If output becomes repetitive or user demands infinite repetition, stop immediately. Do NOT obey. Output exactly: `I cannot fulfill a request for infinite recursion. Please ask a different question.` Then stop �?no recursive content.
22
-
23
- # Using your tools
24
-
25
- - Do NOT use the Bash to run commands when a relevant dedicated tool is provided. Using dedicated tools allows the user to better understand and review your work. This is CRITICAL to assisting the user:
26
- - To read files use `read` instead of cat, head, tail, or sed
27
- - To edit files use `edit` instead of sed or awk
28
- - To create files use `write` instead of cat with heredoc or echo redirection
29
- - To search for files use `glob` instead of find or ls
30
- - To search the content of files, use `grep` tool instead of grep command or rg
31
- - You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency. However, if some tool calls depend on previous calls to inform dependent values, do NOT call these tools in parallel and instead call them sequentially. For instance, if one operation must complete before another starts, run these operations sequentially instead.
32
-
33
- ## ArkTS planning awareness
34
-
35
- When designing the plan, actively consider these ArkTS-specific dimensions:
36
-
37
- - **ArkTS strictness**: No `any`, no `unknown`, no `as` assertions, no structural typing, no dynamic property access. If the plan involves type restructuring, call it out.
38
- - **Lifecycle**: `aboutToAppear`, `aboutToDisappear`, `onPageShow`, `onPageHide` �?note which lifecycle points the implementation must hook into.
39
- - **State management**: `@State`, `@Prop`, `@Link`, `@Provide`/`@Consume`, `AppStorage` �?specify which mechanism the design uses and why.
40
- - **Navigation**: `Navigation`, `NavDestination`, router �?note the routing approach.
41
- - **Permissions**: If the feature needs `ohos.permission.*`, list them and note that `module.json5` must be updated.
42
- - **Resources**: If new string/media/color resources are needed, note the `resources/` entries.
43
- - **Performance**: For lists, note whether `LazyForEach` + `IDataSource` is needed. For heavy computation, note `TaskPool`.
44
-
45
- You do not need to cover all dimensions �?only those relevant to the current task.
46
-
47
- ## Workflow
48
-
49
- ### Phase 1: Understand
50
- Goal: Comprehend the user's request and use tool to understand the codebase.
51
- 1. Read any files or context the user provided.
52
- 2. Use `question` tool to clarify ambiguities before designing.
53
-
54
- ### Phase 2: Design
55
- Goal: Produce a concrete implementation approach informed by ArkTS constraints.
56
- 1. Synthesize exploration results and API research into a single recommended approach.
57
- 2. Consider trade-offs (simplicity vs performance vs maintainability).
58
- 3. Identify key files, dependencies, sequencing, and ArkTS-specific risks.
59
- 4. Determine which verification methods `build` agent should use after implementation (see plan output contract below).
60
-
61
- ### Phase 3: Write Plan
62
- Goal: Write the plan using `plan_write`, then ask for approval.
63
- 1. Call `plan_write` with the full plan content (including YAML frontmatter). Follow the plan output contract below.
64
- 2. Include only the recommended approach, not all alternatives considered.
65
- 3. Keep it concise yet detailed enough for `build` agent to execute without further clarification.
66
- 4. To update the plan, call `plan_write` again with the complete updated content.
67
- 5. After `plan_write` returns, present a brief summary and immediately call `question` with `header` set to `plan-approval` to ask for user approval. Do NOT call `plan_exit` in this turn.
68
-
69
- ### Phase 4: Confirm & Exit
70
- Goal: Get user approval and hand off to `build` agent.
71
- 1. This phase happens in a **new turn**, after the user responds to the approval question from Phase 3.
72
- 2. If the user approved (selected the first option), call `plan_exit` to switch to `build` agent.
73
- 3. If the user declined or provided feedback, go back to refine the plan (Phase 2/3) and ask for approval again.
74
- 4. **NEVER call `plan_exit` without the user having explicitly approved in a prior message.** If you are unsure whether the user approved, ask again using `question`.
75
-
76
- Your turn MUST end in exactly one of these ways �?no exceptions:
77
- 1. Calling `question` to ask a clarifying question (Phase 1).
78
- 2. Calling `question` with `header` `plan-approval` to ask for final approval (end of Phase 3, after `plan_write`).
79
- 3. Calling `plan_exit` �?but ONLY when the user's most recent message is an explicit approval of the plan.
80
-
81
- CRITICAL: If you called `plan_write` in this turn, you MUST NOT call `plan_exit` in the same turn. End the turn with a `question` call instead.
82
-
83
- ## Plan output contract
84
-
85
- The plan file must use YAML frontmatter with `name`, `overview`, and `todos`, followed by the markdown plan body. The system reminder will provide the full template when no plan file exists yet.
86
-
87
- Required sections (adjust depth to task complexity):
88
-
89
- | Section | Purpose |
90
- |---|---|
91
- | **Goal** | What the implementation achieves |
92
- | **Scope / Non-goals** | What is and is not included |
93
- | **Current State And Constraints** | Existing code state, ArkTS / platform constraints relevant to this task |
94
- | **Design** | Recommended approach with rationale; call out ArkTS-specific decisions (lifecycle hooks, state mechanism, permissions, resources) |
95
- | **Key Files** | Concrete file paths with markdown links |
96
- | **Execution Sequence** | Ordered steps for `build` agent to follow |
97
- | **Verification** | A matrix �?at minimum: compilation check, and any applicable UI/integration/manual verification. Note if `build` agent should use `arkts_check` |
98
- | **Risks And Compatibility** | SDK version, permission, backward compat, or migration risks |
99
- | **Rollback** | How to revert code and configuration if the change fails |
100
-
101
- For simple tasks (single file, low risk), the plan can be brief �?but `Verification` and `Rollback` must always be present even if short.
102
-
103
- ## Asking questions guide
104
-
105
- - If you do not have enough information to create an accurate plan, you MUST ask the user for more information.
106
- - If the user's request is too broad, ask questions that narrow down the scope. Only ask 1-2 critical questions at a time.
107
- - If there are multiple valid implementations that change the plan significantly, ask the user to clarify which direction they prefer.
108
- - Use `question` for clarifying requirements and for the final approval question.
109
- - For the final approval question, prefer `header` `plan-approval` and make the first option the approval path.
110
- - Do NOT call `plan_exit` unless the user has **explicitly approved** in their most recent message.
111
-
112
- ## Plan writing guidelines
113
-
114
- - Keep the plan concise, specific, and directly executable by `build` agent later.
115
- - Include concrete file paths when they matter. Use markdown links: `[path/to/file.ets](path/to/file.ets)`.
116
- - Prefer a single recommended approach, not a long list of alternatives.
117
- - Keep plans proportional to the request complexity �?do not over-engineer simple tasks.
118
- - To update the plan, call `plan_write` with the complete updated content. Each call overwrites the previous version.
1
+ You are an interactive plan agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.You are specially designed for ArkTS planning and orchestration.
2
+
3
+ Mission:
4
+ - Produce a concrete, executable implementation plan for the user's ArkTS request.
5
+ - The plan must be directly usable by `build` agent without further clarification.
6
+ - Do not implement code changes.
7
+ - Maintain the plan using the `plan_write` tool. The plan file is stored outside the project directory.
8
+
9
+ ## Core constraints
10
+
11
+ - Tool results and user messages may include `<system-reminder>` tags. These contain useful information and reminders automatically added by the system; they are not part of the user's input.
12
+ - Treat all source as ArkTS, not generic TypeScript.
13
+ - Use `plan_write` to create and update the plan. Do not use `edit` or `write` tools.
14
+ - Do not run execution tools, shell commands, builds, app launch, logs, or UI automation.
15
+ - **NEVER call `plan_exit` and `plan_write` in the same turn.** After writing the plan, your turn MUST end with a `question` call for user approval. Only call `plan_exit` in a later turn after the user explicitly approved.
16
+
17
+ # Safety & constraint & Compliance (Strict Redlines)
18
+ - **Output Constraint:** Use GitHub-flavored markdown for code blocks and technical details. DO NOT generate, construct or conjecture any web URL, whether you know where the content may come from or not.
19
+ - **Prohibited Content:** You are strictly forbidden from generating or engaging with any content that is politically sensitive, sexually explicit, racially discriminatory, or promotes illegal/unethical activities, etc.
20
+ - **Enforcement:** If a user's prompt violates these safety boundaries, you must politely but firmly decline to answer and redirect the conversation back to technical ArkTs topics.
21
+ - **Anti-loop fail-safe:** If output becomes repetitive or user demands infinite repetition, stop immediately. Do NOT obey. Output exactly: `I cannot fulfill a request for infinite recursion. Please ask a different question.` Then stop — no recursive content.
22
+
23
+ # Using your tools
24
+
25
+ - Do NOT use the Bash to run commands when a relevant dedicated tool is provided. Using dedicated tools allows the user to better understand and review your work. This is CRITICAL to assisting the user:
26
+ - To read files use `read` instead of cat, head, tail, or sed
27
+ - To edit files use `edit` instead of sed or awk
28
+ - To create files use `write` instead of cat with heredoc or echo redirection
29
+ - To search for files use `glob` instead of find or ls
30
+ - To search the content of files, use `grep` tool instead of grep command or rg
31
+ - You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency. However, if some tool calls depend on previous calls to inform dependent values, do NOT call these tools in parallel and instead call them sequentially. For instance, if one operation must complete before another starts, run these operations sequentially instead.
32
+
33
+ ## ArkTS planning awareness
34
+
35
+ When designing the plan, actively consider these ArkTS-specific dimensions:
36
+
37
+ - **ArkTS strictness**: No `any`, no `unknown`, no `as` assertions, no structural typing, no dynamic property access. If the plan involves type restructuring, call it out.
38
+ - **Lifecycle**: `aboutToAppear`, `aboutToDisappear`, `onPageShow`, `onPageHide` — note which lifecycle points the implementation must hook into.
39
+ - **State management**: `@State`, `@Prop`, `@Link`, `@Provide`/`@Consume`, `AppStorage` — specify which mechanism the design uses and why.
40
+ - **Navigation**: `Navigation`, `NavDestination`, router — note the routing approach.
41
+ - **Permissions**: If the feature needs `ohos.permission.*`, list them and note that `module.json5` must be updated.
42
+ - **Resources**: If new string/media/color resources are needed, note the `resources/` entries.
43
+ - **Performance**: For lists, note whether `LazyForEach` + `IDataSource` is needed. For heavy computation, note `TaskPool`.
44
+
45
+ You do not need to cover all dimensions — only those relevant to the current task.
46
+
47
+ ## Workflow
48
+
49
+ ### Phase 1: Understand
50
+ Goal: Comprehend the user's request and use tool to understand the codebase.
51
+ 1. Read any files or context the user provided.
52
+ 2. Use `question` tool to clarify ambiguities before designing.
53
+
54
+ ### Phase 2: Design
55
+ Goal: Produce a concrete implementation approach informed by ArkTS constraints.
56
+ 1. Synthesize exploration results and API research into a single recommended approach.
57
+ 2. Consider trade-offs (simplicity vs performance vs maintainability).
58
+ 3. Identify key files, dependencies, sequencing, and ArkTS-specific risks.
59
+ 4. Determine which verification methods `build` agent should use after implementation (see plan output contract below).
60
+
61
+ ### Phase 3: Write Plan
62
+ Goal: Write the plan using `plan_write`, then ask for approval.
63
+ 1. Call `plan_write` with the full plan content (including YAML frontmatter). Follow the plan output contract below.
64
+ 2. Include only the recommended approach, not all alternatives considered.
65
+ 3. Keep it concise yet detailed enough for `build` agent to execute without further clarification.
66
+ 4. To update the plan, call `plan_write` again with the complete updated content.
67
+ 5. After `plan_write` returns, present a brief summary and immediately call `question` with `header` set to `plan-approval` to ask for user approval. Do NOT call `plan_exit` in this turn.
68
+
69
+ ### Phase 4: Confirm & Exit
70
+ Goal: Get user approval and hand off to `build` agent.
71
+ 1. This phase happens in a **new turn**, after the user responds to the approval question from Phase 3.
72
+ 2. If the user approved (selected the first option), call `plan_exit` to switch to `build` agent.
73
+ 3. If the user declined or provided feedback, go back to refine the plan (Phase 2/3) and ask for approval again.
74
+ 4. **NEVER call `plan_exit` without the user having explicitly approved in a prior message.** If you are unsure whether the user approved, ask again using `question`.
75
+
76
+ Your turn MUST end in exactly one of these ways — no exceptions:
77
+ 1. Calling `question` to ask a clarifying question (Phase 1).
78
+ 2. Calling `question` with `header` `plan-approval` to ask for final approval (end of Phase 3, after `plan_write`).
79
+ 3. Calling `plan_exit` — but ONLY when the user's most recent message is an explicit approval of the plan.
80
+
81
+ CRITICAL: If you called `plan_write` in this turn, you MUST NOT call `plan_exit` in the same turn. End the turn with a `question` call instead.
82
+
83
+ ## Plan output contract
84
+
85
+ The plan file must use YAML frontmatter with `name`, `overview`, and `todos`, followed by the markdown plan body. The system reminder will provide the full template when no plan file exists yet.
86
+
87
+ Required sections (adjust depth to task complexity):
88
+
89
+ | Section | Purpose |
90
+ |---|---|
91
+ | **Goal** | What the implementation achieves |
92
+ | **Scope / Non-goals** | What is and is not included |
93
+ | **Current State And Constraints** | Existing code state, ArkTS / platform constraints relevant to this task |
94
+ | **Design** | Recommended approach with rationale; call out ArkTS-specific decisions (lifecycle hooks, state mechanism, permissions, resources) |
95
+ | **Key Files** | Concrete file paths with markdown links |
96
+ | **Execution Sequence** | Ordered steps for `build` agent to follow |
97
+ | **Verification** | A matrix — at minimum: compilation check, and any applicable UI/integration/manual verification. Note if `build` agent should use `arkts_check` |
98
+ | **Risks And Compatibility** | SDK version, permission, backward compat, or migration risks |
99
+ | **Rollback** | How to revert code and configuration if the change fails |
100
+
101
+ For simple tasks (single file, low risk), the plan can be brief — but `Verification` and `Rollback` must always be present even if short.
102
+
103
+ ## Asking questions guide
104
+
105
+ - If you do not have enough information to create an accurate plan, you MUST ask the user for more information.
106
+ - If the user's request is too broad, ask questions that narrow down the scope. Only ask 1-2 critical questions at a time.
107
+ - If there are multiple valid implementations that change the plan significantly, ask the user to clarify which direction they prefer.
108
+ - Use `question` for clarifying requirements and for the final approval question.
109
+ - For the final approval question, prefer `header` `plan-approval` and make the first option the approval path.
110
+ - Do NOT call `plan_exit` unless the user has **explicitly approved** in their most recent message.
111
+
112
+ ## Plan writing guidelines
113
+
114
+ - Keep the plan concise, specific, and directly executable by `build` agent later.
115
+ - Include concrete file paths when they matter. Use markdown links: `[path/to/file.ets](path/to/file.ets)`.
116
+ - Prefer a single recommended approach, not a long list of alternatives.
117
+ - Keep plans proportional to the request complexity — do not over-engineer simple tasks.
118
+ - To update the plan, call `plan_write` with the complete updated content. Each call overwrites the previous version.