@cydm/pie 1.0.23 → 1.0.24

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.md CHANGED
@@ -20,7 +20,7 @@ Pie is developed by [cydream](https://cydream.tech).
20
20
  npm install -g @cydm/pie
21
21
  ```
22
22
 
23
- Pie supports Node.js 20 and newer. Release builds are validated with npm's lockfile workflow (`npm ci`) so dependency resolution is reproducible.
23
+ Pie requires Node.js 20.19 or newer. Release builds are validated with npm's lockfile workflow (`npm ci`) so dependency resolution is reproducible.
24
24
 
25
25
  ## Quick Start
26
26
 
@@ -199,6 +199,7 @@ Pie uses a hierarchical slash-command menu. The current built-in commands includ
199
199
  | `/skills/list` | List available skills |
200
200
  | `/skills/use` | Use a skill |
201
201
  | `/skills/reload` | Reload skills from disk |
202
+ | `/extensions` | List extensions and toggle enable/disable |
202
203
  | `/tools/subagent` | Spawn a subagent for a task |
203
204
  | `/debugs/cache-test` | Run provider cache diagnostics with a dedicated 2-request probe |
204
205
  | `/debugs/context` | Append a context summary to `~/.pie/logs/pie-cli.log` |
@@ -228,6 +229,33 @@ Pie supports Markdown-based skills and built-in extensions.
228
229
 
229
230
  That is part of what makes Pie embeddable: the CLI is only one interface on top of a broader agent toolkit.
230
231
 
232
+ ## Extension Sources, Priority, And Toggles
233
+
234
+ Extensions are discovered from four sources in ascending priority (later sources shadow earlier ones by stable extension identity):
235
+
236
+ 1. `builtin` — shipped with the CLI (`ask-user`, `todo`, `plan-mode`, `subagent`, `init`, `changelog`, `deploy`, `files`, attachment handlers)
237
+ 2. `global` — `~/.pie/extensions/`
238
+ 3. `project` — `./.pie/extensions/`
239
+ 4. `configured` — repeated `--extension-path <dir>` flags
240
+
241
+ Every extension is enabled by default. Toggles are sparse overrides stored in settings and applied by extension identity across all sources:
242
+
243
+ - Interactive: `/extensions` opens the user-default toggle menu; `/extensions --project` edits project overrides. `/extensions list|enable|disable ...` remains available for command-driven use.
244
+ - Scripts and third-party UIs: `pie extensions list [--json]`, `pie extensions enable|disable <name> [--project|--user]`
245
+ - Process flags: `--no-builtin-extensions` (skip built-ins) and `--no-extensions` (skip all discovered sources; `--extension-path` still loads)
246
+
247
+ Example override in `~/.pie/settings.json` (or `./.pie/settings.json` for project scope, which wins per identity):
248
+
249
+ ```jsonc
250
+ {
251
+ "extensions": {
252
+ "plan-mode": { "enabled": false }
253
+ }
254
+ }
255
+ ```
256
+
257
+ The full contract (identity rules, schema, host integration) lives in [`docs/extensions-enablement.md`](../../docs/extensions-enablement.md).
258
+
231
259
  ## Browser Tools
232
260
 
233
261
  The built-in `browser-tools` skill uses Microsoft's Playwright CLI for visible browser automation. Its runtime dependencies ship with the CLI; do not run `npm install` inside the skill directory.
@@ -239,7 +267,7 @@ node <resolvedPath for browser-tools/playwright-cli.js> open https://example.com
239
267
  node <resolvedPath for browser-tools/playwright-cli.js> snapshot
240
268
  node <resolvedPath for browser-tools/playwright-cli.js> screenshot
241
269
  node <resolvedPath for browser-tools/playwright-cli.js> console
242
- node <resolvedPath for browser-tools/playwright-cli.js> network
270
+ node <resolvedPath for browser-tools/playwright-cli.js> requests
243
271
  ```
244
272
 
245
273
  If Playwright's Chromium browser is not installed, run:
@@ -1,9 +1,10 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createAskUserCapability
4
- } from "../../../chunks/chunk-AFTBFF6J.js";
5
- import "../../../chunks/chunk-PUZP2Q3F.js";
6
- import "../../../chunks/chunk-7ABSJC2D.js";
4
+ } from "../../../chunks/chunk-XWNIIJ3X.js";
5
+ import "../../../chunks/chunk-X44YTB6R.js";
6
+ import "../../../chunks/chunk-J4P2LP7K.js";
7
+ import "../../../chunks/chunk-HAAYC2N5.js";
7
8
  import "../../../chunks/chunk-TG2EQLX2.js";
8
9
 
9
10
  // builtin/extensions/ask-user/index.ts
@@ -65,54 +65,54 @@ function changelogExtension(ctx) {
65
65
  if (!commits2) {
66
66
  return "No git history found. Cannot check for missing entries.";
67
67
  }
68
- return `\u{1F50D} CHANGELOG \u9057\u6F0F\u68C0\u67E5
68
+ return `\u{1F50D} Check for CHANGELOG gaps
69
69
 
70
- \u8BF7\u5206\u6790\u4EE5\u4E0B\u4FE1\u606F\uFF0C\u68C0\u67E5 CHANGELOG \u662F\u5426\u6709\u9057\u6F0F\uFF1A
70
+ Analyze the following information for missing CHANGELOG entries:
71
71
 
72
- ## \u6700\u8FD1 Git \u63D0\u4EA4
73
- ${commits2 || "(\u65E0\u6CD5\u83B7\u53D6)"}
72
+ ## Recent Git commits
73
+ ${commits2 || "(unavailable)"}
74
74
 
75
- ## \u53D8\u66F4\u6587\u4EF6
76
- ${changedFiles2 || "(\u65E0\u6CD5\u83B7\u53D6)"}
75
+ ## Changed files
76
+ ${changedFiles2 || "(unavailable)"}
77
77
 
78
- ## \u5F53\u524D CHANGELOG
79
- ${changelog2 ? changelog2.slice(0, 1500) + "\n..." : "(\u6587\u4EF6\u4E0D\u5B58\u5728)"}
78
+ ## Current CHANGELOG
79
+ ${changelog2 ? changelog2.slice(0, 1500) + "\n..." : "(file does not exist)"}
80
80
 
81
- \u8BF7\u5BF9\u6BD4\u5206\u6790\uFF1A
82
- 1. \u54EA\u4E9B\u91CD\u8981\u7684\u53D8\u66F4\u5DF2\u7ECF\u63D0\u4EA4\u5230 git \u4F46\u6CA1\u6709\u8BB0\u5F55\u5728 CHANGELOG\uFF1F
83
- 2. \u5F53\u524D [Unreleased] \u90E8\u5206\u662F\u5426\u5B8C\u6574\u53CD\u6620\u4E86\u6700\u8FD1\u7684\u5DE5\u4F5C\uFF1F
84
- 3. \u5217\u51FA\u9057\u6F0F\u7684\u6761\u76EE\u5EFA\u8BAE\uFF08\u6309 Added/Changed/Fixed \u5206\u7C7B\uFF09
81
+ Compare the sources and report:
82
+ 1. Which important committed changes are not recorded in the CHANGELOG?
83
+ 2. Does the current [Unreleased] section accurately cover recent work?
84
+ 3. Which missing entries should be added under Added, Changed, or Fixed?
85
85
 
86
- \u53EA\u8FD4\u56DE\u5206\u6790\u62A5\u544A\uFF0C\u4E0D\u8981\u4FEE\u6539\u6587\u4EF6\u3002`;
86
+ Return the analysis report only. Do not modify files.`;
87
87
  }
88
88
  if (args?.startsWith("add ")) {
89
89
  const description = args.slice(4).trim();
90
90
  const existingChangelog = await readChangelog(ctx2.cwd);
91
- ctx2.ui.notify(`\u{1F4DD} \u6B63\u5728\u751F\u6210 changelog \u6761\u76EE...`, "info");
92
- return `\u8BF7\u5C06\u4EE5\u4E0B\u63CF\u8FF0\u8F6C\u6362\u4E3A\u4E13\u4E1A\u7684 CHANGELOG \u6761\u76EE\uFF1A
91
+ ctx2.ui.notify("\u{1F4DD} Generating a changelog entry...", "info");
92
+ return `Convert the following description into a professional CHANGELOG entry:
93
93
 
94
- \u63CF\u8FF0\uFF1A"${description}"
94
+ Description: "${description}"
95
95
 
96
96
  ${existingChangelog ? `
97
- \u53C2\u8003\u73B0\u6709\u683C\u5F0F\uFF1A
97
+ Follow the existing format:
98
98
  \`\`\`
99
99
  ${existingChangelog.slice(0, 800)}
100
100
  ...
101
101
  \`\`\`` : ""}
102
102
 
103
- \u8981\u6C42\uFF1A
104
- 1. \u9009\u62E9\u5408\u9002\u7684\u5206\u7C7B\uFF1A**Added** / **Changed** / **Fixed** / **Removed** / **Deprecated** / **Security**
105
- 2. \u4F7F\u7528\u73B0\u5728\u65F6\u6001\uFF0C\u7B80\u6D01\u4F46\u5305\u542B\u5173\u952E\u6280\u672F\u7EC6\u8282
106
- 3. \u5982\u6709\u76F8\u5173\u6587\u4EF6\u8DEF\u5F84\uFF0C\u8BF7\u5305\u542B
103
+ Requirements:
104
+ 1. Choose the appropriate category: **Added** / **Changed** / **Fixed** / **Removed** / **Deprecated** / **Security**.
105
+ 2. Use present tense and concise wording while preserving important technical details.
106
+ 3. Include relevant file paths when useful.
107
107
 
108
- \u683C\u5F0F\u793A\u4F8B\uFF1A
109
- - **Added**: \u65B0\u589E\u7528\u6237\u8BA4\u8BC1\u6A21\u5757\uFF0C\u652F\u6301 JWT token \u9A8C\u8BC1\uFF08src/auth/\uFF09
110
- - **Fixed**: \u4FEE\u590D\u5185\u5B58\u6CC4\u6F0F\u95EE\u9898\uFF0C\u4F18\u5316\u4E86\u5927\u6587\u4EF6\u5904\u7406\u6027\u80FD
108
+ Examples:
109
+ - **Added**: Add JWT token validation to the authentication module (src/auth/).
110
+ - **Fixed**: Prevent a memory leak during large-file processing.
111
111
 
112
- \u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md\uFF1A
113
- - \u5982\u679C\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u6807\u51C6\u683C\u5F0F\uFF08\u5305\u542B ## [Unreleased] \u90E8\u5206\uFF09
114
- - \u5C06\u65B0\u6761\u76EE\u6DFB\u52A0\u5230 [Unreleased] \u90E8\u5206\u7684\u5408\u9002\u4F4D\u7F6E
115
- - \u4FDD\u6301\u73B0\u6709\u6761\u76EE\u4E0D\u53D8`;
112
+ Use the write tool to update CHANGELOG.md:
113
+ - Create a standard file with an ## [Unreleased] section if it does not exist.
114
+ - Add the new entry to the appropriate subsection under [Unreleased].
115
+ - Preserve existing entries.`;
116
116
  }
117
117
  if (args?.startsWith("release")) {
118
118
  const versionHint = args.slice(7).trim();
@@ -121,30 +121,30 @@ ${existingChangelog.slice(0, 800)}
121
121
  return "No CHANGELOG.md found. Create one first with /changelog";
122
122
  }
123
123
  ctx2.ui.notify(`\u{1F4DD} Preparing release ${versionHint || "..."}`, "info");
124
- return `\u8BF7\u5C06 [Unreleased] \u90E8\u5206\u7684\u5185\u5BB9\u6574\u7406\u4E3A\u4E00\u4E2A\u65B0\u7248\u672C\u53D1\u5E03\u3002
124
+ return `Turn the [Unreleased] section into a new version release.
125
125
 
126
- \u5F53\u524D CHANGELOG\uFF1A
126
+ Current CHANGELOG:
127
127
  \`\`\`
128
128
  ${existingChangelog.slice(0, 1500)}
129
129
  ...
130
130
  \`\`\`
131
131
 
132
- \u7248\u672C\u63D0\u793A\uFF1A${versionHint || "\u6839\u636E\u53D8\u66F4\u5185\u5BB9\u81EA\u52A8\u5224\u65AD\uFF08patch/minor/major\uFF09"}
132
+ Version hint: ${versionHint || "infer patch, minor, or major from the changes"}
133
133
 
134
- Semantic Versioning \u89C4\u5219\uFF1A
134
+ Semantic Versioning rules:
135
135
  - **patch** (0.0.x): Bug fixes only
136
136
  - **minor** (0.x.0): New features, backward compatible
137
137
  - **major** (x.0.0): Breaking changes
138
138
 
139
- \u4EFB\u52A1\uFF1A
140
- 1. \u5206\u6790 [Unreleased] \u4E2D\u7684\u53D8\u66F4\u7C7B\u578B
141
- 2. \u786E\u5B9A\u5408\u9002\u7684\u7248\u672C\u53F7\uFF08\u5982\u679C\u7528\u6237\u672A\u6307\u5B9A\uFF09
142
- 3. \u521B\u5EFA\u65B0\u7684\u7248\u672C\u8282\uFF08\u5982 ## [1.2.0] - 2024-03-06\uFF09
143
- 4. \u5C06 [Unreleased] \u7684\u5185\u5BB9\u79FB\u52A8\u5230\u65B0\u7248\u672C\u8282
144
- 5. \u6E05\u7A7A [Unreleased] \u90E8\u5206\uFF0C\u53EA\u4FDD\u7559\u7A7A\u5217\u8868
145
- 6. \u5728\u6587\u4EF6\u5E95\u90E8\u66F4\u65B0\u7248\u672C\u5BF9\u6BD4\u94FE\u63A5\uFF08\u5982\u679C\u9700\u8981\uFF09
139
+ Tasks:
140
+ 1. Analyze the change types in [Unreleased].
141
+ 2. Choose the appropriate version when the user did not specify one.
142
+ 3. Create a version section such as ## [1.2.0] - 2024-03-06.
143
+ 4. Move the [Unreleased] entries into the new version section.
144
+ 5. Leave an empty [Unreleased] section.
145
+ 6. Update version comparison links at the bottom when needed.
146
146
 
147
- \u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md`;
147
+ Use the write tool to update CHANGELOG.md.`;
148
148
  }
149
149
  const commits = getRecentCommits(ctx2.cwd, 15);
150
150
  const changelog = await readChangelog(ctx2.cwd);
@@ -152,40 +152,40 @@ Semantic Versioning \u89C4\u5219\uFF1A
152
152
  if (!commits && !changelog) {
153
153
  return "No git history or CHANGELOG.md found. Initialize with: /changelog add <description>";
154
154
  }
155
- ctx2.ui.notify("\u{1F50D} \u5206\u6790\u53D8\u66F4\u5E76\u68C0\u67E5\u9057\u6F0F...", "info");
156
- return `\u{1F4DD} \u667A\u80FD Changelog \u66F4\u65B0
155
+ ctx2.ui.notify("\u{1F50D} Analyzing changes and checking for gaps...", "info");
156
+ return `\u{1F4DD} Smart CHANGELOG update
157
157
 
158
- \u8BF7\u5206\u6790\u4EE5\u4E0B\u4FE1\u606F\uFF0C\u68C0\u67E5\u5E76\u8865\u5145\u9057\u6F0F\u7684 CHANGELOG \u6761\u76EE\uFF1A
158
+ Analyze the following information, identify missing CHANGELOG entries, and add them when appropriate:
159
159
 
160
- ## \u6700\u8FD1 Git \u63D0\u4EA4\u8BB0\u5F55
161
- ${commits || "(\u65E0\u6CD5\u83B7\u53D6 git \u5386\u53F2)"}
160
+ ## Recent Git commits
161
+ ${commits || "(git history unavailable)"}
162
162
 
163
- ## \u6700\u8FD1\u53D8\u66F4\u7684\u6587\u4EF6
164
- ${changedFiles || "(\u65E0\u6CD5\u83B7\u53D6)"}
163
+ ## Recently changed files
164
+ ${changedFiles || "(unavailable)"}
165
165
 
166
- ## \u5F53\u524D CHANGELOG.md
167
- ${changelog ? "\n```\n" + changelog.slice(0, 2e3) + "\n...\n```" : "(\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u9700\u8981\u521B\u5EFA)"}
166
+ ## Current CHANGELOG.md
167
+ ${changelog ? "\n```\n" + changelog.slice(0, 2e3) + "\n...\n```" : "(file does not exist and must be created)"}
168
168
 
169
- ## \u4EFB\u52A1
169
+ ## Tasks
170
170
 
171
- 1. **\u5BF9\u6BD4\u5206\u6790**\uFF1A
172
- - \u67E5\u770B git \u63D0\u4EA4\u4E2D\u6709\u54EA\u4E9B\u91CD\u8981\u53D8\u66F4
173
- - \u5BF9\u6BD4 CHANGELOG \u7684 [Unreleased] \u90E8\u5206
174
- - \u8BC6\u522B\u9057\u6F0F\u7684\u6761\u76EE
171
+ 1. **Compare sources**:
172
+ - Identify important changes in Git commits.
173
+ - Compare them with the CHANGELOG [Unreleased] section.
174
+ - Identify missing entries.
175
175
 
176
- 2. **\u8865\u5145\u9057\u6F0F**\uFF08\u5982\u679C\u6709\uFF09\uFF1A
177
- - \u4E3A\u6BCF\u4E2A\u9057\u6F0F\u7684\u53D8\u66F4\u521B\u5EFA\u4E13\u4E1A\u6761\u76EE
178
- - \u5206\u7C7B\uFF1A**Added** / **Changed** / **Fixed** / **Removed**
179
- - \u5305\u542B\u6280\u672F\u7EC6\u8282\u548C\u6587\u4EF6\u8DEF\u5F84
176
+ 2. **Add missing entries when needed**:
177
+ - Write a professional entry for each missing change.
178
+ - Classify it under **Added**, **Changed**, **Fixed**, or **Removed**.
179
+ - Include useful technical details and file paths.
180
180
 
181
- 3. **\u66F4\u65B0\u6587\u4EF6**\uFF1A
182
- - \u4F7F\u7528 write \u5DE5\u5177\u66F4\u65B0 CHANGELOG.md
183
- - \u5982\u679C\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u6807\u51C6\u683C\u5F0F
184
- - \u53EA\u6DFB\u52A0\u9057\u6F0F\u7684\u6761\u76EE\uFF0C\u4FDD\u6301\u73B0\u6709\u5185\u5BB9
181
+ 3. **Update the file**:
182
+ - Use the write tool to update CHANGELOG.md.
183
+ - Create a standard CHANGELOG if it does not exist.
184
+ - Add only missing entries and preserve existing content.
185
185
 
186
- 4. **\u62A5\u544A\u7ED3\u679C**\uFF1A
187
- - \u6DFB\u52A0\u4E86\u54EA\u4E9B\u6761\u76EE
188
- - \u662F\u5426\u6709\u4E0D\u786E\u5B9A\u662F\u5426\u9700\u8981\u8BB0\u5F55\u7684\u5185\u5BB9`;
186
+ 4. **Report the result**:
187
+ - List the entries that were added.
188
+ - Note any changes whose inclusion is uncertain.`;
189
189
  }
190
190
  });
191
191
  ctx.log("Changelog extension ready");
@@ -28,48 +28,48 @@ function buildResearchPrompt(params) {
28
28
  const { isUpdate, existingContent, userIntent, cwd, projectRoot, agentsPath } = params;
29
29
  if (isUpdate && existingContent) {
30
30
  const truncatedContent = existingContent.length > 4e3 ? existingContent.slice(0, 4e3) + "\n... (truncated)" : existingContent;
31
- return `\u{1F4DD} \u66F4\u65B0 root AGENTS.md \u9879\u76EE\u4E0A\u4E0B\u6587
31
+ return `\u{1F4DD} Update the root AGENTS.md project context
32
32
 
33
- \u76EE\u6807\u6587\u4EF6\uFF1A${agentsPath}
34
- \u9879\u76EE\u6839\u76EE\u5F55\uFF1A${projectRoot}
35
- \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}
33
+ Target file: ${agentsPath}
34
+ Project root: ${projectRoot}
35
+ Current working directory: ${cwd}
36
36
 
37
- \u5F53\u524D root AGENTS.md \u5185\u5BB9\uFF1A
37
+ Current root AGENTS.md content:
38
38
  \`\`\`
39
39
  ${truncatedContent}
40
40
  \`\`\`
41
41
 
42
- ${userIntent ? `\u{1F4CC} \u7528\u6237\u66F4\u65B0\u610F\u56FE\uFF1A${userIntent}
42
+ ${userIntent ? `\u{1F4CC} User update intent: ${userIntent}
43
43
 
44
- ` : ""}\u8BF7\u91CD\u65B0\u7814\u7A76\u9879\u76EE\u5E76\u66F4\u65B0 root AGENTS.md\uFF1A
44
+ ` : ""}Research the project again and update the root AGENTS.md:
45
45
 
46
- 1. \u4FDD\u6301 AGENTS.md \u662F progressive disclosure index\uFF0C\u4E0D\u8981\u5199\u6210\u957F\u7BC7\u9879\u76EE\u767E\u79D1
47
- 2. \u4FDD\u7559\u7B80\u77ED root instructions\uFF0C\u7136\u540E\u7EF4\u62A4 Repo Map
48
- 3. Repo Map \u91CC\u7684\u6BCF\u4E2A\u91CD\u8981\u76EE\u5F55\u90FD\u8981\u6709 desc\uFF0C\u8BF4\u660E\u4EC0\u4E48\u65F6\u5019\u9700\u8981\u8BFB\u8BE5\u76EE\u5F55\u6216\u76F8\u5173\u6587\u6863
49
- 4. \u53EA\u8865\u5145\u7A33\u5B9A\u89C4\u5219\u3001\u76EE\u5F55\u8DEF\u7531\u3001\u9A8C\u8BC1\u95E8\u7981\u548C\u751F\u6210\u7269\u89C4\u5219
50
- 5. \u5220\u9664\u8FC7\u65F6\u6216\u91CD\u590D README/ARCHITECTURE \u7684\u5927\u6BB5\u5185\u5BB9
46
+ 1. Keep AGENTS.md as a progressive-disclosure index, not a long project encyclopedia.
47
+ 2. Preserve concise root instructions and maintain the Repo Map.
48
+ 3. Give every important Repo Map directory a desc explaining when to read it or its related documentation.
49
+ 4. Include only stable rules, directory routing, verification gates, and generated-artifact rules.
50
+ 5. Remove obsolete content and large sections that duplicate README or ARCHITECTURE.
51
51
 
52
- \u8BF7\u4F7F\u7528 write_file \u5DE5\u5177\u66F4\u65B0\u76EE\u6807\u6587\u4EF6\uFF1A${agentsPath}
53
- CLI \u6587\u4EF6\u5DE5\u5177\u4F1A\u4EE5\u9879\u76EE\u6839\u76EE\u5F55\u4F5C\u4E3A\u8BBF\u95EE\u8FB9\u754C\uFF1B\u4E0D\u8981\u4F7F\u7528\u989D\u5916\u7684 root \u53C2\u6570\u3002`;
52
+ Use the write_file tool to update: ${agentsPath}
53
+ CLI file tools already use the project root as their access boundary; do not pass an additional root argument.`;
54
54
  }
55
- return `\u{1F50D} \u521D\u59CB\u5316 root AGENTS.md \u9879\u76EE\u4E0A\u4E0B\u6587
55
+ return `\u{1F50D} Initialize the root AGENTS.md project context
56
56
 
57
- \u76EE\u6807\u6587\u4EF6\uFF1A${agentsPath}
58
- \u9879\u76EE\u6839\u76EE\u5F55\uFF1A${projectRoot}
59
- \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${cwd}
57
+ Target file: ${agentsPath}
58
+ Project root: ${projectRoot}
59
+ Current working directory: ${cwd}
60
60
 
61
- ${userIntent ? `\u{1F4CC} \u7528\u6237\u7814\u7A76\u610F\u56FE\uFF1A${userIntent}
61
+ ${userIntent ? `\u{1F4CC} User research intent: ${userIntent}
62
62
 
63
- ` : ""}\u8BF7\u7814\u7A76\u5F53\u524D\u9879\u76EE\u5E76\u521B\u5EFA root \`AGENTS.md\`\u3002\u8FD9\u4E2A\u6587\u4EF6\u5E94\u8BE5\u662F progressive disclosure index\uFF0C\u7528\u6765\u6307\u5BFC\u540E\u7EED agent \u6309\u9700\u8BFB\u53D6\u76F8\u5173\u6587\u6863\uFF0C\u800C\u4E0D\u662F\u4E00\u6B21\u6027\u603B\u7ED3\u6574\u4E2A\u4ED3\u5E93\u3002
63
+ ` : ""}Research the current project and create the root \`AGENTS.md\`. It should be a progressive disclosure index that tells future agents which documentation to read on demand, rather than a one-time summary of the entire repository.
64
64
 
65
- \u7814\u7A76\u4EFB\u52A1\uFF1A
66
- 1. \u8BC6\u522B\u9879\u76EE\u7C7B\u578B\u548C\u6280\u672F\u6808\uFF08\u67E5\u770B package.json, Cargo.toml, go.mod, requirements.txt, pyproject.toml \u7B49\uFF09
67
- 2. \u63A2\u7D22\u9876\u5C42\u76EE\u5F55\u7ED3\u6784\u548C\u5173\u952E package/product \u8FB9\u754C
68
- 3. \u8BFB\u53D6 README\u3001ARCHITECTURE\u3001docs/public-api \u7B49\u5DF2\u6709\u6587\u6863\uFF0C\u907F\u514D\u91CD\u590D\u7C98\u8D34
69
- 4. \u8BC6\u522B\u751F\u6210\u7269\u89C4\u5219\u3001\u6D4B\u8BD5\u95E8\u7981\u3001\u4EE3\u7801\u5206\u5C42\u548C\u9AD8\u98CE\u9669\u6539\u52A8\u8FB9\u754C
70
- 5. \u751F\u6210\u7B80\u77ED\u3001\u7A33\u5B9A\u3001\u53EF\u7EF4\u62A4\u7684\u76EE\u5F55\u8DEF\u7531\u8BF4\u660E
65
+ Research tasks:
66
+ 1. Identify the project type and technology stack by checking package.json, Cargo.toml, go.mod, requirements.txt, pyproject.toml, and similar files.
67
+ 2. Explore the top-level directory structure and important package/product boundaries.
68
+ 3. Read existing README, ARCHITECTURE, and docs/public-api material without duplicating it.
69
+ 4. Identify generated-artifact rules, verification gates, code-layer boundaries, and high-risk change boundaries.
70
+ 5. Produce concise, stable, maintainable directory-routing guidance.
71
71
 
72
- \u8BF7\u751F\u6210\u5305\u542B\u4EE5\u4E0B\u7AE0\u8282\u7684 AGENTS.md\uFF1A
72
+ Create an AGENTS.md with these sections:
73
73
 
74
74
  \`\`\`
75
75
  # AGENTS.md
@@ -91,8 +91,8 @@ Rules for AGENTS.md, generated bundles, and source-of-truth files.
91
91
  Which focused tests/checks to run by touched area.
92
92
  \`\`\`
93
93
 
94
- \u8BF7\u4F7F\u7528 write_file \u5DE5\u5177\u521B\u5EFA\u76EE\u6807\u6587\u4EF6\uFF1A${agentsPath}
95
- CLI \u6587\u4EF6\u5DE5\u5177\u4F1A\u4EE5\u9879\u76EE\u6839\u76EE\u5F55\u4F5C\u4E3A\u8BBF\u95EE\u8FB9\u754C\uFF1B\u4E0D\u8981\u4F7F\u7528\u989D\u5916\u7684 root \u53C2\u6570\u3002`;
94
+ Use the write_file tool to create: ${agentsPath}
95
+ CLI file tools already use the project root as their access boundary; do not pass an additional root argument.`;
96
96
  }
97
97
  async function initExtension(ctx) {
98
98
  ctx.log("Init extension loaded");
@@ -110,7 +110,7 @@ async function initExtension(ctx) {
110
110
  }
111
111
  ctx.registerCommand({
112
112
  path: ["tools", "init"],
113
- description: "\u7814\u7A76\u9879\u76EE\u5E76\u751F\u6210/\u66F4\u65B0 root AGENTS.md \u9879\u76EE\u4E0A\u4E0B\u6587\u7D22\u5F15",
113
+ description: "Research the project and create or update the root AGENTS.md context index",
114
114
  handler: async (ctx2, args) => {
115
115
  const existing = await loadExistingKnowledge(ctx2.cwd);
116
116
  const existingContent = existing.content;
@@ -119,12 +119,12 @@ async function initExtension(ctx) {
119
119
  cachedKnowledge = existingContent;
120
120
  if (isUpdate) {
121
121
  if (userIntent) {
122
- ctx2.ui.notify(`\u{1F4DD} \u6B63\u5728\u66F4\u65B0\u9879\u76EE\u77E5\u8BC6\uFF08${userIntent}\uFF09...`, "info");
122
+ ctx2.ui.notify(`\u{1F4DD} Updating project context (${userIntent})...`, "info");
123
123
  } else {
124
- ctx2.ui.notify("\u{1F4DD} \u6B63\u5728\u66F4\u65B0 root AGENTS.md...", "info");
124
+ ctx2.ui.notify("\u{1F4DD} Updating root AGENTS.md...", "info");
125
125
  }
126
126
  } else {
127
- ctx2.ui.notify("\u{1F50D} \u6B63\u5728\u521D\u59CB\u5316 root AGENTS.md...", "info");
127
+ ctx2.ui.notify("\u{1F50D} Initializing root AGENTS.md...", "info");
128
128
  }
129
129
  const researchPrompt = buildResearchPrompt({
130
130
  isUpdate,
@@ -23,7 +23,7 @@ function kimiAttachmentsExtension(ctx) {
23
23
  if (!fileId) {
24
24
  return {
25
25
  items: [{ type: "text", text: `[${attachment.id}]` }],
26
- warnings: ["\u9644\u4EF6\u7F3A\u5C11 fileId\uFF0C\u65E0\u6CD5\u8D70 Kimi \u539F\u751F\u5F15\u7528"]
26
+ warnings: ["The attachment has no fileId, so Kimi native references are unavailable."]
27
27
  };
28
28
  }
29
29
  const modality = getModality(attachment.mimeType);
@@ -1,20 +1,26 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
+ BUILTIN_TOOL_CAPABILITY_METADATA,
4
+ DEFAULT_PLAN_MODE_TOOL_NAMES,
3
5
  buildExecutionReminder,
4
6
  createExecutionStateFromPlan,
5
7
  createPlanCapability,
6
8
  extractPlanTodoItems,
9
+ getToolCapabilityMetadata,
7
10
  isPlanModeSafeCommand,
11
+ isToolAllowedInPlanMode,
8
12
  markCompletedPlanSteps,
9
13
  restoreExecutionState
10
- } from "../../../chunks/chunk-AFTBFF6J.js";
11
- import "../../../chunks/chunk-PUZP2Q3F.js";
12
- import "../../../chunks/chunk-7ABSJC2D.js";
14
+ } from "../../../chunks/chunk-XWNIIJ3X.js";
15
+ import "../../../chunks/chunk-X44YTB6R.js";
16
+ import "../../../chunks/chunk-J4P2LP7K.js";
17
+ import "../../../chunks/chunk-HAAYC2N5.js";
13
18
  import "../../../chunks/chunk-TG2EQLX2.js";
14
19
 
15
20
  // builtin/extensions/plan-mode/index.ts
16
21
  var SESSION_METADATA_KEY = "planModeEnabled";
17
22
  var EXECUTION_METADATA_KEY = "executionState";
23
+ var PLAN_ALLOWED_BUILTIN_TOOLS = new Set(DEFAULT_PLAN_MODE_TOOL_NAMES);
18
24
  var planModeEnabled = false;
19
25
  var executionMode = false;
20
26
  function toPlanTodoItems(state) {
@@ -80,9 +86,32 @@ function planModeExtension(ctx) {
80
86
  }
81
87
  });
82
88
  ctx.on("tool:call", async (event) => {
83
- if (!planModeEnabled || event.toolName !== "bash") return;
89
+ if (!planModeEnabled) return;
90
+ if (event.runtimeTool && event.runtimeTool.name !== event.toolName) {
91
+ ctx.ui.notify(`Plan mode: Tool blocked (runtime instance mismatch).
92
+ Tool: ${event.toolName}`, "error");
93
+ return { block: true, reason: `Plan mode: runtime tool instance does not match "${event.toolName}".` };
94
+ }
95
+ const runtimeTool = event.runtimeTool;
96
+ const builtinMetadata = BUILTIN_TOOL_CAPABILITY_METADATA[event.toolName];
97
+ const metadata = runtimeTool ? getToolCapabilityMetadata(runtimeTool) : builtinMetadata;
98
+ const allowed = runtimeTool ? isToolAllowedInPlanMode(runtimeTool) : builtinMetadata ? PLAN_ALLOWED_BUILTIN_TOOLS.has(event.toolName) : true;
99
+ if (!allowed) {
100
+ ctx.ui.notify(
101
+ `Plan mode: Tool blocked (read-only). Use /plan to disable plan mode first.
102
+ Tool: ${event.toolName}`,
103
+ "error"
104
+ );
105
+ return { block: true, reason: `Plan mode: tool "${event.toolName}" is not available in plan mode (read-only). Disable plan mode with /plan to use it.` };
106
+ }
107
+ if (!metadata?.executesShell) return;
84
108
  const command = event.args?.command;
85
- if (command && !isPlanModeSafeCommand(command)) {
109
+ if (typeof command !== "string" || command.trim().length === 0) {
110
+ ctx.ui.notify(`Plan mode: Shell tool blocked (missing command).
111
+ Tool: ${event.toolName}`, "error");
112
+ return { block: true, reason: `Plan mode: shell tool "${event.toolName}" requires a non-empty string command.` };
113
+ }
114
+ if (!isPlanModeSafeCommand(command)) {
86
115
  ctx.ui.notify(
87
116
  `Plan mode: Command blocked (not allowlisted). Use /plan to disable plan mode first.
88
117
  Command: ${command}`,
@@ -1,13 +1,14 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createCliHostCapabilities
4
- } from "../../../chunks/chunk-4WU5VAX4.js";
4
+ } from "../../../chunks/chunk-QYYRJ7JW.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-AFTBFF6J.js";
9
- import "../../../chunks/chunk-PUZP2Q3F.js";
10
- import "../../../chunks/chunk-7ABSJC2D.js";
8
+ } from "../../../chunks/chunk-XWNIIJ3X.js";
9
+ import "../../../chunks/chunk-X44YTB6R.js";
10
+ import "../../../chunks/chunk-J4P2LP7K.js";
11
+ import "../../../chunks/chunk-HAAYC2N5.js";
11
12
  import "../../../chunks/chunk-TG2EQLX2.js";
12
13
 
13
14
  // builtin/extensions/subagent/index.ts
@@ -7,9 +7,10 @@ import {
7
7
  executeManageTodoList,
8
8
  executionStateToTodos,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-AFTBFF6J.js";
11
- import "../../../chunks/chunk-PUZP2Q3F.js";
12
- import "../../../chunks/chunk-7ABSJC2D.js";
10
+ } from "../../../chunks/chunk-XWNIIJ3X.js";
11
+ import "../../../chunks/chunk-X44YTB6R.js";
12
+ import "../../../chunks/chunk-J4P2LP7K.js";
13
+ import "../../../chunks/chunk-HAAYC2N5.js";
13
14
  import "../../../chunks/chunk-TG2EQLX2.js";
14
15
 
15
16
  // builtin/extensions/todo/index.ts
@@ -10,7 +10,7 @@ node playwright-cli.js open https://example.com
10
10
  node playwright-cli.js snapshot
11
11
  node playwright-cli.js screenshot
12
12
  node playwright-cli.js console
13
- node playwright-cli.js network
13
+ node playwright-cli.js requests
14
14
  node playwright-cli.js close
15
15
  ```
16
16
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: browser-tools
3
- description: Interactive browser automation via Microsoft Playwright CLI. Use when you need to open pages, inspect DOM snapshots, click/type, capture screenshots, inspect console/network output, or test frontend flows in a real browser.
3
+ description: Interactive browser automation via Microsoft Playwright CLI. Use when you need to open pages, inspect DOM snapshots, click/type, capture screenshots, inspect console/request output, or test frontend flows in a real browser.
4
4
  ---
5
5
 
6
6
  # Browser Tools
@@ -19,7 +19,7 @@ node <baseDir>/playwright-cli.js click "Submit"
19
19
  node <baseDir>/playwright-cli.js type "hello"
20
20
  node <baseDir>/playwright-cli.js screenshot
21
21
  node <baseDir>/playwright-cli.js console
22
- node <baseDir>/playwright-cli.js network
22
+ node <baseDir>/playwright-cli.js requests
23
23
  node <baseDir>/playwright-cli.js close
24
24
  ```
25
25
 
@@ -27,7 +27,7 @@ Use `node <baseDir>/playwright-cli.js --help` for the full command list.
27
27
 
28
28
  ## Workflow
29
29
 
30
- Start with `open` or `goto`, then use `snapshot` before interacting. Prefer snapshot, console, and network output for diagnosis; use screenshots when visual layout matters. Use named sessions with `-s=<session>` when you need to keep multiple browser flows separate.
30
+ Start with `open` or `goto`, then use `snapshot` before interacting. Prefer snapshot, console, and request output for diagnosis; use screenshots when visual layout matters. Use named sessions with `-s=<session>` when you need to keep multiple browser flows separate.
31
31
 
32
32
  If the browser is not installed, run:
33
33
 
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from "node:child_process";
4
+ import fs from "node:fs";
4
5
  import { createRequire } from "node:module";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
5
8
 
6
9
  const require = createRequire(import.meta.url);
7
10
 
@@ -18,7 +21,25 @@ export function runPlaywrightCli(args = process.argv.slice(2), options = {}) {
18
21
  });
19
22
  }
20
23
 
21
- if (import.meta.url === `file://${process.argv[1]}`) {
24
+ function normalizeDirectEntryPath(candidate) {
25
+ const resolved = path.resolve(candidate);
26
+ const real = fs.realpathSync.native(resolved);
27
+ const normalized = path.normalize(real);
28
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
29
+ }
30
+
31
+ export function isDirectEntry(moduleUrl = import.meta.url, argvPath = process.argv[1]) {
32
+ if (!argvPath) return false;
33
+ try {
34
+ const modulePath = normalizeDirectEntryPath(fileURLToPath(moduleUrl));
35
+ const entryPath = normalizeDirectEntryPath(argvPath);
36
+ return modulePath === entryPath;
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ if (isDirectEntry()) {
22
43
  const result = runPlaywrightCli();
23
44
  process.exitCode = result.status ?? 1;
24
45
  }