pipeline-worker 0.1.15 → 0.1.17
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 +4 -0
- package/dist/agent/claude.d.ts +1 -1
- package/dist/agent/claude.js +9 -4
- package/dist/agent/claude.js.map +1 -1
- package/dist/agent/copilot.d.ts +7 -1
- package/dist/agent/copilot.js +17 -4
- package/dist/agent/copilot.js.map +1 -1
- package/dist/agent/types.d.ts +18 -0
- package/dist/agent/types.js +9 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli.js +47 -2
- package/dist/cli.js.map +1 -1
- package/dist/state/lock.d.ts +19 -0
- package/dist/state/lock.js +69 -0
- package/dist/state/lock.js.map +1 -0
- package/dist/state/runState.d.ts +18 -0
- package/dist/state/runState.js +56 -4
- package/dist/state/runState.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/ui/sessions.d.ts +10 -0
- package/dist/ui/sessions.js +61 -0
- package/dist/ui/sessions.js.map +1 -0
- package/dist/ui/steps.d.ts +10 -0
- package/dist/ui/steps.js +14 -0
- package/dist/ui/steps.js.map +1 -1
- package/dist/workflow/captureIntent.js +2 -0
- package/dist/workflow/captureIntent.js.map +1 -1
- package/dist/workflow/orchestrate.d.ts +10 -0
- package/dist/workflow/orchestrate.js +126 -83
- package/dist/workflow/orchestrate.js.map +1 -1
- package/dist/workflow/watchPipeline.js +17 -13
- package/dist/workflow/watchPipeline.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,6 +117,10 @@ A stage with no command (`—`) is skipped. If no toolchain is detected and no c
|
|
|
117
117
|
| `pipeline-worker serve` | Start the forge MCP server over stdio (used by the agent during fix runs) |
|
|
118
118
|
| `pipeline-worker resume --branch <name>` | Resume watching/fixing a run after a crash |
|
|
119
119
|
| `pipeline-worker status --branch <name>` | Print the persisted state of a run |
|
|
120
|
+
| `pipeline-worker sessions [--branch <name>]` | List every persisted run in this repo, or show one run's full step-by-step timeline |
|
|
121
|
+
| `pipeline-worker update` | Install the latest release from npm (`npm install -g pipeline-worker@latest`) |
|
|
122
|
+
|
|
123
|
+
Every time a run hands a turn to Claude Code or the Copilot CLI (resolving a conflict, capturing intent, fixing a failed pipeline), the output includes that turn's duration and an `agent session: <id>` line — `claude --resume <id>` (or `copilot --resume <id>`) opens the same session later to see exactly what it did and why. Copilot CLI has no way to report the session id it picked for itself, so pipeline-worker assigns one via `--name` instead and reports that.
|
|
120
124
|
|
|
121
125
|
## How the fix loop stays bounded
|
|
122
126
|
|
package/dist/agent/claude.d.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* surfaces the command line + stderr, so without this the most useful failure
|
|
21
21
|
* information is silently dropped.
|
|
22
22
|
*/
|
|
23
|
-
import type
|
|
23
|
+
import { type AgentAdapter } from './types.js';
|
|
24
24
|
/** Subset of the rejection shape Node's promisified execFile produces. */
|
|
25
25
|
interface ExecErrorShape {
|
|
26
26
|
code?: number | string | null;
|
package/dist/agent/claude.js
CHANGED
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { execFile } from 'node:child_process';
|
|
24
24
|
import { promisify } from 'node:util';
|
|
25
|
+
import { AGENT_INVOKE_TIMEOUT_MS } from './types.js';
|
|
25
26
|
import { writePromptToStdin } from './stdinPrompt.js';
|
|
26
27
|
const execFileAsync = promisify(execFile);
|
|
27
|
-
const INVOKE_TIMEOUT_MS = 300_000;
|
|
28
28
|
/**
|
|
29
29
|
* Tail-truncation cap for stdout/stderr in the rejection message. Mirrors
|
|
30
30
|
* `watchPipeline.ts`'s `.slice(-4000)` so a verbose agent failure (e.g. an
|
|
@@ -100,11 +100,12 @@ export const claudeAdapter = {
|
|
|
100
100
|
if (opts.model) {
|
|
101
101
|
args.push('--model', opts.model);
|
|
102
102
|
}
|
|
103
|
+
const start = Date.now();
|
|
103
104
|
let stdout;
|
|
104
105
|
try {
|
|
105
106
|
const invocation = execFileAsync('claude', args, {
|
|
106
107
|
cwd: opts.cwd,
|
|
107
|
-
timeout:
|
|
108
|
+
timeout: AGENT_INVOKE_TIMEOUT_MS,
|
|
108
109
|
maxBuffer: 64 * 1024 * 1024,
|
|
109
110
|
});
|
|
110
111
|
// stdin is always a pipe here since stdio isn't overridden in execFileAsync's options.
|
|
@@ -117,13 +118,17 @@ export const claudeAdapter = {
|
|
|
117
118
|
throw new Error(formatProcessError(err));
|
|
118
119
|
}
|
|
119
120
|
try {
|
|
121
|
+
// duration_ms/session_id come straight from the CLI's own JSON envelope
|
|
122
|
+
// (see the module comment's `claude -p --output-format json` sample);
|
|
123
|
+
// falling back to our own wall-clock reading only covers the
|
|
124
|
+
// never-observed case where that envelope omits duration_ms.
|
|
120
125
|
const parsed = JSON.parse(stdout);
|
|
121
|
-
return { text: parsed.result ?? stdout, raw: parsed };
|
|
126
|
+
return { text: parsed.result ?? stdout, raw: parsed, sessionId: parsed.session_id, durationMs: parsed.duration_ms ?? Date.now() - start };
|
|
122
127
|
}
|
|
123
128
|
catch {
|
|
124
129
|
// --output-format json should always produce parseable JSON; fall back
|
|
125
130
|
// to the raw stream rather than throwing, since the invocation itself succeeded.
|
|
126
|
-
return { text: stdout };
|
|
131
|
+
return { text: stdout, durationMs: Date.now() - start };
|
|
127
132
|
}
|
|
128
133
|
},
|
|
129
134
|
};
|
package/dist/agent/claude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agent/claude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agent/claude.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/copilot.d.ts
CHANGED
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
* - no per-invocation tool allowlist -> `--allow-all-tools` is always passed,
|
|
20
20
|
* so `allowedTools` is ignored; a read-only step (e.g. captureIntent.ts)
|
|
21
21
|
* gets full tool access under this adapter instead of being restricted.
|
|
22
|
+
* - no way to learn the session id the CLI picked for itself in
|
|
23
|
+
* non-interactive mode (open feature request: github/copilot-cli#807) ->
|
|
24
|
+
* every invocation is given an explicit `--name`, which `copilot --resume
|
|
25
|
+
* <name>` (or `/resume` in an interactive session) can look up later, so
|
|
26
|
+
* callers still get a stable identifier to report even though it isn't
|
|
27
|
+
* the CLI's own internal session id.
|
|
22
28
|
*
|
|
23
29
|
* The prompt is piped over stdin rather than passed via `-p <prompt>`.
|
|
24
30
|
* captureIntent.ts embeds a full git diff in the prompt, and a large diff can
|
|
@@ -28,5 +34,5 @@
|
|
|
28
34
|
* non-interactively since stdin isn't a TTY (documented as
|
|
29
35
|
* `echo "..." | copilot`).
|
|
30
36
|
*/
|
|
31
|
-
import type
|
|
37
|
+
import { type AgentAdapter } from './types.js';
|
|
32
38
|
export declare const copilotAdapter: AgentAdapter;
|
package/dist/agent/copilot.js
CHANGED
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
* - no per-invocation tool allowlist -> `--allow-all-tools` is always passed,
|
|
20
20
|
* so `allowedTools` is ignored; a read-only step (e.g. captureIntent.ts)
|
|
21
21
|
* gets full tool access under this adapter instead of being restricted.
|
|
22
|
+
* - no way to learn the session id the CLI picked for itself in
|
|
23
|
+
* non-interactive mode (open feature request: github/copilot-cli#807) ->
|
|
24
|
+
* every invocation is given an explicit `--name`, which `copilot --resume
|
|
25
|
+
* <name>` (or `/resume` in an interactive session) can look up later, so
|
|
26
|
+
* callers still get a stable identifier to report even though it isn't
|
|
27
|
+
* the CLI's own internal session id.
|
|
22
28
|
*
|
|
23
29
|
* The prompt is piped over stdin rather than passed via `-p <prompt>`.
|
|
24
30
|
* captureIntent.ts embeds a full git diff in the prompt, and a large diff can
|
|
@@ -30,9 +36,10 @@
|
|
|
30
36
|
*/
|
|
31
37
|
import { execFile } from 'node:child_process';
|
|
32
38
|
import { promisify } from 'node:util';
|
|
39
|
+
import { randomUUID } from 'node:crypto';
|
|
40
|
+
import { AGENT_INVOKE_TIMEOUT_MS } from './types.js';
|
|
33
41
|
import { writePromptToStdin } from './stdinPrompt.js';
|
|
34
42
|
const execFileAsync = promisify(execFile);
|
|
35
|
-
const INVOKE_TIMEOUT_MS = 300_000;
|
|
36
43
|
/** Pulls the outermost JSON object out of a text answer that may have prose around it. */
|
|
37
44
|
function extractJsonObject(text) {
|
|
38
45
|
const start = text.indexOf('{');
|
|
@@ -55,15 +62,21 @@ export const copilotAdapter = {
|
|
|
55
62
|
console.error(`pipeline-worker: copilot CLI has no per-invocation model flag; ignoring the configured model "${opts.model}". ` +
|
|
56
63
|
"Switch copilot's model via its own /model command or config instead.");
|
|
57
64
|
}
|
|
58
|
-
const
|
|
65
|
+
const sessionName = `pipeline-worker-${randomUUID()}`;
|
|
66
|
+
const start = Date.now();
|
|
67
|
+
const invocation = execFileAsync('copilot', ['-s', '--no-ask-user', '--allow-all-tools', '--allow-all-paths', '--name', sessionName], {
|
|
59
68
|
cwd: opts.cwd,
|
|
60
|
-
timeout:
|
|
69
|
+
timeout: AGENT_INVOKE_TIMEOUT_MS,
|
|
61
70
|
maxBuffer: 64 * 1024 * 1024,
|
|
62
71
|
});
|
|
63
72
|
// stdin is always a pipe here since stdio isn't overridden in execFileAsync's options.
|
|
64
73
|
writePromptToStdin(invocation.child.stdin, prompt);
|
|
65
74
|
const { stdout } = await invocation;
|
|
66
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
text: opts.jsonSchema ? extractJsonObject(stdout) : stdout.trim(),
|
|
77
|
+
sessionId: sessionName,
|
|
78
|
+
durationMs: Date.now() - start,
|
|
79
|
+
};
|
|
67
80
|
},
|
|
68
81
|
};
|
|
69
82
|
//# sourceMappingURL=copilot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agent/copilot.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agent/copilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAsE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,0FAA0F;AAC1F,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,KAAK,CAAC,MAAM,CAAC,IAAwB;QACnC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM;gBACJ,oGAAoG;oBACpG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CACX,mFAAmF;gBACjF,iFAAiF,CACpF,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,iGAAiG,IAAI,CAAC,KAAK,KAAK;gBAC9G,sEAAsE,CACzE,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,mBAAmB,UAAU,EAAE,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,aAAa,CAC9B,SAAS,EACT,CAAC,IAAI,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,WAAW,CAAC,EACxF;YACE,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,uBAAuB;YAChC,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CACF,CAAC;QACF,uFAAuF;QACvF,kBAAkB,CAAC,UAAU,CAAC,KAAK,CAAC,KAAM,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC;QAEpC,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;YACjE,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC/B,CAAC;IACJ,CAAC;CACF,CAAC"}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
/** Common interface both the Claude Code and Copilot CLI adapters implement. */
|
|
2
|
+
/**
|
|
3
|
+
* Hard ceiling on a single headless agent invocation, shared by both
|
|
4
|
+
* adapters. Conflict resolution and CI-fix turns run under acceptEdits with
|
|
5
|
+
* full tool access (reading/editing multiple files, sometimes re-running
|
|
6
|
+
* build/test commands), so they can legitimately take much longer than a
|
|
7
|
+
* plain completion — 15 minutes gives that room while still bounding a hung
|
|
8
|
+
* unattended run.
|
|
9
|
+
*/
|
|
10
|
+
export declare const AGENT_INVOKE_TIMEOUT_MS = 900000;
|
|
2
11
|
export interface AgentInvokeOptions {
|
|
3
12
|
/** The instruction given to the agent for this turn. */
|
|
4
13
|
prompt: string;
|
|
@@ -24,6 +33,15 @@ export interface AgentInvokeResult {
|
|
|
24
33
|
text: string;
|
|
25
34
|
/** The parsed structured payload, when the adapter's output format returns one. */
|
|
26
35
|
raw?: unknown;
|
|
36
|
+
/**
|
|
37
|
+
* Identifier for the underlying agent CLI's own session, so a user can look
|
|
38
|
+
* up what it did later — `claude --resume <id>` or, for Copilot (which has
|
|
39
|
+
* no way to report the session id it picked itself), the `--name` we chose
|
|
40
|
+
* for it, resumable via `copilot --resume <id>`.
|
|
41
|
+
*/
|
|
42
|
+
sessionId?: string;
|
|
43
|
+
/** Wall-clock duration of this invocation in milliseconds. */
|
|
44
|
+
durationMs?: number;
|
|
27
45
|
}
|
|
28
46
|
export interface AgentAdapter {
|
|
29
47
|
invoke(opts: AgentInvokeOptions): Promise<AgentInvokeResult>;
|
package/dist/agent/types.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
/** Common interface both the Claude Code and Copilot CLI adapters implement. */
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Hard ceiling on a single headless agent invocation, shared by both
|
|
4
|
+
* adapters. Conflict resolution and CI-fix turns run under acceptEdits with
|
|
5
|
+
* full tool access (reading/editing multiple files, sometimes re-running
|
|
6
|
+
* build/test commands), so they can legitimately take much longer than a
|
|
7
|
+
* plain completion — 15 minutes gives that room while still bounding a hung
|
|
8
|
+
* unattended run.
|
|
9
|
+
*/
|
|
10
|
+
export const AGENT_INVOKE_TIMEOUT_MS = 900_000;
|
|
3
11
|
//# sourceMappingURL=types.js.map
|
package/dist/agent/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA,gFAAgF"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
5
6
|
import { Command } from 'commander';
|
|
6
7
|
import { runWorkflow } from './workflow/orchestrate.js';
|
|
7
8
|
import { watchPipeline } from './workflow/watchPipeline.js';
|
|
@@ -9,7 +10,8 @@ import { startServer } from './mcp/server.js';
|
|
|
9
10
|
import { loadConfig } from './config/loader.js';
|
|
10
11
|
import { createForge } from './forge/index.js';
|
|
11
12
|
import { selectAgent } from './agent/index.js';
|
|
12
|
-
import { loadRunState,
|
|
13
|
+
import { loadRunState, listRunStates, recordEvent } from './state/runState.js';
|
|
14
|
+
import { printSessionList, printSessionDetail } from './ui/sessions.js';
|
|
13
15
|
import { isWorktreeOnBranch, checkoutExistingBranch, removeWorktree } from './git/worktree.js';
|
|
14
16
|
import { buildEnvelope, errorEnvelope } from './toon/envelope.js';
|
|
15
17
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -67,7 +69,7 @@ program
|
|
|
67
69
|
: await checkoutExistingBranch(repoRoot, state.branch);
|
|
68
70
|
if (worktreePath !== state.worktreePath) {
|
|
69
71
|
state.worktreePath = worktreePath;
|
|
70
|
-
|
|
72
|
+
recordEvent(repoRoot, state, `Recreated worktree at ${worktreePath}`);
|
|
71
73
|
}
|
|
72
74
|
let cleanedUp = false;
|
|
73
75
|
const cleanup = async () => {
|
|
@@ -84,6 +86,11 @@ program
|
|
|
84
86
|
try {
|
|
85
87
|
await watchPipeline(forge, config, agent, worktreePath, state.branch, state.targetBranch, state.mrIid, state, repoRoot);
|
|
86
88
|
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
recordEvent(repoRoot, state, `Resume failed: ${message}`, 'error');
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
87
94
|
finally {
|
|
88
95
|
await cleanup();
|
|
89
96
|
}
|
|
@@ -107,6 +114,44 @@ program
|
|
|
107
114
|
}
|
|
108
115
|
console.log(buildEnvelope({ status: 'success', data: state }));
|
|
109
116
|
});
|
|
117
|
+
program
|
|
118
|
+
.command('sessions')
|
|
119
|
+
.description("List this repo's persisted pipeline-worker runs, or inspect one run's full timeline")
|
|
120
|
+
.option('--branch <name>', 'show the full step-by-step timeline for one run instead of listing all')
|
|
121
|
+
.action((opts) => {
|
|
122
|
+
const repoRoot = process.cwd();
|
|
123
|
+
if (opts.branch) {
|
|
124
|
+
const state = loadRunState(repoRoot, opts.branch);
|
|
125
|
+
if (!state) {
|
|
126
|
+
console.error(`pipeline-worker: no session found for branch ${opts.branch}.`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
printSessionDetail({ branch: state.branch, state });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
printSessionList(listRunStates(repoRoot));
|
|
133
|
+
});
|
|
134
|
+
program
|
|
135
|
+
.command('update')
|
|
136
|
+
.description(`Install the latest ${pkg.name} release from npm (npm install -g ${pkg.name}@latest)`)
|
|
137
|
+
.action(async () => {
|
|
138
|
+
console.log(`pipeline-worker: currently v${pkg.version}, installing latest via npm install -g ${pkg.name}@latest ...`);
|
|
139
|
+
try {
|
|
140
|
+
await new Promise((resolve, reject) => {
|
|
141
|
+
// stdio: 'inherit' streams npm's own progress/errors straight to the
|
|
142
|
+
// user's terminal rather than buffering it — an install can take a
|
|
143
|
+
// while and users expect to see npm's usual output live.
|
|
144
|
+
const npm = spawn('npm', ['install', '-g', `${pkg.name}@latest`], { stdio: 'inherit' });
|
|
145
|
+
npm.on('error', reject);
|
|
146
|
+
npm.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`npm install exited with code ${code}`))));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error('pipeline-worker update failed:', error instanceof Error ? error.message : error);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
console.log(`pipeline-worker: updated — run "${pkg.name} -v" to confirm the installed version.`);
|
|
154
|
+
});
|
|
110
155
|
program.parseAsync(process.argv).catch((error) => {
|
|
111
156
|
console.error('pipeline-worker: unexpected error:', error instanceof Error ? error.message : error);
|
|
112
157
|
process.exit(1);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-repo lockfile at <repoRoot>/.pipeline-worker/run.lock, preventing two
|
|
3
|
+
* `pipeline-worker run` invocations from racing against the same working
|
|
4
|
+
* tree — e.g. one instance's `resetRepo` (`git reset --hard`) wiping out
|
|
5
|
+
* uncommitted changes another instance's `captureDiff` hasn't processed yet.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Acquires the lock, throwing if another live process already holds it. A
|
|
9
|
+
* lock left behind by a process that's no longer running (crash, kill -9) is
|
|
10
|
+
* treated as stale and reclaimed. Returns a release function; safe to call
|
|
11
|
+
* more than once.
|
|
12
|
+
*
|
|
13
|
+
* The final write uses the 'wx' flag (fails with EEXIST if the path already
|
|
14
|
+
* exists) as the actual mutual-exclusion guard — the existsSync/liveness
|
|
15
|
+
* check above is only a fast path to produce a clear "who's holding it"
|
|
16
|
+
* error message, since it's inherently racy against another process doing
|
|
17
|
+
* the same check concurrently.
|
|
18
|
+
*/
|
|
19
|
+
export declare function acquireLock(repoRoot: string): () => void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-repo lockfile at <repoRoot>/.pipeline-worker/run.lock, preventing two
|
|
3
|
+
* `pipeline-worker run` invocations from racing against the same working
|
|
4
|
+
* tree — e.g. one instance's `resetRepo` (`git reset --hard`) wiping out
|
|
5
|
+
* uncommitted changes another instance's `captureDiff` hasn't processed yet.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
function lockPath(repoRoot) {
|
|
10
|
+
return join(repoRoot, '.pipeline-worker', 'run.lock');
|
|
11
|
+
}
|
|
12
|
+
function isProcessAlive(pid) {
|
|
13
|
+
try {
|
|
14
|
+
// Signal 0 sends nothing but still validates the pid exists/is
|
|
15
|
+
// accessible — the standard liveness check on POSIX and Windows.
|
|
16
|
+
process.kill(pid, 0);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function removeIfPresent(path) {
|
|
24
|
+
try {
|
|
25
|
+
unlinkSync(path);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Already gone (e.g. a concurrent process reclaimed it first) — fine.
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Acquires the lock, throwing if another live process already holds it. A
|
|
33
|
+
* lock left behind by a process that's no longer running (crash, kill -9) is
|
|
34
|
+
* treated as stale and reclaimed. Returns a release function; safe to call
|
|
35
|
+
* more than once.
|
|
36
|
+
*
|
|
37
|
+
* The final write uses the 'wx' flag (fails with EEXIST if the path already
|
|
38
|
+
* exists) as the actual mutual-exclusion guard — the existsSync/liveness
|
|
39
|
+
* check above is only a fast path to produce a clear "who's holding it"
|
|
40
|
+
* error message, since it's inherently racy against another process doing
|
|
41
|
+
* the same check concurrently.
|
|
42
|
+
*/
|
|
43
|
+
export function acquireLock(repoRoot) {
|
|
44
|
+
const dir = join(repoRoot, '.pipeline-worker');
|
|
45
|
+
mkdirSync(dir, { recursive: true });
|
|
46
|
+
const path = lockPath(repoRoot);
|
|
47
|
+
if (existsSync(path)) {
|
|
48
|
+
const heldPid = Number.parseInt(readFileSync(path, 'utf-8').trim(), 10);
|
|
49
|
+
if (Number.isInteger(heldPid) && isProcessAlive(heldPid)) {
|
|
50
|
+
throw new Error(`pipeline-worker: another run (pid ${heldPid}) is already in progress in this repo. ` +
|
|
51
|
+
'Wait for it to finish, or if it crashed without cleaning up, remove .pipeline-worker/run.lock.');
|
|
52
|
+
}
|
|
53
|
+
removeIfPresent(path);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
writeFileSync(path, String(process.pid), { flag: 'wx' });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new Error('pipeline-worker: another run just started in this repo — try again.');
|
|
60
|
+
}
|
|
61
|
+
let released = false;
|
|
62
|
+
return () => {
|
|
63
|
+
if (released)
|
|
64
|
+
return;
|
|
65
|
+
released = true;
|
|
66
|
+
removeIfPresent(path);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/state/lock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,SAAS,QAAQ,CAAC,QAAgB;IAChC,OAAO,IAAI,CAAC,QAAQ,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,+DAA+D;QAC/D,iEAAiE;QACjE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;IACxE,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAC/C,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEhC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CACb,qCAAqC,OAAO,yCAAyC;gBACnF,gGAAgG,CACnG,CAAC;QACJ,CAAC;QACD,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO,GAAG,EAAE;QACV,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/state/runState.d.ts
CHANGED
|
@@ -7,3 +7,21 @@
|
|
|
7
7
|
import type { RunState } from '../types.js';
|
|
8
8
|
export declare function saveRunState(repoRoot: string, state: RunState): void;
|
|
9
9
|
export declare function loadRunState(repoRoot: string, branch: string): RunState | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Appends a timestamped entry to state.history and persists it — this is the
|
|
12
|
+
* narration `pipeline-worker sessions --branch <name>` renders. Mutates
|
|
13
|
+
* `state` in place, matching how saveRunState is already called throughout
|
|
14
|
+
* orchestrate.ts/watchPipeline.ts.
|
|
15
|
+
*/
|
|
16
|
+
export declare function recordEvent(repoRoot: string, state: RunState, message: string, level?: 'info' | 'error'): void;
|
|
17
|
+
export interface RunSession {
|
|
18
|
+
branch: string;
|
|
19
|
+
state: RunState;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Lists every persisted run in this repo (one per state file), most
|
|
23
|
+
* recently updated first. A corrupt/partial state file is skipped rather
|
|
24
|
+
* than failing the whole listing — `pipeline-worker sessions` should show
|
|
25
|
+
* what it can even if one run's file is damaged.
|
|
26
|
+
*/
|
|
27
|
+
export declare function listRunStates(repoRoot: string): RunSession[];
|
package/dist/state/runState.js
CHANGED
|
@@ -4,17 +4,31 @@
|
|
|
4
4
|
* lost state file only degrades `resume`/`status`, it never corrupts GitLab
|
|
5
5
|
* state (the forge client's findExistingMr is the real idempotency guard).
|
|
6
6
|
*/
|
|
7
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
8
9
|
import { join } from 'node:path';
|
|
10
|
+
/** Caps state.history so a long-running CI-fix loop can't grow the state file unboundedly. */
|
|
11
|
+
const MAX_HISTORY_ENTRIES = 200;
|
|
12
|
+
function stateDir(repoRoot) {
|
|
13
|
+
return join(repoRoot, '.pipeline-worker', 'state');
|
|
14
|
+
}
|
|
9
15
|
function statePath(repoRoot, branch) {
|
|
10
16
|
const safeName = branch.replace(/\//g, '_');
|
|
11
|
-
return join(repoRoot,
|
|
17
|
+
return join(stateDir(repoRoot), `${safeName}.json`);
|
|
12
18
|
}
|
|
13
19
|
export function saveRunState(repoRoot, state) {
|
|
14
20
|
try {
|
|
21
|
+
const dir = stateDir(repoRoot);
|
|
22
|
+
mkdirSync(dir, { recursive: true });
|
|
15
23
|
const path = statePath(repoRoot, state.branch);
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
// Write to a temp file in the same directory, then rename over the real
|
|
25
|
+
// path. A same-directory rename is atomic on POSIX and Windows, so a
|
|
26
|
+
// process kill mid-write can never leave a truncated/corrupt state file
|
|
27
|
+
// at `path` — a reader always sees either the previous complete write or
|
|
28
|
+
// the new one, never a partial one.
|
|
29
|
+
const tmpPath = join(dir, `.${randomUUID()}.tmp`);
|
|
30
|
+
writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
|
|
31
|
+
renameSync(tmpPath, path);
|
|
18
32
|
}
|
|
19
33
|
catch (error) {
|
|
20
34
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -34,4 +48,42 @@ export function loadRunState(repoRoot, branch) {
|
|
|
34
48
|
return undefined;
|
|
35
49
|
}
|
|
36
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Appends a timestamped entry to state.history and persists it — this is the
|
|
53
|
+
* narration `pipeline-worker sessions --branch <name>` renders. Mutates
|
|
54
|
+
* `state` in place, matching how saveRunState is already called throughout
|
|
55
|
+
* orchestrate.ts/watchPipeline.ts.
|
|
56
|
+
*/
|
|
57
|
+
export function recordEvent(repoRoot, state, message, level = 'info') {
|
|
58
|
+
const now = new Date().toISOString();
|
|
59
|
+
state.startedAt ??= now;
|
|
60
|
+
state.updatedAt = now;
|
|
61
|
+
const history = [...(state.history ?? []), { at: now, phase: state.phase, level, message }];
|
|
62
|
+
state.history = history.length > MAX_HISTORY_ENTRIES ? history.slice(history.length - MAX_HISTORY_ENTRIES) : history;
|
|
63
|
+
saveRunState(repoRoot, state);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Lists every persisted run in this repo (one per state file), most
|
|
67
|
+
* recently updated first. A corrupt/partial state file is skipped rather
|
|
68
|
+
* than failing the whole listing — `pipeline-worker sessions` should show
|
|
69
|
+
* what it can even if one run's file is damaged.
|
|
70
|
+
*/
|
|
71
|
+
export function listRunStates(repoRoot) {
|
|
72
|
+
const dir = stateDir(repoRoot);
|
|
73
|
+
if (!existsSync(dir))
|
|
74
|
+
return [];
|
|
75
|
+
const sessions = [];
|
|
76
|
+
for (const entry of readdirSync(dir)) {
|
|
77
|
+
if (!entry.endsWith('.json'))
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
const state = JSON.parse(readFileSync(join(dir, entry), 'utf-8'));
|
|
81
|
+
sessions.push({ branch: state.branch, state });
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return sessions.sort((a, b) => (b.state.updatedAt ?? '').localeCompare(a.state.updatedAt ?? ''));
|
|
88
|
+
}
|
|
37
89
|
//# sourceMappingURL=runState.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runState.js","sourceRoot":"","sources":["../../src/state/runState.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"runState.js","sourceRoot":"","sources":["../../src/state/runState.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -29,6 +29,13 @@ export interface PipelineWorkerConfig {
|
|
|
29
29
|
runLintAndTest: boolean;
|
|
30
30
|
}
|
|
31
31
|
export type RunPhase = 'diff' | 'intent' | 'checks' | 'mr' | 'watch' | 'done' | 'escalated';
|
|
32
|
+
/** One entry in RunState.history — a timestamped narration of what happened during the run, for `pipeline-worker sessions`. */
|
|
33
|
+
export interface RunHistoryEntry {
|
|
34
|
+
at: string;
|
|
35
|
+
phase: RunPhase;
|
|
36
|
+
level: 'info' | 'error';
|
|
37
|
+
message: string;
|
|
38
|
+
}
|
|
32
39
|
export interface RunState {
|
|
33
40
|
branch: string;
|
|
34
41
|
targetBranch: string;
|
|
@@ -37,6 +44,12 @@ export interface RunState {
|
|
|
37
44
|
pipelineId?: number;
|
|
38
45
|
attempt: number;
|
|
39
46
|
phase: RunPhase;
|
|
47
|
+
/** ISO 8601 timestamp of when this run was first created. Absent on state files written before this field existed. */
|
|
48
|
+
startedAt?: string;
|
|
49
|
+
/** ISO 8601 timestamp of the most recent state write. Absent on state files written before this field existed. */
|
|
50
|
+
updatedAt?: string;
|
|
51
|
+
/** Chronological log of phase transitions, escalations, and errors. Absent on state files written before this field existed. */
|
|
52
|
+
history?: RunHistoryEntry[];
|
|
40
53
|
}
|
|
41
54
|
export type RiskLevel = 'low' | 'medium' | 'high';
|
|
42
55
|
export type ChangeType = 'feature' | 'bugfix' | 'chore';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-facing rendering for `pipeline-worker sessions` — lists and inspects
|
|
3
|
+
* runs persisted under .pipeline-worker/state/, mirroring the emoji/color
|
|
4
|
+
* narration style ui/steps.ts uses for a live run.
|
|
5
|
+
*/
|
|
6
|
+
import type { RunSession } from '../state/runState.js';
|
|
7
|
+
/** `pipeline-worker sessions` with no --branch: one line per persisted run, most recently updated first. */
|
|
8
|
+
export declare function printSessionList(sessions: RunSession[]): void;
|
|
9
|
+
/** `pipeline-worker sessions --branch <name>`: one run's metadata plus its full step-by-step history. */
|
|
10
|
+
export declare function printSessionDetail(session: RunSession): void;
|