crewly 1.20.167 → 1.20.169
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/config/constants.ts +4 -0
- package/config/skills/_common/lib.sh +5 -0
- package/dist/backend/backend/src/constants.d.ts +52 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +50 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +9 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +171 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +5 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/agent-origin.middleware.d.ts +45 -0
- package/dist/backend/backend/src/middleware/agent-origin.middleware.d.ts.map +1 -0
- package/dist/backend/backend/src/middleware/agent-origin.middleware.js +148 -0
- package/dist/backend/backend/src/middleware/agent-origin.middleware.js.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-process-origin.service.d.ts +86 -0
- package/dist/backend/backend/src/services/agent/agent-process-origin.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-process-origin.service.js +114 -0
- package/dist/backend/backend/src/services/agent/agent-process-origin.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/codex-daemon.utils.d.ts +56 -0
- package/dist/backend/backend/src/services/agent/codex-daemon.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/codex-daemon.utils.js +100 -0
- package/dist/backend/backend/src/services/agent/codex-daemon.utils.js.map +1 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +15 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +27 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +12 -4
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +11 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +14 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +11 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +24 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.service.d.ts +15 -5
- package/dist/backend/backend/src/services/system/auto-update.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.service.js +26 -21
- package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.utils.d.ts +51 -0
- package/dist/backend/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.utils.js +103 -0
- package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/backend/config/constants.d.ts +4 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +4 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +52 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +50 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/codex-daemon.utils.d.ts +56 -0
- package/dist/cli/backend/src/services/agent/codex-daemon.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/codex-daemon.utils.js +100 -0
- package/dist/cli/backend/src/services/agent/codex-daemon.utils.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +15 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +27 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +12 -4
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +11 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +14 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts +11 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js +24 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/cli/backend/src/services/system/auto-update.utils.d.ts +51 -0
- package/dist/cli/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
- package/dist/cli/backend/src/services/system/auto-update.utils.js +103 -0
- package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/dist/cli/config/constants.d.ts +4 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +4 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Origin Middleware
|
|
3
|
+
*
|
|
4
|
+
* Checks a local skill request's claimed identity (`X-Agent-Session`) against
|
|
5
|
+
* the agent PTY its process actually runs under (`X-Agent-Pid`, walked up the
|
|
6
|
+
* process tree). When the process provably belongs to a different agent, the
|
|
7
|
+
* request is treated as that agent: `X-Agent-Session` is rewritten and the
|
|
8
|
+
* claim is kept in `X-Agent-Session-Claimed`. Either way it WARNs, because a
|
|
9
|
+
* wrong CREWLY_SESSION_NAME means the runtime leaked another agent's
|
|
10
|
+
* environment (Codex's shared app-server daemon did, 2026-09-30).
|
|
11
|
+
*
|
|
12
|
+
* It only ever corrects a header that is already there — it never gives an
|
|
13
|
+
* anonymous request an agent identity — and only on loopback, where the pid
|
|
14
|
+
* means something. A slow or failed lookup leaves the request as it came.
|
|
15
|
+
*
|
|
16
|
+
* @module agent-origin.middleware
|
|
17
|
+
*/
|
|
18
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
19
|
+
import { AgentProcessOriginService, type ProcessOrigin } from '../services/agent/agent-process-origin.service.js';
|
|
20
|
+
/**
|
|
21
|
+
* Apply a resolved origin to the request: rewrite a contradicted header and
|
|
22
|
+
* warn about it, or warn that the command ran in a shared daemon.
|
|
23
|
+
*
|
|
24
|
+
* @param req - Request (headers are mutated when corrected)
|
|
25
|
+
* @param claimed - The X-Agent-Session the shell sent
|
|
26
|
+
* @param origin - Where its process really runs
|
|
27
|
+
*/
|
|
28
|
+
export declare function applyAgentOrigin(req: Request, claimed: string, origin: ProcessOrigin): void;
|
|
29
|
+
/**
|
|
30
|
+
* Express middleware; see the module doc. Runs after the API-token gate and
|
|
31
|
+
* before the heartbeat middleware, so the heartbeat and every controller see
|
|
32
|
+
* the corrected identity.
|
|
33
|
+
*
|
|
34
|
+
* @param req - Express request
|
|
35
|
+
* @param _res - Express response
|
|
36
|
+
* @param next - Next handler
|
|
37
|
+
*/
|
|
38
|
+
export declare function agentOriginMiddleware(req: Request, _res: Response, next: NextFunction): void;
|
|
39
|
+
/**
|
|
40
|
+
* Replace the origin service (tests).
|
|
41
|
+
*
|
|
42
|
+
* @param service - Service to use, or null to rebuild the default lazily
|
|
43
|
+
*/
|
|
44
|
+
export declare function setAgentOriginServiceForTesting(service: AgentProcessOriginService | null): void;
|
|
45
|
+
//# sourceMappingURL=agent-origin.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-origin.middleware.d.ts","sourceRoot":"","sources":["../../../../../backend/src/middleware/agent-origin.middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAAE,yBAAyB,EAAE,KAAK,aAAa,EAAE,MAAM,mDAAmD,CAAC;AA8DlH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAkB3F;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAuB5F;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI,CAG/F"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Origin Middleware
|
|
3
|
+
*
|
|
4
|
+
* Checks a local skill request's claimed identity (`X-Agent-Session`) against
|
|
5
|
+
* the agent PTY its process actually runs under (`X-Agent-Pid`, walked up the
|
|
6
|
+
* process tree). When the process provably belongs to a different agent, the
|
|
7
|
+
* request is treated as that agent: `X-Agent-Session` is rewritten and the
|
|
8
|
+
* claim is kept in `X-Agent-Session-Claimed`. Either way it WARNs, because a
|
|
9
|
+
* wrong CREWLY_SESSION_NAME means the runtime leaked another agent's
|
|
10
|
+
* environment (Codex's shared app-server daemon did, 2026-09-30).
|
|
11
|
+
*
|
|
12
|
+
* It only ever corrects a header that is already there — it never gives an
|
|
13
|
+
* anonymous request an agent identity — and only on loopback, where the pid
|
|
14
|
+
* means something. A slow or failed lookup leaves the request as it came.
|
|
15
|
+
*
|
|
16
|
+
* @module agent-origin.middleware
|
|
17
|
+
*/
|
|
18
|
+
import { AGENT_ORIGIN_CONSTANTS } from '../constants.js';
|
|
19
|
+
import { LoggerService } from '../services/core/logger.service.js';
|
|
20
|
+
import { getSessionBackendSync } from '../services/session/session-backend.factory.js';
|
|
21
|
+
import { AgentProcessOriginService } from '../services/agent/agent-process-origin.service.js';
|
|
22
|
+
import { isLoopbackAddress, isLoopbackRequest } from './api-token.middleware.js';
|
|
23
|
+
const logger = LoggerService.getInstance().createComponentLogger('AgentOriginMiddleware');
|
|
24
|
+
/**
|
|
25
|
+
* PTY shell pid → session name for the live sessions.
|
|
26
|
+
*
|
|
27
|
+
* @returns Map (empty when no session backend is up)
|
|
28
|
+
*/
|
|
29
|
+
function liveSessionPids() {
|
|
30
|
+
const out = new Map();
|
|
31
|
+
const backend = getSessionBackendSync();
|
|
32
|
+
if (!backend)
|
|
33
|
+
return out;
|
|
34
|
+
for (const name of backend.listSessions()) {
|
|
35
|
+
const pid = backend.getSession(name)?.pid;
|
|
36
|
+
if (typeof pid === 'number' && pid > 1)
|
|
37
|
+
out.set(pid, name);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
let originService = null;
|
|
42
|
+
const lastWarned = new Map();
|
|
43
|
+
/**
|
|
44
|
+
* Log at most once per WARN_THROTTLE_MS per key.
|
|
45
|
+
*
|
|
46
|
+
* @param key - Throttle key
|
|
47
|
+
* @param message - Log message
|
|
48
|
+
* @param meta - Log fields
|
|
49
|
+
*/
|
|
50
|
+
function warnThrottled(key, message, meta) {
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
const last = lastWarned.get(key);
|
|
53
|
+
if (last !== undefined && now - last < AGENT_ORIGIN_CONSTANTS.WARN_THROTTLE_MS)
|
|
54
|
+
return;
|
|
55
|
+
lastWarned.set(key, now);
|
|
56
|
+
logger.warn(message, meta);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve with `null` if the lookup takes longer than `ms`.
|
|
60
|
+
*
|
|
61
|
+
* @param promise - Lookup
|
|
62
|
+
* @param ms - Timeout
|
|
63
|
+
* @returns The lookup's result or null
|
|
64
|
+
*/
|
|
65
|
+
function withTimeout(promise, ms) {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
const timer = setTimeout(() => resolve(null), ms);
|
|
68
|
+
promise.then((value) => {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
resolve(value);
|
|
71
|
+
}, () => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve(null);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Apply a resolved origin to the request: rewrite a contradicted header and
|
|
79
|
+
* warn about it, or warn that the command ran in a shared daemon.
|
|
80
|
+
*
|
|
81
|
+
* @param req - Request (headers are mutated when corrected)
|
|
82
|
+
* @param claimed - The X-Agent-Session the shell sent
|
|
83
|
+
* @param origin - Where its process really runs
|
|
84
|
+
*/
|
|
85
|
+
export function applyAgentOrigin(req, claimed, origin) {
|
|
86
|
+
if (origin.session && origin.session !== claimed) {
|
|
87
|
+
req.headers[AGENT_ORIGIN_CONSTANTS.CLAIMED_SESSION_HEADER] = claimed;
|
|
88
|
+
req.headers[AGENT_ORIGIN_CONSTANTS.SESSION_HEADER] = origin.session;
|
|
89
|
+
warnThrottled(`mismatch:${claimed}:${origin.session}`, 'Skill request claimed another agent\'s identity — its process runs under a different agent PTY; treating it as that agent. The runtime leaked the wrong CREWLY_SESSION_NAME into the agent\'s shell.', {
|
|
90
|
+
claimedSession: claimed,
|
|
91
|
+
actualSession: origin.session,
|
|
92
|
+
viaSharedDaemon: origin.viaSharedDaemon,
|
|
93
|
+
path: req.path,
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!origin.session && origin.viaSharedDaemon) {
|
|
98
|
+
warnThrottled(`daemon:${claimed}`, 'Skill request came from a shared Codex app-server daemon, not an agent PTY — its X-Agent-Session may belong to whichever agent started the daemon. Restart the agent so Codex launches with --no-daemon.', {
|
|
99
|
+
claimedSession: claimed,
|
|
100
|
+
path: req.path,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Express middleware; see the module doc. Runs after the API-token gate and
|
|
106
|
+
* before the heartbeat middleware, so the heartbeat and every controller see
|
|
107
|
+
* the corrected identity.
|
|
108
|
+
*
|
|
109
|
+
* @param req - Express request
|
|
110
|
+
* @param _res - Express response
|
|
111
|
+
* @param next - Next handler
|
|
112
|
+
*/
|
|
113
|
+
export function agentOriginMiddleware(req, _res, next) {
|
|
114
|
+
const claimed = req.headers[AGENT_ORIGIN_CONSTANTS.SESSION_HEADER];
|
|
115
|
+
const rawPid = req.headers[AGENT_ORIGIN_CONSTANTS.PID_HEADER];
|
|
116
|
+
if (typeof claimed !== 'string' || !claimed || typeof rawPid !== 'string' || !/^\d+$/.test(rawPid)) {
|
|
117
|
+
next();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const pid = Number(rawPid);
|
|
121
|
+
if (pid <= 1 || !isLoopbackAddress(req.socket?.remoteAddress ?? '') || !isLoopbackRequest(req)) {
|
|
122
|
+
next();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
originService ??= new AgentProcessOriginService({ listSessionPids: liveSessionPids });
|
|
126
|
+
void withTimeout(originService.resolve(pid), AGENT_ORIGIN_CONSTANTS.LOOKUP_TIMEOUT_MS).then((origin) => {
|
|
127
|
+
try {
|
|
128
|
+
if (origin)
|
|
129
|
+
applyAgentOrigin(req, claimed, origin);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
logger.debug('Agent origin check failed (request left as sent)', {
|
|
133
|
+
error: error instanceof Error ? error.message : String(error),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
next();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Replace the origin service (tests).
|
|
141
|
+
*
|
|
142
|
+
* @param service - Service to use, or null to rebuild the default lazily
|
|
143
|
+
*/
|
|
144
|
+
export function setAgentOriginServiceForTesting(service) {
|
|
145
|
+
originService = service;
|
|
146
|
+
lastWarned.clear();
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=agent-origin.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-origin.middleware.js","sourceRoot":"","sources":["../../../../../backend/src/middleware/agent-origin.middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which agent PTY a local skill process really belongs to.
|
|
3
|
+
*
|
|
4
|
+
* Skills name their caller with `X-Agent-Session`, read from
|
|
5
|
+
* CREWLY_SESSION_NAME in the shell that ran them. That variable is only as
|
|
6
|
+
* good as the process tree it came from: Codex's shared app-server daemon ran
|
|
7
|
+
* every Codex agent's commands with the orchestrator's environment
|
|
8
|
+
* (2026-09-30), so each of them claimed to be `crewly-orc`.
|
|
9
|
+
*
|
|
10
|
+
* Skills also send `X-Agent-Pid` (the skill shell's own pid). On this machine
|
|
11
|
+
* that pid's parent chain leads to exactly one agent PTY shell — the process
|
|
12
|
+
* Crewly spawned for the session — unless it runs under a shared daemon, in
|
|
13
|
+
* which case it leads to no PTY at all. This service walks that chain.
|
|
14
|
+
*
|
|
15
|
+
* @module services/agent/agent-process-origin.service
|
|
16
|
+
*/
|
|
17
|
+
/** One row of the process table. */
|
|
18
|
+
export interface ProcessEntry {
|
|
19
|
+
ppid: number;
|
|
20
|
+
/** Full command line (only matched against, never logged) */
|
|
21
|
+
args: string;
|
|
22
|
+
}
|
|
23
|
+
/** Where a skill process came from. */
|
|
24
|
+
export interface ProcessOrigin {
|
|
25
|
+
/** The agent session whose PTY is an ancestor, or null when none is */
|
|
26
|
+
session: string | null;
|
|
27
|
+
/** True when the chain reaches Codex's shared app-server daemon (session is then null) */
|
|
28
|
+
viaSharedDaemon: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Walk from `pid` up through its parents until an agent PTY shell is found.
|
|
32
|
+
*
|
|
33
|
+
* A shared Codex daemon ends the walk: it is often still the child of the
|
|
34
|
+
* TUI that started it (the orchestrator's), so walking on would "prove" the
|
|
35
|
+
* very identity that leaked.
|
|
36
|
+
*
|
|
37
|
+
* @param pid - Starting process (the skill shell)
|
|
38
|
+
* @param table - pid → {ppid, args}
|
|
39
|
+
* @param sessionPids - PTY shell pid → session name
|
|
40
|
+
* @returns The owning session (or null) and whether a shared Codex daemon sits in between
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveProcessOrigin(pid: number, table: ReadonlyMap<number, ProcessEntry>, sessionPids: ReadonlyMap<number, string>): ProcessOrigin;
|
|
43
|
+
/**
|
|
44
|
+
* Parse `ps -Ao pid=,ppid=,args=` output.
|
|
45
|
+
*
|
|
46
|
+
* @param output - Raw ps output
|
|
47
|
+
* @returns pid → entry
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseProcessTable(output: string): Map<number, ProcessEntry>;
|
|
50
|
+
/**
|
|
51
|
+
* Read the process table with one `ps` call (same flags on Linux and macOS).
|
|
52
|
+
*
|
|
53
|
+
* @returns pid → entry
|
|
54
|
+
*/
|
|
55
|
+
export declare function readProcessTable(): Promise<Map<number, ProcessEntry>>;
|
|
56
|
+
/** Injectable pieces (tests). */
|
|
57
|
+
export interface AgentProcessOriginDeps {
|
|
58
|
+
readTable?: () => Promise<Map<number, ProcessEntry>>;
|
|
59
|
+
/** PTY shell pid → session name for the live agent sessions */
|
|
60
|
+
listSessionPids?: () => Map<number, string>;
|
|
61
|
+
now?: () => number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolves skill pids to agent sessions, caching per pid for a short while
|
|
65
|
+
* (one skill run makes several API calls from the same shell).
|
|
66
|
+
*/
|
|
67
|
+
export declare class AgentProcessOriginService {
|
|
68
|
+
private readonly cache;
|
|
69
|
+
private readonly readTable;
|
|
70
|
+
private readonly listSessionPids;
|
|
71
|
+
private readonly now;
|
|
72
|
+
/**
|
|
73
|
+
* @param deps - Injectable dependencies
|
|
74
|
+
*/
|
|
75
|
+
constructor(deps: AgentProcessOriginDeps & {
|
|
76
|
+
listSessionPids: () => Map<number, string>;
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Where a local skill process came from.
|
|
80
|
+
*
|
|
81
|
+
* @param pid - The skill shell's pid (from X-Agent-Pid)
|
|
82
|
+
* @returns The origin; `{session: null}` when there are no agent sessions
|
|
83
|
+
*/
|
|
84
|
+
resolve(pid: number): Promise<ProcessOrigin>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=agent-process-origin.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-process-origin.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/agent-process-origin.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACb;AAED,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC7B,uEAAuE;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0FAA0F;IAC1F,eAAe,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,aAAa,CAaf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAQ3E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CASrE;AAED,iCAAiC;AACjC,MAAM,WAAW,sBAAsB;IACtC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACrD,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,yBAAyB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4D;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;IACrE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC;;OAEG;gBACS,IAAI,EAAE,sBAAsB,GAAG;QAAE,eAAe,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IAMzF;;;;;OAKG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAclD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which agent PTY a local skill process really belongs to.
|
|
3
|
+
*
|
|
4
|
+
* Skills name their caller with `X-Agent-Session`, read from
|
|
5
|
+
* CREWLY_SESSION_NAME in the shell that ran them. That variable is only as
|
|
6
|
+
* good as the process tree it came from: Codex's shared app-server daemon ran
|
|
7
|
+
* every Codex agent's commands with the orchestrator's environment
|
|
8
|
+
* (2026-09-30), so each of them claimed to be `crewly-orc`.
|
|
9
|
+
*
|
|
10
|
+
* Skills also send `X-Agent-Pid` (the skill shell's own pid). On this machine
|
|
11
|
+
* that pid's parent chain leads to exactly one agent PTY shell — the process
|
|
12
|
+
* Crewly spawned for the session — unless it runs under a shared daemon, in
|
|
13
|
+
* which case it leads to no PTY at all. This service walks that chain.
|
|
14
|
+
*
|
|
15
|
+
* @module services/agent/agent-process-origin.service
|
|
16
|
+
*/
|
|
17
|
+
import { execFile } from 'child_process';
|
|
18
|
+
import { AGENT_ORIGIN_CONSTANTS } from '../../constants.js';
|
|
19
|
+
/**
|
|
20
|
+
* Walk from `pid` up through its parents until an agent PTY shell is found.
|
|
21
|
+
*
|
|
22
|
+
* A shared Codex daemon ends the walk: it is often still the child of the
|
|
23
|
+
* TUI that started it (the orchestrator's), so walking on would "prove" the
|
|
24
|
+
* very identity that leaked.
|
|
25
|
+
*
|
|
26
|
+
* @param pid - Starting process (the skill shell)
|
|
27
|
+
* @param table - pid → {ppid, args}
|
|
28
|
+
* @param sessionPids - PTY shell pid → session name
|
|
29
|
+
* @returns The owning session (or null) and whether a shared Codex daemon sits in between
|
|
30
|
+
*/
|
|
31
|
+
export function resolveProcessOrigin(pid, table, sessionPids) {
|
|
32
|
+
let current = pid;
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
for (let depth = 0; depth < AGENT_ORIGIN_CONSTANTS.MAX_ANCESTRY_DEPTH && current > 1 && !seen.has(current); depth++) {
|
|
35
|
+
seen.add(current);
|
|
36
|
+
const session = sessionPids.get(current);
|
|
37
|
+
if (session)
|
|
38
|
+
return { session, viaSharedDaemon: false };
|
|
39
|
+
const entry = table.get(current);
|
|
40
|
+
if (!entry)
|
|
41
|
+
break;
|
|
42
|
+
if (AGENT_ORIGIN_CONSTANTS.SHARED_DAEMON_ARGS_RE.test(entry.args))
|
|
43
|
+
return { session: null, viaSharedDaemon: true };
|
|
44
|
+
current = entry.ppid;
|
|
45
|
+
}
|
|
46
|
+
return { session: null, viaSharedDaemon: false };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse `ps -Ao pid=,ppid=,args=` output.
|
|
50
|
+
*
|
|
51
|
+
* @param output - Raw ps output
|
|
52
|
+
* @returns pid → entry
|
|
53
|
+
*/
|
|
54
|
+
export function parseProcessTable(output) {
|
|
55
|
+
const table = new Map();
|
|
56
|
+
for (const line of output.split('\n')) {
|
|
57
|
+
const match = /^\s*(\d+)\s+(\d+)\s?(.*)$/.exec(line);
|
|
58
|
+
if (!match)
|
|
59
|
+
continue;
|
|
60
|
+
table.set(Number(match[1]), { ppid: Number(match[2]), args: match[3] ?? '' });
|
|
61
|
+
}
|
|
62
|
+
return table;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the process table with one `ps` call (same flags on Linux and macOS).
|
|
66
|
+
*
|
|
67
|
+
* @returns pid → entry
|
|
68
|
+
*/
|
|
69
|
+
export function readProcessTable() {
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
execFile('ps', ['-Ao', 'pid=,ppid=,args='], { timeout: AGENT_ORIGIN_CONSTANTS.LOOKUP_TIMEOUT_MS, maxBuffer: AGENT_ORIGIN_CONSTANTS.PS_MAX_BUFFER_BYTES }, (error, stdout) => (error ? reject(error) : resolve(parseProcessTable(stdout))));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolves skill pids to agent sessions, caching per pid for a short while
|
|
76
|
+
* (one skill run makes several API calls from the same shell).
|
|
77
|
+
*/
|
|
78
|
+
export class AgentProcessOriginService {
|
|
79
|
+
cache = new Map();
|
|
80
|
+
readTable;
|
|
81
|
+
listSessionPids;
|
|
82
|
+
now;
|
|
83
|
+
/**
|
|
84
|
+
* @param deps - Injectable dependencies
|
|
85
|
+
*/
|
|
86
|
+
constructor(deps) {
|
|
87
|
+
this.readTable = deps.readTable ?? readProcessTable;
|
|
88
|
+
this.listSessionPids = deps.listSessionPids;
|
|
89
|
+
this.now = deps.now ?? Date.now;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Where a local skill process came from.
|
|
93
|
+
*
|
|
94
|
+
* @param pid - The skill shell's pid (from X-Agent-Pid)
|
|
95
|
+
* @returns The origin; `{session: null}` when there are no agent sessions
|
|
96
|
+
*/
|
|
97
|
+
async resolve(pid) {
|
|
98
|
+
const hit = this.cache.get(pid);
|
|
99
|
+
if (hit && this.now() - hit.at < AGENT_ORIGIN_CONSTANTS.RESULT_CACHE_TTL_MS)
|
|
100
|
+
return hit.origin;
|
|
101
|
+
const sessionPids = this.listSessionPids();
|
|
102
|
+
const origin = sessionPids.size === 0
|
|
103
|
+
? { session: null, viaSharedDaemon: false }
|
|
104
|
+
: resolveProcessOrigin(pid, await this.readTable(), sessionPids);
|
|
105
|
+
if (this.cache.size >= AGENT_ORIGIN_CONSTANTS.RESULT_CACHE_MAX_ENTRIES) {
|
|
106
|
+
const oldest = this.cache.keys().next().value;
|
|
107
|
+
if (oldest !== undefined)
|
|
108
|
+
this.cache.delete(oldest);
|
|
109
|
+
}
|
|
110
|
+
this.cache.set(pid, { origin, at: this.now() });
|
|
111
|
+
return origin;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=agent-process-origin.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-process-origin.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/agent-process-origin.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep each Codex agent's shell commands in that agent's own process.
|
|
3
|
+
*
|
|
4
|
+
* Codex 0.157+ runs the TUI against one shared background app server
|
|
5
|
+
* (`codex app-server --listen unix:// --managed-daemon`), started by whichever
|
|
6
|
+
* Codex session on the machine starts first — usually the orchestrator. Tool
|
|
7
|
+
* and shell commands run inside that daemon, so they inherit ITS environment:
|
|
8
|
+
* every Codex agent's skills sent `X-Agent-Session: crewly-orc` and acted as
|
|
9
|
+
* the orchestrator (steamfun-ops, 2026-09-30: Avery's reply-channel 404'd
|
|
10
|
+
* because the orc was not in the room, and her answer was lost).
|
|
11
|
+
*
|
|
12
|
+
* `codex --no-daemon` runs the app server inside the TUI process instead, so
|
|
13
|
+
* commands inherit the PTY's spawn env (CREWLY_SESSION_NAME, CREWLY_ROLE, the
|
|
14
|
+
* API keys …). Login is untouched: every session still reads the same
|
|
15
|
+
* `$CODEX_HOME/auth.json`.
|
|
16
|
+
*
|
|
17
|
+
* @module services/agent/codex-daemon.utils
|
|
18
|
+
*/
|
|
19
|
+
import type { RunCommand } from '../harness/harness.types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Add `--no-daemon` to a Codex launch command (`codex …` or `codex resume …`).
|
|
22
|
+
* A command that does not run codex, or already picks its app server
|
|
23
|
+
* (`--no-daemon`, `--remote`), is returned unchanged.
|
|
24
|
+
*
|
|
25
|
+
* @param command - One launch command line
|
|
26
|
+
* @returns The command with the flag right after `codex` / `codex resume`
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* withCodexNoDaemon('codex -a never -s danger-full-access')
|
|
30
|
+
* // => 'codex --no-daemon -a never -s danger-full-access'
|
|
31
|
+
*/
|
|
32
|
+
export declare function withCodexNoDaemon(command: string): string;
|
|
33
|
+
/** Injectable pieces of the capability check (tests). */
|
|
34
|
+
export interface CodexNoDaemonProbeDeps {
|
|
35
|
+
run?: RunCommand;
|
|
36
|
+
/** Finds the codex binary the agent shell would run */
|
|
37
|
+
resolveCodex?: () => string | null;
|
|
38
|
+
env?: NodeJS.ProcessEnv;
|
|
39
|
+
now?: () => number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether the installed Codex has `--no-daemon`. Passing the flag to a Codex
|
|
43
|
+
* that lacks it would stop the agent from starting (clap rejects unknown
|
|
44
|
+
* arguments), so the flag is only added once `codex --help` lists it. A yes is
|
|
45
|
+
* kept for the life of the process; a no is re-checked after
|
|
46
|
+
* NO_DAEMON_PROBE_RETRY_MS in case Codex was upgraded meanwhile.
|
|
47
|
+
*
|
|
48
|
+
* Never throws: a missing or broken codex counts as "no".
|
|
49
|
+
*
|
|
50
|
+
* @param deps - Injectable dependencies
|
|
51
|
+
* @returns True when `codex --help` mentions `--no-daemon`
|
|
52
|
+
*/
|
|
53
|
+
export declare function codexSupportsNoDaemon(deps?: CodexNoDaemonProbeDeps): Promise<boolean>;
|
|
54
|
+
/** Forget the cached capability check (tests). */
|
|
55
|
+
export declare function resetCodexNoDaemonProbe(): void;
|
|
56
|
+
//# sourceMappingURL=codex-daemon.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-daemon.utils.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/codex-daemon.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAO9D;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,yDAAyD;AACzD,MAAM,WAAW,sBAAsB;IACtC,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAiBD;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,OAAO,CAAC,CAuB/F;AAED,kDAAkD;AAClD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep each Codex agent's shell commands in that agent's own process.
|
|
3
|
+
*
|
|
4
|
+
* Codex 0.157+ runs the TUI against one shared background app server
|
|
5
|
+
* (`codex app-server --listen unix:// --managed-daemon`), started by whichever
|
|
6
|
+
* Codex session on the machine starts first — usually the orchestrator. Tool
|
|
7
|
+
* and shell commands run inside that daemon, so they inherit ITS environment:
|
|
8
|
+
* every Codex agent's skills sent `X-Agent-Session: crewly-orc` and acted as
|
|
9
|
+
* the orchestrator (steamfun-ops, 2026-09-30: Avery's reply-channel 404'd
|
|
10
|
+
* because the orc was not in the room, and her answer was lost).
|
|
11
|
+
*
|
|
12
|
+
* `codex --no-daemon` runs the app server inside the TUI process instead, so
|
|
13
|
+
* commands inherit the PTY's spawn env (CREWLY_SESSION_NAME, CREWLY_ROLE, the
|
|
14
|
+
* API keys …). Login is untouched: every session still reads the same
|
|
15
|
+
* `$CODEX_HOME/auth.json`.
|
|
16
|
+
*
|
|
17
|
+
* @module services/agent/codex-daemon.utils
|
|
18
|
+
*/
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import { HARNESS_CONSTANTS } from '../../constants.js';
|
|
21
|
+
import { buildHarnessPath, getUserNpmBinDir, resolveExecutable, runCommand } from '../harness/harness-exec.utils.js';
|
|
22
|
+
const CODEX = HARNESS_CONSTANTS.CODEX;
|
|
23
|
+
/** The codex binary as a command word, plus `resume` when present. */
|
|
24
|
+
const CODEX_COMMAND_RE = /(?<=^|[\s;&|(])(?:[^\s;&|()=]*\/)?codex(?:\s+resume)?(?=\s|$)/;
|
|
25
|
+
/**
|
|
26
|
+
* Add `--no-daemon` to a Codex launch command (`codex …` or `codex resume …`).
|
|
27
|
+
* A command that does not run codex, or already picks its app server
|
|
28
|
+
* (`--no-daemon`, `--remote`), is returned unchanged.
|
|
29
|
+
*
|
|
30
|
+
* @param command - One launch command line
|
|
31
|
+
* @returns The command with the flag right after `codex` / `codex resume`
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* withCodexNoDaemon('codex -a never -s danger-full-access')
|
|
35
|
+
* // => 'codex --no-daemon -a never -s danger-full-access'
|
|
36
|
+
*/
|
|
37
|
+
export function withCodexNoDaemon(command) {
|
|
38
|
+
const tokens = command.split(/\s+/);
|
|
39
|
+
const picksServer = tokens.some((tok) => CODEX.APP_SERVER_SELECT_FLAGS.some((flag) => tok === flag || tok.startsWith(`${flag}=`)));
|
|
40
|
+
if (picksServer)
|
|
41
|
+
return command;
|
|
42
|
+
// `codex` / `/path/to/codex` as a command word (not `CODEX_HOME=~/.codex`),
|
|
43
|
+
// optionally followed by the `resume` subcommand.
|
|
44
|
+
return command.replace(CODEX_COMMAND_RE, (m) => `${m} ${CODEX.NO_DAEMON_FLAG}`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The PATH an agent shell ends up with: the backend's node first (the
|
|
48
|
+
* runtime re-export in the PTY), the user npm prefix, then the harness PATH.
|
|
49
|
+
* The `codex` npm shim is `#!/usr/bin/env node`, so the node on PATH matters.
|
|
50
|
+
*
|
|
51
|
+
* @param env - Base environment
|
|
52
|
+
* @returns PATH string
|
|
53
|
+
*/
|
|
54
|
+
function agentShellPath(env) {
|
|
55
|
+
const dirs = [path.dirname(process.execPath), getUserNpmBinDir(), buildHarnessPath(env.PATH)];
|
|
56
|
+
return dirs.filter((d, i, a) => d && a.indexOf(d) === i).join(path.delimiter);
|
|
57
|
+
}
|
|
58
|
+
let cached = null;
|
|
59
|
+
/**
|
|
60
|
+
* Whether the installed Codex has `--no-daemon`. Passing the flag to a Codex
|
|
61
|
+
* that lacks it would stop the agent from starting (clap rejects unknown
|
|
62
|
+
* arguments), so the flag is only added once `codex --help` lists it. A yes is
|
|
63
|
+
* kept for the life of the process; a no is re-checked after
|
|
64
|
+
* NO_DAEMON_PROBE_RETRY_MS in case Codex was upgraded meanwhile.
|
|
65
|
+
*
|
|
66
|
+
* Never throws: a missing or broken codex counts as "no".
|
|
67
|
+
*
|
|
68
|
+
* @param deps - Injectable dependencies
|
|
69
|
+
* @returns True when `codex --help` mentions `--no-daemon`
|
|
70
|
+
*/
|
|
71
|
+
export async function codexSupportsNoDaemon(deps = {}) {
|
|
72
|
+
const now = deps.now ?? Date.now;
|
|
73
|
+
if (cached && (cached.supported || now() - cached.checkedAt < CODEX.NO_DAEMON_PROBE_RETRY_MS)) {
|
|
74
|
+
return cached.supported;
|
|
75
|
+
}
|
|
76
|
+
const env = deps.env ?? process.env;
|
|
77
|
+
const shellPath = agentShellPath(env);
|
|
78
|
+
const resolveCodex = deps.resolveCodex ?? (() => resolveExecutable('codex', shellPath));
|
|
79
|
+
let supported = false;
|
|
80
|
+
try {
|
|
81
|
+
const binary = resolveCodex();
|
|
82
|
+
if (binary) {
|
|
83
|
+
const result = await (deps.run ?? runCommand)(binary, ['--help'], {
|
|
84
|
+
env: { ...env, PATH: shellPath },
|
|
85
|
+
timeoutMs: CODEX.HELP_PROBE_TIMEOUT_MS,
|
|
86
|
+
});
|
|
87
|
+
supported = result.code === 0 && `${result.stdout}\n${result.stderr}`.includes(CODEX.NO_DAEMON_FLAG);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
supported = false;
|
|
92
|
+
}
|
|
93
|
+
cached = { supported, checkedAt: now() };
|
|
94
|
+
return supported;
|
|
95
|
+
}
|
|
96
|
+
/** Forget the cached capability check (tests). */
|
|
97
|
+
export function resetCodexNoDaemonProbe() {
|
|
98
|
+
cached = null;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=codex-daemon.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-daemon.utils.js","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/codex-daemon.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -69,6 +69,21 @@ export declare abstract class RuntimeAgentService {
|
|
|
69
69
|
* @returns The commands, with `--settings` appended when the guard applies
|
|
70
70
|
*/
|
|
71
71
|
protected applyControlPlaneGuard(sessionName: string, commands: string[], targetPath?: string): Promise<string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Launch Codex with `--no-daemon` so its shell commands run in this
|
|
74
|
+
* agent's own process and carry this agent's identity env.
|
|
75
|
+
*
|
|
76
|
+
* Without it every Codex TUI on the machine attaches to one shared
|
|
77
|
+
* `codex app-server` daemon, started by whichever Codex session came
|
|
78
|
+
* first (usually the orchestrator), and every agent's skills then ran as
|
|
79
|
+
* that session (see codex-daemon.utils). A Codex too old to know the flag
|
|
80
|
+
* launches as before, with a WARN, rather than failing to start.
|
|
81
|
+
*
|
|
82
|
+
* @param sessionName - PTY session name
|
|
83
|
+
* @param commands - Codex launch commands built so far
|
|
84
|
+
* @returns The commands, with `--no-daemon` added when supported
|
|
85
|
+
*/
|
|
86
|
+
protected keepCodexOffSharedDaemon(sessionName: string, commands: string[]): Promise<string[]>;
|
|
72
87
|
/**
|
|
73
88
|
* Template method for executing runtime initialization script.
|
|
74
89
|
* Most logic is shared, only runtime-specific parts are delegated to abstract methods.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-agent.service.abstract.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/runtime-agent.service.abstract.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAuF,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-agent.service.abstract.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/runtime-agent.service.abstract.ts"],"names":[],"mappings":"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"}
|