@clipboard-health/groundcrew 1.0.1 → 1.0.2
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/README.md +16 -0
- package/bin/run.js +4 -2
- package/bin/runCli.js +42 -0
- package/package.json +11 -2
- package/src/commands/cleaner.d.ts +3 -3
- package/src/commands/cleanupWorkspace.d.ts +1 -1
- package/src/commands/dispatcher.d.ts +4 -4
- package/src/commands/eligibility.d.ts +5 -5
- package/src/commands/sandboxAuth.d.ts +1 -1
- package/src/commands/setupWorkspace.d.ts +1 -1
- package/src/commands/teardownReporter.d.ts +1 -1
- package/src/index.d.ts +8 -8
- package/src/lib/boardSource.d.ts +1 -1
- package/src/lib/isolation.d.ts +2 -2
- package/src/lib/launchCommand.d.ts +2 -2
- package/src/lib/usage.d.ts +1 -1
- package/src/lib/workspaces.d.ts +2 -2
- package/src/lib/worktrees.d.ts +3 -3
- package/src/main.d.ts +1 -0
- package/src/main.js +10 -0
- package/src/main.js.map +1 -0
package/README.md
CHANGED
|
@@ -139,3 +139,19 @@ crew cleanup <TICKET>
|
|
|
139
139
|
- **Project must be on a single Linear team in practice.** Cross-team projects work — the orchestrator caches the in-progress state ID per team — but every team in the project must use the same status name for `linear.statuses.inProgress`.
|
|
140
140
|
- **Doctor's command introspection is shallow.** For sandbox-backed models it checks `sbx` plus `sbx diagnose`. For non-sandbox models it tokenizes `cmd` and checks the first two non-flag tokens against PATH (so `safehouse claude --foo` checks both `safehouse` and `claude`). Boolean flags without values, env-var assignments (`FOO=1`), shell pipelines, and subshells are not parsed — verify those manually. In particular, `npx -y claude` and `env FOO=1 claude` only check the wrapper, not the wrapped CLI.
|
|
141
141
|
- **Agent CLI must accept a positional prompt.** The handoff is `<your cmd> "<prompt>"`. `claude`, `codex`, and `cursor-agent` all support this.
|
|
142
|
+
|
|
143
|
+
## Hacking on groundcrew
|
|
144
|
+
|
|
145
|
+
For developers working on the package itself, the source lives in [`ClipboardHealth/core-utils`](https://github.com/ClipboardHealth/core-utils). Clone it, run `npm install`, and the repo's `crew` / `crew:op` scripts execute groundcrew straight from TypeScript source — no build step. The bin's `runCli` helper re-execs node with `--conditions @clipboard-health/source` so `@clipboard-health/clearance` also resolves to source.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
cd ~/dev/c/core-utils
|
|
149
|
+
GROUNDCREW_CONFIG=~/.config/groundcrew/config.ts node --run crew -- doctor
|
|
150
|
+
|
|
151
|
+
# With 1Password for LINEAR_API_KEY:
|
|
152
|
+
GROUNDCREW_OP_ENV_FILE=~/.config/groundcrew/op.env \
|
|
153
|
+
GROUNDCREW_CONFIG=~/.config/groundcrew/config.ts \
|
|
154
|
+
node --run crew:op -- run --watch
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`GROUNDCREW_OP_ENV_FILE` defaults to `.crew.1password.env` at the repo root. Source edits in `packages/{clearance,groundcrew}/src/**` are picked up on the next invocation. Requires Node ≥ 24.3 (the version with native `.ts` type stripping enabled by default).
|
package/bin/run.js
CHANGED
package/bin/runCli.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { constants as osConstants } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Load a side-effecting entrypoint by basename. In published/built mode, dynamically
|
|
9
|
+
* imports the compiled `${name}.js` in-process. In source/dev mode (no compiled output
|
|
10
|
+
* present), spawns a child node that loads the `.ts` source with
|
|
11
|
+
* `--conditions @clipboard-health/source` so cross-package bare imports of
|
|
12
|
+
* `@clipboard-health/*` workspace deps also resolve to source.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} packageRoot
|
|
15
|
+
* @param {string} name
|
|
16
|
+
*/
|
|
17
|
+
export async function runCli(packageRoot, name) {
|
|
18
|
+
const compiledPath = join(packageRoot, "src", `${name}.js`);
|
|
19
|
+
if (existsSync(compiledPath)) {
|
|
20
|
+
await import(pathToFileURL(compiledPath).href);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sourcePath = join(packageRoot, "src", `${name}.ts`);
|
|
25
|
+
const result = spawnSync(
|
|
26
|
+
process.execPath,
|
|
27
|
+
["--conditions", "@clipboard-health/source", sourcePath, ...process.argv.slice(2)],
|
|
28
|
+
{ stdio: "inherit" },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (result.error !== undefined) {
|
|
32
|
+
throw result.error;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (result.signal !== null) {
|
|
36
|
+
const signalNumber = osConstants.signals[result.signal];
|
|
37
|
+
process.exitCode = signalNumber === undefined ? 1 : 128 + signalNumber;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
process.exitCode = result.status ?? 1;
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/groundcrew",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Linear-driven orchestrator that launches AI coding agents in isolated git worktrees, with workspace lifecycle, sandbox auth, and usage tracking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -24,11 +24,20 @@
|
|
|
24
24
|
"type": "module",
|
|
25
25
|
"main": "./src/index.js",
|
|
26
26
|
"typings": "./src/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
"./package.json": "./package.json",
|
|
29
|
+
".": {
|
|
30
|
+
"@clipboard-health/source": "./src/index.ts",
|
|
31
|
+
"types": "./src/index.d.ts",
|
|
32
|
+
"import": "./src/index.js",
|
|
33
|
+
"default": "./src/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
27
36
|
"publishConfig": {
|
|
28
37
|
"access": "public"
|
|
29
38
|
},
|
|
30
39
|
"dependencies": {
|
|
31
|
-
"@clipboard-health/clearance": "1.0.
|
|
40
|
+
"@clipboard-health/clearance": "1.0.2",
|
|
32
41
|
"@linear/sdk": "83.0.0",
|
|
33
42
|
"tslib": "2.8.1"
|
|
34
43
|
},
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* tickets that have reached a terminal status. One per `orchestrate()`
|
|
4
4
|
* invocation; stateless across iterations. Mirrors `Dispatcher`.
|
|
5
5
|
*/
|
|
6
|
-
import { type BoardState } from "../lib/boardSource.
|
|
7
|
-
import type { ResolvedConfig } from "../lib/config.
|
|
8
|
-
import { type WorktreeEntry } from "../lib/worktrees.
|
|
6
|
+
import { type BoardState } from "../lib/boardSource.ts";
|
|
7
|
+
import type { ResolvedConfig } from "../lib/config.ts";
|
|
8
|
+
import { type WorktreeEntry } from "../lib/worktrees.ts";
|
|
9
9
|
interface CleanerDeps {
|
|
10
10
|
config: ResolvedConfig;
|
|
11
11
|
}
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* for telemetry, Linear writes, and side-effecting setupWorkspace calls.
|
|
8
8
|
*/
|
|
9
9
|
import type { LinearClient } from "@linear/sdk";
|
|
10
|
-
import type { BoardState } from "../lib/boardSource.
|
|
11
|
-
import type { ResolvedConfig } from "../lib/config.
|
|
12
|
-
import type { UsageByModel } from "../lib/usage.
|
|
13
|
-
import type { WorktreeEntry } from "../lib/worktrees.
|
|
10
|
+
import type { BoardState } from "../lib/boardSource.ts";
|
|
11
|
+
import type { ResolvedConfig } from "../lib/config.ts";
|
|
12
|
+
import type { UsageByModel } from "../lib/usage.ts";
|
|
13
|
+
import type { WorktreeEntry } from "../lib/worktrees.ts";
|
|
14
14
|
interface DispatcherDeps {
|
|
15
15
|
config: ResolvedConfig;
|
|
16
16
|
client: LinearClient;
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* The Dispatcher consumes the verdict list to drive logging and side
|
|
7
7
|
* effects.
|
|
8
8
|
*/
|
|
9
|
-
import { type Issue } from "../lib/boardSource.
|
|
10
|
-
import { type ResolvedConfig } from "../lib/config.
|
|
11
|
-
import type { UsageByModel } from "../lib/usage.
|
|
12
|
-
import type { WorkspaceProbe } from "../lib/workspaces.
|
|
13
|
-
import type { WorktreeEntry } from "../lib/worktrees.
|
|
9
|
+
import { type Issue } from "../lib/boardSource.ts";
|
|
10
|
+
import { type ResolvedConfig } from "../lib/config.ts";
|
|
11
|
+
import type { UsageByModel } from "../lib/usage.ts";
|
|
12
|
+
import type { WorkspaceProbe } from "../lib/workspaces.ts";
|
|
13
|
+
import type { WorktreeEntry } from "../lib/worktrees.ts";
|
|
14
14
|
type SkipReason = "blocked" | "blockers_paginated" | "agent_any_capacity" | "model_exhausted" | "workspace_list_unavailable" | "workspace_missing";
|
|
15
15
|
export interface StartVerdict {
|
|
16
16
|
kind: "start";
|
package/src/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { run } from "./cli.
|
|
2
|
-
export { cleanupWorkspace, type CleanupWorkspaceOptions } from "./commands/cleanupWorkspace.
|
|
3
|
-
export { doctor } from "./commands/doctor.
|
|
4
|
-
export { orchestrate, type OrchestratorOptions } from "./commands/orchestrator.
|
|
5
|
-
export { setupWorkspace, type SetupWorkspaceOptions } from "./commands/setupWorkspace.
|
|
6
|
-
export type { Config, ModelDefinition, ResolvedConfig } from "./lib/config.
|
|
7
|
-
export { loadConfig } from "./lib/config.
|
|
8
|
-
export { getUsageByModel, type UsageByModel } from "./lib/usage.
|
|
1
|
+
export { run } from "./cli.ts";
|
|
2
|
+
export { cleanupWorkspace, type CleanupWorkspaceOptions } from "./commands/cleanupWorkspace.ts";
|
|
3
|
+
export { doctor } from "./commands/doctor.ts";
|
|
4
|
+
export { orchestrate, type OrchestratorOptions } from "./commands/orchestrator.ts";
|
|
5
|
+
export { setupWorkspace, type SetupWorkspaceOptions } from "./commands/setupWorkspace.ts";
|
|
6
|
+
export type { Config, ModelDefinition, ResolvedConfig } from "./lib/config.ts";
|
|
7
|
+
export { loadConfig } from "./lib/config.ts";
|
|
8
|
+
export { getUsageByModel, type UsageByModel } from "./lib/usage.ts";
|
package/src/lib/boardSource.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* typed `BoardState` instead of raw nodes.
|
|
5
5
|
*/
|
|
6
6
|
import type { LinearClient } from "@linear/sdk";
|
|
7
|
-
import { type ResolvedConfig } from "./config.
|
|
7
|
+
import { type ResolvedConfig } from "./config.ts";
|
|
8
8
|
export interface Blocker {
|
|
9
9
|
id: string;
|
|
10
10
|
title: string;
|
package/src/lib/isolation.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* capabilities into a concrete launch strategy. Pure: takes everything
|
|
4
4
|
* it needs as arguments so callers can test without touching the host.
|
|
5
5
|
*/
|
|
6
|
-
import type { IsolationStrategy, ResolvedConfig } from "./config.
|
|
7
|
-
import type { HostCapabilities } from "./host.
|
|
6
|
+
import type { IsolationStrategy, ResolvedConfig } from "./config.ts";
|
|
7
|
+
import type { HostCapabilities } from "./host.ts";
|
|
8
8
|
/**
|
|
9
9
|
* The concrete strategy that will run a model. `auto` is never returned —
|
|
10
10
|
* it's resolved here against the host into one of the leaf strategies.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type ModelDefinition } from "./config.
|
|
2
|
-
import type { ResolvedIsolationStrategy } from "./isolation.
|
|
1
|
+
import { type ModelDefinition } from "./config.ts";
|
|
2
|
+
import type { ResolvedIsolationStrategy } from "./isolation.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Build-time secrets we shuttle from groundcrew's process env into the
|
|
5
5
|
* setup phase of the launched workspace and then strip before exec'ing
|
package/src/lib/usage.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `orchestrator.sessionLimitPercentage`. There is no CLI surface for usage —
|
|
6
6
|
* `codexbar` itself is the user-facing inspection tool.
|
|
7
7
|
*/
|
|
8
|
-
import type { ResolvedConfig } from "./config.
|
|
8
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
9
9
|
interface NormalizedUsage {
|
|
10
10
|
session: number | null;
|
|
11
11
|
sessionEndDuration: number | null;
|
package/src/lib/workspaces.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* callers key on it. Adapters do their own internal lookup when their
|
|
5
5
|
* backend uses opaque refs.
|
|
6
6
|
*/
|
|
7
|
-
import type { ResolvedConfig, WorkspaceKindSetting } from "./config.
|
|
8
|
-
import { type HostCapabilities } from "./host.
|
|
7
|
+
import type { ResolvedConfig, WorkspaceKindSetting } from "./config.ts";
|
|
8
|
+
import { type HostCapabilities } from "./host.ts";
|
|
9
9
|
export type WorkspaceKind = "cmux" | "tmux";
|
|
10
10
|
export interface Workspace {
|
|
11
11
|
/** Ticket id; the join key callers use. */
|
package/src/lib/worktrees.d.ts
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* adapter by `spec.strategy` (for `create`) or `entry.kind` (for `remove`),
|
|
14
14
|
* mirroring the `workspaces` module's adapter pattern.
|
|
15
15
|
*/
|
|
16
|
-
import type { ResolvedConfig } from "./config.
|
|
17
|
-
import type { ResolvedIsolationStrategy } from "./isolation.
|
|
18
|
-
import { type WorkspaceProbe } from "./workspaces.
|
|
16
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
17
|
+
import type { ResolvedIsolationStrategy } from "./isolation.ts";
|
|
18
|
+
import { type WorkspaceProbe } from "./workspaces.ts";
|
|
19
19
|
export type WorktreeKind = "host" | "sandbox";
|
|
20
20
|
export interface WorktreeEntry {
|
|
21
21
|
repository: string;
|
package/src/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/main.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { run } from "./cli.js";
|
|
2
|
+
try {
|
|
3
|
+
await run(process.argv.slice(2));
|
|
4
|
+
}
|
|
5
|
+
catch (error) {
|
|
6
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
+
process.stderr.write(`${message}\n`);
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=main.js.map
|
package/src/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../packages/groundcrew/src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,IAAI,CAAC;IACH,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAAC,OAAO,KAAc,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|