@glrs-dev/cli 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/{chunk-EM4MJBOD.js → chunk-2AZKRWC6.js} +4 -4
- package/dist/{chunk-UXBOTMDY.js → chunk-2P3ETOT2.js} +2 -2
- package/dist/chunk-2VMFXAJH.js +795 -0
- package/dist/chunk-5ZVUFNCP.js +140 -0
- package/dist/{chunk-W37UX3U2.js → chunk-6Y27RQQL.js} +2 -2
- package/dist/{chunk-RZWOWTKF.js → chunk-EKNRKZWR.js} +4 -4
- package/dist/{chunk-YGNDPKIW.js → chunk-HQUCVJ4G.js} +3 -1
- package/dist/{chunk-OABVEBWW.js → chunk-MBEVC327.js} +1 -1
- package/dist/{chunk-SB3MLROC.js → chunk-MCM47HH4.js} +8 -3
- package/dist/{chunk-F3AFRUT2.js → chunk-PTIO556V.js} +2 -2
- package/dist/{chunk-E2UNZIZT.js → chunk-R2WXQ54P.js} +1 -1
- package/dist/{chunk-I2KUXY3I.js → chunk-SMDIOB5B.js} +2 -2
- package/dist/{chunk-SPULDN7P.js → chunk-YY7EWHMA.js} +5 -3
- package/dist/cli.js +31 -20
- package/dist/commands/autopilot-interactive.d.ts +89 -0
- package/dist/commands/autopilot-interactive.js +248 -0
- package/dist/commands/autopilot-raw.d.ts +1 -0
- package/dist/commands/autopilot-raw.js +368 -0
- package/dist/commands/autopilot-tui.d.ts +7 -0
- package/dist/commands/autopilot-tui.js +7 -0
- package/dist/commands/autopilot.d.ts +39 -0
- package/dist/commands/autopilot.js +395 -0
- package/dist/commands/cleanup.js +3 -3
- package/dist/commands/create.js +4 -4
- package/dist/commands/dashboard.d.ts +3 -0
- package/dist/commands/dashboard.js +1549 -0
- package/dist/commands/debrief.d.ts +57 -0
- package/dist/commands/debrief.js +9 -0
- package/dist/commands/delete.js +3 -3
- package/dist/commands/go.js +2 -2
- package/dist/commands/list.js +3 -3
- package/dist/commands/loop.d.ts +42 -0
- package/dist/commands/loop.js +133 -0
- package/dist/commands/plan-picker.d.ts +15 -0
- package/dist/commands/plan-picker.js +76 -0
- package/dist/commands/scoper.d.ts +54 -0
- package/dist/commands/scoper.js +341 -0
- package/dist/commands/switch.js +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/lib/auto-update.js +1 -1
- package/dist/lib/config.d.ts +3 -2
- package/dist/lib/config.js +1 -1
- package/dist/lib/registry.d.ts +2 -0
- package/dist/lib/registry.js +1 -1
- package/dist/lib/worktree.js +3 -3
- package/dist/vendor/harness-opencode/dist/agents/prompts/build.md +16 -0
- package/dist/vendor/harness-opencode/dist/agents/prompts/code-reviewer-thorough.md +6 -7
- package/dist/vendor/harness-opencode/dist/agents/prompts/debriefer.md +55 -0
- package/dist/vendor/harness-opencode/dist/agents/prompts/plan-reviewer.md +2 -1
- package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +104 -7
- package/dist/vendor/harness-opencode/dist/agents/prompts/prime.md +4 -2
- package/dist/vendor/harness-opencode/dist/agents/prompts/scoper.md +129 -0
- package/dist/vendor/harness-opencode/dist/agents/prompts/spec-reviewer.md +0 -1
- package/dist/vendor/harness-opencode/dist/agents/prompts/spec-reviewer.open.md +0 -1
- package/dist/vendor/harness-opencode/dist/chunk-GILWWWMB.js +66 -0
- package/dist/vendor/harness-opencode/dist/cli.js +328 -687
- package/dist/vendor/harness-opencode/dist/index.js +123 -20
- package/dist/vendor/harness-opencode/dist/plugin-check-GJRD2OK6.js +14 -0
- package/dist/vendor/harness-opencode/dist/skills/spear-protocol/SKILL.md +2 -1
- package/dist/vendor/harness-opencode/package.json +1 -1
- package/package.json +10 -2
- package/dist/vendor/harness-opencode/dist/autopilot/prompt-template.md +0 -80
- package/dist/vendor/harness-opencode/dist/bin/plan-check.sh +0 -255
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AgentAdapter, AgentHandle, LoopResult } from '@glrs-dev/autopilot';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Autopilot post-run debrief module.
|
|
5
|
+
*
|
|
6
|
+
* After the Ralph loop exits (any exit reason), runDebrief spawns a
|
|
7
|
+
* @debriefer session, sends a structured context blob, waits for the
|
|
8
|
+
* response, and prints the structured summary to stdout.
|
|
9
|
+
*
|
|
10
|
+
* On any failure, prints a warning and returns gracefully — the loop
|
|
11
|
+
* result is the source of truth for exit code.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface DebriefOptions {
|
|
15
|
+
/** The agent adapter + handle (owned by the CLI). */
|
|
16
|
+
agentHandle: {
|
|
17
|
+
adapter: AgentAdapter;
|
|
18
|
+
handle: AgentHandle;
|
|
19
|
+
};
|
|
20
|
+
/** The result from runRalphLoop. */
|
|
21
|
+
loopResult: LoopResult & {
|
|
22
|
+
sessionId?: string;
|
|
23
|
+
cumulativeCostUsd?: number;
|
|
24
|
+
};
|
|
25
|
+
/** The original prompt passed to the loop. */
|
|
26
|
+
prompt: string;
|
|
27
|
+
/** Working directory (used for git diff stat). */
|
|
28
|
+
cwd: string;
|
|
29
|
+
/**
|
|
30
|
+
* Injectable dependencies for testing.
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
_deps?: {
|
|
34
|
+
execGitDiffStat?: (cwd: string) => Promise<string>;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface ShouldRunDebriefOptions {
|
|
38
|
+
noDebrief: boolean;
|
|
39
|
+
env: Record<string, string | undefined>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns true if the debrief should run given the CLI flag and env var.
|
|
43
|
+
*
|
|
44
|
+
* - `--no-debrief` flag → false
|
|
45
|
+
* - `GLRS_AUTOPILOT_DEBRIEF=off` (case-insensitive) → false
|
|
46
|
+
* - Otherwise → true
|
|
47
|
+
*/
|
|
48
|
+
declare function shouldRunDebrief(opts: ShouldRunDebriefOptions): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Run the post-loop debrief. Spawns a @debriefer session, sends context,
|
|
51
|
+
* waits for the response, and prints it to stdout.
|
|
52
|
+
*
|
|
53
|
+
* Never throws — on any error, prints a warning to stderr and returns.
|
|
54
|
+
*/
|
|
55
|
+
declare function runDebrief(opts: DebriefOptions): Promise<void>;
|
|
56
|
+
|
|
57
|
+
export { type DebriefOptions, type ShouldRunDebriefOptions, runDebrief, shouldRunDebrief };
|
package/dist/commands/delete.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
del
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-W37UX3U2.js";
|
|
3
|
+
} from "../chunk-EKNRKZWR.js";
|
|
5
4
|
import "../chunk-P7PRH4I3.js";
|
|
5
|
+
import "../chunk-6Y27RQQL.js";
|
|
6
6
|
import "../chunk-LMRDQ4GW.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-YY7EWHMA.js";
|
|
8
8
|
import "../chunk-YBCA3IP6.js";
|
|
9
9
|
import "../chunk-3RG5ZIWI.js";
|
|
10
10
|
export {
|
package/dist/commands/go.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
go
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-R2WXQ54P.js";
|
|
4
4
|
import "../chunk-P7PRH4I3.js";
|
|
5
5
|
import "../chunk-LMRDQ4GW.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-YY7EWHMA.js";
|
|
7
7
|
import "../chunk-YBCA3IP6.js";
|
|
8
8
|
import "../chunk-3RG5ZIWI.js";
|
|
9
9
|
export {
|
package/dist/commands/list.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
list
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-SMDIOB5B.js";
|
|
4
|
+
import "../chunk-R2WXQ54P.js";
|
|
5
5
|
import "../chunk-P7PRH4I3.js";
|
|
6
6
|
import "../chunk-LMRDQ4GW.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-YY7EWHMA.js";
|
|
8
8
|
import "../chunk-YBCA3IP6.js";
|
|
9
9
|
import "../chunk-3RG5ZIWI.js";
|
|
10
10
|
export {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as cmd_ts_dist_cjs_runner_js from 'cmd-ts/dist/cjs/runner.js';
|
|
2
|
+
import * as cmd_ts_dist_cjs_helpdoc_js from 'cmd-ts/dist/cjs/helpdoc.js';
|
|
3
|
+
import * as cmd_ts_dist_cjs_argparser_js from 'cmd-ts/dist/cjs/argparser.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `glrs oc loop` — Ralph loop CLI driver.
|
|
7
|
+
*
|
|
8
|
+
* Starts an OpenCode server, creates a session with PRIME, sends the
|
|
9
|
+
* user's prompt each iteration, and exits when the agent emits
|
|
10
|
+
* `<autopilot-done>` or a budget is exhausted.
|
|
11
|
+
*
|
|
12
|
+
* PR 3 diverged `loop` and `autopilot`: `loop` is the raw-prompt
|
|
13
|
+
* Ralph-loop runner; `autopilot` is the interactive three-phase
|
|
14
|
+
* orchestrator (scope → plan → loop). They are now separate subcommands.
|
|
15
|
+
*
|
|
16
|
+
* After the loop exits, optionally runs a @debriefer session to produce
|
|
17
|
+
* a structured post-run summary. Skip with --no-debrief or
|
|
18
|
+
* GLRS_AUTOPILOT_DEBRIEF=off.
|
|
19
|
+
*/
|
|
20
|
+
declare const loopCmd: Partial<cmd_ts_dist_cjs_argparser_js.Register> & {
|
|
21
|
+
parse(context: cmd_ts_dist_cjs_argparser_js.ParseContext): Promise<cmd_ts_dist_cjs_argparser_js.ParsingResult<{
|
|
22
|
+
prompt: string;
|
|
23
|
+
maxIterations: number | undefined;
|
|
24
|
+
timeout: number | undefined;
|
|
25
|
+
stallTimeout: number | undefined;
|
|
26
|
+
noDebrief: boolean;
|
|
27
|
+
notify: string | undefined;
|
|
28
|
+
debriefOnly: boolean;
|
|
29
|
+
}>>;
|
|
30
|
+
} & cmd_ts_dist_cjs_helpdoc_js.PrintHelp & cmd_ts_dist_cjs_helpdoc_js.ProvidesHelp & cmd_ts_dist_cjs_helpdoc_js.Named & Partial<cmd_ts_dist_cjs_helpdoc_js.Versioned> & cmd_ts_dist_cjs_argparser_js.Register & cmd_ts_dist_cjs_runner_js.Handling<{
|
|
31
|
+
prompt: string;
|
|
32
|
+
maxIterations: number | undefined;
|
|
33
|
+
timeout: number | undefined;
|
|
34
|
+
stallTimeout: number | undefined;
|
|
35
|
+
noDebrief: boolean;
|
|
36
|
+
notify: string | undefined;
|
|
37
|
+
debriefOnly: boolean;
|
|
38
|
+
}, Promise<never>> & {
|
|
39
|
+
run(context: cmd_ts_dist_cjs_argparser_js.ParseContext): Promise<cmd_ts_dist_cjs_argparser_js.ParsingResult<Promise<never>>>;
|
|
40
|
+
} & Partial<cmd_ts_dist_cjs_helpdoc_js.Versioned & cmd_ts_dist_cjs_helpdoc_js.Descriptive & cmd_ts_dist_cjs_helpdoc_js.Aliased>;
|
|
41
|
+
|
|
42
|
+
export { loopCmd };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runDebrief,
|
|
3
|
+
shouldRunDebrief
|
|
4
|
+
} from "../chunk-5ZVUFNCP.js";
|
|
5
|
+
import "../chunk-3RG5ZIWI.js";
|
|
6
|
+
|
|
7
|
+
// src/commands/loop.ts
|
|
8
|
+
import { command, option, positional, string as stringType, optional, number as numberType, flag } from "cmd-ts";
|
|
9
|
+
import { runRalphLoop, MAX_ITERATIONS, TIMEOUT_MS } from "@glrs-dev/autopilot";
|
|
10
|
+
var loopCmd = command({
|
|
11
|
+
name: "loop",
|
|
12
|
+
description: "Run the Ralph loop: send a prompt to PRIME repeatedly until it emits <autopilot-done> or a budget is exhausted.",
|
|
13
|
+
args: {
|
|
14
|
+
prompt: positional({
|
|
15
|
+
type: stringType,
|
|
16
|
+
displayName: "prompt",
|
|
17
|
+
description: "The prompt to send to PRIME each iteration (e.g. a Linear issue ref or free-form task)."
|
|
18
|
+
}),
|
|
19
|
+
maxIterations: option({
|
|
20
|
+
long: "max-iterations",
|
|
21
|
+
type: optional(numberType),
|
|
22
|
+
description: `Maximum number of loop iterations (default: ${MAX_ITERATIONS}).`
|
|
23
|
+
}),
|
|
24
|
+
timeout: option({
|
|
25
|
+
long: "timeout",
|
|
26
|
+
type: optional(numberType),
|
|
27
|
+
description: `Total wall-clock timeout in milliseconds (default: ${TIMEOUT_MS} = 4 hours).`
|
|
28
|
+
}),
|
|
29
|
+
stallTimeout: option({
|
|
30
|
+
long: "stall-timeout",
|
|
31
|
+
type: optional(numberType),
|
|
32
|
+
description: "Per-iteration stall timeout in milliseconds. Overrides the tier-based default (deep=30m, mid=15m, mid-execute/autopilot-execute=10m, fast=5m)."
|
|
33
|
+
}),
|
|
34
|
+
noDebrief: flag({
|
|
35
|
+
long: "no-debrief",
|
|
36
|
+
description: "Skip the post-run debrief session."
|
|
37
|
+
}),
|
|
38
|
+
notify: option({
|
|
39
|
+
long: "notify",
|
|
40
|
+
type: optional(stringType),
|
|
41
|
+
description: "Webhook URL to POST lifecycle events to (supports plain webhooks and Slack incoming webhooks)."
|
|
42
|
+
}),
|
|
43
|
+
debriefOnly: flag({
|
|
44
|
+
long: "debrief-only",
|
|
45
|
+
description: "Run the debrief against the most recent log file without re-executing the loop. (Not yet implemented \u2014 requires log-directory discovery.)"
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
handler: async ({ prompt, maxIterations, timeout, stallTimeout, noDebrief, notify, debriefOnly }) => {
|
|
49
|
+
const cwd = process.cwd();
|
|
50
|
+
let loopStarted = false;
|
|
51
|
+
const earlyExit = (signal) => {
|
|
52
|
+
if (loopStarted) return;
|
|
53
|
+
process.stderr.write(`
|
|
54
|
+
${signal} received before loop start \u2014 exiting
|
|
55
|
+
`);
|
|
56
|
+
process.exit(130);
|
|
57
|
+
};
|
|
58
|
+
const earlySigint = () => earlyExit("SIGINT");
|
|
59
|
+
const earlySigterm = () => earlyExit("SIGTERM");
|
|
60
|
+
process.on("SIGINT", earlySigint);
|
|
61
|
+
process.on("SIGTERM", earlySigterm);
|
|
62
|
+
if (debriefOnly) {
|
|
63
|
+
process.stderr.write(
|
|
64
|
+
"\x1B[33m\u26A0 --debrief-only is not yet implemented.\x1B[0m\n It requires discovering the most recent log file from the per-run log directory.\n The log directory convention is: <cwd>/.agent/autopilot-logs/<timestamp>.log\n To implement: read the most recent file from that directory and pass it to runDebrief.\n"
|
|
65
|
+
);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const willDebrief = shouldRunDebrief({ noDebrief, env: process.env });
|
|
69
|
+
const { OpenCodeAdapter } = await import("@glrs-dev/adapter-opencode");
|
|
70
|
+
const adapter = new OpenCodeAdapter();
|
|
71
|
+
const result = await runRalphLoop({
|
|
72
|
+
prompt,
|
|
73
|
+
cwd,
|
|
74
|
+
maxIterations: maxIterations ?? void 0,
|
|
75
|
+
timeoutMs: timeout ?? void 0,
|
|
76
|
+
stallMs: stallTimeout ?? void 0,
|
|
77
|
+
notifyUrl: notify ?? void 0,
|
|
78
|
+
keepAlive: willDebrief,
|
|
79
|
+
adapter
|
|
80
|
+
});
|
|
81
|
+
loopStarted = true;
|
|
82
|
+
process.removeListener("SIGINT", earlySigint);
|
|
83
|
+
process.removeListener("SIGTERM", earlySigterm);
|
|
84
|
+
const icon = result.exitReason === "sentinel" ? "\x1B[32m\u2713\x1B[0m" : result.exitReason === "kill-switch" ? "\x1B[33m\u2298\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
85
|
+
process.stdout.write(`
|
|
86
|
+
${icon} ${result.message}
|
|
87
|
+
`);
|
|
88
|
+
process.stdout.write(` Iterations: ${result.iterations}
|
|
89
|
+
|
|
90
|
+
`);
|
|
91
|
+
if (willDebrief) {
|
|
92
|
+
const loopHandle = result.agentHandle;
|
|
93
|
+
if (loopHandle) {
|
|
94
|
+
try {
|
|
95
|
+
await runDebrief({
|
|
96
|
+
agentHandle: loopHandle,
|
|
97
|
+
loopResult: result,
|
|
98
|
+
prompt,
|
|
99
|
+
cwd
|
|
100
|
+
});
|
|
101
|
+
} catch {
|
|
102
|
+
process.stderr.write("\x1B[33m\u26A0 Debrief failed (non-fatal)\x1B[0m\n");
|
|
103
|
+
} finally {
|
|
104
|
+
await loopHandle.adapter.shutdown(loopHandle.handle).catch(() => {
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
const debriefAdapter = new OpenCodeAdapter();
|
|
109
|
+
const debriefHandle = await debriefAdapter.start({ cwd });
|
|
110
|
+
try {
|
|
111
|
+
await runDebrief({
|
|
112
|
+
agentHandle: { adapter: debriefAdapter, handle: debriefHandle },
|
|
113
|
+
loopResult: result,
|
|
114
|
+
prompt,
|
|
115
|
+
cwd
|
|
116
|
+
});
|
|
117
|
+
} catch {
|
|
118
|
+
process.stderr.write("\x1B[33m\u26A0 Debrief agent failed to start (non-fatal)\x1B[0m\n");
|
|
119
|
+
} finally {
|
|
120
|
+
await debriefAdapter.shutdown(debriefHandle).catch(() => {
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (result.exitReason !== "sentinel" && result.exitReason !== "kill-switch") {
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
export {
|
|
132
|
+
loopCmd
|
|
133
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive file picker for plan files.
|
|
3
|
+
*
|
|
4
|
+
* Starts at the given root directory, shows .md files and subdirectories.
|
|
5
|
+
* The user can drill into directories or select a file. Returns the
|
|
6
|
+
* absolute path to the selected file, or null if cancelled.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Browse for a plan file starting at `rootDir`.
|
|
10
|
+
* Returns the absolute path to the selected .md file or directory
|
|
11
|
+
* (if it contains main.md), or null if the user cancels.
|
|
12
|
+
*/
|
|
13
|
+
declare function pickPlanFile(rootDir: string): Promise<string | null>;
|
|
14
|
+
|
|
15
|
+
export { pickPlanFile };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import "../chunk-3RG5ZIWI.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/plan-picker.ts
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
async function pickPlanFile(rootDir) {
|
|
7
|
+
const { select } = await import("@inquirer/prompts");
|
|
8
|
+
let currentDir = path.resolve(rootDir);
|
|
9
|
+
while (true) {
|
|
10
|
+
let entries;
|
|
11
|
+
try {
|
|
12
|
+
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
17
|
+
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name).sort();
|
|
18
|
+
if (dirs.length === 0 && files.length === 0) {
|
|
19
|
+
process.stderr.write(` No .md files found in ${currentDir}
|
|
20
|
+
`);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const choices = [];
|
|
24
|
+
for (const d of dirs) {
|
|
25
|
+
const dirPath = path.join(currentDir, d);
|
|
26
|
+
const hasMain = fs.existsSync(path.join(dirPath, "main.md"));
|
|
27
|
+
if (hasMain) {
|
|
28
|
+
const phaseCount = fs.readdirSync(dirPath).filter(
|
|
29
|
+
(f) => f.endsWith(".md") && f !== "main.md" && f !== "scope.md" && f !== "scope-seed.md"
|
|
30
|
+
).length;
|
|
31
|
+
choices.push({
|
|
32
|
+
name: `\u{1F4CB} ${d}/ (plan: main.md + ${phaseCount} phases)`,
|
|
33
|
+
value: `plan:${dirPath}`
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
choices.push({
|
|
37
|
+
name: `\u{1F4C1} ${d}/`,
|
|
38
|
+
value: `dir:${dirPath}`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const f of files) {
|
|
43
|
+
choices.push({
|
|
44
|
+
name: ` ${f}`,
|
|
45
|
+
value: `file:${path.join(currentDir, f)}`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (currentDir !== path.resolve(rootDir)) {
|
|
49
|
+
choices.push({ name: "\u21A9 Back", value: "back" });
|
|
50
|
+
}
|
|
51
|
+
choices.push({ name: "\u2715 Cancel", value: "cancel" });
|
|
52
|
+
const relDir = path.relative(rootDir, currentDir) || ".";
|
|
53
|
+
const answer = await select({
|
|
54
|
+
message: `Select a plan (${relDir}):`,
|
|
55
|
+
choices
|
|
56
|
+
});
|
|
57
|
+
if (answer === "cancel") return null;
|
|
58
|
+
if (answer === "back") {
|
|
59
|
+
currentDir = path.dirname(currentDir);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (answer.startsWith("plan:")) {
|
|
63
|
+
return answer.slice("plan:".length);
|
|
64
|
+
}
|
|
65
|
+
if (answer.startsWith("file:")) {
|
|
66
|
+
return answer.slice("file:".length);
|
|
67
|
+
}
|
|
68
|
+
if (answer.startsWith("dir:")) {
|
|
69
|
+
currentDir = answer.slice("dir:".length);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
pickPlanFile
|
|
76
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ScoperSessionOptions, ScoperSessionResult } from '@glrs-dev/autopilot';
|
|
2
|
+
export { ScoperSessionOptions, ScoperSessionResult } from '@glrs-dev/autopilot';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Scoper session runner — inquirer-driven wizard loop.
|
|
6
|
+
*
|
|
7
|
+
* Starts an opencode server + creates a persistent @scoper session.
|
|
8
|
+
* Sends the user's initial goal as the first prompt, then drives a
|
|
9
|
+
* wizard loop:
|
|
10
|
+
*
|
|
11
|
+
* 1. Wait for the agent's response (idle).
|
|
12
|
+
* 2. Parse the response:
|
|
13
|
+
* - Question (≤200 chars, ends with '?') → prompt the user via
|
|
14
|
+
* inquirer, send the answer back, repeat.
|
|
15
|
+
* - SCOPE_COMPLETE sentinel → validate scope.md exists, return path.
|
|
16
|
+
* - Parse error → retry once with a reminder; second failure throws.
|
|
17
|
+
* 3. Hard cap: after 8 user answers, send a forced-finalize message.
|
|
18
|
+
* If the agent still doesn't emit the sentinel, throw.
|
|
19
|
+
*
|
|
20
|
+
* autoRejectPermissions: true — the question tool is disabled at the
|
|
21
|
+
* agent level, but we defend in depth.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Parse a question from an agent response.
|
|
25
|
+
* A valid question is a single line, ≤200 chars, ending with '?'.
|
|
26
|
+
* Returns the question string, or null if the response is not a question.
|
|
27
|
+
*/
|
|
28
|
+
declare function parseQuestion(response: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Parse a scope summary from an agent response.
|
|
31
|
+
* A valid summary starts with 'SCOPE_SUMMARY:' on the first line,
|
|
32
|
+
* followed by the summary text on subsequent lines.
|
|
33
|
+
* Returns the summary text (without the prefix), or null.
|
|
34
|
+
*/
|
|
35
|
+
declare function parseScopeSummary(response: string): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Extract the scope.md path from the SCOPE_COMPLETE sentinel line.
|
|
38
|
+
* Returns the path string, or null if no sentinel is found.
|
|
39
|
+
*
|
|
40
|
+
* Uses the LAST occurrence if multiple sentinel lines appear (the
|
|
41
|
+
* agent may emit intermediate progress lines before the final one).
|
|
42
|
+
*/
|
|
43
|
+
declare function extractScopeCompletePath(output: string): string | null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Run the @scoper wizard loop.
|
|
47
|
+
*
|
|
48
|
+
* Starts an opencode server, creates a persistent session with @scoper,
|
|
49
|
+
* sends the initial goal prompt, then drives the wizard loop until the
|
|
50
|
+
* agent emits SCOPE_COMPLETE or the hard cap is reached.
|
|
51
|
+
*/
|
|
52
|
+
declare function runScoperSession(opts: ScoperSessionOptions): Promise<ScoperSessionResult>;
|
|
53
|
+
|
|
54
|
+
export { extractScopeCompletePath, parseQuestion, parseScopeSummary, runScoperSession };
|