@givolt/i3-composer-agent 2.3.3 → 2.3.4
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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +2 -2
- package/bin/i3-composer-agent.cjs +18 -15
- package/bin/wizard.cjs +12 -52
- package/docs/codebuddy-setup.md +21 -7
- package/docs/codex-setup.md +1 -1
- package/docs/other-hosts.md +1 -1
- package/docs/workbuddy-setup.md +18 -2
- package/hooks/manage.cjs +22 -14
- package/package.json +5 -1
- package/plugin.json +1 -1
- package/scripts/ui-prototype-buddy-lifecycle-test.js +89 -0
- package/scripts/ui-prototype-codebuddy-hook-test.js +1 -1
- package/scripts/ui-prototype-dependencies-test.js +13 -0
- package/scripts/ui-prototype-execution-gates-test.js +24 -0
- package/scripts/ui-prototype-execution-policy-test.js +12 -1
- package/scripts/ui-prototype-recovery-test.js +72 -0
- package/skills/i3-ui-prototype/SKILL.md +5 -3
- package/skills/i3-ui-prototype/assets/hosts/codebuddy/profile.json +10 -6
- package/skills/i3-ui-prototype/references/entry-contract.md +1 -1
- package/skills/i3-ui-prototype/references/execution-evidence.md +25 -8
- package/skills/i3-ui-prototype/references/interaction-acceptance.md +1 -1
- package/skills/i3-ui-prototype/references/project-layout.md +1 -1
- package/skills/i3-ui-prototype/scripts/buddy-host.cjs +40 -0
- package/skills/i3-ui-prototype/scripts/codebuddy-context.cjs +14 -14
- package/skills/i3-ui-prototype/scripts/codebuddy-hook.cjs +74 -35
- package/skills/i3-ui-prototype/scripts/codebuddy-registration.cjs +7 -5
- package/skills/i3-ui-prototype/scripts/execution-evidence.cjs +1 -1
- package/skills/i3-ui-prototype/scripts/execution-gates.cjs +23 -2
- package/skills/i3-ui-prototype/scripts/execution-policy.cjs +28 -7
- package/skills/i3-ui-prototype/scripts/execution-recovery.cjs +52 -0
- package/skills/i3-ui-prototype/scripts/execution-runtime.cjs +1 -1
- package/skills/i3-ui-prototype/scripts/hosts/codebuddy.cjs +9 -5
- package/skills/i3-ui-prototype/scripts/native-command.cjs +18 -0
- package/skills/i3-ui-prototype/scripts/native-pilot-lib.cjs +2 -4
- package/skills/i3-ui-prototype/scripts/native-pilot.cjs +5 -1
- package/skills/i3-ui-prototype/scripts/prototype-dependencies.cjs +28 -6
- package/skills/i3-ui-prototype/scripts/prototype-hooks.cjs +13 -13
- package/skills/i3-ui-prototype/scripts/prototype-locations.cjs +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
const fs=require('node:fs'),path=require('node:path'),os=require('node:os'),assert=require('node:assert/strict');
|
|
5
5
|
const R=require('./codebuddy-registration.cjs'),C=require('./codebuddy-context.cjs'),E=require('./execution-evidence.cjs');
|
|
6
6
|
function context(options) {
|
|
7
|
-
|
|
7
|
+
const host=options.host||'codebuddy';assert.ok(['codebuddy','workbuddy'].includes(host),'A+B supports CodeBuddy and WorkBuddy');
|
|
8
8
|
const project=fs.realpathSync(path.resolve(options.project||'.')),scope=options.scope;
|
|
9
9
|
assert.ok(['project','global'].includes(scope),'Specify project or global installation scope');
|
|
10
10
|
const base=scope==='project'?path.join(project,'.codebuddy'):C.globalBase(options);
|
|
@@ -12,7 +12,7 @@ function context(options) {
|
|
|
12
12
|
const record=recordText?JSON.parse(recordText):null;
|
|
13
13
|
const unified=path.join(base,'i3-composer-agent/hooks/i3-prototype.cjs');
|
|
14
14
|
const scriptPath=options.entryPath||(fs.existsSync(unified)?unified:path.join(base,'skills/i3-ui-prototype/scripts/hosts/codebuddy.cjs'));
|
|
15
|
-
return {project,scope,base,record,scriptPath};
|
|
15
|
+
return {project,scope,base,record,scriptPath,host};
|
|
16
16
|
}
|
|
17
17
|
function prepare(options,runtime={}) {
|
|
18
18
|
const current=runtime.current||context(options),readText=runtime.readText||R.fileIO.read,action=options.action||'keep';
|
|
@@ -21,12 +21,8 @@ function prepare(options,runtime={}) {
|
|
|
21
21
|
if(action==='disable'){const settings=R.config(readText(path.join(current.base,'settings.json')));assert.ok(!Object.values(settings.hooks||{}).flat().some(g=>g.hooks.some(h=>h.command?.includes(R.OWNER))),'Unknown owned-looking Hook has no ownership record; preserve it for review');}
|
|
22
22
|
return {summary:{status:'not-enabled',scope:current.scope,changed:false},unchanged:true};
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const manifest=readText(path.join(current.base,'.i3-composer-agent.json'));
|
|
27
|
-
if(manifest)assert.ok(!JSON.parse(manifest).agents?.includes('workbuddy'),'Shared CodeBuddy/WorkBuddy registration cannot safely identify the product; preserve settings and use an exclusive CodeBuddy scope');
|
|
28
|
-
assert.ok(!options.agents?.includes('workbuddy')||current.scope!=='project','Do not enable CodeBuddy audit in a shared WorkBuddy project target');
|
|
29
|
-
}
|
|
24
|
+
assert.ok(options.product===undefined||['auto','ide','cli'].includes(options.product),'Invalid Buddy product profile');
|
|
25
|
+
const product='auto'; // Legacy product arguments are hints, never a second new registration.
|
|
30
26
|
const explicit=options.transcriptRoot,roots=explicit==='auto'?[]:explicit?[path.resolve(explicit)]:current.record?.transcriptRoots||[];
|
|
31
27
|
const mode=explicit?(explicit==='auto'?'auto':'manual'):current.record?.transcriptMode||(roots.length?'manual':'auto');
|
|
32
28
|
if(action!=='disable') {
|
|
@@ -34,7 +30,7 @@ function prepare(options,runtime={}) {
|
|
|
34
30
|
}
|
|
35
31
|
const settingsText=readText(path.join(current.base,'settings.json')),settings=R.config(settingsText);
|
|
36
32
|
if(action!=='disable')assert.ok(!settings.disableAllHooks&&!settings.allowManagedHooksOnly,'Host policy prevents automatic auditing; preserve the existing policy');
|
|
37
|
-
return R.plan({action,...current,product,nodePath:process.execPath,scriptDigest:runtime.scriptDigest||C.bundle(options.entrySource||(path.basename(current.scriptPath)==='i3-prototype.cjs'?current.scriptPath:path.join(__dirname,'hosts/codebuddy.cjs'))),currentText:settingsText,
|
|
33
|
+
return R.plan({action,...current,product,hosts:options.hosts,agents:options.agents,nodePath:process.execPath,scriptDigest:runtime.scriptDigest||C.bundle(options.entrySource||(path.basename(current.scriptPath)==='i3-prototype.cjs'?current.scriptPath:path.join(__dirname,'hosts/codebuddy.cjs'))),currentText:settingsText,
|
|
38
34
|
transcriptMode:mode,transcriptRoots:roots,productVersion:options.productVersion||current.record?.productVersion||'unreported'});
|
|
39
35
|
}
|
|
40
36
|
function configure(options) {
|
|
@@ -51,8 +47,9 @@ function check(options,runtime={}) {
|
|
|
51
47
|
return {...result,status:result.filesPresent?'files-present':'not-enabled'};
|
|
52
48
|
}
|
|
53
49
|
try {
|
|
54
|
-
const record=(runtime.registration||C.registration)(current.base),
|
|
55
|
-
Object.
|
|
50
|
+
const record=(runtime.registration||C.registration)(current.base),host=options.host||'codebuddy',products=record.product==='auto'?(host==='workbuddy'?['ide']:['ide','cli']):[record.product];
|
|
51
|
+
const effectiveByProduct=Object.fromEntries(products.map(product=>[product,(runtime.select||C.select)({project:current.project,product,host,home:options.home,env:options.env})?.base===current.base]));
|
|
52
|
+
Object.assign(result,{host,product:record.product,productVersion:record.productVersion,registrationDigest:record.registrationDigest,effective:Object.values(effectiveByProduct).every(Boolean),effectiveByProduct,transcriptRoots:record.transcriptRoots,
|
|
56
53
|
transcript:{mode:record.transcriptMode||(record.transcriptRoots?.length?'manual':'auto'),status:'awaiting-native-event',invocationVerified:false}});
|
|
57
54
|
let observation=null;
|
|
58
55
|
const parent=path.join(current.base,'state/i3-prototype',C.projectKey(current.project));
|
|
@@ -62,18 +59,21 @@ function check(options,runtime={}) {
|
|
|
62
59
|
const raw=R.fileIO.read(path.join(parent,name,'session.json'));if(!raw)continue;
|
|
63
60
|
entries.push(...Object.values(JSON.parse(raw).bindings||{}));
|
|
64
61
|
}
|
|
65
|
-
for(const entry of entries)if(entry.project===current.project&&entry.registrationDigest===record.registrationDigest&&entry.settingsDigest===record.settingsDigest&&(!observation||entry.lastHook.at>observation.lastHook.at))observation=entry;
|
|
62
|
+
for(const entry of entries)if((entry.host||'codebuddy')===host&&entry.project===current.project&&entry.registrationDigest===record.registrationDigest&&entry.settingsDigest===record.settingsDigest&&(!observation||entry.lastHook.at>observation.lastHook.at))observation=entry;
|
|
66
63
|
if(observation) {
|
|
67
64
|
result.transcript.path=observation.source.path;
|
|
68
65
|
C.prefix(observation.source.path,observation.source.bytes,observation.source.digest);
|
|
69
66
|
C.source({session_id:observation.sessionId,transcript_path:observation.source.path},record,current.project);
|
|
70
67
|
Object.assign(result.transcript,{status:'verified',invocationVerified:true});
|
|
71
68
|
result.observation={sessionId:observation.sessionId,projectKey:observation.projectKey,runId:observation.runId,event:observation.lastHook.event,at:observation.lastHook.at};
|
|
69
|
+
const observedProduct=observation.product||(record.product!=='auto'?record.product:null);
|
|
70
|
+
assert.ok(['ide','cli'].includes(observedProduct),'Observed native product identity missing');
|
|
71
|
+
Object.assign(result,{product:observedProduct,productVersion:observation.productVersion||'unreported',effective:effectiveByProduct[observedProduct]===true,identitySource:observation.identitySource||'legacy-profile',recovery:observation.recovery||null});
|
|
72
72
|
}
|
|
73
73
|
const recent=observation&&Date.now()-Date.parse(observation.lastHook.at)>=0&&Date.now()-Date.parse(observation.lastHook.at)<30*60*1000;
|
|
74
74
|
return {...result,status:result.effective&&recent?'active':record.product==='cli'?'pending-host-review':'registered',
|
|
75
75
|
activationScope:'Only the displayed project/session/configuration and adapter bytes; not all projects or business acceptance',
|
|
76
|
-
next:
|
|
76
|
+
next:'CLI: review /hooks; desktop: reload. Verify an actual Skill invocation and missing-Skill recovery in the chosen host.'};
|
|
77
77
|
}catch(error){if(result.transcript)Object.assign(result.transcript,{status:'unverified',invocationVerified:false});return {...result,status:'failed',errors:[error.message]};}
|
|
78
78
|
}
|
|
79
79
|
function main(argv=process.argv.slice(2)) {
|
|
@@ -12,7 +12,7 @@ function globalSkillsDir(agent, home, env) {
|
|
|
12
12
|
let base = home;
|
|
13
13
|
if (config.base === 'config') base = env.XDG_CONFIG_HOME && path.isAbsolute(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path.join(home, '.config');
|
|
14
14
|
if (config.base === 'env') base = env[config.env]?.trim() || path.join(home, config.fallback);
|
|
15
|
-
if (config.env
|
|
15
|
+
if (['CODEBUDDY_CONFIG_DIR','WORKBUDDY_CONFIG_DIR'].includes(config.env) && (!path.isAbsolute(base) || /[\x00\r\n]/.test(base))) throw new Error(`${config.env} must be an absolute safe directory`);
|
|
16
16
|
if (config.alternatives && !fs.existsSync(path.join(home, path.dirname(config.path)))) {
|
|
17
17
|
const alternative = config.alternatives.find(relative => fs.existsSync(path.join(home, path.dirname(relative))));
|
|
18
18
|
if (alternative) return path.join(home, alternative);
|