@jc_stack/ez-agents 0.1.0-beta.29 → 0.1.0-beta.31

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/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.0-beta.31
6
+
7
+ - Make the owner-authorized contribution lifecycle explicit in shipped agent
8
+ guidance: take a coherent change through independent final-head review, CI,
9
+ applicable QA and, when authorized, merge. Release authority includes the
10
+ merge needed for publication, which continues through the reviewed GitHub
11
+ publisher, registry readback and eligible runtime verification. Preserve local
12
+ QA, diagnostics, auth-only work and deployment as separate boundaries.
13
+
14
+ ## 0.1.0-beta.30
15
+
16
+ - Bind installed native command launchers to the deployment's canonical control
17
+ directory. This makes application registration use the owning agent's state
18
+ and prevents caller environment variables from redirecting that authority.
19
+
5
20
  ## 0.1.0-beta.29
6
21
 
7
22
  - Republish the beta.28 Voice connection and web-serving contract at a monotonic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jc_stack/ez-agents",
3
- "version": "0.1.0-beta.29",
3
+ "version": "0.1.0-beta.31",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "A lightweight foundation for persistent business AI assistants using existing AI harnesses, workspaces and plugins.",
@@ -19,7 +19,7 @@ export async function bindUpdates(home,hostConfig,packageRoot=fileURLToPath(new
19
19
  await fs.writeFile(path.join(bin,'ez'),`#!${process.execPath}\nimport fs from 'node:fs';import {pathToFileURL} from 'node:url';const c=JSON.parse(fs.readFileSync(${configFile}));const m=await import(pathToFileURL(c.packageRoot+'/src/plugins/manager.mjs'));m.main(['--home',${JSON.stringify(home)},...process.argv.slice(2)]).catch(e=>{console.error(e.message);process.exitCode=1});\n`,{mode:0o700});
20
20
  for(const [name,entry] of Object.entries(pkg.bin)) {
21
21
  const dest=path.join(bin,name);await fs.rm(dest,{force:true});
22
- await fs.writeFile(dest,`#!${process.execPath}\nimport fs from 'node:fs';import {spawn} from 'node:child_process';const c=JSON.parse(fs.readFileSync(${configFile}));const child=spawn(c.packageRoot+'/'+${JSON.stringify(entry)},process.argv.slice(2),{stdio:'inherit',env:{...process.env,EZ_DEPLOYMENT_DIR:c.deploymentDir}});for(const s of ['SIGTERM','SIGINT'])process.on(s,()=>child.kill(s));child.on('error',e=>{console.error(e.message);process.exitCode=1});child.on('close',c=>process.exitCode=c??1);\n`,{mode:0o700});
22
+ await fs.writeFile(dest,`#!${process.execPath}\nimport fs from 'node:fs';import {spawn} from 'node:child_process';const c=JSON.parse(fs.readFileSync(${configFile}));const child=spawn(c.packageRoot+'/'+${JSON.stringify(entry)},process.argv.slice(2),{stdio:'inherit',env:{...process.env,EZ_DEPLOYMENT_DIR:c.deploymentDir,EZ_CONTROL_DIR:c.deploymentDir+'/control'}});for(const s of ['SIGTERM','SIGINT'])process.on(s,()=>child.kill(s));child.on('error',e=>{console.error(e.message);process.exitCode=1});child.on('close',c=>process.exitCode=c??1);\n`,{mode:0o700});
23
23
  }
24
24
  await bindToolDiscovery(home,config.workspace);
25
25
  return {ok:true,home,deploymentDir,packageRoot,policy:'Automatic compatible beta-channel updates by default; saved stable-only or manual policies take precedence. Local candidates require an explicit owner request.'};
@@ -67,6 +67,16 @@ a conflicting runner, context/prompt reconstruction or competing agent-turn queu
67
67
  Revise a violating patch before approval or merge; document real capability gaps
68
68
  instead of weakening the boundary to fit existing code.
69
69
 
70
+ For an owner-authorized product, fix or contribution, complete one coherent
71
+ loop: current main, focused PR, independent final-head review, required CI and
72
+ applicable QA. When the owner request or saved maintainer mandate includes merge
73
+ or release authority, then merge; release authority includes the merge needed for
74
+ the release. Otherwise leave the reviewed PR ready and state the remaining
75
+ authority. When release authority applies, continue through immutable
76
+ artifact publication, the repository's reviewed GitHub publisher, registry
77
+ readback and eligible installed-runtime verification. Local QA,
78
+ diagnostics, auth-only work and deployment remain separate authority boundaries.
79
+
70
80
  Within the owner's request or saved contribution mandate, you may report evidenced
71
81
  existing violations and submit focused fixes. Check existing issues, PRs and active
72
82
  owners first; add sanitized evidence and a concrete next action to the existing
@@ -25,6 +25,14 @@ test('shared guidance makes direct owner chat replies a native transport action'
25
25
  assert.match(guidance, /unchanged scheduled\nmonitoring stays quiet/)
26
26
  })
27
27
 
28
+ test('shared guidance completes authorized contribution and release loops', () => {
29
+ const guidance = agentGuidance()
30
+ assert.match(guidance, /independent final-head review, required CI and\napplicable QA/)
31
+ assert.match(guidance, /mandate includes merge\nor release authority, then merge; release authority includes the merge needed for\nthe release. Otherwise leave the reviewed PR ready and state the remaining\nauthority/)
32
+ assert.match(guidance, /immutable\nartifact publication, the repository's reviewed GitHub publisher, registry\nreadback/)
33
+ assert.match(guidance, /Local QA,\ndiagnostics, auth-only work and deployment remain separate authority boundaries/)
34
+ })
35
+
28
36
  test('package guidance resolution ignores a workspace shadow file', async () => {
29
37
  const root = path.join(tmpdir(), `ez-guidance-${randomUUID()}`)
30
38
  await mkdir(root, { recursive: true })
@@ -210,8 +210,9 @@ test('bound dispatch follows active package root and retains private scope',asyn
210
210
  assert.match(await fs.readFile(path.join(f.agent.workspace,'AGENTS.md'),'utf8'),/tools list --details/);
211
211
  const config=await read(path.join(f.home,'config.json'));config.packageRoot=f.source;await atomic(path.join(f.home,'config.json'),config);
212
212
  // A native launcher from the real package looks up its entry point in the active root.
213
- await fs.writeFile(path.join(f.source,'bin/ezenciel-agents.mjs'),'#!/usr/bin/env node\nconsole.log(process.env.EZ_DEPLOYMENT_DIR)',{mode:0o755});
214
- const result=await exec(path.join(f.home,'bin/ezenciel-agents'),['--version']);assert.equal(result.stdout.trim(),f.config.deploymentDir);
213
+ await fs.writeFile(path.join(f.source,'bin/ezenciel-agents.mjs'),'#!/usr/bin/env node\nconsole.log(process.env.EZ_DEPLOYMENT_DIR+"|"+process.env.EZ_CONTROL_DIR)',{mode:0o755});
214
+ const result=await exec(path.join(f.home,'bin/ezenciel-agents'),['--version'],{env:{...process.env,EZ_CONTROL_DIR:'/attacker'}});
215
+ assert.equal(result.stdout.trim(),f.config.deploymentDir+'|'+f.agent.controlDir);
215
216
  assert((await fs.readFile(path.join(f.agent.workspace,'TOOLS.md'),'utf8')).startsWith('My notes'));
216
217
  });
217
218
  test('upgrade subprocess environment never inherits relay/provider secrets',()=>{