crewly 1.20.168 → 1.20.170

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.
Files changed (152) hide show
  1. package/config/constants.ts +4 -0
  2. package/config/skills/_common/lib.sh +5 -0
  3. package/config/skills/agent/core/reply/SKILL.md +71 -0
  4. package/config/skills/agent/core/reply/execute.sh +81 -0
  5. package/config/skills/agent/core/reply/execute.test.sh +87 -0
  6. package/dist/backend/backend/src/constants.d.ts +101 -0
  7. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  8. package/dist/backend/backend/src/constants.js +105 -0
  9. package/dist/backend/backend/src/constants.js.map +1 -1
  10. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +36 -0
  11. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -0
  12. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +182 -0
  13. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -0
  14. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +30 -0
  15. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  16. package/dist/backend/backend/src/controllers/chat/chat.controller.js +171 -0
  17. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  18. package/dist/backend/backend/src/controllers/chat/chat.routes.d.ts.map +1 -1
  19. package/dist/backend/backend/src/controllers/chat/chat.routes.js +4 -0
  20. package/dist/backend/backend/src/controllers/chat/chat.routes.js.map +1 -1
  21. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts +55 -0
  22. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  23. package/dist/backend/backend/src/controllers/slack/slack.controller.js +1 -1
  24. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  25. package/dist/backend/backend/src/index.d.ts +10 -0
  26. package/dist/backend/backend/src/index.d.ts.map +1 -1
  27. package/dist/backend/backend/src/index.js +119 -1
  28. package/dist/backend/backend/src/index.js.map +1 -1
  29. package/dist/backend/backend/src/middleware/agent-origin.middleware.d.ts +45 -0
  30. package/dist/backend/backend/src/middleware/agent-origin.middleware.d.ts.map +1 -0
  31. package/dist/backend/backend/src/middleware/agent-origin.middleware.js +148 -0
  32. package/dist/backend/backend/src/middleware/agent-origin.middleware.js.map +1 -0
  33. package/dist/backend/backend/src/routes/modules/system.routes.d.ts.map +1 -1
  34. package/dist/backend/backend/src/routes/modules/system.routes.js +6 -0
  35. package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
  36. package/dist/backend/backend/src/services/agent/agent-process-origin.service.d.ts +86 -0
  37. package/dist/backend/backend/src/services/agent/agent-process-origin.service.d.ts.map +1 -0
  38. package/dist/backend/backend/src/services/agent/agent-process-origin.service.js +114 -0
  39. package/dist/backend/backend/src/services/agent/agent-process-origin.service.js.map +1 -0
  40. package/dist/backend/backend/src/services/agent/codex-daemon.utils.d.ts +56 -0
  41. package/dist/backend/backend/src/services/agent/codex-daemon.utils.d.ts.map +1 -0
  42. package/dist/backend/backend/src/services/agent/codex-daemon.utils.js +100 -0
  43. package/dist/backend/backend/src/services/agent/codex-daemon.utils.js.map +1 -0
  44. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +15 -0
  45. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +27 -0
  47. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  48. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +18 -0
  49. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  50. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +48 -3
  51. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  52. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +271 -0
  53. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +605 -0
  55. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -0
  56. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.d.ts +179 -0
  57. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js +327 -0
  59. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js.map +1 -0
  60. package/dist/backend/backend/src/services/orc/agent-reply-target.d.ts +95 -0
  61. package/dist/backend/backend/src/services/orc/agent-reply-target.d.ts.map +1 -0
  62. package/dist/backend/backend/src/services/orc/agent-reply-target.js +85 -0
  63. package/dist/backend/backend/src/services/orc/agent-reply-target.js.map +1 -0
  64. package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts +20 -0
  65. package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -1
  66. package/dist/backend/backend/src/services/orc/orc-reply-route.service.js +34 -1
  67. package/dist/backend/backend/src/services/orc/orc-reply-route.service.js.map +1 -1
  68. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/slack/slack-initializer.js +5 -0
  70. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  71. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +13 -0
  72. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  73. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +40 -0
  74. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  75. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +2 -0
  77. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  78. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +33 -0
  79. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +68 -0
  81. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  82. package/dist/backend/backend/src/services/slack/slack.service.d.ts +16 -0
  83. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/slack/slack.service.js +22 -5
  85. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  86. package/dist/backend/backend/src/services/system/auto-update.service.d.ts +15 -5
  87. package/dist/backend/backend/src/services/system/auto-update.service.d.ts.map +1 -1
  88. package/dist/backend/backend/src/services/system/auto-update.service.js +26 -21
  89. package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -1
  90. package/dist/backend/backend/src/services/system/auto-update.utils.d.ts +51 -0
  91. package/dist/backend/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
  92. package/dist/backend/backend/src/services/system/auto-update.utils.js +103 -0
  93. package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -1
  94. package/dist/backend/backend/src/types/slack.types.d.ts +6 -0
  95. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  96. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  97. package/dist/backend/build-info.json +2 -2
  98. package/dist/backend/config/constants.d.ts +4 -0
  99. package/dist/backend/config/constants.d.ts.map +1 -1
  100. package/dist/backend/config/constants.js +4 -0
  101. package/dist/backend/config/constants.js.map +1 -1
  102. package/dist/cli/backend/src/constants.d.ts +101 -0
  103. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  104. package/dist/cli/backend/src/constants.js +105 -0
  105. package/dist/cli/backend/src/constants.js.map +1 -1
  106. package/dist/cli/backend/src/services/agent/codex-daemon.utils.d.ts +56 -0
  107. package/dist/cli/backend/src/services/agent/codex-daemon.utils.d.ts.map +1 -0
  108. package/dist/cli/backend/src/services/agent/codex-daemon.utils.js +100 -0
  109. package/dist/cli/backend/src/services/agent/codex-daemon.utils.js.map +1 -0
  110. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +15 -0
  111. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  112. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +27 -0
  113. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  114. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +18 -0
  115. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  116. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +48 -3
  117. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  118. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +271 -0
  119. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -0
  120. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +605 -0
  121. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -0
  122. package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts +20 -0
  123. package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -1
  124. package/dist/cli/backend/src/services/orc/orc-reply-route.service.js +34 -1
  125. package/dist/cli/backend/src/services/orc/orc-reply-route.service.js.map +1 -1
  126. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +13 -0
  127. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  128. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +40 -0
  129. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  130. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  131. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +2 -0
  132. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  133. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +33 -0
  134. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  135. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +68 -0
  136. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  137. package/dist/cli/backend/src/services/slack/slack.service.d.ts +16 -0
  138. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  139. package/dist/cli/backend/src/services/slack/slack.service.js +22 -5
  140. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  141. package/dist/cli/backend/src/services/system/auto-update.utils.d.ts +51 -0
  142. package/dist/cli/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
  143. package/dist/cli/backend/src/services/system/auto-update.utils.js +103 -0
  144. package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -1
  145. package/dist/cli/backend/src/types/slack.types.d.ts +6 -0
  146. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  147. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  148. package/dist/cli/config/constants.d.ts +4 -0
  149. package/dist/cli/config/constants.d.ts.map +1 -1
  150. package/dist/cli/config/constants.js +4 -0
  151. package/dist/cli/config/constants.js.map +1 -1
  152. 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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"system.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/routes/modules/system.routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CA0BvF"}
1
+ {"version":3,"file":"system.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/routes/modules/system.routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAIpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAgCvF"}
@@ -1,4 +1,5 @@
1
1
  import * as systemHandlers from '../../controllers/system/system.controller.js';
2
+ import { getOwnerMessageWatchdog } from '../../services/messaging/owner-message-watchdog.service.js';
2
3
  export function registerSystemRoutes(router, apiController) {
3
4
  // System Administration Routes
4
5
  router.get('/system/health', (req, res) => systemHandlers.getSystemHealth.call(apiController, req, res));
@@ -10,6 +11,11 @@ export function registerSystemRoutes(router, apiController) {
10
11
  router.get('/system/logs', (req, res) => systemHandlers.getSystemLogs.call(apiController, req, res));
11
12
  router.get('/system/alerts', (req, res) => systemHandlers.getAlerts.call(apiController, req, res));
12
13
  router.patch('/system/alerts/:conditionId', (req, res) => systemHandlers.updateAlertCondition.call(apiController, req, res));
14
+ // Owner messages still waiting for an answer (debug; specs/2026-09-30-owner-message-guarantee.md)
15
+ router.get('/system/unanswered-owner-messages', (_req, res) => {
16
+ const watchdog = getOwnerMessageWatchdog();
17
+ res.json({ success: true, data: { running: !!watchdog, messages: watchdog?.list() ?? [] } });
18
+ });
13
19
  // Server restart
14
20
  router.post('/system/restart', (req, res) => systemHandlers.restartServer.call(apiController, req, res));
15
21
  // API Health within /api scope
@@ -1 +1 @@
1
- {"version":3,"file":"system.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/routes/modules/system.routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"system.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/routes/modules/system.routes.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.