@clipboard-health/groundcrew 4.7.2 → 4.7.3

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/bin/run.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { dirname } from "node:path";
3
+ import path from "node:path";
4
4
 
5
5
  import { runCli } from "./runCli.js";
6
6
 
7
- await runCli(dirname(import.meta.dirname), "main");
7
+ await runCli(path.dirname(import.meta.dirname), "main");
package/bin/runCli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { constants as osConstants } from "node:os";
4
- import { join } from "node:path";
4
+ import path from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
 
7
7
  /**
@@ -14,13 +14,13 @@ import { pathToFileURL } from "node:url";
14
14
  * @param {string} name
15
15
  */
16
16
  export async function runCli(packageRoot, name) {
17
- const compiledPath = join(packageRoot, "dist", `${name}.js`);
17
+ const compiledPath = path.join(packageRoot, "dist", `${name}.js`);
18
18
  if (existsSync(compiledPath)) {
19
19
  await import(pathToFileURL(compiledPath).href);
20
20
  return;
21
21
  }
22
22
 
23
- const sourcePath = join(packageRoot, "src", `${name}.ts`);
23
+ const sourcePath = path.join(packageRoot, "src", `${name}.ts`);
24
24
  const result = spawnSync(process.execPath, [sourcePath, ...process.argv.slice(2)], {
25
25
  stdio: "inherit",
26
26
  });
@@ -5,7 +5,7 @@
5
5
  * `cp` dance documented in the README.
6
6
  */
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
- import { dirname, resolve } from "node:path";
8
+ import path from "node:path";
9
9
  import { LOCAL_RUNNER_SETTINGS } from "../lib/config.js";
10
10
  import { shellSingleQuote } from "../lib/shell.js";
11
11
  import { log, writeOutput } from "../lib/util.js";
@@ -28,7 +28,7 @@ export function initConfig(options = {}) {
28
28
  log(`[dry-run] would write ${destination}`);
29
29
  return { destination, outcome: "dry-run-would-write" };
30
30
  }
31
- mkdirSync(dirname(destination), { recursive: true });
31
+ mkdirSync(path.dirname(destination), { recursive: true });
32
32
  writeFileSync(destination, renderConfig(source, options));
33
33
  log(`[wrote] ${destination}`);
34
34
  return { destination, outcome: "wrote" };
@@ -117,12 +117,12 @@ function destinationFor(args) {
117
117
  if (args.scope === "global") {
118
118
  return xdgConfigPath("groundcrew", CONFIG_FILE_NAME);
119
119
  }
120
- return resolve(args.cwd, CONFIG_FILE_NAME);
120
+ return path.resolve(args.cwd, CONFIG_FILE_NAME);
121
121
  }
122
122
  function resolveExamplePath() {
123
123
  // `init.ts` lives at src/commands/init.ts in source and dist/commands/init.js
124
124
  // after build; the example ships at the package root in both cases.
125
- return resolve(import.meta.dirname, "..", "..", EXAMPLE_FILE_NAME);
125
+ return path.resolve(import.meta.dirname, "..", "..", EXAMPLE_FILE_NAME);
126
126
  }
127
127
  function readOptionValue(argv, index, flag) {
128
128
  const value = argv[index + 1];
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import path from "node:path";
3
3
  import { runCommand } from "../lib/commandRunner.js";
4
4
  import { which } from "../lib/host.js";
5
5
  import { classifyInstall, createDefaultNpmSpawner, detectInstallPath, detectIsSymlink, detectNpmRootGlobal, runNpmInstallGlobal, } from "../lib/npmGlobal.js";
@@ -137,7 +137,7 @@ export async function createDefaultUpgradeCliOptions(args) {
137
137
  function readInstalledVersionFromDisk(installPath) {
138
138
  let raw;
139
139
  try {
140
- raw = readFileSync(join(installPath, "package.json"), "utf8");
140
+ raw = readFileSync(path.join(installPath, "package.json"), "utf8");
141
141
  }
142
142
  catch {
143
143
  return undefined;
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { __rewriteRelativeImportExtension } from "tslib";
13
13
  import { readdirSync } from "node:fs";
14
- import { resolve } from "node:path";
14
+ import path from "node:path";
15
15
  import { z } from "zod";
16
16
  /**
17
17
  * Pure logic: given a list of subdirectory names and an async loader, build a
@@ -62,7 +62,7 @@ const here = import.meta.dirname;
62
62
  async function defaultImportLoader(directoryName) {
63
63
  // Resolve relative to this module's directory. tsx maps `.js` → `.ts` in dev;
64
64
  // prod Node ESM resolves the actual `.js` file.
65
- const modulePath = resolve(here, directoryName, "index.js");
65
+ const modulePath = path.resolve(here, directoryName, "index.js");
66
66
  // oxlint-disable-next-line typescript/no-unsafe-assignment -- dynamic import return type is `any`; adapter contract is enforced by buildRegistry
67
67
  const mod = await import(__rewriteRelativeImportExtension(modulePath));
68
68
  return mod.default;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { __rewriteRelativeImportExtension } from "tslib";
2
2
  import { existsSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
- import { resolve } from "node:path";
4
+ import path from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import { cosmiconfig } from "cosmiconfig";
7
7
  import { debug, log, readEnvironmentVariable, setLogFile } from "./util.js";
@@ -88,7 +88,7 @@ function expandHome(p) {
88
88
  return homedir();
89
89
  }
90
90
  if (p.startsWith("~/")) {
91
- return resolve(homedir(), p.slice(2));
91
+ return path.resolve(homedir(), p.slice(2));
92
92
  }
93
93
  return p;
94
94
  }
@@ -98,45 +98,45 @@ function fail(message) {
98
98
  function isNonEmptyString(value) {
99
99
  return typeof value === "string" && value.length > 0;
100
100
  }
101
- function requireString(value, path) {
101
+ function requireString(value, configKey) {
102
102
  if (!isNonEmptyString(value)) {
103
- fail(`${path} must be a non-empty string (got ${JSON.stringify(value)})`);
103
+ fail(`${configKey} must be a non-empty string (got ${JSON.stringify(value)})`);
104
104
  }
105
105
  }
106
- function requirePositiveInt(value, path, min = 1) {
106
+ function requirePositiveInt(value, configKey, min = 1) {
107
107
  if (typeof value !== "number" || !Number.isInteger(value) || value < min) {
108
- fail(`${path} must be an integer ≥ ${min} (got ${JSON.stringify(value)})`);
108
+ fail(`${configKey} must be an integer ≥ ${min} (got ${JSON.stringify(value)})`);
109
109
  }
110
110
  }
111
- function requirePercent(value, path) {
111
+ function requirePercent(value, configKey) {
112
112
  if (typeof value !== "number" ||
113
113
  !Number.isFinite(value) ||
114
114
  value <= PERCENT_MIN_EXCLUSIVE ||
115
115
  value > PERCENT_MAX) {
116
- fail(`${path} must be a finite number in (0, 100] (got ${JSON.stringify(value)})`);
116
+ fail(`${configKey} must be a finite number in (0, 100] (got ${JSON.stringify(value)})`);
117
117
  }
118
118
  }
119
119
  function cloneModelDefinition(definition) {
120
120
  return structuredClone(definition);
121
121
  }
122
- function normalizeOptionalString(value, path) {
122
+ function normalizeOptionalString(value, configKey) {
123
123
  if (value === undefined) {
124
124
  return undefined;
125
125
  }
126
126
  if (typeof value !== "string" || value.trim().length === 0) {
127
- fail(`${path} must be a non-empty string`);
127
+ fail(`${configKey} must be a non-empty string`);
128
128
  }
129
129
  return value.trim();
130
130
  }
131
131
  const ENV_VAR_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
132
132
  function validatePreLaunchEnv(modelName, value) {
133
- const path = `models.definitions.${modelName}.preLaunchEnv`;
133
+ const configPath = `models.definitions.${modelName}.preLaunchEnv`;
134
134
  if (!Array.isArray(value)) {
135
- fail(`${path} must be an array of env var names (got ${JSON.stringify(value)})`);
135
+ fail(`${configPath} must be an array of env var names (got ${JSON.stringify(value)})`);
136
136
  }
137
137
  for (const [index, entry] of value.entries()) {
138
138
  if (typeof entry !== "string" || !ENV_VAR_NAME_PATTERN.test(entry)) {
139
- fail(`${path}[${index}] must be a POSIX env var name matching ${ENV_VAR_NAME_PATTERN.source} (got ${JSON.stringify(entry)})`);
139
+ fail(`${configPath}[${index}] must be a POSIX env var name matching ${ENV_VAR_NAME_PATTERN.source} (got ${JSON.stringify(entry)})`);
140
140
  }
141
141
  // Build secrets are sourced into the host launch shell, forwarded only to
142
142
  // the Safehouse *setup* wrap, and `unset` on the host before the agent
@@ -144,7 +144,7 @@ function validatePreLaunchEnv(modelName, value) {
144
144
  // fail loudly so the operator picks a different name (or removes the
145
145
  // entry) instead of debugging a missing env var at runtime.
146
146
  if (BUILD_SECRET_NAMES.includes(entry)) {
147
- fail(`${path}[${index}] cannot be a BUILD_SECRET_NAMES entry (${BUILD_SECRET_NAMES.join(", ")}); ` +
147
+ fail(`${configPath}[${index}] cannot be a BUILD_SECRET_NAMES entry (${BUILD_SECRET_NAMES.join(", ")}); ` +
148
148
  "those are unset on the host before the agent wrap is exec'd, so forwarding them via --env-pass would be a no-op.");
149
149
  }
150
150
  }
@@ -165,52 +165,52 @@ export function hasPreLaunchEnv(definition) {
165
165
  function isWorkspaceKindSetting(value) {
166
166
  return (typeof value === "string" && WORKSPACE_KIND_SETTINGS.includes(value));
167
167
  }
168
- function normalizeWorkspaceKind(value, path) {
168
+ function normalizeWorkspaceKind(value, configKey) {
169
169
  if (value === undefined) {
170
170
  return undefined;
171
171
  }
172
172
  if (!isWorkspaceKindSetting(value)) {
173
- fail(`${path} must be one of ${WORKSPACE_KIND_SETTINGS.join(", ")} (got ${JSON.stringify(value)})`);
173
+ fail(`${configKey} must be one of ${WORKSPACE_KIND_SETTINGS.join(", ")} (got ${JSON.stringify(value)})`);
174
174
  }
175
175
  return value;
176
176
  }
177
177
  function isLocalRunnerSetting(value) {
178
178
  return typeof value === "string" && LOCAL_RUNNER_SETTINGS.includes(value);
179
179
  }
180
- function normalizeLocalRunner(value, path) {
180
+ function normalizeLocalRunner(value, configKey) {
181
181
  if (value === undefined) {
182
182
  return undefined;
183
183
  }
184
184
  if (!isLocalRunnerSetting(value)) {
185
- fail(`${path} must be one of ${LOCAL_RUNNER_SETTINGS.join(", ")} (got ${JSON.stringify(value)})`);
185
+ fail(`${configKey} must be one of ${LOCAL_RUNNER_SETTINGS.join(", ")} (got ${JSON.stringify(value)})`);
186
186
  }
187
187
  return value;
188
188
  }
189
- function normalizeSandbox(value, path) {
189
+ function normalizeSandbox(value, configKey) {
190
190
  if (!isPlainObject(value)) {
191
- fail(`${path} must be an object`);
191
+ fail(`${configKey} must be an object`);
192
192
  }
193
193
  if (Object.hasOwn(value, "template")) {
194
- failRemovedConfigKey(`${path}.template`, "Groundcrew no longer creates or re-templates sdx sandboxes.");
194
+ failRemovedConfigKey(`${configKey}.template`, "Groundcrew no longer creates or re-templates sdx sandboxes.");
195
195
  }
196
196
  if (Object.hasOwn(value, "kits")) {
197
- failRemovedConfigKey(`${path}.kits`, "Groundcrew no longer creates sdx sandboxes or applies sandbox kits.");
197
+ failRemovedConfigKey(`${configKey}.kits`, "Groundcrew no longer creates sdx sandboxes or applies sandbox kits.");
198
198
  }
199
199
  const { agent, setupCommand } = value;
200
- requireString(agent, `${path}.agent`);
200
+ requireString(agent, `${configKey}.agent`);
201
201
  const trimmedAgent = agent.trim();
202
202
  if (trimmedAgent.length === 0) {
203
- fail(`${path}.agent must be a non-empty string (got ${JSON.stringify(agent)})`);
203
+ fail(`${configKey}.agent must be a non-empty string (got ${JSON.stringify(agent)})`);
204
204
  }
205
205
  const sandbox = { agent: trimmedAgent };
206
- const normalizedSetup = normalizeOptionalString(setupCommand, `${path}.setupCommand`);
206
+ const normalizedSetup = normalizeOptionalString(setupCommand, `${configKey}.setupCommand`);
207
207
  if (normalizedSetup !== undefined) {
208
208
  sandbox.setupCommand = normalizedSetup;
209
209
  }
210
210
  return sandbox;
211
211
  }
212
- function failRemovedConfigKey(path, reason) {
213
- fail(`${path} is no longer supported: ${reason} ` +
212
+ function failRemovedConfigKey(configKey, reason) {
213
+ fail(`${configKey} is no longer supported: ${reason} ` +
214
214
  "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.");
215
215
  }
216
216
  function failIfLegacyModelKeys(name, override) {
@@ -322,9 +322,9 @@ function mergeDefinitions(user) {
322
322
  function isPlainObject(value) {
323
323
  return typeof value === "object" && value !== null && !Array.isArray(value);
324
324
  }
325
- function requireObject(value, path) {
325
+ function requireObject(value, configKey) {
326
326
  if (!isPlainObject(value)) {
327
- fail(`${path} must be an object (got ${JSON.stringify(value)})`);
327
+ fail(`${configKey} must be an object (got ${JSON.stringify(value)})`);
328
328
  }
329
329
  }
330
330
  function failOnLegacyLinearShape(user) {
@@ -362,12 +362,12 @@ function normalizeSources(raw) {
362
362
  }
363
363
  const names = new Map();
364
364
  for (const [index, entry] of raw.entries()) {
365
- const path = `sources[${index}]`;
365
+ const configPath = `sources[${index}]`;
366
366
  if (!isPlainObject(entry)) {
367
- fail(`${path} must be an object`);
367
+ fail(`${configPath} must be an object`);
368
368
  }
369
369
  const { kind, name } = entry;
370
- requireString(kind, `${path}.kind`);
370
+ requireString(kind, `${configPath}.kind`);
371
371
  // Per-adapter Zod validation runs in `buildSources`. Here we check name
372
372
  // uniqueness — the Board composer relies on it for writeback routing.
373
373
  // When `name` is omitted, the adapter's runtime default is `kind` (the
@@ -375,14 +375,14 @@ function normalizeSources(raw) {
375
375
  // dedup on the effective runtime name to catch e.g. two `{kind: "linear"}`
376
376
  // entries that would both produce a source named `"linear"`.
377
377
  if (name !== undefined) {
378
- requireString(name, `${path}.name`);
378
+ requireString(name, `${configPath}.name`);
379
379
  }
380
380
  /* v8 ignore next @preserve -- both `name`-set and `name`-unset paths are covered by separate dedup tests; coverage for the fallback's `kind` arm only fires when both entries in the dedup set come from `name`, which the second test already covers */
381
381
  const effectiveName = name ?? kind;
382
382
  const previous = names.get(effectiveName);
383
383
  if (previous !== undefined) {
384
384
  /* v8 ignore next 3 @preserve -- the `name === undefined` ternary arm requires two unnamed entries colliding; we keep the conditional for the better error message but only one path is exercised in tests */
385
- fail(`${path} would produce a source named "${effectiveName}" (from ${name === undefined ? "default `kind` since `name` is omitted" : "`name`"}), duplicating sources[${previous}]. Configure distinct \`name\` fields.`);
385
+ fail(`${configPath} would produce a source named "${effectiveName}" (from ${name === undefined ? "default `kind` since `name` is omitted" : "`name`"}), duplicating sources[${previous}]. Configure distinct \`name\` fields.`);
386
386
  }
387
387
  names.set(effectiveName, index);
388
388
  }
@@ -567,12 +567,12 @@ async function loadAt(filepath) {
567
567
  return result;
568
568
  }
569
569
  function findXdgConfigFile() {
570
- return XDG_FALLBACK_NAMES.map((name) => xdgConfigPath("groundcrew", name)).find((path) => existsSync(path));
570
+ return XDG_FALLBACK_NAMES.map((name) => xdgConfigPath("groundcrew", name)).find((p) => existsSync(p));
571
571
  }
572
572
  async function discoverUserConfig() {
573
573
  const override = readEnvironmentVariable("GROUNDCREW_CONFIG");
574
574
  if (override !== undefined && override.length > 0) {
575
- const overridePath = resolve(override);
575
+ const overridePath = path.resolve(override);
576
576
  if (!existsSync(overridePath)) {
577
577
  fail(`GROUNDCREW_CONFIG=${overridePath} not found`);
578
578
  }
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
- import { basename, dirname, resolve } from "node:path";
2
+ import path from "node:path";
3
3
  import { BUILD_SECRET_NAMES, hasPreLaunchEnv, } from "./config.js";
4
4
  import { shellSingleQuote } from "./shell.js";
5
5
  export { shellSingleQuote } from "./shell.js";
@@ -22,7 +22,7 @@ export function resolveSafehouseClearancePath(baseUrl = import.meta.url) {
22
22
  throw new Error("@clipboard-health/clearance is required by @clipboard-health/groundcrew but could not be resolved. " +
23
23
  "Install it alongside groundcrew (for example: `npm install -g @clipboard-health/clearance`).", { cause: error });
24
24
  }
25
- return resolve(dirname(clearancePackageJson), "safehouse", "safehouse-clearance");
25
+ return path.resolve(path.dirname(clearancePackageJson), "safehouse", "safehouse-clearance");
26
26
  }
27
27
  const SAFEHOUSE_CLEARANCE_WRAPPER_PATH = resolveSafehouseClearancePath();
28
28
  /**
@@ -155,7 +155,7 @@ function safehouseProfileCommandName(agentCmd) {
155
155
  if (commandToken === undefined) {
156
156
  throw new Error(`Cannot infer Safehouse agent profile command from model cmd ${JSON.stringify(agentCmd)}.`);
157
157
  }
158
- const commandName = basename(commandToken);
158
+ const commandName = path.basename(commandToken);
159
159
  if (commandName === "." ||
160
160
  commandName === ".." ||
161
161
  commandName.startsWith("-") ||
@@ -211,7 +211,7 @@ function shouldWrapWithSafehouse(arguments_) {
211
211
  * host shell because there is no groundcrew-managed sandbox to run them inside.
212
212
  */
213
213
  function buildUnwrappedHostLaunchCommand(arguments_) {
214
- const promptDir = dirname(arguments_.promptFile);
214
+ const promptDir = path.dirname(arguments_.promptFile);
215
215
  const agentCmd = renderAgentCommand({
216
216
  agentCmd: arguments_.definition.cmd,
217
217
  worktreeDir: arguments_.worktreeDir,
@@ -243,7 +243,7 @@ function buildUnwrappedHostLaunchCommand(arguments_) {
243
243
  * 2. **Agent wrap**: `safehouse-clearance "$shim" -c '<exec agent>' sh "$_p"`
244
244
  * where `$shim` is a `mktemp`-d symlink to `/bin/sh` named after the
245
245
  * agent (e.g. `claude`). Safehouse selects the matching agent profile
246
- * from the wrapped command's basename (`claude-code.sb` etc.) without
246
+ * from the wrapped command's path.basename (`claude-code.sb` etc.) without
247
247
  * needing every agent profile enabled globally.
248
248
  *
249
249
  * Host ordering matters: when a `preLaunch` hook is present, inherited
@@ -263,7 +263,7 @@ function buildUnwrappedHostLaunchCommand(arguments_) {
263
263
  * reach the profile-neutral setup phase.
264
264
  */
265
265
  function buildSafehouseLaunchCommand(arguments_) {
266
- const promptDir = dirname(arguments_.promptFile);
266
+ const promptDir = path.dirname(arguments_.promptFile);
267
267
  const safehouseCommandName = safehouseProfileCommandName(arguments_.definition.cmd);
268
268
  const agentCmd = renderAgentCommand({
269
269
  agentCmd: arguments_.definition.cmd,
@@ -315,7 +315,7 @@ function buildSdxLaunchCommand(arguments_) {
315
315
  if (arguments_.sandboxName === undefined || arguments_.definition.sandbox === undefined) {
316
316
  throw new Error("buildLaunchCommand: runner='sdx' requires sandboxName and a model `sandbox` config block (set sandbox.agent on the model in config.ts).");
317
317
  }
318
- const promptDir = dirname(arguments_.promptFile);
318
+ const promptDir = path.dirname(arguments_.promptFile);
319
319
  const agentCmd = renderAgentCommand({
320
320
  agentCmd: arguments_.definition.cmd,
321
321
  worktreeDir: arguments_.worktreeDir,
@@ -25,6 +25,6 @@ export declare function runNpmInstallGlobal(options: RunNpmInstallOptions): Prom
25
25
  export declare function detectInstallPath(cliMetaUrl: string): string;
26
26
  export type NpmRootRunner = (command: string, args: readonly string[]) => string;
27
27
  export declare function detectNpmRootGlobal(npmBin: string, runner: NpmRootRunner): string | undefined;
28
- export declare function detectIsSymlink(path: string): boolean;
28
+ export declare function detectIsSymlink(filePath: string): boolean;
29
29
  export declare function createDefaultNpmSpawner(): NpmSpawner;
30
30
  //# sourceMappingURL=npmGlobal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"npmGlobal.d.ts","sourceRoot":"","sources":["../../src/lib/npmGlobal.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,WAAW,CAY5E;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC,CAQ9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAEjF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAM7F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMrD;AAED,wBAAgB,uBAAuB,IAAI,UAAU,CAmBpD"}
1
+ {"version":3,"file":"npmGlobal.d.ts","sourceRoot":"","sources":["../../src/lib/npmGlobal.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,WAAW,CAY5E;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC,CAQ9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAEjF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAM7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMzD;AAED,wBAAgB,uBAAuB,IAAI,UAAU,CAmBpD"}
@@ -1,16 +1,16 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { lstatSync } from "node:fs";
3
- import { dirname, sep } from "node:path";
3
+ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  export function classifyInstall(options) {
6
6
  const { installPath, npmRootGlobal, isSymlink } = options;
7
- if (npmRootGlobal !== undefined && installPath.startsWith(`${npmRootGlobal}${sep}`)) {
7
+ if (npmRootGlobal !== undefined && installPath.startsWith(`${npmRootGlobal}${path.sep}`)) {
8
8
  return isSymlink(installPath) ? "linked" : "global";
9
9
  }
10
- if (installPath.includes(`${sep}_npx${sep}`)) {
10
+ if (installPath.includes(`${path.sep}_npx${path.sep}`)) {
11
11
  return "npx";
12
12
  }
13
- if (installPath.includes(`${sep}node_modules${sep}`)) {
13
+ if (installPath.includes(`${path.sep}node_modules${path.sep}`)) {
14
14
  return "project";
15
15
  }
16
16
  return "unknown";
@@ -25,7 +25,7 @@ export async function runNpmInstallGlobal(options) {
25
25
  };
26
26
  }
27
27
  export function detectInstallPath(cliMetaUrl) {
28
- return dirname(dirname(fileURLToPath(cliMetaUrl)));
28
+ return path.dirname(path.dirname(fileURLToPath(cliMetaUrl)));
29
29
  }
30
30
  export function detectNpmRootGlobal(npmBin, runner) {
31
31
  try {
@@ -35,9 +35,9 @@ export function detectNpmRootGlobal(npmBin, runner) {
35
35
  return undefined;
36
36
  }
37
37
  }
38
- export function detectIsSymlink(path) {
38
+ export function detectIsSymlink(filePath) {
39
39
  try {
40
- return lstatSync(path).isSymbolicLink();
40
+ return lstatSync(filePath).isSymbolicLink();
41
41
  }
42
42
  catch {
43
43
  return false;
@@ -1,5 +1,5 @@
1
1
  import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
2
+ import path from "node:path";
3
3
  const TICKET_RE = /^[a-z][\da-z]*-\d+$/;
4
4
  const RUN_STATE_DIRECTORY_NAME = "runs";
5
5
  function ticketKey(ticket) {
@@ -10,10 +10,10 @@ function ticketKey(ticket) {
10
10
  return normalized;
11
11
  }
12
12
  export function runStateDirectory(config) {
13
- return resolve(dirname(config.logging.file), RUN_STATE_DIRECTORY_NAME);
13
+ return path.resolve(path.dirname(config.logging.file), RUN_STATE_DIRECTORY_NAME);
14
14
  }
15
15
  export function runStatePath(config, ticket) {
16
- return resolve(runStateDirectory(config), `${ticketKey(ticket)}.json`);
16
+ return path.resolve(runStateDirectory(config), `${ticketKey(ticket)}.json`);
17
17
  }
18
18
  function nowIso() {
19
19
  return new Date().toISOString();
@@ -80,11 +80,11 @@ function parseRunState(value) {
80
80
  };
81
81
  }
82
82
  function writeState(config, state) {
83
- const path = runStatePath(config, state.ticket);
84
- mkdirSync(dirname(path), { recursive: true });
85
- const tmpPath = `${path}.${process.pid}.tmp`;
83
+ const statePath = runStatePath(config, state.ticket);
84
+ mkdirSync(path.dirname(statePath), { recursive: true });
85
+ const tmpPath = `${statePath}.${process.pid}.tmp`;
86
86
  writeFileSync(tmpPath, `${JSON.stringify(state, undefined, 2)}\n`, { mode: 0o600 });
87
- renameSync(tmpPath, path);
87
+ renameSync(tmpPath, statePath);
88
88
  }
89
89
  export function readRunState(config, ticket) {
90
90
  let raw;
@@ -1,6 +1,6 @@
1
1
  import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
- import { join } from "node:path";
3
+ import path from "node:path";
4
4
  import { BUILD_SECRET_NAMES } from "./config.js";
5
5
  import { shellSingleQuote } from "./launchCommand.js";
6
6
  import { readEnvironmentVariable } from "./util.js";
@@ -13,8 +13,8 @@ function renderPromptTemplate(template, variables) {
13
13
  .replaceAll("{{workspaceContinuationInstruction}}", variables.workspaceContinuationInstruction);
14
14
  }
15
15
  export function stagePromptText(input) {
16
- const promptDir = mkdtempSync(join(tmpdir(), `${input.prefix}-${input.ticket}-`));
17
- const promptFile = join(promptDir, "prompt.txt");
16
+ const promptDir = mkdtempSync(path.join(tmpdir(), `${input.prefix}-${input.ticket}-`));
17
+ const promptFile = path.join(promptDir, "prompt.txt");
18
18
  writeFileSync(promptFile, input.text);
19
19
  return { directory: promptDir, file: promptFile };
20
20
  }
@@ -42,12 +42,12 @@ export function stageBuildSecrets(promptDir) {
42
42
  if (lines.length === 0) {
43
43
  return undefined;
44
44
  }
45
- const secretsFile = join(promptDir, "secrets.env");
45
+ const secretsFile = path.join(promptDir, "secrets.env");
46
46
  writeFileSync(secretsFile, `${lines.join("\n")}\n`, { mode: 0o600 });
47
47
  return secretsFile;
48
48
  }
49
49
  function stageLaunchScript(promptDir, command) {
50
- const launcherFile = join(promptDir, "launch.sh");
50
+ const launcherFile = path.join(promptDir, "launch.sh");
51
51
  writeFileSync(launcherFile, `#!/usr/bin/env bash\n${command}\n`, { mode: 0o700 });
52
52
  return launcherFile;
53
53
  }
@@ -7,7 +7,7 @@ export declare function okMark(): string;
7
7
  export declare function failMark(): string;
8
8
  export declare function styleWarning(text: string): string;
9
9
  export declare function styleDim(text: string): string;
10
- export declare function setLogFile(path: string | undefined): void;
10
+ export declare function setLogFile(filePath: string | undefined): void;
11
11
  export declare function withLogOutputSuppressed<T>(operation: () => Promise<T>): Promise<T>;
12
12
  /** Important tier: always on the console (dimmed timestamp) and the log file. */
13
13
  export declare function log(message: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/lib/util.ts"],"names":[],"mappings":"AAIA,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,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/C;AAED,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAWD,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;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;AAuBD,iFAAiF;AACjF,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAOzC;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAS3C;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,CAiBxF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;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"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/lib/util.ts"],"names":[],"mappings":"AAIA,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,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/C;AAED,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAWD,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAQD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAE7D;AAED,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOxF;AAuBD,iFAAiF;AACjF,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAOzC;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAS3C;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,CAiBxF;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;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
@@ -1,5 +1,5 @@
1
1
  import { appendFileSync, mkdirSync } from "node:fs";
2
- import { dirname } from "node:path";
2
+ import path from "node:path";
3
3
  import { styleText } from "node:util";
4
4
  export async function sleep(ms, signal) {
5
5
  if (signal?.aborted === true) {
@@ -62,8 +62,8 @@ export function styleDim(text) {
62
62
  // loadConfig() resolves `logging.file`.
63
63
  let logFilePath;
64
64
  let suppressedLogDepth = 0;
65
- export function setLogFile(path) {
66
- logFilePath = path;
65
+ export function setLogFile(filePath) {
66
+ logFilePath = filePath;
67
67
  }
68
68
  export async function withLogOutputSuppressed(operation) {
69
69
  suppressedLogDepth += 1;
@@ -79,7 +79,7 @@ function appendLogLine(line) {
79
79
  return;
80
80
  }
81
81
  try {
82
- mkdirSync(dirname(logFilePath), { recursive: true });
82
+ mkdirSync(path.dirname(logFilePath), { recursive: true });
83
83
  appendFileSync(logFilePath, `${line}\n`);
84
84
  }
85
85
  catch {
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { existsSync, readdirSync, rmSync } from "node:fs";
11
11
  import { userInfo } from "node:os";
12
- import { isAbsolute, relative, resolve } from "node:path";
12
+ import path from "node:path";
13
13
  import { runCommandAsync } from "./commandRunner.js";
14
14
  import { resolveDefaultBranch } from "./defaultBranch.js";
15
15
  import { debug, errorMessage, isVerbose } from "./util.js";
@@ -42,7 +42,7 @@ function repoDirFor(config, repository) {
42
42
  if (!config.workspace.knownRepositories.includes(repository)) {
43
43
  throw new Error(`Repository "${repository}" is not in workspace.knownRepositories: ${config.workspace.knownRepositories.join(", ")}`);
44
44
  }
45
- const repoDir = resolve(config.workspace.projectDir, repository);
45
+ const repoDir = path.resolve(config.workspace.projectDir, repository);
46
46
  if (!existsSync(repoDir)) {
47
47
  throw new Error(`Repository not found: ${repoDir}`);
48
48
  }
@@ -51,14 +51,14 @@ function repoDirFor(config, repository) {
51
51
  function basePaths(config, repository, ticket) {
52
52
  // Tickets must match the same shape the worktree discovery regexes use,
53
53
  // so create()/list()/findByTicket() agree on what's a valid worktree.
54
- // This also rejects traversal tokens before they reach resolve().
54
+ // This also rejects traversal tokens before they reach path.resolve().
55
55
  if (!TICKET_RE.test(ticket)) {
56
56
  throw new Error(`Invalid ticket "${ticket}": must be a plain ticket id`);
57
57
  }
58
- const projectDir = resolve(config.workspace.projectDir);
58
+ const projectDir = path.resolve(config.workspace.projectDir);
59
59
  const repoDir = repoDirFor(config, repository);
60
60
  const hostWorktreeName = `${repository}-${ticket}`;
61
- const hostWorktreeDir = resolve(projectDir, hostWorktreeName);
61
+ const hostWorktreeDir = path.resolve(projectDir, hostWorktreeName);
62
62
  return {
63
63
  projectDir,
64
64
  repoDir,
@@ -122,17 +122,17 @@ async function createWorktree(config, spec, signal) {
122
122
  };
123
123
  }
124
124
  function listWorktrees(config) {
125
- const projectDir = resolve(config.workspace.projectDir);
125
+ const projectDir = path.resolve(config.workspace.projectDir);
126
126
  const entries = [];
127
127
  // Worktrees live at `projectDir/<repository>-<ticket>`. When `repository`
128
- // contains a slash (e.g. "owner/repo"), `resolve()` nests one level
128
+ // contains a slash (e.g. "owner/repo"), `path.resolve()` nests one level
129
129
  // deeper, so the worktree path is `projectDir/owner/repo-<ticket>`.
130
130
  // Scan each known repository's parent directory rather than the project
131
131
  // root, so nested worktrees are discovered alongside bare ones.
132
132
  const reposByParent = new Map();
133
133
  for (const repository of config.workspace.knownRepositories) {
134
134
  const lastSlash = repository.lastIndexOf("/");
135
- const parentDir = lastSlash === -1 ? projectDir : resolve(projectDir, repository.slice(0, lastSlash));
135
+ const parentDir = lastSlash === -1 ? projectDir : path.resolve(projectDir, repository.slice(0, lastSlash));
136
136
  const basename = lastSlash === -1 ? repository : repository.slice(lastSlash + 1);
137
137
  let repoByBasename = reposByParent.get(parentDir);
138
138
  if (repoByBasename === undefined) {
@@ -170,7 +170,7 @@ function listWorktrees(config) {
170
170
  repository,
171
171
  ticket,
172
172
  branchName: branchNameForTicket(ticket),
173
- dir: resolve(parentDir, entry.name),
173
+ dir: path.resolve(parentDir, entry.name),
174
174
  kind: "host",
175
175
  });
176
176
  }
@@ -178,8 +178,8 @@ function listWorktrees(config) {
178
178
  return entries;
179
179
  }
180
180
  async function removeWorktree(config, entry, options) {
181
- const projectDir = resolve(config.workspace.projectDir);
182
- const repoDir = resolve(projectDir, entry.repository);
181
+ const projectDir = path.resolve(config.workspace.projectDir);
182
+ const repoDir = path.resolve(projectDir, entry.repository);
183
183
  if (existsSync(entry.dir)) {
184
184
  debug(`Removing worktree ${entry.dir}${options.force ? " (--force)" : ""}...`);
185
185
  const removeArguments = ["-C", repoDir, "worktree", "remove"];
@@ -297,12 +297,12 @@ async function probeWorktreeRegistration(arguments_) {
297
297
  catch {
298
298
  return "unknown";
299
299
  }
300
- const resolvedWorktreeDir = resolve(arguments_.worktreeDir);
300
+ const resolvedWorktreeDir = path.resolve(arguments_.worktreeDir);
301
301
  for (const line of output.split("\n")) {
302
302
  if (!line.startsWith(WORKTREE_LIST_PREFIX)) {
303
303
  continue;
304
304
  }
305
- if (resolve(line.slice(WORKTREE_LIST_PREFIX.length)) === resolvedWorktreeDir) {
305
+ if (path.resolve(line.slice(WORKTREE_LIST_PREFIX.length)) === resolvedWorktreeDir) {
306
306
  return "registered";
307
307
  }
308
308
  }
@@ -313,18 +313,18 @@ function describeOrphanWorktree(arguments_) {
313
313
  return `directory exists but is not a registered git worktree. Run \`crew cleanup --force ${ticket}\` to remove ${dir}, or inspect it first if it may contain valuable files.`;
314
314
  }
315
315
  function expectedHostWorktreeDir(config, entry) {
316
- return resolve(config.workspace.projectDir, `${entry.repository}-${entry.ticket}`);
316
+ return path.resolve(config.workspace.projectDir, `${entry.repository}-${entry.ticket}`);
317
317
  }
318
318
  function isInsideDirectory(parentDir, childDir) {
319
- const childRelativePath = relative(parentDir, childDir);
319
+ const childRelativePath = path.relative(parentDir, childDir);
320
320
  return (childRelativePath.length > 0 &&
321
321
  !childRelativePath.startsWith("..") &&
322
- !isAbsolute(childRelativePath));
322
+ !path.isAbsolute(childRelativePath));
323
323
  }
324
324
  function removeOrphanWorktreeDirectory(config, entry) {
325
- const projectDir = resolve(config.workspace.projectDir);
325
+ const projectDir = path.resolve(config.workspace.projectDir);
326
326
  const expectedDir = expectedHostWorktreeDir(config, entry);
327
- const targetDir = resolve(entry.dir);
327
+ const targetDir = path.resolve(entry.dir);
328
328
  if (targetDir !== expectedDir || !isInsideDirectory(projectDir, targetDir)) {
329
329
  throw new Error(`Refusing to force-delete ${entry.dir}: expected groundcrew worktree path ${expectedDir}.`);
330
330
  }
package/dist/lib/xdg.js CHANGED
@@ -1,19 +1,19 @@
1
1
  import { homedir } from "node:os";
2
- import { isAbsolute, resolve } from "node:path";
2
+ import path from "node:path";
3
3
  import { readEnvironmentVariable } from "./util.js";
4
4
  // Per the XDG Base Directory spec, relative override paths are invalid and
5
5
  // must be ignored — without this guard, a relative override would anchor to
6
6
  // the cwd via `resolve` instead of falling back to $HOME.
7
7
  function xdgBase(envName, fallbackSegments) {
8
8
  const override = readEnvironmentVariable(envName);
9
- if (override !== undefined && override.length > 0 && isAbsolute(override)) {
9
+ if (override !== undefined && override.length > 0 && path.isAbsolute(override)) {
10
10
  return override;
11
11
  }
12
- return resolve(homedir(), ...fallbackSegments);
12
+ return path.resolve(homedir(), ...fallbackSegments);
13
13
  }
14
14
  export function xdgConfigPath(...segments) {
15
- return resolve(xdgBase("XDG_CONFIG_HOME", [".config"]), ...segments);
15
+ return path.resolve(xdgBase("XDG_CONFIG_HOME", [".config"]), ...segments);
16
16
  }
17
17
  export function xdgStatePath(...segments) {
18
- return resolve(xdgBase("XDG_STATE_HOME", [".local", "state"]), ...segments);
18
+ return path.resolve(xdgBase("XDG_STATE_HOME", [".local", "state"]), ...segments);
19
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/groundcrew",
3
- "version": "4.7.2",
3
+ "version": "4.7.3",
4
4
  "description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
5
5
  "keywords": [
6
6
  "agent",