@clipboard-health/groundcrew 4.0.2 → 4.1.0

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 (62) hide show
  1. package/README.md +32 -13
  2. package/crew.config.example.ts +5 -18
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +64 -10
  5. package/dist/commands/interruptWorkspace.d.ts.map +1 -1
  6. package/dist/commands/interruptWorkspace.js +3 -3
  7. package/dist/commands/resumeWorkspace.d.ts.map +1 -1
  8. package/dist/commands/resumeWorkspace.js +1 -2
  9. package/dist/commands/setupRepos.d.ts.map +1 -1
  10. package/dist/commands/setupRepos.js +2 -13
  11. package/dist/commands/setupWorkspace.d.ts.map +1 -1
  12. package/dist/commands/setupWorkspace.js +1 -7
  13. package/dist/lib/agentLaunch.d.ts +0 -6
  14. package/dist/lib/agentLaunch.d.ts.map +1 -1
  15. package/dist/lib/agentLaunch.js +1 -12
  16. package/dist/lib/cmuxAdapter.d.ts +8 -0
  17. package/dist/lib/cmuxAdapter.d.ts.map +1 -0
  18. package/dist/lib/cmuxAdapter.js +163 -0
  19. package/dist/lib/config.d.ts +2 -76
  20. package/dist/lib/config.d.ts.map +1 -1
  21. package/dist/lib/config.js +29 -102
  22. package/dist/lib/launchCommand.d.ts +3 -3
  23. package/dist/lib/sandboxName.d.ts +9 -0
  24. package/dist/lib/sandboxName.d.ts.map +1 -0
  25. package/dist/lib/sandboxName.js +12 -0
  26. package/dist/lib/tmuxAdapter.d.ts +9 -0
  27. package/dist/lib/tmuxAdapter.d.ts.map +1 -0
  28. package/dist/lib/tmuxAdapter.js +156 -0
  29. package/dist/lib/util.d.ts +11 -0
  30. package/dist/lib/util.d.ts.map +1 -1
  31. package/dist/lib/util.js +21 -0
  32. package/dist/lib/workspaceAdapter.d.ts +79 -0
  33. package/dist/lib/workspaceAdapter.d.ts.map +1 -0
  34. package/dist/lib/workspaceAdapter.js +17 -0
  35. package/dist/lib/workspaces.d.ts +7 -55
  36. package/dist/lib/workspaces.d.ts.map +1 -1
  37. package/dist/lib/workspaces.js +8 -404
  38. package/package.json +1 -2
  39. package/dist/commands/sandbox/auth.d.ts +0 -3
  40. package/dist/commands/sandbox/auth.d.ts.map +0 -1
  41. package/dist/commands/sandbox/auth.js +0 -227
  42. package/dist/commands/sandbox/index.d.ts +0 -2
  43. package/dist/commands/sandbox/index.d.ts.map +0 -1
  44. package/dist/commands/sandbox/index.js +0 -47
  45. package/dist/commands/sandbox/inspect.d.ts +0 -2
  46. package/dist/commands/sandbox/inspect.d.ts.map +0 -1
  47. package/dist/commands/sandbox/inspect.js +0 -18
  48. package/dist/commands/sandbox/lifecycle.d.ts +0 -7
  49. package/dist/commands/sandbox/lifecycle.d.ts.map +0 -1
  50. package/dist/commands/sandbox/lifecycle.js +0 -68
  51. package/dist/commands/sandbox/model.d.ts +0 -10
  52. package/dist/commands/sandbox/model.d.ts.map +0 -1
  53. package/dist/commands/sandbox/model.js +0 -37
  54. package/dist/commands/sandbox/picker.d.ts +0 -20
  55. package/dist/commands/sandbox/picker.d.ts.map +0 -1
  56. package/dist/commands/sandbox/picker.js +0 -23
  57. package/dist/lib/dockerSandbox.d.ts +0 -43
  58. package/dist/lib/dockerSandbox.d.ts.map +0 -1
  59. package/dist/lib/dockerSandbox.js +0 -69
  60. package/dist/lib/sandboxGitDefaults.d.ts +0 -10
  61. package/dist/lib/sandboxGitDefaults.d.ts.map +0 -1
  62. package/dist/lib/sandboxGitDefaults.js +0 -31
@@ -41,16 +41,12 @@ export type LocalRunnerSetting = LocalRunner | "auto";
41
41
  export declare const LOCAL_RUNNER_SETTINGS: readonly LocalRunnerSetting[];
42
42
  /**
43
43
  * Per-model Docker Sandboxes (sdx) binding. Required at launch when
44
- * `local.runner` resolves to `sdx` so groundcrew knows which sbx agent
45
- * to address and how to seed the sandbox.
44
+ * `local.runner` resolves to `sdx` so groundcrew knows which existing
45
+ * sbx sandbox to address.
46
46
  */
47
47
  export interface SandboxDefinition {
48
48
  /** sbx agent name (e.g. "claude", "codex"). */
49
49
  agent: string;
50
- /** Optional `sbx run --template` value. */
51
- template?: string;
52
- /** Optional `sbx run --kit` values (each passed as a separate flag). */
53
- kits?: string[];
54
50
  /**
55
51
  * Setup command run **inside** the sandbox before the agent exec.
56
52
  * Defaults to the shared `.groundcrew/setup.sh --deps-only` convention
@@ -58,42 +54,6 @@ export interface SandboxDefinition {
58
54
  */
59
55
  setupCommand?: string;
60
56
  }
61
- /**
62
- * Recipe used by `crew sandbox auth <model>` to drive an interactive
63
- * login flow inside a sbx sandbox and then verify it. The flow is
64
- * picker-driven — no positional `<tool>` argument; the picker lists
65
- * every recipe visible to the current sandbox.
66
- *
67
- * `binary` defaults to the recipe key (typically the agent or CLI name).
68
- * `authenticatedPattern` matches against combined stdout+stderr from
69
- * `statusArgs` — exit code alone isn't reliable because some CLIs
70
- * report "not logged in" while still exiting 0.
71
- * `kind` controls visibility in the interactive picker: `"agent"`
72
- * recipes are scoped to a specific sbx agent and only appear when you
73
- * `auth` against that agent's sandbox; `"tool"` recipes (default)
74
- * appear in every sandbox's picker because they're cross-cutting
75
- * (github, npm, gcloud, …). Defaults to `"tool"` when omitted.
76
- *
77
- * Ship-side recipes for `claude`, `codex`, and `cursor` live in
78
- * `src/commands/sandbox/auth.ts`; users register additional tools
79
- * under `sandbox.authRecipes` in their config.
80
- */
81
- export interface AuthRecipe {
82
- displayName: string;
83
- binary?: string;
84
- loginArgs: readonly string[];
85
- statusArgs: readonly string[];
86
- authenticatedPattern: RegExp;
87
- kind?: "agent" | "tool";
88
- /**
89
- * Environment variables passed to `sbx exec` for both the login and
90
- * status calls. Use this for CLIs whose default flow assumes a
91
- * browser or other host-only feature — e.g. cursor-agent wants
92
- * `NO_OPEN_BROWSER=1` to print a device code instead of trying to
93
- * launch a browser inside the sandbox.
94
- */
95
- env?: Record<string, string>;
96
- }
97
57
  export interface ModelDefinition {
98
58
  /**
99
59
  * Shell command launched for the model. Wrapped with Safehouse/clearance
@@ -201,32 +161,6 @@ export interface Config {
201
161
  local?: {
202
162
  runner?: LocalRunnerSetting;
203
163
  };
204
- /**
205
- * Sandbox-wide settings. `authRecipes` lets users register additional
206
- * tools (github, npm, gcloud, …) for `crew sandbox auth <model>` to
207
- * authenticate inside the sandbox. The auth flow is picker-driven —
208
- * registered recipes show up in the picker alongside the shipped ones,
209
- * and a user recipe under the same key (e.g. "claude") overrides the
210
- * shipped one.
211
- */
212
- sandbox?: {
213
- authRecipes?: Record<string, AuthRecipe>;
214
- /**
215
- * When true (default), every `crew sandbox ensure` / `auth` run applies
216
- * a small set of git defaults inside the sandbox so robot commits push
217
- * over `gh`-managed HTTPS regardless of how the user cloned the repo:
218
- *
219
- * - disable GPG signing for commits and tags
220
- * - rewrite `git@github.com:` and `ssh://git@github.com/` URLs to
221
- * `https://github.com/` so push uses gh's credential helper
222
- * - after a successful `github` auth recipe login, run
223
- * `gh auth setup-git` inside the sandbox
224
- *
225
- * Set `false` to skip both the git-config block and the post-login
226
- * `gh auth setup-git` step.
227
- */
228
- gitDefaults?: boolean;
229
- };
230
164
  logging?: {
231
165
  /**
232
166
  * Append-mode log file destination. `log()` and `logEvent()` tee here
@@ -281,14 +215,6 @@ export interface ResolvedConfig {
281
215
  local: {
282
216
  runner: LocalRunnerSetting;
283
217
  };
284
- /**
285
- * Sandbox-wide settings. Always present after defaults; `authRecipes`
286
- * is `{}` when the user provides none.
287
- */
288
- sandbox: {
289
- authRecipes: Record<string, AuthRecipe>;
290
- gitDefaults: boolean;
291
- };
292
218
  logging: {
293
219
  file: string;
294
220
  };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5D,eAAO,MAAM,uBAAuB,EAAE,SAAS,oBAAoB,EAIzD,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,MAAM,CAAC;AAEtD,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAKrD,CAAC;AAEX;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACjD,CAAC;IACF;;;;OAIG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;;;;;GASG;AACH,KAAK,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAC/D,KAAK,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,GAAG;IAC1E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AACF,UAAU,2BAA2B;IACnC,QAAQ,EAAE,IAAI,CAAC;CAChB;AACD,KAAK,mBAAmB,GAAG,0BAA0B,GAAG,2BAA2B,CAAC;AAEpF;;;;;;;;;GASG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,GAAG,CAAC,EAAE;QACJ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,SAAS,EAAE;QACT,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB;;;;;WAKG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;KACnD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF;;;;OAIG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC;;;;OAIG;IACH,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,kBAAkB,CAAC;KAC7B,CAAC;IACF;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzC;;;;;;;;;;;;;WAaG;QACH,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,OAAO,CAAC,EAAE;QACR;;;;;WAKG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,GAAG,EAAE;QACH,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,SAAS,EAAE;QACT,UAAU,EAAE,MAAM,CAAC;QACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF,YAAY,EAAE;QACZ,iBAAiB,EAAE,MAAM,CAAC;QAC1B,wBAAwB,EAAE,MAAM,CAAC;QACjC,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;KAC9C,CAAC;IACF,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;;OAGG;IACH,aAAa,EAAE,oBAAoB,CAAC;IACpC;;;;OAIG;IACH,KAAK,EAAE;QACL,MAAM,EAAE,kBAAkB,CAAC;KAC5B,CAAC;IACF;;;OAGG;IACH,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AA0OD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,EACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAKT;AA+cD,wBAAsB,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAwBpE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -126,29 +126,6 @@ function normalizeOptionalString(value, path) {
126
126
  }
127
127
  return value.trim();
128
128
  }
129
- function normalizeOptionalBoolean(value, path) {
130
- if (value === undefined) {
131
- return undefined;
132
- }
133
- if (typeof value !== "boolean") {
134
- fail(`${path} must be a boolean`);
135
- }
136
- return value;
137
- }
138
- function normalizeOptionalStringArray(value, path) {
139
- if (value === undefined) {
140
- return undefined;
141
- }
142
- if (!Array.isArray(value)) {
143
- fail(`${path} must be an array`);
144
- }
145
- return value.map((entry, index) => {
146
- if (typeof entry !== "string" || entry.trim().length === 0) {
147
- fail(`${path}[${index}] must be a non-empty string`);
148
- }
149
- return entry.trim();
150
- });
151
- }
152
129
  function isWorkspaceKindSetting(value) {
153
130
  return (typeof value === "string" && WORKSPACE_KIND_SETTINGS.includes(value));
154
131
  }
@@ -177,27 +154,29 @@ function normalizeSandbox(value, path) {
177
154
  if (!isPlainObject(value)) {
178
155
  fail(`${path} must be an object`);
179
156
  }
180
- const { agent, template, kits, setupCommand } = value;
157
+ if (Object.hasOwn(value, "template")) {
158
+ failRemovedConfigKey(`${path}.template`, "Groundcrew no longer creates or re-templates sdx sandboxes.");
159
+ }
160
+ if (Object.hasOwn(value, "kits")) {
161
+ failRemovedConfigKey(`${path}.kits`, "Groundcrew no longer creates sdx sandboxes or applies sandbox kits.");
162
+ }
163
+ const { agent, setupCommand } = value;
181
164
  requireString(agent, `${path}.agent`);
182
165
  const trimmedAgent = agent.trim();
183
166
  if (trimmedAgent.length === 0) {
184
167
  fail(`${path}.agent must be a non-empty string (got ${JSON.stringify(agent)})`);
185
168
  }
186
169
  const sandbox = { agent: trimmedAgent };
187
- const normalizedTemplate = normalizeOptionalString(template, `${path}.template`);
188
- if (normalizedTemplate !== undefined) {
189
- sandbox.template = normalizedTemplate;
190
- }
191
- const normalizedKits = normalizeOptionalStringArray(kits, `${path}.kits`);
192
- if (normalizedKits !== undefined) {
193
- sandbox.kits = normalizedKits;
194
- }
195
170
  const normalizedSetup = normalizeOptionalString(setupCommand, `${path}.setupCommand`);
196
171
  if (normalizedSetup !== undefined) {
197
172
  sandbox.setupCommand = normalizedSetup;
198
173
  }
199
174
  return sandbox;
200
175
  }
176
+ function failRemovedConfigKey(path, reason) {
177
+ fail(`${path} is no longer supported: ${reason} ` +
178
+ "Provision and manage the sandbox yourself with `sbx` (for example `sbx create --name groundcrew-<agent> <agent> <projectDir>`), then keep only `models.definitions.<model>.sandbox.agent` plus optional `setupCommand` in crew.config.ts.");
179
+ }
201
180
  function failIfLegacyModelKeys(name, override) {
202
181
  if (!isPlainObject(override)) {
203
182
  fail(`models.definitions.${name} must be an object`);
@@ -296,11 +275,6 @@ function requireObject(value, path) {
296
275
  fail(`${path} must be an object (got ${JSON.stringify(value)})`);
297
276
  }
298
277
  }
299
- function requireOptionalObject(value, path) {
300
- if (value !== undefined && !isPlainObject(value)) {
301
- fail(`${path} must be an object`);
302
- }
303
- }
304
278
  function failOnLegacyLinearShape(user) {
305
279
  if (!Object.hasOwn(user, "linear")) {
306
280
  return;
@@ -312,6 +286,21 @@ function failOnLegacyLinearShape(user) {
312
286
  "If you only want a subset of your Linear tickets to be picked up, leave the unwanted tickets unassigned or remove their `agent-*` label.",
313
287
  ].join("\n"));
314
288
  }
289
+ function failOnRemovedSandboxSettings(user) {
290
+ const { sandbox } = user;
291
+ if (sandbox === undefined) {
292
+ return;
293
+ }
294
+ if (!isPlainObject(sandbox)) {
295
+ fail("sandbox must be an object");
296
+ }
297
+ if (Object.hasOwn(sandbox, "authRecipes")) {
298
+ failRemovedConfigKey("sandbox.authRecipes", "Groundcrew no longer drives in-sandbox auth flows.");
299
+ }
300
+ if (Object.hasOwn(sandbox, "gitDefaults")) {
301
+ failRemovedConfigKey("sandbox.gitDefaults", "Groundcrew no longer seeds git defaults inside sdx sandboxes.");
302
+ }
303
+ }
315
304
  function normalizeSources(raw) {
316
305
  if (raw === undefined) {
317
306
  return [];
@@ -348,71 +337,14 @@ function normalizeSources(raw) {
348
337
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- structural validation above guarantees array of {kind: string} entries; per-source Zod validation lives in buildSources
349
338
  return raw;
350
339
  }
351
- function normalizeAuthRecipes(value, path) {
352
- if (value === undefined) {
353
- return {};
354
- }
355
- if (!isPlainObject(value)) {
356
- fail(`${path} must be an object`);
357
- }
358
- const recipes = {};
359
- for (const [key, raw] of Object.entries(value)) {
360
- const recipePath = `${path}.${key}`;
361
- if (!isPlainObject(raw)) {
362
- fail(`${recipePath} must be an object`);
363
- }
364
- const { displayName, binary, loginArgs, statusArgs, authenticatedPattern, kind, env } = raw;
365
- requireString(displayName, `${recipePath}.displayName`);
366
- const loginArray = normalizeOptionalStringArray(loginArgs, `${recipePath}.loginArgs`);
367
- const statusArray = normalizeOptionalStringArray(statusArgs, `${recipePath}.statusArgs`);
368
- if (loginArray === undefined) {
369
- fail(`${recipePath}.loginArgs is required`);
370
- }
371
- if (statusArray === undefined) {
372
- fail(`${recipePath}.statusArgs is required`);
373
- }
374
- if (!(authenticatedPattern instanceof RegExp)) {
375
- fail(`${recipePath}.authenticatedPattern must be a RegExp`);
376
- }
377
- const recipe = {
378
- displayName,
379
- loginArgs: loginArray,
380
- statusArgs: statusArray,
381
- authenticatedPattern,
382
- };
383
- const binaryString = normalizeOptionalString(binary, `${recipePath}.binary`);
384
- if (binaryString !== undefined) {
385
- recipe.binary = binaryString;
386
- }
387
- if (kind !== undefined) {
388
- if (kind !== "agent" && kind !== "tool") {
389
- fail(`${recipePath}.kind must be "agent" or "tool"`);
390
- }
391
- recipe.kind = kind;
392
- }
393
- if (env !== undefined) {
394
- if (!isPlainObject(env)) {
395
- fail(`${recipePath}.env must be an object`);
396
- }
397
- const normalizedEnv = {};
398
- for (const [envKey, envValue] of Object.entries(env)) {
399
- if (typeof envValue !== "string") {
400
- fail(`${recipePath}.env.${envKey} must be a string`);
401
- }
402
- normalizedEnv[envKey] = envValue;
403
- }
404
- recipe.env = normalizedEnv;
405
- }
406
- recipes[key] = recipe;
407
- }
408
- return recipes;
409
- }
410
340
  function applyDefaults(user) {
411
341
  // Guard the top-level shape before reading nested fields, so a
412
342
  // malformed runtime config produces a `groundcrew config: ...` error
413
343
  // instead of a raw `TypeError: Cannot read properties of undefined`.
414
344
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- `user` is loosely typed input from the loader; we narrow with requireObject below
415
- failOnLegacyLinearShape(user);
345
+ const rawUser = user;
346
+ failOnLegacyLinearShape(rawUser);
347
+ failOnRemovedSandboxSettings(rawUser);
416
348
  requireObject(user.workspace, "workspace");
417
349
  if (isPlainObject(user.models) && Object.hasOwn(user.models, "isolation")) {
418
350
  fail("models.isolation is no longer supported: set `local.runner` ('safehouse' | 'sdx' | 'none' | 'auto') instead");
@@ -420,7 +352,6 @@ function applyDefaults(user) {
420
352
  if (Object.hasOwn(user, "remote")) {
421
353
  fail("remote is no longer supported: groundcrew runs locally via safehouse/sdx/none; remove the remote block from your config");
422
354
  }
423
- requireOptionalObject(user.sandbox, "sandbox");
424
355
  const userLocal = user.local;
425
356
  if (userLocal !== undefined && !isPlainObject(userLocal)) {
426
357
  fail("local must be an object");
@@ -445,10 +376,6 @@ function applyDefaults(user) {
445
376
  local: {
446
377
  runner: normalizeLocalRunner(userLocal?.runner, "local.runner") ?? "auto",
447
378
  },
448
- sandbox: {
449
- authRecipes: normalizeAuthRecipes(user.sandbox?.authRecipes, "sandbox.authRecipes"),
450
- gitDefaults: normalizeOptionalBoolean(user.sandbox?.gitDefaults, "sandbox.gitDefaults") ?? true,
451
- },
452
379
  logging: {
453
380
  file: expandHome(normalizeOptionalString(user.logging?.file, "logging.file") ?? defaultLogFile()),
454
381
  },
@@ -36,9 +36,9 @@ interface LaunchCommandArguments {
36
36
  runner: LocalRunner;
37
37
  /**
38
38
  * sbx sandbox name when `runner === "sdx"`. Derived by the caller from
39
- * `sandboxNameFor({ repository, model })`. Required for sdx; ignored
40
- * otherwise. Kept off the model definition so a model can launch under
41
- * safehouse on one host and sdx on another without config edits.
39
+ * `sandboxNameFor({ agent })`. Required for sdx; ignored otherwise.
40
+ * Kept off the model definition so a model can launch under safehouse
41
+ * on one host and sdx on another without config edits.
42
42
  */
43
43
  sandboxName?: string | undefined;
44
44
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Derive the sbx sandbox name groundcrew expects for a given sbx agent.
3
+ * Groundcrew only addresses this existing sandbox at launch time; it does
4
+ * not probe, create, mutate, or remove it.
5
+ */
6
+ export declare function sandboxNameFor(arguments_: {
7
+ agent: string;
8
+ }): string;
9
+ //# sourceMappingURL=sandboxName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxName.d.ts","sourceRoot":"","sources":["../../src/lib/sandboxName.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAMpE"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Derive the sbx sandbox name groundcrew expects for a given sbx agent.
3
+ * Groundcrew only addresses this existing sandbox at launch time; it does
4
+ * not probe, create, mutate, or remove it.
5
+ */
6
+ export function sandboxNameFor(arguments_) {
7
+ const raw = `groundcrew-${arguments_.agent}`.toLowerCase();
8
+ return raw
9
+ .replaceAll(/[^a-z0-9.+-]+/g, "-")
10
+ .replaceAll(/-+/g, "-")
11
+ .replaceAll(/^-|-$/g, "");
12
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * tmux Workspace backend. Workspaces live as windows inside one dedicated
3
+ * `groundcrew` tmux session; the window name is the ticket id. tmux can't
4
+ * paint status pills, so `open` silently drops `spec.status`. This is the
5
+ * Linux/WSL path where cmux is unavailable.
6
+ */
7
+ import { type Adapter } from "./workspaceAdapter.ts";
8
+ export declare const tmuxAdapter: Adapter;
9
+ //# sourceMappingURL=tmuxAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmuxAdapter.d.ts","sourceRoot":"","sources":["../../src/lib/tmuxAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,OAAO,EAIb,MAAM,uBAAuB,CAAC;AAY/B,eAAO,MAAM,WAAW,EAAE,OAgEzB,CAAC"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * tmux Workspace backend. Workspaces live as windows inside one dedicated
3
+ * `groundcrew` tmux session; the window name is the ticket id. tmux can't
4
+ * paint status pills, so `open` silently drops `spec.status`. This is the
5
+ * Linux/WSL path where cmux is unavailable.
6
+ */
7
+ import { isSignalAborted, runWorkspaceCommand, } from "./workspaceAdapter.js";
8
+ import { errorMessage, log, readEnvironmentVariable } from "./util.js";
9
+ const TMUX_SESSION = "groundcrew";
10
+ // `tmux new-session -d -s …` always creates one initial window. Without
11
+ // `-n`, that window is named after the running shell (e.g. "0" / "zsh") and
12
+ // would surface from `list()` as a phantom workspace. We name it with this
13
+ // sentinel and filter it out — it stays around as a placeholder so the
14
+ // session doesn't collapse when the last ticket window closes.
15
+ const TMUX_IDLE_WINDOW = "_groundcrew_idle";
16
+ export const tmuxAdapter = {
17
+ async open(spec, signal) {
18
+ await ensureTmuxSession(signal);
19
+ const target = tmuxTarget(spec.name);
20
+ const keepDeadWindowsEnv = readEnvironmentVariable("GROUNDCREW_KEEP_DEAD_WINDOWS");
21
+ const keepDeadWindows = keepDeadWindowsEnv !== undefined && keepDeadWindowsEnv.length > 0;
22
+ await runWorkspaceCommand("tmux", [
23
+ "new-window",
24
+ "-d",
25
+ "-t",
26
+ TMUX_SESSION,
27
+ "-n",
28
+ spec.name,
29
+ "-c",
30
+ spec.cwd,
31
+ spec.command,
32
+ ";",
33
+ "set-window-option",
34
+ "-t",
35
+ target,
36
+ "remain-on-exit",
37
+ keepDeadWindows ? "on" : "off",
38
+ ";",
39
+ "set-window-option",
40
+ "-t",
41
+ target,
42
+ "allow-rename",
43
+ "off",
44
+ ], signal);
45
+ // tmux can't paint status pills; spec.status is silently dropped.
46
+ },
47
+ async list(signal) {
48
+ const probe = await probeTmuxList("#{window_name}\t#{pane_dead}", signal);
49
+ if (probe.status === "missing") {
50
+ return [];
51
+ }
52
+ if (probe.status === "failed") {
53
+ log(`tmux list-windows failed: ${probe.reason}`);
54
+ // oxlint-disable-next-line unicorn/no-useless-undefined -- undefined marks the workspace backend as unavailable.
55
+ return undefined;
56
+ }
57
+ return parseTmuxWindows(probe.output);
58
+ },
59
+ async close(name, signal) {
60
+ try {
61
+ await runWorkspaceCommand("tmux", ["kill-window", "-t", tmuxTarget(name)], signal);
62
+ return { kind: "closed" };
63
+ }
64
+ catch (error) {
65
+ if (isSignalAborted(signal)) {
66
+ throw error;
67
+ }
68
+ if (isTmuxNotFoundError(error)) {
69
+ return { kind: "missing" };
70
+ }
71
+ throw error;
72
+ }
73
+ },
74
+ accessHint(name) {
75
+ return { kind: "attachCommand", command: `tmux attach -t ${tmuxTarget(name)}` };
76
+ },
77
+ };
78
+ function tmuxTarget(name) {
79
+ return `${TMUX_SESSION}:${name}`;
80
+ }
81
+ function isTmuxNotFoundError(error) {
82
+ // runCommand surfaces the child's stderr in error.message, so the "no
83
+ // server" / "missing session" / "can't find window" signatures are visible
84
+ // without a separate stderr probe.
85
+ const message = errorMessage(error);
86
+ return (message.includes("no server running") ||
87
+ message.includes("can't find session") ||
88
+ message.includes("can't find window"));
89
+ }
90
+ async function probeTmuxList(format, signal) {
91
+ try {
92
+ return {
93
+ status: "ok",
94
+ output: await runWorkspaceCommand("tmux", ["list-windows", "-t", TMUX_SESSION, "-F", format], signal),
95
+ };
96
+ }
97
+ catch (error) {
98
+ if (isSignalAborted(signal)) {
99
+ throw error;
100
+ }
101
+ if (isTmuxNotFoundError(error)) {
102
+ return { status: "missing" };
103
+ }
104
+ return { status: "failed", reason: errorMessage(error) };
105
+ }
106
+ }
107
+ async function ensureTmuxSession(signal) {
108
+ try {
109
+ await runWorkspaceCommand("tmux", ["has-session", "-t", TMUX_SESSION], signal);
110
+ return;
111
+ }
112
+ catch (error) {
113
+ if (isSignalAborted(signal)) {
114
+ throw error;
115
+ }
116
+ /* session missing or server down; create it */
117
+ }
118
+ try {
119
+ await runWorkspaceCommand("tmux", ["new-session", "-d", "-s", TMUX_SESSION, "-n", TMUX_IDLE_WINDOW], signal);
120
+ }
121
+ catch (error) {
122
+ if (isSignalAborted(signal)) {
123
+ throw error;
124
+ }
125
+ try {
126
+ await runWorkspaceCommand("tmux", ["has-session", "-t", TMUX_SESSION], signal);
127
+ }
128
+ catch {
129
+ throw error;
130
+ }
131
+ }
132
+ }
133
+ function parseTmuxWindows(output) {
134
+ const items = [];
135
+ for (const line of output.split("\n")) {
136
+ if (line.length === 0) {
137
+ continue;
138
+ }
139
+ const [name, deadFlag] = line.split("\t");
140
+ /* v8 ignore next 3 @preserve -- split on a non-empty string always yields a non-empty first element */
141
+ if (name === undefined || name.length === 0) {
142
+ continue;
143
+ }
144
+ if (name === TMUX_IDLE_WINDOW) {
145
+ continue;
146
+ }
147
+ // pane_dead != 0 means the command exited and the window is a zombie
148
+ // (only happens when remain-on-exit is on; defense in depth in case a
149
+ // user-globally-set value beats our per-window override).
150
+ if (deadFlag !== undefined && deadFlag !== "0") {
151
+ continue;
152
+ }
153
+ items.push({ name });
154
+ }
155
+ return items;
156
+ }
@@ -34,6 +34,17 @@ export declare function lazyLinearClient(factory: () => LinearClient): () => Lin
34
34
  * each subcommand's arg parser stays DRY.
35
35
  */
36
36
  export declare function readTicketArgument(argv: string[], index: number, command: string): string;
37
+ export interface DryRunPositionals {
38
+ dryRun: boolean;
39
+ positionals: string[];
40
+ }
41
+ /**
42
+ * Parses an argv that accepts an optional `--dry-run` flag plus free
43
+ * positionals, rejecting any other dash-prefixed token. Shared by the
44
+ * subcommands whose only flag is `--dry-run` so each parser stays DRY; pass the
45
+ * command's `usage` string for the "Unknown option" error.
46
+ */
47
+ export declare function parseDryRunPositionals(argv: string[], usage: string): DryRunPositionals;
37
48
  export declare function errorMessage(error: unknown): string;
38
49
  export {};
39
50
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/lib/util.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB3E;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGhD;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAEzD;AAED,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOxF;AAkBD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAQzC;AAED,KAAK,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;AAUpF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,IAAI,CAcxF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,QAAA,MAAM,sBAAsB,YAAI,2BAA2B,EAAE,gBAAgB,CAAU,CAAC;AAExF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,IAAI,oBAAoB,GAAG,SAAS,CAQtE;AAED,wBAAgB,eAAe,IAAI,YAAY,CAQ9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,YAAY,GAAG,MAAM,YAAY,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAMzF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcnD"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/lib/util.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB3E;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGhD;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAEzD;AAED,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOxF;AAkBD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAQzC;AAED,KAAK,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;AAUpF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,IAAI,CAcxF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,QAAA,MAAM,sBAAsB,YAAI,2BAA2B,EAAE,gBAAgB,CAAU,CAAC;AAExF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,IAAI,oBAAoB,GAAG,SAAS,CAQtE;AAED,wBAAgB,eAAe,IAAI,YAAY,CAQ9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,YAAY,GAAG,MAAM,YAAY,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAMzF;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAcvF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcnD"}
package/dist/lib/util.js CHANGED
@@ -146,6 +146,27 @@ export function readTicketArgument(argv, index, command) {
146
146
  }
147
147
  return value;
148
148
  }
149
+ /**
150
+ * Parses an argv that accepts an optional `--dry-run` flag plus free
151
+ * positionals, rejecting any other dash-prefixed token. Shared by the
152
+ * subcommands whose only flag is `--dry-run` so each parser stays DRY; pass the
153
+ * command's `usage` string for the "Unknown option" error.
154
+ */
155
+ export function parseDryRunPositionals(argv, usage) {
156
+ let dryRun = false;
157
+ const positionals = [];
158
+ for (const argument of argv) {
159
+ if (argument === "--dry-run") {
160
+ dryRun = true;
161
+ continue;
162
+ }
163
+ if (argument.startsWith("-")) {
164
+ throw new Error(`Unknown option: ${argument}\nUsage: ${usage}`);
165
+ }
166
+ positionals.push(argument);
167
+ }
168
+ return { dryRun, positionals };
169
+ }
149
170
  export function errorMessage(error) {
150
171
  if (error instanceof Error) {
151
172
  return error.message;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shared contract for Workspace backends. A Workspace is the host-side
3
+ * terminal session that runs an agent for one ticket; `Workspace.name` is
4
+ * the ticket id callers key on. The cmux and tmux adapters implement this
5
+ * interface in their own files (`cmuxAdapter.ts`, `tmuxAdapter.ts`);
6
+ * `workspaces.ts` resolves and fronts them. This is internal cleanup, not a
7
+ * plugin contract — nothing here is a published extension point.
8
+ */
9
+ export type WorkspaceKind = "cmux" | "tmux";
10
+ export interface Workspace {
11
+ /** Ticket id; the join key callers use. */
12
+ name: string;
13
+ }
14
+ export interface WorkspaceStatus {
15
+ text: string;
16
+ color?: string;
17
+ icon?: string;
18
+ }
19
+ export interface WorkspaceAccessHint {
20
+ kind: "attachCommand";
21
+ command: string;
22
+ }
23
+ export interface OpenSpec {
24
+ /** Ticket id; becomes the workspace's name. */
25
+ name: string;
26
+ /** Working directory the workspace runs in. */
27
+ cwd: string;
28
+ /** Shell string the workspace executes (host setup + agent exec). */
29
+ command: string;
30
+ /** Optional status painting. Adapters that can't paint silently drop it. */
31
+ status?: WorkspaceStatus;
32
+ }
33
+ /**
34
+ * `unavailable` is "we don't know" — never treat it as "empty," or callers
35
+ * would close every live workspace by deduction.
36
+ */
37
+ export type WorkspaceProbe = {
38
+ kind: "ok";
39
+ names: Set<string>;
40
+ } | {
41
+ kind: "unavailable";
42
+ error?: unknown;
43
+ };
44
+ export type WorkspaceInterruptResult = {
45
+ kind: "interrupted";
46
+ } | {
47
+ kind: "missing";
48
+ } | {
49
+ kind: "unavailable";
50
+ error?: unknown;
51
+ };
52
+ export type WorkspaceCloseResult = {
53
+ kind: "closed";
54
+ } | {
55
+ kind: "missing";
56
+ } | {
57
+ kind: "unavailable";
58
+ error?: unknown;
59
+ };
60
+ export interface Adapter {
61
+ open(spec: OpenSpec, signal?: AbortSignal): Promise<void>;
62
+ /**
63
+ * Live workspaces only. Returns:
64
+ * - `Workspace[]` when the adapter probe succeeded (may be empty).
65
+ * - `undefined` when the adapter binary failed in a way that doesn't
66
+ * distinguish "no live workspaces" from "couldn't ask".
67
+ */
68
+ list(signal?: AbortSignal): Promise<Workspace[] | undefined>;
69
+ /** Closes the workspace or confirms it is not present. */
70
+ close(name: string, signal?: AbortSignal): Promise<WorkspaceCloseResult>;
71
+ /**
72
+ * User-facing way to reach the workspace, or `undefined` when the backend
73
+ * has no concise external hint.
74
+ */
75
+ accessHint(name: string): WorkspaceAccessHint | undefined;
76
+ }
77
+ export declare function runWorkspaceCommand(command: string, arguments_: readonly string[], signal?: AbortSignal): Promise<string>;
78
+ export declare function isSignalAborted(signal?: AbortSignal): boolean;
79
+ //# sourceMappingURL=workspaceAdapter.d.ts.map