@agfpd/iapeer 0.2.69 → 0.2.70
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/package.json
CHANGED
|
@@ -107,6 +107,46 @@ describe('buildLaunchInvocation — differential vs the verbatim pre-extraction
|
|
|
107
107
|
})
|
|
108
108
|
})
|
|
109
109
|
|
|
110
|
+
// Silent-loss guard — the claude-hosting canary caught a warm-deliver false-fail: a launch INITIATED
|
|
111
|
+
// from inside a claude session leaked CLAUDE_CODE_SESSION_ID + CLAUDE_CODE_CHILD_SESSION into the
|
|
112
|
+
// child, which then wrote no own transcript → newestActivityMtime null → landed-confirm blind while
|
|
113
|
+
// the message landed. buildLaunchInvocation must strip the claude-code-internal namespace so a
|
|
114
|
+
// launched claude is always a FRESH top-level session, regardless of initiator env.
|
|
115
|
+
describe('buildLaunchInvocation — strips the claude-code-internal session namespace', () => {
|
|
116
|
+
const DIRTY: LaunchAdapterConfig & { env: NodeJS.ProcessEnv } = {
|
|
117
|
+
claudeBin: '/bin/claude',
|
|
118
|
+
codexBin: '/bin/codex',
|
|
119
|
+
env: {
|
|
120
|
+
PATH: '/test/path',
|
|
121
|
+
BASE_VAR: 'base',
|
|
122
|
+
CLAUDE_CODE_SESSION_ID: 'spawner-session-uuid', // the corruptor (pins the child to the spawner's session)
|
|
123
|
+
CLAUDE_CODE_CHILD_SESSION: '1', // the corruptor (marks a child sub-session → suppresses own transcript)
|
|
124
|
+
CLAUDECODE: '1',
|
|
125
|
+
CLAUDE_CODE_ENTRYPOINT: 'cli',
|
|
126
|
+
CLAUDE_CODE_EXECPATH: '/v/2.1.177',
|
|
127
|
+
CLAUDE_EFFORT: 'xhigh', // NOT in the claude-code namespace → must survive (scoped strip, not a wipe)
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
test('claude launch: the whole CLAUDE_CODE_* namespace + CLAUDECODE is removed', () => {
|
|
131
|
+
const { env } = buildLaunchInvocation(spec({ runtime: 'claude', identity: 'claude-p' }), claudeAdapter, DIRTY)
|
|
132
|
+
expect(env.CLAUDE_CODE_SESSION_ID).toBeUndefined()
|
|
133
|
+
expect(env.CLAUDE_CODE_CHILD_SESSION).toBeUndefined()
|
|
134
|
+
expect(env.CLAUDECODE).toBeUndefined()
|
|
135
|
+
expect(env.CLAUDE_CODE_ENTRYPOINT).toBeUndefined()
|
|
136
|
+
expect(env.CLAUDE_CODE_EXECPATH).toBeUndefined()
|
|
137
|
+
// scoped: non-namespace vars (incl. a CLAUDE_-prefixed-but-not-CLAUDE_CODE_ one) survive
|
|
138
|
+
expect(env.BASE_VAR).toBe('base')
|
|
139
|
+
expect(env.CLAUDE_EFFORT).toBe('xhigh')
|
|
140
|
+
expect(env.PEER_IDENTITY).toBe('claude-p')
|
|
141
|
+
})
|
|
142
|
+
test('codex launch: same strip applies (harmless — codex ignores CLAUDE_*) and the bearer stub stays', () => {
|
|
143
|
+
const { env } = buildLaunchInvocation(spec({ runtime: 'codex', identity: 'codex-p' }), codexAdapter, DIRTY)
|
|
144
|
+
expect(env.CLAUDE_CODE_SESSION_ID).toBeUndefined()
|
|
145
|
+
expect(env.CLAUDECODE).toBeUndefined()
|
|
146
|
+
expect(env[CODEX_BEARER_ENV_VAR]).toBe(CODEX_DUMMY_BEARER)
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
110
150
|
// Independent contract anchors — expectations come from the CONTRACT, not from the function output.
|
|
111
151
|
describe('buildLaunchInvocation — identity ABI + system-prompt swap (contract values)', () => {
|
|
112
152
|
test('codex carries the non-secret IAPEER_BEARER stub; claude does NOT (identity in .mcp.json)', () => {
|
package/src/launch/invocation.ts
CHANGED
|
@@ -52,5 +52,20 @@ export function buildLaunchInvocation(
|
|
|
52
52
|
PEER_IDENTITY: spec.identity,
|
|
53
53
|
PATH: env.PATH ?? `${homedir()}/.bun/bin:${homedir()}/.local/bin:/opt/homebrew/bin:/usr/bin:/bin`,
|
|
54
54
|
}
|
|
55
|
+
// Strip the claude-code-internal session namespace from the inherited env. When a launch is
|
|
56
|
+
// INITIATED from inside a running claude session (an operator CLI, or a claude peer shelling out),
|
|
57
|
+
// process.env carries that session's CLAUDE_CODE_SESSION_ID + CLAUDE_CODE_CHILD_SESSION. Inherited
|
|
58
|
+
// by a newly-launched claude, they make it believe it is a CHILD sub-session of the initiator → it
|
|
59
|
+
// writes NO independent ~/.claude/projects transcript → newestActivityMtime(cwd) is permanently
|
|
60
|
+
// null → the warm-deliver landed-confirm false-fails WHILE the message actually lands (a silent-
|
|
61
|
+
// loss, the class the contract forbids). Stripping the whole namespace makes a launched claude
|
|
62
|
+
// always start as a FRESH top-level session (it re-establishes its own vars), independent of who
|
|
63
|
+
// initiated the launch — the env-composition analogue of the supervisor's TMUX strip. Caught live
|
|
64
|
+
// by the claude-hosting canary. Harmless for codex (no CLAUDE_* usage). NOTE: a launch driven by
|
|
65
|
+
// the always-on daemon already has a clean env (no claude session) — this hardens the CLI / peer-
|
|
66
|
+
// initiated paths and removes the silent-loss class regardless of initiator.
|
|
67
|
+
for (const k of Object.keys(childEnv)) {
|
|
68
|
+
if (k.startsWith('CLAUDE_CODE_') || k === 'CLAUDECODE') delete childEnv[k]
|
|
69
|
+
}
|
|
55
70
|
return { argv, env: childEnv }
|
|
56
71
|
}
|