@clipboard-health/groundcrew 1.12.2 → 1.12.4

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.
@@ -1,3 +1,4 @@
1
+ import { type RemoteRunnerConfig } from "../lib/config.ts";
1
2
  export interface McpServer {
2
3
  name: string;
3
4
  url: string;
@@ -23,6 +24,8 @@ export interface RemoteBootstrapOptions {
23
24
  owner: string;
24
25
  baseBranch: string;
25
26
  gitRemote?: string;
27
+ repoRoot?: string;
28
+ remoteConfig?: RemoteRunnerConfig;
26
29
  secretNames: string[];
27
30
  shouldRequireSelectedSecrets: boolean;
28
31
  shouldUseSecrets: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"remoteSetup.d.ts","sourceRoot":"","sources":["../../src/commands/remoteSetup.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,OAAO,CAAC;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,EAAE,OAAO,CAAC;IAClC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,4BAA4B,EAAE,OAAO,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAaD,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAw1BD,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC9F;AAUD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAItF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAItF;AAED,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AAYD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgClF;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B7D"}
1
+ {"version":3,"file":"remoteSetup.d.ts","sourceRoot":"","sources":["../../src/commands/remoteSetup.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAkB1B,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,OAAO,CAAC;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,EAAE,OAAO,CAAC;IAClC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,4BAA4B,EAAE,OAAO,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA02BD,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC9F;AAUD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAItF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAItF;AAED,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AAYD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgClF;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B7D"}
@@ -2,9 +2,9 @@ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { homedir, tmpdir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { setTimeout as sleep } from "node:timers/promises";
5
- import { BUILD_SECRET_NAMES, DEFAULT_REMOTE_SETUP_COMMAND, loadConfig, } from "../lib/config.js";
5
+ import { DEFAULT_REMOTE_SETUP_COMMAND, loadConfig, } from "../lib/config.js";
6
6
  import { shellSingleQuote } from "../lib/shell.js";
7
- import { getRemoteRunnerProvider, remoteConfigWithRunnerName, } from "../lib/spriteRemoteRunnerProvider.js";
7
+ import { getRemoteRunnerProvider, remotePathJoin, remoteConfigWithRunnerName, remoteRepositoryDirectoryName, remoteRepositorySlug, } from "../lib/spriteRemoteRunnerProvider.js";
8
8
  import { log, readEnvironmentVariable, writeOutput } from "../lib/util.js";
9
9
  const KNOWN_MCP_SERVER_URLS = {
10
10
  linear: "https://mcp.linear.app/mcp",
@@ -13,8 +13,8 @@ const KNOWN_MCP_SERVER_URLS = {
13
13
  };
14
14
  const DEFAULT_CHECKPOINT_COMMENT = "groundcrew remote runner baseline: selected agent auth, git identity, and MCP config";
15
15
  const CLAUDE_SUBSCRIPTION_LOGIN_FLAG = ["--claude", "ai"].join("");
16
- const DEFAULT_REPOSITORY_OWNER = "ClipboardHealth";
17
16
  const DEFAULT_GIT_REMOTE = "origin";
17
+ const BOOTSTRAP_SECRET_FLAGS_CONFLICT_MESSAGE = "--secret and --no-secrets are mutually exclusive. Use --secret to forward selected build secrets or --no-secrets to disable secret forwarding.";
18
18
  const DATADOG_PUP_VERSION = "0.63.0";
19
19
  const DATADOG_OAUTH_CALLBACK_PORT = 8000;
20
20
  const DATADOG_AUTH_STATUS_RETRY_ATTEMPTS = 5;
@@ -53,9 +53,9 @@ function usage() {
53
53
  "Bootstrap options:",
54
54
  " --branch <branch> Checkout/create a ticket branch before installing deps",
55
55
  " --base <branch> Base branch used when creating a missing branch (default: git.defaultBranch)",
56
- " --owner <owner> GitHub owner for bare repo names (default: ClipboardHealth)",
56
+ " --owner <owner> GitHub owner for bare repo names (default: remote.owner)",
57
57
  " --secret <env-name> Forward one required build secret; repeat for multiple",
58
- " --no-secrets Do not forward NPM_TOKEN/BUF_TOKEN even if present",
58
+ " --no-secrets Do not forward configured build secrets even if present",
59
59
  "",
60
60
  "Bootstrap example:",
61
61
  " crew remote bootstrap crew-claude-1 core-utils --branch rocky-team-123",
@@ -232,7 +232,7 @@ function parseBootstrapArguments(argv) {
232
232
  throw new Error(usage());
233
233
  }
234
234
  validateRepository(repository);
235
- let owner = DEFAULT_REPOSITORY_OWNER;
235
+ let owner;
236
236
  let baseBranch;
237
237
  let branchName;
238
238
  let shouldUseSecrets = true;
@@ -259,6 +259,9 @@ function parseBootstrapArguments(argv) {
259
259
  continue;
260
260
  }
261
261
  if (argument === "--secret") {
262
+ if (!shouldUseSecrets) {
263
+ throw new Error(BOOTSTRAP_SECRET_FLAGS_CONFLICT_MESSAGE);
264
+ }
262
265
  const secretName = requireValue(argv, index, "--secret");
263
266
  validateSecretName(secretName);
264
267
  selectedSecretNames.push(secretName);
@@ -267,6 +270,9 @@ function parseBootstrapArguments(argv) {
267
270
  continue;
268
271
  }
269
272
  if (argument === "--no-secrets") {
273
+ if (selectedSecretNames.length > 0 || shouldRequireSelectedSecrets) {
274
+ throw new Error(BOOTSTRAP_SECRET_FLAGS_CONFLICT_MESSAGE);
275
+ }
270
276
  shouldUseSecrets = false;
271
277
  continue;
272
278
  }
@@ -275,10 +281,10 @@ function parseBootstrapArguments(argv) {
275
281
  return {
276
282
  runnerName,
277
283
  repository,
278
- owner,
279
- secretNames: selectedSecretNames.length > 0 ? selectedSecretNames : [...BUILD_SECRET_NAMES],
280
284
  shouldRequireSelectedSecrets,
281
285
  shouldUseSecrets,
286
+ ...(owner === undefined ? {} : { owner }),
287
+ ...(selectedSecretNames.length > 0 ? { secretNames: selectedSecretNames } : {}),
282
288
  ...(baseBranch === undefined ? {} : { baseBranch }),
283
289
  ...(branchName === undefined ? {} : { branchName }),
284
290
  };
@@ -620,20 +626,22 @@ async function checkpoint(arguments_) {
620
626
  }
621
627
  await provider.checkpoint(config, options.checkpointComment);
622
628
  }
623
- function repositorySlug(options) {
624
- return options.repository.includes("/")
625
- ? options.repository
626
- : `${options.owner}/${options.repository}`;
627
- }
628
- function repositoryDirectoryName(repository) {
629
- const name = repository.includes("/")
630
- ? repository.slice(repository.lastIndexOf("/") + 1)
631
- : repository;
632
- return name.endsWith(".git") ? name.slice(0, -4) : name;
629
+ function validateRemoteBootstrapOptions(options) {
630
+ validateRepository(options.repository);
631
+ validateRepositoryOwner(options.owner);
632
+ validateGitRef(options.baseBranch, "base branch");
633
+ validateGitRef(options.gitRemote, "git remote");
634
+ if (options.branchName !== undefined) {
635
+ validateGitRef(options.branchName, "branch");
636
+ }
637
+ for (const name of options.secretNames) {
638
+ validateSecretName(name);
639
+ }
633
640
  }
634
641
  function remoteBootstrapCommand(options) {
635
- const slug = repositorySlug(options);
636
- const directoryName = repositoryDirectoryName(options.repository);
642
+ const slug = remoteRepositorySlug(options.owner, options.repository);
643
+ const directoryName = remoteRepositoryDirectoryName(options.owner, options.repository);
644
+ const repoDir = remotePathJoin(options.repoRoot, directoryName);
637
645
  const baseRef = `${options.gitRemote}/${options.baseBranch}`;
638
646
  const unsetSecretsLine = options.secretNames.length === 0 ? ":" : `unset ${options.secretNames.join(" ")}`;
639
647
  const checkoutLines = options.branchName === undefined
@@ -649,9 +657,10 @@ function remoteBootstrapCommand(options) {
649
657
  "set -euo pipefail",
650
658
  `cleanup() { rm -f ${shellSingleQuote(REMOTE_SECRETS_FILE)}; ${unsetSecretsLine}; }`,
651
659
  "trap cleanup EXIT",
660
+ `repo_root=${shellSingleQuote(options.repoRoot)}`,
661
+ `repo_dir=${shellSingleQuote(repoDir)}`,
652
662
  `git_remote=${shellSingleQuote(options.gitRemote)}`,
653
- 'mkdir -p "$HOME/dev"',
654
- `repo_dir="$HOME/dev/${directoryName}"`,
663
+ 'mkdir -p "$repo_root"',
655
664
  'if [ ! -d "$repo_dir/.git" ]; then',
656
665
  ` gh repo clone ${shellSingleQuote(slug)} "$repo_dir"`,
657
666
  "fi",
@@ -668,10 +677,19 @@ function remoteBootstrapCommand(options) {
668
677
  }
669
678
  async function resolveBootstrapOptions(options) {
670
679
  const config = await loadConfig();
680
+ const remoteConfig = {
681
+ ...config.remote,
682
+ runnerName: options.runnerName,
683
+ secretNames: [...config.remote.secretNames],
684
+ };
671
685
  return {
672
686
  ...options,
687
+ owner: options.owner ?? remoteConfig.owner,
673
688
  baseBranch: options.baseBranch ?? config.git.defaultBranch,
674
689
  gitRemote: config.git.remote,
690
+ repoRoot: remoteConfig.repoRoot,
691
+ remoteConfig,
692
+ secretNames: options.secretNames ?? [...remoteConfig.secretNames],
675
693
  };
676
694
  }
677
695
  function noSecretCleanup() {
@@ -709,11 +727,14 @@ function stageBuildSecrets(options) {
709
727
  };
710
728
  }
711
729
  export async function bootstrapRemoteRepository(options) {
730
+ const config = options.remoteConfig ?? remoteConfigWithRunnerName(options.runnerName);
712
731
  const bootstrapOptions = {
713
732
  ...options,
714
733
  gitRemote: options.gitRemote ?? DEFAULT_GIT_REMOTE,
734
+ repoRoot: options.repoRoot ?? config.repoRoot,
735
+ remoteConfig: config,
715
736
  };
716
- const config = remoteConfigWithRunnerName(options.runnerName);
737
+ validateRemoteBootstrapOptions(bootstrapOptions);
717
738
  const provider = providerFor(config);
718
739
  if (!(await provider.runnerExists(config))) {
719
740
  throw new Error(`Remote runner ${options.runnerName} does not exist. Run crew remote setup first.`);
@@ -726,7 +747,7 @@ export async function bootstrapRemoteRepository(options) {
726
747
  const files = stagedSecrets.filePath === undefined
727
748
  ? []
728
749
  : [{ localPath: stagedSecrets.filePath, remotePath: REMOTE_SECRETS_FILE }];
729
- log(`Bootstrapping ${repositorySlug(bootstrapOptions)} in ${options.runnerName}`);
750
+ log(`Bootstrapping ${remoteRepositorySlug(bootstrapOptions.owner, bootstrapOptions.repository)} in ${options.runnerName}`);
730
751
  await provider.runCommand({
731
752
  config,
732
753
  files,
@@ -1 +1 @@
1
- {"version":3,"file":"setupRepos.d.ts","sourceRoot":"","sources":["../../src/commands/setupRepos.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAInE,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,wCAAwC;IACxC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,EAAE,CAAC;IACzC,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AA6JD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAyD3B;AAwBD,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAajE"}
1
+ {"version":3,"file":"setupRepos.d.ts","sourceRoot":"","sources":["../../src/commands/setupRepos.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAInE,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,wCAAwC;IACxC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,EAAE,CAAC;IACzC,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AA6JD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA0D3B;AAwBD,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAajE"}
@@ -5,8 +5,8 @@
5
5
  * entries are skipped with a hint, because they have no canonical URL
6
6
  * we can guess at without involving the user's gh login. Idempotent.
7
7
  */
8
- import { opendirSync, statSync } from "node:fs";
9
- import { isAbsolute, relative, resolve } from "node:path";
8
+ import { mkdirSync, opendirSync, statSync } from "node:fs";
9
+ import { dirname, isAbsolute, relative, resolve } from "node:path";
10
10
  import { runCommandAsync } from "../lib/commandRunner.js";
11
11
  import { loadConfig } from "../lib/config.js";
12
12
  import { which } from "../lib/host.js";
@@ -173,6 +173,7 @@ export async function setupRepos(config, options) {
173
173
  const target = resolve(projectDir, entry);
174
174
  log(`[clone] ${entry} → ${target}`);
175
175
  try {
176
+ mkdirSync(dirname(target), { recursive: true });
176
177
  // oxlint-disable-next-line no-await-in-loop -- see comment above
177
178
  await runCommandAsync("gh", ["repo", "clone", entry, target], {
178
179
  stdio: "inherit",
@@ -66,6 +66,9 @@ export interface RemoteRunnerProvider {
66
66
  createWorktree(arguments_: RemoteWorktreeCreateArguments): Promise<RemoteWorktreeLocation>;
67
67
  removeWorktree(arguments_: RemoteWorktreeRemoveArguments): Promise<void>;
68
68
  }
69
+ export declare function remotePathJoin(root: string, leaf: string): string;
70
+ export declare function remoteRepositorySlug(owner: string, repository: string): string;
71
+ export declare function remoteRepositoryDirectoryName(owner: string, repository: string): string;
69
72
  export declare const spriteRemoteRunnerProvider: RemoteRunnerProvider;
70
73
  export declare function remoteConfigWithRunnerName(runnerName: string): RemoteRunnerConfig;
71
74
  export declare function getRemoteRunnerProvider(provider: RemoteRunnerProviderName): RemoteRunnerProvider;
@@ -1 +1 @@
1
- {"version":3,"file":"spriteRemoteRunnerProvider.d.ts","sourceRoot":"","sources":["../../src/lib/spriteRemoteRunnerProvider.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAShF,eAAO,MAAM,+BAA+B;uBAChC,QAAQ;yBACN,eAAe;oBACpB,iBAAiB;uBACd,kBAAkB;2BACd,mCAAmC;CACS,CAAC;AAE7D,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,KAAK,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,UAAU,yBAAyB;IACjC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,KAAK,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,UAAU,6BAA6B;IACrC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,UAAU,sBAAsB;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,UAAU,6BAA6B;IACrC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,UAAU,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxE,aAAa,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,eAAe,CAAC,UAAU,EAAE,yBAAyB,GAAG,MAAM,CAAC;IAC/D,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9F,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzF,UAAU,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,cAAc,CAAC,UAAU,EAAE,6BAA6B,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC3F,cAAc,CAAC,UAAU,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E;AA+SD,eAAO,MAAM,0BAA0B,EAAE,oBAwHxC,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,CAMjF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,oBAAoB,CAKhG"}
1
+ {"version":3,"file":"spriteRemoteRunnerProvider.d.ts","sourceRoot":"","sources":["../../src/lib/spriteRemoteRunnerProvider.ts"],"names":[],"mappings":"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"}
@@ -82,18 +82,18 @@ function buildSpriteTtyCommand(arguments_) {
82
82
  ...arguments_.remoteArguments.map(shellSingleQuote),
83
83
  ].join(" ");
84
84
  }
85
- function remotePathJoin(root, leaf) {
85
+ export function remotePathJoin(root, leaf) {
86
86
  let end = root.length;
87
87
  while (end > 0 && root[end - 1] === "/") {
88
88
  end -= 1;
89
89
  }
90
90
  return `${root.slice(0, end)}/${leaf}`;
91
91
  }
92
- function repositorySlug(owner, repository) {
92
+ export function remoteRepositorySlug(owner, repository) {
93
93
  return repository.includes("/") ? repository : `${owner}/${repository}`;
94
94
  }
95
- function repositoryDirectoryName(owner, repository) {
96
- const slug = repositorySlug(owner, repository);
95
+ export function remoteRepositoryDirectoryName(owner, repository) {
96
+ const slug = remoteRepositorySlug(owner, repository);
97
97
  const normalizedSlug = slug.endsWith(".git") ? slug.slice(0, -4) : slug;
98
98
  return normalizedSlug.replaceAll("/", "--");
99
99
  }
@@ -104,7 +104,7 @@ function worktreeTicketComponent(ticket) {
104
104
  return ticket;
105
105
  }
106
106
  function spriteCreateWorktreeCommand(arguments_) {
107
- const slug = repositorySlug(arguments_.owner, arguments_.repository);
107
+ const slug = remoteRepositorySlug(arguments_.owner, arguments_.repository);
108
108
  const branchRemoteRef = `refs/remotes/${arguments_.gitRemote}/${arguments_.branchName}`;
109
109
  const branchRef = `${arguments_.gitRemote}/${arguments_.branchName}`;
110
110
  const baseRef = `${arguments_.gitRemote}/${arguments_.baseBranch}`;
@@ -317,7 +317,7 @@ export const spriteRemoteRunnerProvider = {
317
317
  },
318
318
  async createWorktree(arguments_) {
319
319
  const { config, repository, ticket, branchName, baseBranch, gitRemote, signal } = arguments_;
320
- const remoteRepositoryName = repositoryDirectoryName(config.owner, repository);
320
+ const remoteRepositoryName = remoteRepositoryDirectoryName(config.owner, repository);
321
321
  const remoteRepoDir = remotePathJoin(config.repoRoot, remoteRepositoryName);
322
322
  const remoteWorktreeDir = remotePathJoin(config.worktreeRoot, `${remoteRepositoryName}-${worktreeTicketComponent(ticket)}`);
323
323
  await runCommandAsync("sprite", [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/groundcrew",
3
- "version": "1.12.2",
3
+ "version": "1.12.4",
4
4
  "description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle, remote runners, and usage tracking.",
5
5
  "keywords": [
6
6
  "agent",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "devDependencies": {
74
74
  "@clipboard-health/ai-rules": "2.18.4",
75
- "@clipboard-health/oxlint-config": "1.7.0",
75
+ "@clipboard-health/oxlint-config": "1.9.4",
76
76
  "@nx/js": "22.7.1",
77
77
  "@tsconfig/node24": "24.0.4",
78
78
  "@tsconfig/strictest": "2.0.8",
@@ -88,8 +88,8 @@
88
88
  "markdownlint-cli2": "0.22.1",
89
89
  "nx": "22.7.1",
90
90
  "oxfmt": "0.47.0",
91
- "oxlint": "1.60.0",
92
- "oxlint-tsgolint": "0.21.1",
91
+ "oxlint": "1.64.0",
92
+ "oxlint-tsgolint": "0.22.1",
93
93
  "syncpack": "15.0.0",
94
94
  "vite": "8.0.10",
95
95
  "vitest": "4.1.5"