@givolt/i3-composer-agent 2.3.5 → 2.3.7
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/.agents/plugins/marketplace.json +1 -1
- package/.claude/commands/i3-prototype.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.gemini/commands/i3-prototype.toml +1 -1
- package/README.md +1 -1
- package/commands/i3-prototype.toml +1 -1
- package/docs/codebuddy-setup.md +1 -1
- package/docs/codex-setup.md +1 -1
- package/docs/other-hosts.md +1 -1
- package/docs/workbuddy-setup.md +1 -1
- package/hooks/PROTOTYPE.md +23 -0
- package/hooks/i3-prototype.cjs +2 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/ui-prototype-buddy-lifecycle-test.js +10 -5
- package/scripts/ui-prototype-codebuddy-hook-test.js +8 -2
- package/scripts/ui-prototype-recovery-test.js +11 -2
- package/skills/i3-ui-prototype/SKILL.md +2 -8
- package/skills/i3-ui-prototype/references/execution-evidence.md +9 -3
- package/skills/i3-ui-prototype/scripts/codebuddy-context.cjs +20 -3
- package/skills/i3-ui-prototype/scripts/codebuddy-hook.cjs +123 -36
- package/skills/i3-ui-prototype/scripts/execution-diagnostics.cjs +91 -0
- package/skills/i3-ui-prototype/scripts/execution-gates.cjs +46 -2
- package/skills/i3-ui-prototype/scripts/execution-recovery.cjs +10 -9
- package/skills/i3-ui-prototype/scripts/execution-runtime.cjs +4 -3
- package/skills/i3-ui-prototype/scripts/native-command.cjs +1 -1
- package/skills/i3-ui-prototype/scripts/native-delivery.cjs +4 -3
- package/skills/i3-ui-prototype/scripts/native-files.cjs +10 -1
- package/skills/i3-ui-prototype/scripts/native-pilot.cjs +6 -1
- package/skills/i3-ui-prototype/scripts/native-tool-result.cjs +14 -0
- package/skills/i3-ui-prototype/scripts/prototype-dependencies.cjs +1 -1
- package/skills/i3-ui-prototype/scripts/prototype-hooks.cjs +7 -3
- package/skills/i3-ui-prototype/scripts/ptc-callbacks.cjs +131 -0
|
@@ -20,4 +20,4 @@ $ARGUMENTS
|
|
|
20
20
|
|
|
21
21
|
With no arguments use create; explicit analysis or read-only limits take precedence. Preserve the user's scope, manual edits, fixed inputs and approved baselines. Use supporting engineering, framework, design and browser skills as the working skill requires; keep its workflow and evidence requirements there.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Create the prototype in the current session. Load the required frontend/framework/design Skills before implementation and use the browser Skill for interaction acceptance. Installed Hooks run automatically; do not inspect Hook internals, search host logs, or run a manual binding step. When a required Skill is missing, invoke it and retry; report an infrastructure failure briefly through the separate maintenance entry.
|
|
@@ -19,5 +19,5 @@ $ARGUMENTS
|
|
|
19
19
|
|
|
20
20
|
With no arguments use create; explicit analysis or read-only limits take precedence. Preserve the user's scope, manual edits, fixed inputs and approved baselines. Use supporting engineering, framework, design and browser skills as the working skill requires; keep its workflow and evidence requirements there.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Create the prototype in the current session. Load the required frontend/framework/design Skills before implementation and use the browser Skill for interaction acceptance. Installed Hooks run automatically; do not inspect Hook internals, search host logs, or run a manual binding step. When a required Skill is missing, invoke it and retry; report an infrastructure failure briefly through the separate maintenance entry.
|
|
23
23
|
"""
|
package/README.md
CHANGED
|
@@ -19,5 +19,5 @@ $ARGUMENTS
|
|
|
19
19
|
|
|
20
20
|
With no arguments use create; explicit analysis or read-only limits take precedence. Preserve the user's scope, manual edits, fixed inputs and approved baselines. Use supporting engineering, framework, design and browser skills as the working skill requires; keep its workflow and evidence requirements there.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Create the prototype in the current session. Load the required frontend/framework/design Skills before implementation and use the browser Skill for interaction acceptance. Installed Hooks run automatically; do not inspect Hook internals, search host logs, or run a manual binding step. When a required Skill is missing, invoke it and retry; report an infrastructure failure briefly through the separate maintenance entry.
|
|
23
23
|
"""
|
package/docs/codebuddy-setup.md
CHANGED
|
@@ -48,7 +48,7 @@ CodeBuddy 与 WorkBuddy 项目共用 `.codebuddy/`;同版本追加客户端会
|
|
|
48
48
|
npx @givolt/i3-composer-agent --codebuddy --scope project --yes --prototype-skills uiux,antdv
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
值为 none、uiux、antdv 或 uiux,antdv;默认 none。可选工具跟随宿主和项目/全局范围,位于基址下 `tools/i3-prototype/`;旧项目 `.prototype-tools` 保持读取兼容。需要固定本次版本时使用 `npx @givolt/i3-composer-agent@2.3.
|
|
51
|
+
值为 none、uiux、antdv 或 uiux,antdv;默认 none。可选工具跟随宿主和项目/全局范围,位于基址下 `tools/i3-prototype/`;旧项目 `.prototype-tools` 保持读取兼容。需要固定本次版本时使用 `npx @givolt/i3-composer-agent@2.3.7`。已安装后可随时单独检测/补装,无需重装 i3:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
node .codebuddy/skills/i3-ui-prototype/scripts/prototype-dependencies.cjs check --host codebuddy --scope project --project .
|
package/docs/codex-setup.md
CHANGED
|
@@ -37,6 +37,6 @@ Codex 已有原生技能路由,勿把元技能全文预加载为常驻上下
|
|
|
37
37
|
|
|
38
38
|
## 可选原型工具
|
|
39
39
|
|
|
40
|
-
原型辅助工具位于本宿主基址的 `tools/i3-prototype/`,支持项目和全局范围;旧项目 `.prototype-tools` 继续读取兼容。项目安装可使用 `npx @givolt/i3-composer-agent@2.3.
|
|
40
|
+
原型辅助工具位于本宿主基址的 `tools/i3-prototype/`,支持项目和全局范围;旧项目 `.prototype-tools` 继续读取兼容。项目安装可使用 `npx @givolt/i3-composer-agent@2.3.7 --codex --scope project --yes --prototype-skills uiux,antdv`;全局安装将 scope 改为 global。可选依赖默认 none,后续也可使用已安装 Skill 的 prototype-dependencies.cjs 单独检测/补装。完整用法见原型 Skill 的 references/optional-skills.md。
|
|
41
41
|
|
|
42
42
|
原型共享资料统一在项目 prototypes/:新索引 prototypes/index.json,准备范围 prototypes/.preparation/<id>/scope.json。新原生 scope.moduleIds 自动生成 appliesTo;旧索引、输入和实例保持兼容,安装升级不自动迁移。工具及运行缓存使用所选宿主基址;全局浏览器缓存按业务项目身份隔离。详细规则和只读查询/显式迁移命令见 i3-ui-prototype/references/project-layout.md。
|
package/docs/other-hosts.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## 使用本地分发目录
|
|
8
8
|
|
|
9
|
-
以下命令使用完整分发包解压目录里的 CLI,适用于本地测试和离线接入。`/absolute/path/to/package` 均替换为实际解压目录;已发布版本也可使用 `npx @givolt/i3-composer-agent@2.3.
|
|
9
|
+
以下命令使用完整分发包解压目录里的 CLI,适用于本地测试和离线接入。`/absolute/path/to/package` 均替换为实际解压目录;已发布版本也可使用 `npx @givolt/i3-composer-agent@2.3.7` 的对应入口。
|
|
10
10
|
|
|
11
11
|
### fx
|
|
12
12
|
|
package/docs/workbuddy-setup.md
CHANGED
|
@@ -85,7 +85,7 @@ npx @givolt/i3-composer-agent --workbuddy --scope global --yes --force
|
|
|
85
85
|
|
|
86
86
|
## 可选原型工具
|
|
87
87
|
|
|
88
|
-
原型辅助工具位于本宿主基址的 `tools/i3-prototype/`,支持项目和全局范围;旧项目 `.prototype-tools` 继续读取兼容。推荐使用 `npx @givolt/i3-composer-agent@2.3.
|
|
88
|
+
原型辅助工具位于本宿主基址的 `tools/i3-prototype/`,支持项目和全局范围;旧项目 `.prototype-tools` 继续读取兼容。推荐使用 `npx @givolt/i3-composer-agent@2.3.7 --workbuddy --scope global --yes --prototype-skills uiux,antdv`;项目安装将 scope 改为 project。可选依赖默认 none,后续也可使用已安装 Skill 的 prototype-dependencies.cjs 单独检测/补装。完整用法见原型 Skill 的 references/optional-skills.md。
|
|
89
89
|
|
|
90
90
|
原型共享资料统一在项目 prototypes/:新索引 prototypes/index.json,准备范围 prototypes/.preparation/<id>/scope.json。新原生 scope.moduleIds 自动生成 appliesTo;旧索引、输入和实例保持兼容,安装升级不自动迁移。工具及运行缓存使用所选宿主基址;全局浏览器缓存按业务项目身份隔离。详细规则和只读查询/显式迁移命令见 i3-ui-prototype/references/project-layout.md。
|
|
91
91
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 原型 Hooks 安装与维护
|
|
2
|
+
|
|
3
|
+
<!-- i3:zh-guide:start -->
|
|
4
|
+
## 中文使用说明
|
|
5
|
+
|
|
6
|
+
按下文完整工程步骤、检查项与验证条件执行。根据任务选择适用步骤,保留证据、风险和退出条件;正文示例中的英文标签在面向用户输出时译为中文。
|
|
7
|
+
|
|
8
|
+
默认使用简体中文解释、追问及生成报告;用户明确要求其他语言时可切换。原方法正文、引用、阈值和审批条件完整保留。代码标识、路径、命令、工具参数、JSON 键/枚举与原文引用保持原样。
|
|
9
|
+
<!-- i3:zh-guide:end -->
|
|
10
|
+
|
|
11
|
+
本文件面向安装器和维护人员。i3-ui-prototype 的正常职责是制作、修订和验收原型,不承担宿主或 Hook 排障。
|
|
12
|
+
|
|
13
|
+
安装器在 CodeBuddy/WorkBuddy 项目或全局范围注册 prototype 组。宿主自动触发;不要求原型使用者额外执行 execution-begin 或确认任务绑定。必要 Skill 的真实调用由原生 Pre/Post 回调记录,PTC/REPL 的内部工具分别记录;REPL 脚本文本不能代替调用成功。Bash 不提供 stdout 时由本包第一方入口捕获实际结果;其他只读查询可使用 native-tool-result.cjs 的本地绝对入口,不安装依赖。
|
|
14
|
+
|
|
15
|
+
漏调检查由当前操作和固定原型策略决定,不根据最新一句话是否包含“原型”启停采集。缺少 Skill 时拦截并提示通过宿主工具补调,真实成功后重试原操作;普通追问保持同一会话/有效上下文内的调用记录和原型运行。新会话或上下文压缩后重核 Skill,输入、实例或构建变化按原有合同重核业务证据。明确只读、暂停或取消独立限制受管变更,收到 UserPromptSubmit 即生效,不等待日志写盘;普通追问不解除,明确继续实施后解除。这个授权限制不控制回调采集,也不生成新的任务身份。
|
|
16
|
+
|
|
17
|
+
Stop 只对本轮实际操作过的原型检查完成声明;无关文件任务不会被历史原型的验收接管。finalize 仍核验当前原型的真实调用、构建和浏览器证据。
|
|
18
|
+
|
|
19
|
+
检查命令:`npx --yes @givolt/i3-composer-agent hooks check --host codebuddy --scope project --project .`;全局将 scope 改为 global。检查只读,不启用/修复设置。registered 表示已注册;active 表示观察到当前注册的有效运行;failure 显示当前无法核验的操作、会话和原因。次数只限制重复催调/提示,不构成永久操作锁;新的真实成功结果可恢复。普通追问不清零计数,原型会话不承担 Hook 排障。
|
|
20
|
+
|
|
21
|
+
诊断、补调审计与 PTC 机器回调位于宿主基址的 state/i3-prototype/;项目/全局、宿主/会话/有效上下文和原型实例分别隔离。required、ready-to-retry、recovered、blocked 为兼容的审计显示,放行始终重新核对当前真实结果,不把状态名当额外前置。记录请求、失败或只读 SKILL.md 均不能代替成功调用;recovered 只表示观察到补调及重试,不代表业务验收。保留上游 Hooks、用户注册、旧 HTML 和已有原型;旧 execution-* 命令仅供兼容,不是新流程的前置。
|
|
22
|
+
|
|
23
|
+
CodeBuddy 项目/全局 × IDE/CLI(CLI direct/PTC)真实注册、触发、必要 Skill 调用、缺失补调和失败展示必须分别验收。自动化回放不能冒充真实宿主;正式发布门禁在仓库维护工具中执行,不放到业务原型 Skill 内。
|
package/hooks/i3-prototype.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
// Stable host Hook entry
|
|
3
|
+
// Stable host Hook entry. Shared legacy helpers are an implementation detail;
|
|
4
|
+
// installation, automatic dispatch and diagnostics belong to Hooks, not UI tasks.
|
|
4
5
|
const fs=require('node:fs'),path=require('node:path');
|
|
5
6
|
function main(argv=process.argv.slice(2),raw=fs.readFileSync(0,'utf8'),load=()=>require(path.join(require('./manage.cjs').modules().scripts,'hosts/codebuddy.cjs'))) {
|
|
6
7
|
return load().main(argv,raw);
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -54,6 +54,8 @@ for(const [host,client] of [['codebuddy','CodeBuddyCLI'],['codebuddy','CodeBuddy
|
|
|
54
54
|
});
|
|
55
55
|
test('Stop asks for missing Skills twice, then reports blocked without an endless loop',t=>{
|
|
56
56
|
const f=fixture(t,'codebuddy','project','CodeBuddyCLI');
|
|
57
|
+
const input={file_path:path.join(f.directory,'app/src/Stopped.vue'),content:'fixture'};
|
|
58
|
+
const attempted=f.request('Write',input);f.result(attempted,'Synthetic operation was not completed',true);
|
|
57
59
|
for(let n=0;n<3;n++){
|
|
58
60
|
f.append({type:'assistant',message:{content:'已完成,可以交付 '+n}});
|
|
59
61
|
const answer=f.hook('Stop');
|
|
@@ -62,13 +64,16 @@ test('Stop asks for missing Skills twice, then reports blocked without an endles
|
|
|
62
64
|
f.append({type:'user',message:{content:'先分析,不改代码'}});
|
|
63
65
|
const answer=f.tool('Write',{file_path:path.join(f.directory,'app/src/NoWrite.vue'),content:'no'});assert.equal(answer.decision.deny,true);assert.match(answer.decision.reason,/read-only/);
|
|
64
66
|
});
|
|
65
|
-
test('
|
|
67
|
+
test('late successful Skills release writes after the reminder limit without granting delivery',t=>{
|
|
66
68
|
const f=fixture(t,'codebuddy','project','CodeBuddyCLI');
|
|
67
|
-
for(let n=0;n<3;n++){f.append({type:'assistant',message:{content:'已完成,可以交付 '+n}});f.hook('Stop');}
|
|
68
|
-
f.tool('Skill',{skill:'i3-frontend-ui-engineering'});f.tool('Skill',{skill:'antdv'});
|
|
69
69
|
const file=path.join(f.directory,'app/src/AfterBudget.vue');
|
|
70
|
-
|
|
71
|
-
assert.equal(
|
|
70
|
+
for(let n=0;n<3;n++)assert.equal(f.tool('Write',{file_path:file,content:'fixture'}).decision.deny,true);
|
|
71
|
+
assert.equal(fs.existsSync(file),false);assert.equal(f.read().bindings[f.directory].recovery.status,'blocked');
|
|
72
|
+
f.tool('Skill',{skill:'i3-frontend-ui-engineering'});f.tool('Skill',{skill:'antdv'});
|
|
73
|
+
const answer=f.tool('Write',{file_path:file,content:'fixture'},'written',()=>fs.writeFileSync(file,'fixture'));
|
|
74
|
+
assert.notEqual(answer.decision.deny,true);assert.equal(fs.readFileSync(file,'utf8'),'fixture');assert.equal(f.read().bindings[f.directory].recovery.status,'recovered');
|
|
75
|
+
assert.equal(f.read().bindings[f.directory].recovery.total,2,'Keep reminder counts as audit history');
|
|
76
|
+
assert.equal(X.check(f.directory,'delivery',lib).status,'failed','Successful loading and writing do not replace browser acceptance');
|
|
72
77
|
});
|
|
73
78
|
test('a duplicated native callback does not spend recovery budget when the transcript grows',t=>{
|
|
74
79
|
const f=fixture(t,'workbuddy','project',null),input={file_path:path.join(f.directory,'app/src/Duplicate.vue'),content:'fixture'};
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
const prototypeScripts=(()=>{const fs=require('node:fs'),path=require('node:path'),file=path.join(__dirname,'lib/installation.js');return path.join(fs.existsSync(file)?require(file).loadInstallation().skillsDirectory:path.resolve(__dirname,'../skills'),'i3-ui-prototype/scripts');})();
|
|
3
3
|
const test=require('node:test'),assert=require('node:assert/strict');
|
|
4
4
|
const H=require(prototypeScripts+'/codebuddy-hook.cjs'),E=require(prototypeScripts+'/execution-evidence.cjs');
|
|
5
|
+
test('only explicit implementation instructions release a user restriction in Chinese and English',()=>{
|
|
6
|
+
const C=require(prototypeScripts+'/codebuddy-context.cjs');
|
|
7
|
+
for(const prompt of ['继续实施当前原型','继续吧','那就按这版方案实施吧,先保存任务清单','请帮我生成原型','continue','Please resume implementation'])assert.equal(C.userRestriction(prompt),false,prompt);
|
|
8
|
+
for(const prompt of ['你调用了哪三个skill','继续实施需要哪些技能?','继续解释错误','继续原型方案讨论','continue the prototype discussion','resume the prototype analysis','What skills did you use?'])assert.equal(C.userRestriction(prompt),null,prompt);
|
|
9
|
+
for(const prompt of ['先分析,不改代码','暂停当前原型实施','cancel current implementation'])assert.equal(C.userRestriction(prompt),true,prompt);
|
|
10
|
+
});
|
|
5
11
|
test('native command parsing handles quoted paths without evaluating shell substitutions or chains',()=>{
|
|
6
12
|
const c=H.nativeCommand('Bash',{command:"'/node path/node' '/skills path/native-pilot.cjs' execution-begin '/work/prototypes/a b'"},'/work');
|
|
7
13
|
assert.equal(c.root,'/work/prototypes/a b');assert.equal(c.operation,'execution-begin');
|
|
@@ -75,7 +81,7 @@ test('IDE streaming requests correlate only within the exact native generation a
|
|
|
75
81
|
assert.throws(()=>H.eventCall({...payload,tool_input:{content:'unrelated'}},source),/uniquely/);
|
|
76
82
|
source.calls.push({...source.calls[0],toolCallId:'second-call'});assert.throws(()=>H.eventCall(payload,source),/uniquely/);
|
|
77
83
|
});
|
|
78
|
-
test('IDE transient reads retry
|
|
84
|
+
test('IDE and CLI transient reads retry within a fixed limit; wrong generations and requests remain rejected',()=>{
|
|
79
85
|
const payload={hook_event_name:'PreToolUse',client:'CodeBuddyIDE',generation_id:'g1',tool_name:'Write',tool_input:{content:'ui'}};
|
|
80
86
|
const pending={format:'codebuddy-ide-index-v1',prompts:[{line:1,nativeRequestId:'g1'}],calls:[{name:'Write',toolCallId:'w1',nativeRequestId:'g1',input:{content:'ui'},requestLine:2}]};
|
|
81
87
|
let reads=0,waits=0;
|
|
@@ -84,7 +90,7 @@ test('IDE transient reads retry while wrong generations and mismatched pending r
|
|
|
84
90
|
assert.equal(result.calls[0].toolCallId,'w1');assert.equal(result.nativeReadAttempts,3);assert.equal(waits,2);
|
|
85
91
|
reads=0;assert.throws(()=>H.eventSource({...payload,generation_id:'g2'},{product:'ide'},'/work',{readSource:()=>{reads++;return pending;},pause:()=>{}}),/generation/);assert.equal(reads,8);
|
|
86
92
|
assert.throws(()=>H.eventSource({...payload,tool_input:{content:'different'}},{product:'ide'},'/work',{readSource:()=>pending,pause:()=>{}}),/uniquely/);
|
|
87
|
-
reads=0;assert.throws(()=>H.eventSource({...payload,client:'cli'},{product:'cli'},'/work',{readSource:()=>{reads++;return {...pending,calls:[]};},pause:()=>
|
|
93
|
+
reads=0;assert.throws(()=>H.eventSource({...payload,client:'cli'},{product:'cli'},'/work',{readSource:()=>{reads++;return {...pending,calls:[]};},pause:()=>{}}),/uniquely/);assert.equal(reads,8);
|
|
88
94
|
});
|
|
89
95
|
test('IDE defers current callback evidence until the host persists it and never invents Skill success',()=>{
|
|
90
96
|
const source={format:'codebuddy-ide-index-v1',prompts:[{line:1,nativeRequestId:'g1',text:'implement prototype'}],calls:[],contextLine:0};
|
|
@@ -21,16 +21,25 @@ test('recovery correlates a later successful native Skill and a successful retry
|
|
|
21
21
|
const recovered=R().record(index,{...context,event:'PostToolUse',eventKey:'retry-2-result',retrySucceeded:true,retry:{toolCallId:'retry-write',requestLine:4,resultLine:5}},{continue:true});
|
|
22
22
|
assert.equal(recovered.recovery.status,'recovered');assert.equal(recovered.recovery.invocations[0].toolCallId,'real-front');
|
|
23
23
|
});
|
|
24
|
+
test('duplicate callback counts stay idempotent without replaying a stale denial after a successful Skill',()=>{
|
|
25
|
+
const index={bindings:{}},s=source(),context={source:s,sessionId:'s1',directory:'/p/prototypes/a',event:'PreToolUse',eventKey:'same-callback'};
|
|
26
|
+
R().record(index,context,{deny:true,missing:['frontend'],reason:'missing frontend'});
|
|
27
|
+
s.calls=[{skill:'frontend',sessionId:'s1',toolCallId:'front',requestLine:2,resultLine:3,success:true}];
|
|
28
|
+
const current=R().record(index,context,{continue:true});
|
|
29
|
+
assert.notEqual(current.deny,true,'Return the current gate decision, not its cached historical denial');
|
|
30
|
+
assert.equal(current.recovery.total,1);assert.equal(current.recovery.status,'ready-to-retry');
|
|
31
|
+
});
|
|
24
32
|
test('failed and stale Skill results do not recover and Stop correction is bounded across begin calls',()=>{
|
|
25
33
|
const index={bindings:{}},s=source(),context={source:s,sessionId:'s1',directory:'/p/prototypes/a',event:'Stop'};
|
|
26
34
|
s.calls=[{skill:'frontend',sessionId:'s1',requestLine:2,resultLine:3,success:false}];
|
|
27
35
|
const feedback={feedback:true,missing:['frontend'],reason:'load frontend'};
|
|
28
36
|
for(let n=1;n<=2;n++)assert.equal(R().record(index,{...context,eventKey:'stop-'+n},feedback).feedback,true);
|
|
29
37
|
index.bindings={};
|
|
30
|
-
const exhausted=R().record(index,{...context,eventKey:'stop-3'},feedback);assert.equal(exhausted.feedback,undefined);assert.equal(exhausted.recovery.status,'blocked');assert.match(exhausted.context
|
|
38
|
+
const exhausted=R().record(index,{...context,eventKey:'stop-3'},feedback);assert.equal(exhausted.feedback,undefined);assert.equal(exhausted.recovery.status,'blocked');assert.match(exhausted.context,/停止重复催调/);
|
|
31
39
|
const denied=R().record(index,{...context,event:'PreToolUse',eventKey:'write-3'},{deny:true,missing:['frontend'],reason:'load frontend'});assert.equal(denied.deny,true);
|
|
32
40
|
s.contextLine=10;s.calls=[{skill:'frontend',sessionId:'s1',requestLine:2,resultLine:3,success:true}];
|
|
33
|
-
assert.notEqual(R().record(index,{...context,eventKey:'old-load'},{continue:true}).recovery
|
|
41
|
+
assert.notEqual(R().record(index,{...context,eventKey:'old-load'},{continue:true}).recovery?.status,'recovered');
|
|
42
|
+
assert.ok(R().missing({source:s,binding:{sessionId:'s1',association:'automatic'},policy:P.create({id:P.AUTO_ID,mode:'template'})}).includes('frontend'),'Pre-compaction Skill success remains invalid in the new context');
|
|
34
43
|
});
|
|
35
44
|
test('flat native Hook feedback remains metadata and cannot reset the human task or recovery budget',()=>{
|
|
36
45
|
const rows=[{type:'message',role:'user',sessionId:'s1',content:[{type:'input_text',text:'实现原型'}]},{type:'message',role:'user',sessionId:'s1',providerData:{isMeta:true},content:[{type:'input_text',text:'补调 frontend 后继续'}]}];
|
|
@@ -57,15 +57,9 @@ analyze 的交付是需求/能力覆盖、模板与框架选型、交互验收
|
|
|
57
57
|
|
|
58
58
|
已有 v2 实例先运行一次 `node <skill-root>/scripts/native-pilot.cjs state <prototype-root>`,从聚合结果恢复身份、固定需求、设计/构建/实际QA、负责人和下一步的精确命令。不要为寻找参数反复遍历全仓库、node_modules或阅读控制器内部实现。这里只读检查,不安装、启动浏览器或更新状态。
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
制作前实际调用所需的前端/框架/设计 Skill,真实浏览器验收使用浏览器 Skill;不能以读取 SKILL.md 代替调用。安装器注册的 Hooks 自动运行。收到缺少 Skill 的反馈时,补调该 Skill、等待成功后重试原操作。同一有效上下文内的成功加载可复用,普通追问后继续原任务,不重新绑定或重复加载全部 Skill;基础设施异常只简要报告未验收项,由独立维护入口处理,不在原型任务中排查。
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
CodeBuddy/WorkBuddy 新 create 前,用 `native-pilot.cjs execution-assertions-template --scope <scope-file>` 取得完整场景,按本次 PRD 与能力参数填充每项预期 JSON 事实,存于该原型 `.preparation` 目录。create 增加 `--host <codebuddy|workbuddy> --execution-policy buddy-ab-v2 --execution-assertions <assertions-file>`;官方 Skill 真实不可用时才显式 `--official-source-fallback`,保留其失败调用定位。随后在实际所选宿主主会话执行 `execution-begin <prototype-root>`,以原生 Skill 工具加载当前上下文需要的前端 Skill 后再写业务界面。旧 codebuddy-ab-v1 及未采用 executionPolicy 的实例保留原合同。其他宿主尚未适配此 Hook 合同,按原流程披露调用核验边界。
|
|
65
|
-
|
|
66
|
-
新建后及恢复实施时,从 `state` 的 `commands.executionBegin.shell` 取得绝对路径命令,在该宿主主会话的 Shell 工具中独立执行;也可原样执行门禁反馈给出的命令。不得拼接 `cd &&`、管道、重定向或 `head`;这些组合不能建立原生任务绑定。等待进程退出码为 0 且内层结果 `status=bound`,再进行业务写入。外层 `success:true` 仅表示工具返回,内层 `status=failed`/非零退出仍是失败;失败后立即按反馈补做绑定或 Skill 调用,再重试原操作。任务/上下文变化重新绑定,失败或未完成的 begin 不能继承旧成功;绑定由真实 PreToolUse 创建,CLI 不补造绑定或成功记录。
|
|
67
|
-
|
|
68
|
-
`execution-template <prototype-root>` 返回当前身份与已观察到的真实加载引用;以实际查询、实现复核及浏览器结果补齐 `qa/execution-evidence.json`,不能补造调用 ID。构建、record-run、record-devtools-review、finalize 与 `execution-check --stage <stage>` 共用 A;B 在可识别的写入前检查,反馈明确 Skill 名与下一动作,成功补调后重试;Stop 按同缺项两次、当前原生任务总计六次的预算继续纠正,到上限如实报告阻塞,反复 begin 不清零。只读分析、进度、阻塞及用户停止可正常结束。未通过门禁时交付候选和缺项;新收据的 `native-source-correlated` 不代表不可篡改认证或用户认可。
|
|
62
|
+
新 create 使用实际 `--host <codebuddy|workbuddy>`。按 PRD 和固定能力制定交互验收场景,使用 `native-pilot.cjs execution-assertions-template --scope <scope-file>` 取得场景骨架,填充预期 JSON 事实并传 `--execution-assertions <assertions-file>`。这是原型交互验收,不要求手动绑定会话或填写 Hook 调用记录。旧 HTML 和既有 execution-* 入口保持兼容。
|
|
69
63
|
|
|
70
64
|
### 2. 完整内容模板与需求能力
|
|
71
65
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 原型调用记录:兼容合同
|
|
2
2
|
|
|
3
3
|
<!-- i3:zh-guide:start -->
|
|
4
4
|
## 中文使用说明
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
默认使用简体中文解释、追问及生成报告;用户明确要求其他语言时可切换。原方法正文、引用、阈值和审批条件完整保留。代码标识、路径、命令、工具参数、JSON 键/枚举与原文引用保持原样。
|
|
9
9
|
<!-- i3:zh-guide:end -->
|
|
10
10
|
|
|
11
|
+
当前正常流程由安装器注册的 Hooks 自动采集真实 Skill 和工具调用。原型会话直接制作、修订和验收 UI;没有手动 execution-begin、检查 Hook 或填写内部调用记录的前置。缺少必要 Skill 时只补调该 Skill 并重试原操作。安装、原生协议和失败诊断统一见随包 [Hooks 维护说明](../../../hooks/PROTOTYPE.md),不属于原型工作步骤。
|
|
12
|
+
|
|
13
|
+
以下为已有显式 execution-* 使用者保留的兼容格式与旧手动流程,不作为新任务指导;已有原型不会自动改写。
|
|
14
|
+
|
|
15
|
+
## 旧 Buddy A+B 执行与补调合同
|
|
16
|
+
|
|
11
17
|
本合同适配 CodeBuddy IDE/CLI 和 WorkBuddy 桌面 command Hooks;各宿主项目/全局的真实调用、补调及业务效果仍须逐项手测,profile 保持 pending-user。不是新增专责 Agent,不改 using 的发现/路由、上游前端/浏览器方法或上游 Hooks。A 是确定性门禁,B 采集与绑定原生来源;没有 C 提示词对照表方案。
|
|
12
18
|
|
|
13
19
|
## 安装范围与原生生效
|
|
@@ -42,7 +48,7 @@ node <skill-root>/scripts/native-pilot.cjs execution-assertions-template --scope
|
|
|
42
48
|
|
|
43
49
|
## 会话绑定与阶段
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
以下显式入口仅供已有使用者兼容:通过自然语言/using 选到工作 Skill,或实际 `/i3-prototype` 快捷入口后,执行 `execution-begin <prototype-root>`。B 回查原生来源,关联 projectKey、sessionId、runId、实例、输入、模式、策略与注册。只读或停止请求不能启动写任务。新会话/压缩后的上下文需重新核验适用 Skill;普通追问延续原运行,不要求重新 begin。用户手改保留。初建骨架不等于实际实施。
|
|
46
52
|
|
|
47
53
|
使用 `state` 中的 `commands.executionBegin.shell` 或拒绝反馈中的绝对路径命令,作为一次独立 Shell 调用;不加 `cd &&`、管道、重定向或 `head`。严格解析器不解释组合 Shell。成功须同时满足进程退出 0 和内层 `status=bound`;外层 `status=success`/`success:true` 不足以证明阶段成功。缺绑定、任务切换、上下文变化或输入变化时重新执行,不能由 CLI 自行写入原生绑定;A 和写入门禁回查当前任务最新一次 begin 的成功结果,失败/待返回不可复用旧成功。
|
|
48
54
|
|
|
@@ -82,7 +88,7 @@ PostToolUse 观察到已落盘的 begin/阶段失败时,通过该事件的 a
|
|
|
82
88
|
|
|
83
89
|
重试按 kind 区分 ui-write 和 stage;阶段重试绑定实际 operation、stage 与同一原型目录。两类新记录都以 feedbackLine 核对请求发生在反馈之后,旧成功回调不能恢复后续拒绝;旧无 kind 的记录继续仅按页面写入合同核验。
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
同一会话/有效上下文/原型运行默认同一缺项提示两次、累计六次;重复回调、普通追问、反复 begin 和内部 providerData.isMeta 消息不重置计数。达到上限只停止重复催调,仍缺项则拒绝当前操作,取得真实成功结果后重新按事实放行。required/ready-to-retry/recovered/blocked 保留为兼容审计显示,不构成额外许可或永久锁。允许如实报告阻塞,不无限驱动 Stop。用户只读/暂停优先。入口、Skill 发现、加载成功、CLI 查询、重试成功、交付和用户认可分开记录。
|
|
86
92
|
|
|
87
93
|
每宿主/范围实测:故意漏调 → 写入被拒且文件未被该操作修改 → 本主会话实际 Skill 成功 → 原操作重试成功;失败调用、旧上下文、假 ID、旧会话及当前构建缺项不能放行。持续缺项须在预算耗尽后报告阻塞。源测试里的合成日志只能验证解析和门禁逻辑,不证明模型会补调。原生 Hooks 没有指定下一工具的执行接口,不能承诺必然调用,也不是任意 Shell 安全隔离。
|
|
88
94
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const fs=require('node:fs'),path=require('node:path'),os=require('node:os'),assert=require('node:assert/strict');
|
|
3
3
|
const R=require('./codebuddy-registration.cjs'),E=require('./execution-evidence.cjs'),H=require('./buddy-host.cjs');
|
|
4
|
-
const FILES=['native-tool-name.cjs','native-command.cjs','buddy-host.cjs','execution-recovery.cjs','execution-policy.cjs','execution-evidence.cjs','codebuddy-ide-source.cjs','execution-gates.cjs','execution-assertions.cjs','execution-runtime.cjs','codebuddy-context.cjs','codebuddy-registration.cjs','codebuddy-hook.cjs','prototype-hooks.cjs','hosts/codebuddy.cjs','native-pilot.cjs','native-pilot-lib.cjs','native-delivery.cjs','native-devtools.cjs','native-files.cjs','native-build.cjs'];
|
|
4
|
+
const FILES=['native-tool-name.cjs','native-command.cjs','buddy-host.cjs','execution-recovery.cjs','execution-diagnostics.cjs','ptc-callbacks.cjs','native-tool-result.cjs','prototype-dependencies.cjs','execution-policy.cjs','execution-evidence.cjs','codebuddy-ide-source.cjs','execution-gates.cjs','execution-assertions.cjs','execution-runtime.cjs','codebuddy-context.cjs','codebuddy-registration.cjs','codebuddy-hook.cjs','prototype-hooks.cjs','hosts/codebuddy.cjs','native-pilot.cjs','native-pilot-lib.cjs','native-delivery.cjs','native-devtools.cjs','native-files.cjs','native-build.cjs'];
|
|
5
5
|
const read=file=>R.fileIO.read(file);
|
|
6
6
|
function scriptsForEntry(scriptPath) {
|
|
7
7
|
if(path.basename(scriptPath)!=='i3-prototype.cjs')return path.dirname(path.dirname(scriptPath));
|
|
@@ -60,7 +60,7 @@ function source(payload,record,project) {
|
|
|
60
60
|
assert.ok(value.prompts.length,'Original user task is absent from native transcript');
|
|
61
61
|
assert.ok(value.calls.every(call=>call.sessionId===payload.session_id),'Native session identity missing or mismatched');
|
|
62
62
|
assert.ok(value.prompts.every(prompt=>!prompt.sessionId||prompt.sessionId===payload.session_id),'Native prompt session differs');
|
|
63
|
-
return value;
|
|
63
|
+
return record.product==='cli'?require('./ptc-callbacks.cjs').read(value,{record,project,sessionId:payload.session_id}):value;
|
|
64
64
|
}
|
|
65
65
|
function readOnly(prompt) {
|
|
66
66
|
if(/不(?:要)?(?:改代码|修改(?:任何)?代码|实施|生成原型)|\b(?:analysis only|do not (?:edit|modify|implement))\b/i.test(prompt))return true;
|
|
@@ -68,8 +68,25 @@ function readOnly(prompt) {
|
|
|
68
68
|
if(/先.{0,4}(?:分析|讨论|梳理|检查|解释)/.test(prompt)&&!/(?:然后|再|后).{0,8}(?:实现|实施|修改|继续)/.test(prompt))return true;
|
|
69
69
|
return /^\s*(?:请|先)?(?:暂停|停止|取消)(?:[,。!\s]|(?:这|当前|实施|工作|修改|生成))|^\s*(?:stop|cancel|pause)\b/i.test(prompt);
|
|
70
70
|
}
|
|
71
|
+
function userRestriction(prompt) {
|
|
72
|
+
if(readOnly(prompt))return true;
|
|
73
|
+
// Only an explicit request to resume implementation releases a restriction.
|
|
74
|
+
// Ordinary questions never turn a pause into permission to write.
|
|
75
|
+
if(typeof prompt!=='string'||/[??]|(?:为什么|如何|是否|哪些|什么|是不是|能不能|吗)/.test(prompt))return null;
|
|
76
|
+
const text=prompt.trim().replace(/^(?:(?:那就|好的?|现在|请|可以)[,,\s]*)+/,'').replace(/^please\s+/i,'');
|
|
77
|
+
const resume=/^(?:继续|恢复)(?:[。!!\s]*$|吧[。!!\s]*$|实施|实现|开发|修改|执行|生成|修订|(?:当前|本次)?原型(?:的)?(?:实施|实现|开发|修改|制作|生成|修订))/.test(text)||/^(?:开始实施|开始实现|实施吧|执行吧)/.test(text)||/^(?:按|按照|依照)[^\n]{0,40}(?:方案|计划)[,,\s]*(?:开始)?(?:实施|实现|执行)(?:吧)?(?:[,,。!!\s]|$)/.test(text)||/^(?:帮我)?(?:生成|创建|实现|修订|修改|制作)[^\n]{0,20}原型/.test(text)||/^\/i3-prototype\b[^\n]*(?:生成|实现|创建|修订|修改|继续)/.test(text)||/^(?:continue|resume)(?:[.!\s]*$|\s+(?:the prototype\s+)?(?:implementation|implementing|development|coding)\b)|^(?:proceed|start implementation)[.!\s]*$/i.test(text);
|
|
78
|
+
return resume?false:null;
|
|
79
|
+
}
|
|
80
|
+
function restriction(prompts=[],previous) {
|
|
81
|
+
const value={blocked:previous?.blocked===true,throughLine:previous?.throughLine||0};
|
|
82
|
+
for(const prompt of prompts)if(prompt.line>value.throughLine){
|
|
83
|
+
const control=userRestriction(prompt.text);if(control!==null)value.blocked=control;
|
|
84
|
+
value.throughLine=prompt.line;
|
|
85
|
+
}
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
71
88
|
function prefix(file,bytes,digest) {
|
|
72
89
|
assert.ok(Number.isSafeInteger(bytes)&&bytes>0&&bytes<=64*1024*1024,'Invalid source cursor');
|
|
73
90
|
const raw=E.cursorBytes(file);assert.ok(raw.length>=bytes,'Native transcript was truncated');assert.equal(E.sha(raw.subarray(0,bytes)),digest,'Native transcript prefix changed');
|
|
74
91
|
}
|
|
75
|
-
module.exports={read,scriptsForEntry,bundle,registration,globalBase,select,projectKey,sessionDirectory,source,readOnly,prefix};
|
|
92
|
+
module.exports={FILES:Object.freeze(FILES),read,scriptsForEntry,bundle,registration,globalBase,select,projectKey,sessionDirectory,source,readOnly,userRestriction,restriction,prefix};
|