@cabane/companion 0.6.202 → 0.6.204

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/dist/launch.js CHANGED
@@ -71,25 +71,7 @@ var prepareHookSchema = z.object({
71
71
  // Wall-clock cap for the hook. Provisioning is slow (minutes), so the
72
72
  // default is generous; a hook that hangs past this is killed and the turn
73
73
  // fails with a clear timeout message rather than pinning the companion.
74
- timeoutMs: z.number().int().positive().optional(),
75
- // Re-invoke the hook when a prepared result already exists, in VALIDATE
76
- // mode: the cached result is handed back as `prepared` and stdout is
77
- // ignored, so the cwd cannot move. Its only power is to exit non-zero and
78
- // fail the turn. The hook resolves once per (conversation, agent), so a
79
- // later message asking for a different environment is otherwise silently
80
- // ignored; this lets a hook refuse it out loud.
81
- //
82
- // Default OFF: a hook that provisions unconditionally must not start
83
- // running on every turn because the companion upgraded.
84
- validateCached: z.boolean().optional(),
85
- // Independent operator-owned reporter. Receives sanitized failure metadata
86
- // on stdin; never re-enters this hook and cannot change the turn outcome.
87
- failureReporter: z.object({
88
- command: z.string().min(1),
89
- args: z.array(z.string()).optional(),
90
- env: z.record(z.string(), z.string()).optional(),
91
- timeoutMs: z.number().int().positive().max(3e4).optional()
92
- }).strict().optional()
74
+ timeoutMs: z.number().int().positive().optional()
93
75
  }).strict();
94
76
  var DEFAULT_TIMEOUT_MS = 10 * 6e4;
95
77
  var prepareResultSchema = z.object({
@@ -161,8 +143,7 @@ var companionConfigSchema = z2.object({
161
143
  // The DEVICE-LEVEL prepare hook, for every agent assigned here unless its own
162
144
  // `agents` row names one. Per-agent hooks alone make the config a second
163
145
  // silent roster: an agent nobody listed gets no hook and no error, and starts
164
- // in the operator's `$HOME` (an agent woke in `/home/joshed` this way on
165
- // 2026-08-17).
146
+ // in the operator's `$HOME`.
166
147
  prepareHook: prepareHookSchema.optional(),
167
148
  // `dashboardPort` and `autoOpen` are IGNORED by the CLI (no port, no browser)
168
149
  // but stay in the schema so an existing file still parses; the Electron shell
@@ -199,9 +180,10 @@ var companionConfigSchema = z2.object({
199
180
  root: z2.string().min(1).refine(isRootPath, { message: "must be an absolute path, or start with ~/" }).optional(),
200
181
  // An argv prefix the operator puts in front of every turn's runner: the companion starts
201
182
  // `<prefix…> <its own run-turn command…>` instead of the runner bare. What the prefix does
202
- // is the operator's (a box of their own making, ENG225); the companion knows nothing of it
183
+ // is the operator's (a container or VM per turn, say); the companion knows nothing of it
203
184
  // beyond handing the runner over, with the turn's inputs in its environment and the
204
- // credential and secrets on its stdin (`runner/launch.ts`, `boxed`).
185
+ // credential and secrets on its stdin (`runner/launch.ts`, `wrapped`). The README lists
186
+ // what a wrapper can rely on.
205
187
  runner: z2.object({
206
188
  command: z2.array(z2.string().min(1)).min(1)
207
189
  }).strict().optional()
@@ -93,25 +93,7 @@ var prepareHookSchema = z.object({
93
93
  // Wall-clock cap for the hook. Provisioning is slow (minutes), so the
94
94
  // default is generous; a hook that hangs past this is killed and the turn
95
95
  // fails with a clear timeout message rather than pinning the companion.
96
- timeoutMs: z.number().int().positive().optional(),
97
- // Re-invoke the hook when a prepared result already exists, in VALIDATE
98
- // mode: the cached result is handed back as `prepared` and stdout is
99
- // ignored, so the cwd cannot move. Its only power is to exit non-zero and
100
- // fail the turn. The hook resolves once per (conversation, agent), so a
101
- // later message asking for a different environment is otherwise silently
102
- // ignored; this lets a hook refuse it out loud.
103
- //
104
- // Default OFF: a hook that provisions unconditionally must not start
105
- // running on every turn because the companion upgraded.
106
- validateCached: z.boolean().optional(),
107
- // Independent operator-owned reporter. Receives sanitized failure metadata
108
- // on stdin; never re-enters this hook and cannot change the turn outcome.
109
- failureReporter: z.object({
110
- command: z.string().min(1),
111
- args: z.array(z.string()).optional(),
112
- env: z.record(z.string(), z.string()).optional(),
113
- timeoutMs: z.number().int().positive().max(3e4).optional()
114
- }).strict().optional()
96
+ timeoutMs: z.number().int().positive().optional()
115
97
  }).strict();
116
98
  var DEFAULT_TIMEOUT_MS = 10 * 6e4;
117
99
  var prepareResultSchema = z.object({
@@ -186,8 +168,7 @@ var companionConfigSchema = z2.object({
186
168
  // The DEVICE-LEVEL prepare hook, for every agent assigned here unless its own
187
169
  // `agents` row names one. Per-agent hooks alone make the config a second
188
170
  // silent roster: an agent nobody listed gets no hook and no error, and starts
189
- // in the operator's `$HOME` (an agent woke in `/home/joshed` this way on
190
- // 2026-08-17).
171
+ // in the operator's `$HOME`.
191
172
  prepareHook: prepareHookSchema.optional(),
192
173
  // `dashboardPort` and `autoOpen` are IGNORED by the CLI (no port, no browser)
193
174
  // but stay in the schema so an existing file still parses; the Electron shell
@@ -224,40 +205,43 @@ var companionConfigSchema = z2.object({
224
205
  root: z2.string().min(1).refine(isRootPath, { message: "must be an absolute path, or start with ~/" }).optional(),
225
206
  // An argv prefix the operator puts in front of every turn's runner: the companion starts
226
207
  // `<prefix…> <its own run-turn command…>` instead of the runner bare. What the prefix does
227
- // is the operator's (a box of their own making, ENG225); the companion knows nothing of it
208
+ // is the operator's (a container or VM per turn, say); the companion knows nothing of it
228
209
  // beyond handing the runner over, with the turn's inputs in its environment and the
229
- // credential and secrets on its stdin (`runner/launch.ts`, `boxed`).
210
+ // credential and secrets on its stdin (`runner/launch.ts`, `wrapped`). The README lists
211
+ // what a wrapper can rely on.
230
212
  runner: z2.object({
231
213
  command: z2.array(z2.string().min(1)).min(1)
232
214
  }).strict().optional()
233
215
  });
234
- function retiredConfigKeys(raw) {
235
- if (!raw || typeof raw !== "object") return [];
236
- const obj = raw;
216
+ var RETIRED_ROW_KEYS = ["sandbox"];
217
+ var RETIRED_HOOK_KEYS = ["validateCached", "failureReporter"];
218
+ function isObject(value) {
219
+ return !!value && typeof value === "object" && !Array.isArray(value);
220
+ }
221
+ function splitRetired(raw) {
237
222
  const keys = [];
238
- if ("runners" in obj) keys.push("runners");
239
- const agents = obj.agents;
240
- if (agents && typeof agents === "object") {
241
- for (const [key, row] of Object.entries(agents)) {
242
- if (row && typeof row === "object" && "sandbox" in row) keys.push(`agents.${key}.sandbox`);
223
+ const without = (obj, names, path) => {
224
+ const out = {};
225
+ for (const [k, v] of Object.entries(obj)) {
226
+ if (names.includes(k)) keys.push(`${path}${k}`);
227
+ else out[k] = v;
243
228
  }
229
+ return out;
230
+ };
231
+ const hook = (row, path) => isObject(row.prepareHook) ? { ...row, prepareHook: without(row.prepareHook, RETIRED_HOOK_KEYS, `${path}prepareHook.`) } : row;
232
+ const kept = hook(without(raw, ["runners"], ""), "");
233
+ if (isObject(kept.agents)) {
234
+ const agents = {};
235
+ for (const [key, row] of Object.entries(kept.agents)) {
236
+ const path = `agents.${key}.`;
237
+ agents[key] = isObject(row) ? hook(without(row, RETIRED_ROW_KEYS, path), path) : row;
238
+ }
239
+ kept.agents = agents;
244
240
  }
245
- return keys;
241
+ return { keys, kept };
246
242
  }
247
243
  function withoutRetiredKeys(raw) {
248
- if (retiredConfigKeys(raw).length === 0) return raw;
249
- const { runners: _runners, ...rest } = raw;
250
- if (!rest.agents || typeof rest.agents !== "object") return rest;
251
- const agents = {};
252
- for (const [key, row] of Object.entries(rest.agents)) {
253
- if (row && typeof row === "object" && "sandbox" in row) {
254
- const { sandbox: _sandbox, ...kept } = row;
255
- agents[key] = kept;
256
- } else {
257
- agents[key] = row;
258
- }
259
- }
260
- return { ...rest, agents };
244
+ return isObject(raw) ? splitRetired(raw).kept : raw;
261
245
  }
262
246
  var legacyOfferSchema = z2.object({
263
247
  claudeCode: z2.object({ enabled: z2.boolean().optional() }).passthrough().optional(),