@clipboard-health/groundcrew 4.5.0 → 4.7.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 (47) hide show
  1. package/README.md +60 -483
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +23 -3
  4. package/dist/commands/dispatcher.d.ts.map +1 -1
  5. package/dist/commands/dispatcher.js +17 -8
  6. package/dist/commands/doctor.d.ts.map +1 -1
  7. package/dist/commands/doctor.js +24 -8
  8. package/dist/commands/init.d.ts +13 -0
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +181 -14
  11. package/dist/commands/resumeWorkspace.d.ts.map +1 -1
  12. package/dist/commands/resumeWorkspace.js +2 -1
  13. package/dist/commands/setupWorkspace.d.ts.map +1 -1
  14. package/dist/commands/setupWorkspace.js +26 -11
  15. package/dist/commands/teardownReporter.js +4 -4
  16. package/dist/lib/adapters/linear/fetch.d.ts.map +1 -1
  17. package/dist/lib/adapters/linear/fetch.js +4 -4
  18. package/dist/lib/adapters/linear/writeback.js +2 -2
  19. package/dist/lib/adapters/shell/invoke.js +2 -2
  20. package/dist/lib/agentLaunch.d.ts +1 -0
  21. package/dist/lib/agentLaunch.d.ts.map +1 -1
  22. package/dist/lib/agentLaunch.js +24 -16
  23. package/dist/lib/cmuxAdapter.js +5 -5
  24. package/dist/lib/config.js +2 -2
  25. package/dist/lib/localRunner.d.ts.map +1 -1
  26. package/dist/lib/localRunner.js +2 -2
  27. package/dist/lib/runStateCleanup.js +2 -2
  28. package/dist/lib/tmuxAdapter.js +2 -2
  29. package/dist/lib/usage.d.ts.map +1 -1
  30. package/dist/lib/usage.js +7 -5
  31. package/dist/lib/util.d.ts +13 -0
  32. package/dist/lib/util.d.ts.map +1 -1
  33. package/dist/lib/util.js +54 -5
  34. package/dist/lib/worktrees.d.ts.map +1 -1
  35. package/dist/lib/worktrees.js +30 -20
  36. package/docs/adr/0001-groundcrew-uses-but-does-not-provision-sandboxes.md +17 -0
  37. package/docs/adr/0002-one-ticket-source-path-linear-is-an-adapter.md +17 -0
  38. package/docs/commands.md +68 -0
  39. package/docs/configuration.md +121 -0
  40. package/docs/credentials.md +81 -0
  41. package/docs/runners.md +45 -0
  42. package/docs/setup-hook-agent-prompt.md +62 -0
  43. package/docs/setup-hooks.md +46 -0
  44. package/docs/ticket-sources.md +45 -0
  45. package/docs/troubleshooting.md +48 -0
  46. package/package.json +2 -1
  47. package/static/demo.gif +0 -0
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { resumeWorkspaceCli } from "./commands/resumeWorkspace.js";
8
8
  import { setupWorkspaceCli } from "./commands/setupWorkspace.js";
9
9
  import { statusCli } from "./commands/status.js";
10
10
  import { createDefaultUpgradeCliOptions, upgradeCli } from "./commands/upgrade.js";
11
- import { errorMessage, parseDryRunPositionals, readTicketArgument, writeError, writeOutput, } from "./lib/util.js";
11
+ import { errorMessage, parseDryRunPositionals, readEnvironmentVariable, readTicketArgument, setVerbose, writeError, writeOutput, } from "./lib/util.js";
12
12
  const REMOVED_SANDBOX_COMMAND_MESSAGE = [
13
13
  "`crew sandbox` is no longer supported.",
14
14
  "Groundcrew now launches agents inside existing sbx sandboxes but does not list, create, regenerate, authenticate, or remove them.",
@@ -110,7 +110,7 @@ async function doctorCli(argv) {
110
110
  const SUBCOMMANDS = {
111
111
  init: {
112
112
  summary: "Create a crew.config.ts in the cwd (or --global into the XDG config dir)",
113
- usage: "[--global | --local] [--force] [--dry-run]",
113
+ usage: "[--global | --local] [--force] [--dry-run] [--project-dir <dir>] [--repo <repo>]... [--runner <runner>] [--model <model>]",
114
114
  invoke: initConfigCli,
115
115
  },
116
116
  run: {
@@ -176,6 +176,7 @@ function printHelp() {
176
176
  writeOutput("Options:");
177
177
  writeOutput(" -h, --help Show help");
178
178
  writeOutput(" -v, --version Print version");
179
+ writeOutput(" --verbose Show diagnostic output (or set GROUNDCREW_VERBOSE)");
179
180
  writeOutput("");
180
181
  writeOutput("Commands:");
181
182
  for (const [name, command] of visibleCommands) {
@@ -192,8 +193,27 @@ function packageMetadata() {
192
193
  function packageVersion() {
193
194
  return packageMetadata().version;
194
195
  }
196
+ const VERBOSE_FLAG = "--verbose";
197
+ function environmentVerbose() {
198
+ const raw = readEnvironmentVariable("GROUNDCREW_VERBOSE");
199
+ return raw !== undefined && raw !== "" && raw !== "0" && raw.toLowerCase() !== "false";
200
+ }
201
+ /**
202
+ * Pulls the global `--verbose` flag out of argv before subcommand dispatch so
203
+ * every command supports it and the strict per-command parsers never see it.
204
+ * GROUNDCREW_VERBOSE enables it without the flag.
205
+ */
206
+ function extractVerbose(argv) {
207
+ const commandArgv = argv.filter((argument) => argument !== VERBOSE_FLAG);
208
+ const verbose = commandArgv.length !== argv.length || environmentVerbose();
209
+ return { verbose, commandArgv };
210
+ }
195
211
  export async function run(argv) {
196
- const [subcommand, ...rest] = argv;
212
+ const { verbose, commandArgv } = extractVerbose(argv);
213
+ if (verbose) {
214
+ setVerbose(true);
215
+ }
216
+ const [subcommand, ...rest] = commandArgv;
197
217
  if (subcommand === undefined || subcommand === "-h" || subcommand === "--help") {
198
218
  printHelp();
199
219
  if (subcommand === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EACL,KAAK,UAAU,EAGf,KAAK,KAAK,EAEX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAaD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAqNjE;AAUD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAQrE"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EACL,KAAK,UAAU,EAGf,KAAK,KAAK,EAEX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAaD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAwNjE;AAsBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAQrE"}
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { dispatchableRepository } from "../lib/repositoryValidation.js";
10
10
  import { isGroundcrewIssue, naturalIdFromCanonical, } from "../lib/ticketSource.js";
11
- import { errorMessage, log, logEvent } from "../lib/util.js";
11
+ import { errorMessage, failMark, log, logEvent } from "../lib/util.js";
12
12
  import { workspaces } from "../lib/workspaces.js";
13
13
  import { classifyBlockers, classifyEligibility, classifyUsageExhaustion, } from "./eligibility.js";
14
14
  import { setupWorkspace } from "./setupWorkspace.js";
@@ -79,7 +79,7 @@ export function createDispatcher(deps) {
79
79
  });
80
80
  }
81
81
  catch (error) {
82
- log(`Failed to start ${ticketId}: ${errorMessage(error)}`);
82
+ log(`${failMark()} Failed to start ${ticketId}: ${errorMessage(error)}`);
83
83
  logEvent("dispatch", {
84
84
  outcome: "failed",
85
85
  ticket: ticketId,
@@ -145,18 +145,21 @@ export function createDispatcher(deps) {
145
145
  return;
146
146
  }
147
147
  // usage() is an HTTP call; workspaces.probe shells tmux/cmux. Kick off
148
- // usage first so the workspace probe can overlap with the in-flight request.
148
+ // usage first so any necessary workspace probe can overlap with the
149
+ // in-flight request.
149
150
  const usagePromise = usage(signal);
150
151
  // Snapshot live workspace names once per iteration so eligibility can
151
152
  // distinguish "worktree exists AND its agent is still running" (resume)
152
153
  // from "worktree exists but the workspace is gone" (ambiguous — don't
153
- // auto-recover). Done before slot-counting so a skipped stale ticket
154
- // doesn't consume an eligible slot and starve later Todo tickets.
154
+ // auto-recover). Skip the shell-out entirely for fresh-start-only ticks:
155
+ // if none of the candidates has a matching worktree, classifyRecovery()
156
+ // will never read the probe.
155
157
  let workspaceProbe;
156
158
  try {
157
- workspaceProbe = dryRun
158
- ? { kind: "ok", names: new Set() }
159
- : await workspaces.probe(config, signal);
159
+ workspaceProbe =
160
+ dryRun || !hasRecoverableCandidate(dispatchableUnblocked, worktreeEntries)
161
+ ? { kind: "ok", names: new Set() }
162
+ : await workspaces.probe(config, signal);
160
163
  }
161
164
  catch (error) {
162
165
  usagePromise.catch(() => "ignored");
@@ -196,6 +199,12 @@ export function createDispatcher(deps) {
196
199
  }
197
200
  return { runOnce };
198
201
  }
202
+ function hasRecoverableCandidate(issues, worktreeEntries) {
203
+ return issues.some((issue) => {
204
+ const naturalId = naturalIdFromCanonical(issue.id);
205
+ return worktreeEntries.some((entry) => entry.repository === issue.repository && entry.ticket === naturalId);
206
+ });
207
+ }
199
208
  function formatUsageExhaustion(exhaustion) {
200
209
  if (exhaustion.kind === "session") {
201
210
  const mins = exhaustion.resetMinutes ?? "?";
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgJH,wBAAsB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CA8E/C"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyKH,wBAAsB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CA8E/C"}
@@ -14,6 +14,7 @@ import { resolveWorkspaceKind } from "../lib/workspaces.js";
14
14
  // Tokenization stops after this many non-flag tokens. Two is enough to
15
15
  // catch wrapper + wrapped CLI commands like `safehouse claude --foo`.
16
16
  const MAX_TOKENS_PER_CMD = 2;
17
+ const SHIPPED_DEFAULT_MODEL_NAMES = ["claude", "codex"];
17
18
  async function checkCmd(cmd, required, hint) {
18
19
  const path = await which(cmd);
19
20
  const resolvedHint = path ?? hint;
@@ -103,14 +104,29 @@ function commandTokensToCheck(cmd) {
103
104
  }
104
105
  return result;
105
106
  }
106
- function gatherToolTokens(config) {
107
- const all = new Set();
108
- for (const definition of Object.values(config.models.definitions)) {
107
+ function gatherToolTargets(config) {
108
+ const all = new Map();
109
+ for (const [modelName, definition] of Object.entries(config.models.definitions)) {
109
110
  for (const token of commandTokensToCheck(definition.cmd)) {
110
- all.add(token);
111
+ const hint = modelCliHint(modelName, token);
112
+ if (!all.has(token) || all.get(token) === undefined) {
113
+ all.set(token, hint);
114
+ }
111
115
  }
112
116
  }
113
- return [...all];
117
+ return [...all].map(([token, hint]) => (hint === undefined ? { token } : { token, hint }));
118
+ }
119
+ function modelCliHint(modelName, token) {
120
+ if (token !== modelName) {
121
+ return undefined;
122
+ }
123
+ if (!isShippedDefaultModelName(modelName)) {
124
+ return undefined;
125
+ }
126
+ return `install ${token} or disable it in crew.config.ts: \`models.definitions.${modelName} = { disabled: true }\``;
127
+ }
128
+ function isShippedDefaultModelName(value) {
129
+ return value === "claude" || value === "codex";
114
130
  }
115
131
  function format(check) {
116
132
  let tag;
@@ -163,11 +179,11 @@ export async function doctor() {
163
179
  checkDir(config.workspace.projectDir, "workspace.projectDir"),
164
180
  localCapability,
165
181
  ];
166
- const toolTokens = gatherToolTokens(config);
167
- for (const token of toolTokens) {
182
+ const toolTargets = gatherToolTargets(config);
183
+ for (const { token, hint } of toolTargets) {
168
184
  const required = localCapability.ok;
169
185
  // oxlint-disable-next-line no-await-in-loop -- doctor reports tools in deterministic order
170
- const check = await checkCmd(token, required, required ? undefined : "required for local runs");
186
+ const check = await checkCmd(token, required, required ? hint : "required for local runs");
171
187
  checks.push(check);
172
188
  }
173
189
  const usageGatedModels = gatedModels(config);
@@ -4,7 +4,10 @@
4
4
  * the shipped `crew.config.example.ts` so a fresh install skips the manual
5
5
  * `cp` dance documented in the README.
6
6
  */
7
+ import { type LocalRunnerSetting } from "../lib/config.ts";
8
+ declare const INIT_MODELS: readonly ["claude", "codex"];
7
9
  type InitConfigScope = "global" | "local";
10
+ type InitModel = (typeof INIT_MODELS)[number];
8
11
  interface InitConfigOptions {
9
12
  /** Where to write the config. Defaults to "local" (cwd). */
10
13
  scope?: InitConfigScope;
@@ -14,6 +17,16 @@ interface InitConfigOptions {
14
17
  dryRun?: boolean;
15
18
  /** Override for the working directory; defaults to `process.cwd()`. */
16
19
  cwd?: string;
20
+ /** Pre-fill workspace.projectDir in the generated config. */
21
+ projectDir?: string;
22
+ /** Pre-fill workspace.knownRepositories in the generated config. */
23
+ repositories?: string[];
24
+ /** Pre-fill local.runner in the generated config. */
25
+ runner?: LocalRunnerSetting;
26
+ /** Keep one shipped default model enabled and disable the other. */
27
+ model?: InitModel;
28
+ /** Override the source template path. */
29
+ examplePath?: string;
17
30
  }
18
31
  type InitConfigOutcome = "dry-run-would-write" | "exists" | "wrote";
19
32
  interface InitConfigResult {
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,KAAK,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1C,UAAU,iBAAiB;IACzB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,yCAAyC;IACzC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,KAAK,iBAAiB,GAAG,qBAAqB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpE,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAoB5E;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAUlF,QAAA,MAAM,WAAW,YAAI,QAAQ,EAAE,OAAO,CAAU,CAAC;AAEjD,KAAK,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC1C,KAAK,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,UAAU,iBAAiB;IACzB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,yCAAyC;IACzC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,qDAAqD;IACrD,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,iBAAiB,GAAG,qBAAqB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpE,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAoB5E;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjE"}
@@ -4,16 +4,21 @@
4
4
  * the shipped `crew.config.example.ts` so a fresh install skips the manual
5
5
  * `cp` dance documented in the README.
6
6
  */
7
- import { copyFileSync, existsSync, mkdirSync } from "node:fs";
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
8
  import { dirname, resolve } from "node:path";
9
+ import { LOCAL_RUNNER_SETTINGS } from "../lib/config.js";
10
+ import { shellSingleQuote } from "../lib/shell.js";
9
11
  import { log, writeOutput } from "../lib/util.js";
10
12
  import { xdgConfigPath } from "../lib/xdg.js";
11
13
  const CONFIG_FILE_NAME = "crew.config.ts";
12
14
  const EXAMPLE_FILE_NAME = "crew.config.example.ts";
15
+ const DEFAULT_EXAMPLE_PROJECT_DIR = "~/dev/groundcrew";
16
+ const INIT_USAGE = "Usage: crew init [--global | --local] [--force] [--dry-run] [--project-dir <dir>] [--repo <owner/repo>]... [--runner <auto|safehouse|sdx|none>] [--model <claude|codex>]";
17
+ const INIT_MODELS = ["claude", "codex"];
13
18
  export function initConfig(options = {}) {
14
19
  const scope = options.scope ?? "local";
15
20
  const cwd = options.cwd ?? process.cwd();
16
- const source = resolveExamplePath();
21
+ const source = options.examplePath ?? resolveExamplePath();
17
22
  const destination = destinationFor({ scope, cwd });
18
23
  if (existsSync(destination) && options.force !== true) {
19
24
  log(`[exists] ${destination} — pass --force to overwrite`);
@@ -24,7 +29,7 @@ export function initConfig(options = {}) {
24
29
  return { destination, outcome: "dry-run-would-write" };
25
30
  }
26
31
  mkdirSync(dirname(destination), { recursive: true });
27
- copyFileSync(source, destination);
32
+ writeFileSync(destination, renderConfig(source, options));
28
33
  log(`[wrote] ${destination}`);
29
34
  return { destination, outcome: "wrote" };
30
35
  }
@@ -36,24 +41,27 @@ export async function initConfigCli(argv) {
36
41
  return;
37
42
  }
38
43
  if (result.outcome === "wrote") {
39
- writeOutput("");
40
- writeOutput("Next steps:");
41
- writeOutput(` - Edit ${result.destination}`);
42
- writeOutput(" - Set workspace.projectDir, workspace.knownRepositories");
43
- writeOutput(" - Export GROUNDCREW_LINEAR_API_KEY (or LINEAR_API_KEY)");
44
- writeOutput(" - Assign Linear tickets to yourself and add an agent-* label to opt them in");
45
- writeOutput(" - Verify with `crew doctor`");
44
+ writeInitGuidance(result.destination, options);
46
45
  }
47
46
  }
48
47
  function parseArguments(argv) {
49
48
  let scope;
50
49
  let force = false;
51
50
  let dryRun = false;
52
- for (const argument of argv) {
51
+ let projectDir;
52
+ const repositories = [];
53
+ let runner;
54
+ let model;
55
+ for (let index = 0; index < argv.length; index += 1) {
56
+ const argument = argv[index];
57
+ /* v8 ignore next 3 @preserve -- loop bounds keep argv[index] defined */
58
+ if (argument === undefined) {
59
+ continue;
60
+ }
53
61
  if (argument === "--global" || argument === "--local") {
54
62
  const next = argument === "--global" ? "global" : "local";
55
63
  if (scope !== undefined && scope !== next) {
56
- throw new Error("crew init: --global and --local are mutually exclusive.\nUsage: crew init [--global | --local] [--force] [--dry-run]");
64
+ throw new Error(`crew init: --global and --local are mutually exclusive.\n${INIT_USAGE}`);
57
65
  }
58
66
  scope = next;
59
67
  continue;
@@ -66,9 +74,44 @@ function parseArguments(argv) {
66
74
  dryRun = true;
67
75
  continue;
68
76
  }
69
- throw new Error(`Unknown option: ${argument}\nUsage: crew init [--global | --local] [--force] [--dry-run]`);
77
+ if (argument === "--project-dir") {
78
+ projectDir = readOptionValue(argv, index, argument);
79
+ index += 1;
80
+ continue;
81
+ }
82
+ if (argument === "--repo") {
83
+ repositories.push(readOptionValue(argv, index, argument));
84
+ index += 1;
85
+ continue;
86
+ }
87
+ if (argument === "--runner") {
88
+ runner = parseRunner(readOptionValue(argv, index, argument));
89
+ index += 1;
90
+ continue;
91
+ }
92
+ if (argument === "--model") {
93
+ model = parseModel(readOptionValue(argv, index, argument));
94
+ index += 1;
95
+ continue;
96
+ }
97
+ throw new Error(`Unknown option: ${argument}\n${INIT_USAGE}`);
98
+ }
99
+ const parsed = {
100
+ scope: scope ?? "local",
101
+ force,
102
+ dryRun,
103
+ repositories,
104
+ };
105
+ if (projectDir !== undefined) {
106
+ parsed.projectDir = projectDir;
70
107
  }
71
- return { scope: scope ?? "local", force, dryRun };
108
+ if (runner !== undefined) {
109
+ parsed.runner = runner;
110
+ }
111
+ if (model !== undefined) {
112
+ parsed.model = model;
113
+ }
114
+ return parsed;
72
115
  }
73
116
  function destinationFor(args) {
74
117
  if (args.scope === "global") {
@@ -81,3 +124,127 @@ function resolveExamplePath() {
81
124
  // after build; the example ships at the package root in both cases.
82
125
  return resolve(import.meta.dirname, "..", "..", EXAMPLE_FILE_NAME);
83
126
  }
127
+ function readOptionValue(argv, index, flag) {
128
+ const value = argv[index + 1];
129
+ if (value === undefined || value.length === 0 || value.startsWith("-")) {
130
+ throw new Error(`crew init ${flag}: value is required\n${INIT_USAGE}`);
131
+ }
132
+ return value;
133
+ }
134
+ function parseRunner(value) {
135
+ if (isLocalRunnerSetting(value)) {
136
+ return value;
137
+ }
138
+ throw new Error(`crew init --runner must be one of ${LOCAL_RUNNER_SETTINGS.join(", ")}`);
139
+ }
140
+ function parseModel(value) {
141
+ if (isInitModel(value)) {
142
+ return value;
143
+ }
144
+ throw new Error(`crew init --model must be one of ${INIT_MODELS.join(", ")}`);
145
+ }
146
+ function isLocalRunnerSetting(value) {
147
+ return value === "auto" || value === "safehouse" || value === "sdx" || value === "none";
148
+ }
149
+ function isInitModel(value) {
150
+ return value === "claude" || value === "codex";
151
+ }
152
+ function tsString(value) {
153
+ return JSON.stringify(value);
154
+ }
155
+ function renderConfig(source, options) {
156
+ let contents = readFileSync(source, "utf8");
157
+ if (options.projectDir !== undefined) {
158
+ contents = replaceRequired(contents, `projectDir: ${tsString(DEFAULT_EXAMPLE_PROJECT_DIR)}`, `projectDir: ${tsString(options.projectDir)}`, "--project-dir");
159
+ }
160
+ if (options.repositories !== undefined && options.repositories.length > 0) {
161
+ contents = replaceRequired(contents, 'knownRepositories: ["your-org/your-repo"]', `knownRepositories: [${options.repositories.map(tsString).join(", ")}]`, "--repo");
162
+ }
163
+ if (options.runner !== undefined) {
164
+ contents = replaceRequired(contents, ` // local: { runner: "auto" },`, ` local: { runner: ${tsString(options.runner)} },`, "--runner");
165
+ }
166
+ if (options.model !== undefined) {
167
+ contents = replaceRequired(contents, " // prompts: {", `${modelBlock(options.model)}\n // prompts: {`, "--model");
168
+ }
169
+ return contents;
170
+ }
171
+ function replaceRequired(contents, search, replacement, flag) {
172
+ if (!contents.includes(search)) {
173
+ throw new Error(`crew init ${flag}: template anchor not found in ${EXAMPLE_FILE_NAME}`);
174
+ }
175
+ return contents.replace(search, replacement);
176
+ }
177
+ function modelBlock(model) {
178
+ const disabled = model === "claude" ? "codex" : "claude";
179
+ return [
180
+ " models: {",
181
+ ` default: ${tsString(model)},`,
182
+ " definitions: {",
183
+ ` ${disabled}: { disabled: true },`,
184
+ " },",
185
+ " },",
186
+ "",
187
+ ].join("\n");
188
+ }
189
+ function writeInitGuidance(destination, options) {
190
+ writeOutput("");
191
+ writeOutput("Next steps:");
192
+ writeOutput(` - Review ${destination}`);
193
+ if (options.projectDir === undefined ||
194
+ options.repositories === undefined ||
195
+ options.repositories.length === 0) {
196
+ writeOutput(" - Set workspace.projectDir and workspace.knownRepositories");
197
+ }
198
+ writeCloneGuidance(options);
199
+ writeOutput(" - If using Linear, export your API key:");
200
+ writeOutput(' export GROUNDCREW_LINEAR_API_KEY="lin_api_..."');
201
+ writeOutput(" - In Linear, assign tickets to yourself and add an agent-* label to opt them in");
202
+ writeOutput(" - Validate and start:");
203
+ writeOutput(" crew doctor");
204
+ writeOutput(" crew run --watch");
205
+ }
206
+ function writeCloneGuidance(options) {
207
+ if (options.repositories === undefined || options.repositories.length === 0) {
208
+ return;
209
+ }
210
+ writeOutput(" - Clone configured repositories:");
211
+ writeOutput(` ${projectDirAssignment(options.projectDir ?? DEFAULT_EXAMPLE_PROJECT_DIR)}`);
212
+ for (const repository of options.repositories) {
213
+ for (const command of cloneCommands(repository)) {
214
+ writeOutput(` ${command}`);
215
+ }
216
+ }
217
+ }
218
+ function projectDirAssignment(projectDir) {
219
+ if (projectDir === "~") {
220
+ return 'PROJECT_DIR="$HOME"';
221
+ }
222
+ if (projectDir.startsWith("~/")) {
223
+ return `PROJECT_DIR="$HOME/${escapeDoubleQuotedShellValue(projectDir.slice(2))}"`;
224
+ }
225
+ return `PROJECT_DIR=${shellSingleQuote(projectDir)}`;
226
+ }
227
+ function cloneCommands(repository) {
228
+ const parts = repository.split("/");
229
+ const [owner, name, extra] = parts;
230
+ if (owner !== undefined && name !== undefined && extra === undefined) {
231
+ return [
232
+ `mkdir -p "$PROJECT_DIR/${owner}"`,
233
+ `git clone git@github.com:${owner}/${name}.git "$PROJECT_DIR/${owner}/${name}"`,
234
+ ];
235
+ }
236
+ return [
237
+ 'mkdir -p "$PROJECT_DIR"',
238
+ `git clone <REMOTE_URL_FOR_${repository}> "$PROJECT_DIR/${repository}"`,
239
+ ];
240
+ }
241
+ function escapeDoubleQuotedShellValue(value) {
242
+ let escaped = "";
243
+ for (const character of value) {
244
+ escaped +=
245
+ character === '"' || character === "\\" || character === "$" || character === "`"
246
+ ? `\\${character}`
247
+ : character;
248
+ }
249
+ return escaped;
250
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAcnE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB;AA6HD,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA4Df;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
1
+ {"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAcnE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB;AA6HD,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Df;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
@@ -106,12 +106,13 @@ export async function resumeWorkspace(config, options) {
106
106
  if (definition === undefined) {
107
107
  throw new Error(`Unknown model: ${context.model}`);
108
108
  }
109
- const { runner, sandboxName } = await prepareAgentLaunch({
109
+ const { runner, sandboxName, ensureReady } = await prepareAgentLaunch({
110
110
  config,
111
111
  model: context.model,
112
112
  definition,
113
113
  purpose: "resumes",
114
114
  });
115
+ await ensureReady();
115
116
  const stagedPrompt = stagePromptText({
116
117
  prefix: "groundcrew-resume",
117
118
  ticket,
@@ -1 +1 @@
1
- {"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAiBnE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAuBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA6Gf;AAqHD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
1
+ {"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAiBnE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAuBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA+Gf;AAyID,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
@@ -7,7 +7,7 @@ import { buildLaunchCommand } from "../lib/launchCommand.js";
7
7
  import { recordRunState } from "../lib/runState.js";
8
8
  import { stageBuildSecrets, stagePromptFromTemplate, stageWorkspaceLaunchCommand, } from "../lib/stagedLaunch.js";
9
9
  import { naturalIdFromCanonical } from "../lib/ticketSource.js";
10
- import { errorMessage, log } from "../lib/util.js";
10
+ import { debug, errorMessage, log, okMark } from "../lib/util.js";
11
11
  import { workspaces } from "../lib/workspaces.js";
12
12
  import { isWorktreeAlreadyExistsError, worktrees } from "../lib/worktrees.js";
13
13
  function stagePrompt(input) {
@@ -31,7 +31,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
31
31
  if (!definition) {
32
32
  throw new Error(`Unknown model: ${model}`);
33
33
  }
34
- const { runner, sandboxName } = await prepareAgentLaunch({
34
+ const { runner, sandboxName, ensureReady } = await prepareAgentLaunch({
35
35
  config,
36
36
  model,
37
37
  definition,
@@ -40,11 +40,10 @@ export async function setupWorkspace(config, options, runOptions = {}) {
40
40
  });
41
41
  const spec = { repository, ticket };
42
42
  let created;
43
+ const createdPromise = signal === undefined ? worktrees.create(config, spec) : worktrees.create(config, spec, signal);
44
+ const readinessPromise = startLaunchReadiness(ensureReady);
43
45
  try {
44
- created =
45
- signal === undefined
46
- ? await worktrees.create(config, spec)
47
- : await worktrees.create(config, spec, signal);
46
+ created = await createdPromise;
48
47
  }
49
48
  catch (error) {
50
49
  if (isWorktreeAlreadyExistsError(error)) {
@@ -63,6 +62,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
63
62
  // the ticket strands forever.
64
63
  let promptDir;
65
64
  try {
65
+ await assertLaunchReady(readinessPromise);
66
66
  const ticketDetails = options.details;
67
67
  const accessHint = await workspaces.accessHint(config, ticket, signal);
68
68
  const stagedPrompt = stagePrompt({
@@ -83,7 +83,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
83
83
  sandboxName,
84
84
  });
85
85
  const launchCmd = stageWorkspaceLaunchCommand(promptDir, launchCommand);
86
- log("Opening workspace...");
86
+ debug("Opening workspace...");
87
87
  await openAgentWorkspace({
88
88
  config,
89
89
  name: ticket,
@@ -105,9 +105,9 @@ export async function setupWorkspace(config, options, runOptions = {}) {
105
105
  title: ticketDetails.title,
106
106
  ...(ticketDetails.url === undefined ? {} : { url: ticketDetails.url }),
107
107
  });
108
- log(`Workspace "${ticket}" launched (${model})`);
109
- log(` Worktree: ${launchDir}`);
110
- log(` Branch: ${branchName}`);
108
+ log(`${okMark()} "${ticket}" launched (${model}) worktree ${worktreeName}`);
109
+ debug(` Worktree: ${launchDir}`);
110
+ debug(` Branch: ${branchName}`);
111
111
  if (accessHint !== undefined) {
112
112
  logAccessHint(accessHint);
113
113
  }
@@ -130,6 +130,21 @@ export async function setupWorkspace(config, options, runOptions = {}) {
130
130
  throw error;
131
131
  }
132
132
  }
133
+ async function startLaunchReadiness(ensureReady) {
134
+ try {
135
+ await ensureReady();
136
+ return { kind: "ready" };
137
+ }
138
+ catch (error) {
139
+ return { kind: "failed", error };
140
+ }
141
+ }
142
+ async function assertLaunchReady(readinessPromise) {
143
+ const readiness = await readinessPromise;
144
+ if (readiness.kind === "failed") {
145
+ throw readiness.error;
146
+ }
147
+ }
133
148
  /**
134
149
  * Probe the workspace backend and, if a workspace for `ticket` is still
135
150
  * live, log the access hint. Used on the pre-launch error path (e.g. the
@@ -151,7 +166,7 @@ async function logAccessHintForExistingWorkspace(arguments_) {
151
166
  logAccessHint(accessHint);
152
167
  }
153
168
  function logAccessHint(accessHint) {
154
- log(` Attach: ${accessHint.command}`);
169
+ debug(` Attach: ${accessHint.command}`);
155
170
  }
156
171
  function renderWorkspaceContinuationInstruction(accessHint) {
157
172
  if (accessHint === undefined) {
@@ -1,14 +1,14 @@
1
- import { errorMessage, log, logEvent } from "../lib/util.js";
1
+ import { debug, errorMessage, log, logEvent, okMark } from "../lib/util.js";
2
2
  export function logTeardown(result) {
3
3
  if (result.workspaceProbe.kind === "unavailable" && result.workspaceProbe.error !== undefined) {
4
4
  log(`workspace list failed: ${errorMessage(result.workspaceProbe.error)}`);
5
5
  }
6
6
  for (const ticket of result.closed) {
7
- log(`Closed workspace ${ticket}`);
7
+ debug(`Closed workspace ${ticket}`);
8
8
  }
9
9
  for (const entry of result.removed) {
10
- log(`Cleanup complete for ${entry.ticket} (${entry.kind})`);
11
- log(` Worktree: ${entry.dir} (removed)`);
10
+ log(`${okMark()} Cleanup complete for ${entry.ticket} (${entry.kind})`);
11
+ debug(` Worktree: ${entry.dir} (removed)`);
12
12
  }
13
13
  for (const failure of result.failures) {
14
14
  const message = errorMessage(failure.error);
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/fetch.ts"],"names":[],"mappings":"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"}