@glrs-dev/cli 2.3.0 → 2.4.1

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{chunk-EM4MJBOD.js → chunk-2AZKRWC6.js} +4 -4
  3. package/dist/{chunk-UXBOTMDY.js → chunk-2P3ETOT2.js} +2 -2
  4. package/dist/chunk-2VMFXAJH.js +795 -0
  5. package/dist/chunk-5ZVUFNCP.js +140 -0
  6. package/dist/{chunk-W37UX3U2.js → chunk-6Y27RQQL.js} +2 -2
  7. package/dist/{chunk-RZWOWTKF.js → chunk-EKNRKZWR.js} +4 -4
  8. package/dist/{chunk-YGNDPKIW.js → chunk-HQUCVJ4G.js} +3 -1
  9. package/dist/{chunk-OABVEBWW.js → chunk-MBEVC327.js} +1 -1
  10. package/dist/{chunk-MIWZLETC.js → chunk-MCM47HH4.js} +1 -1
  11. package/dist/{chunk-F3AFRUT2.js → chunk-PTIO556V.js} +2 -2
  12. package/dist/{chunk-E2UNZIZT.js → chunk-R2WXQ54P.js} +1 -1
  13. package/dist/{chunk-I2KUXY3I.js → chunk-SMDIOB5B.js} +2 -2
  14. package/dist/{chunk-SPULDN7P.js → chunk-YY7EWHMA.js} +5 -3
  15. package/dist/cli.js +31 -20
  16. package/dist/commands/autopilot-interactive.d.ts +89 -0
  17. package/dist/commands/autopilot-interactive.js +248 -0
  18. package/dist/commands/autopilot-raw.d.ts +1 -0
  19. package/dist/commands/autopilot-raw.js +368 -0
  20. package/dist/commands/autopilot-tui.d.ts +7 -0
  21. package/dist/commands/autopilot-tui.js +7 -0
  22. package/dist/commands/autopilot.d.ts +39 -0
  23. package/dist/commands/autopilot.js +395 -0
  24. package/dist/commands/cleanup.js +3 -3
  25. package/dist/commands/create.js +4 -4
  26. package/dist/commands/dashboard.d.ts +3 -0
  27. package/dist/commands/dashboard.js +1549 -0
  28. package/dist/commands/debrief.d.ts +57 -0
  29. package/dist/commands/debrief.js +9 -0
  30. package/dist/commands/delete.js +3 -3
  31. package/dist/commands/go.js +2 -2
  32. package/dist/commands/list.js +3 -3
  33. package/dist/commands/loop.d.ts +42 -0
  34. package/dist/commands/loop.js +133 -0
  35. package/dist/commands/plan-picker.d.ts +15 -0
  36. package/dist/commands/plan-picker.js +76 -0
  37. package/dist/commands/scoper.d.ts +54 -0
  38. package/dist/{vendor/harness-opencode/dist/scoper-S77SOK7X.js → commands/scoper.js} +30 -15
  39. package/dist/commands/switch.js +3 -3
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.js +1 -1
  42. package/dist/lib/auto-update.js +1 -1
  43. package/dist/lib/config.d.ts +3 -2
  44. package/dist/lib/config.js +1 -1
  45. package/dist/lib/registry.d.ts +2 -0
  46. package/dist/lib/registry.js +1 -1
  47. package/dist/lib/worktree.js +3 -3
  48. package/dist/node_modules/@glrs-dev/adapter-opencode/dist/index.d.ts +261 -0
  49. package/dist/node_modules/@glrs-dev/adapter-opencode/dist/index.js +488 -0
  50. package/dist/node_modules/@glrs-dev/adapter-opencode/package.json +8 -0
  51. package/dist/node_modules/@glrs-dev/autopilot/dist/auto-ship-LCT6LIH7.js +7 -0
  52. package/dist/node_modules/@glrs-dev/autopilot/dist/changeset-generator-DG3MVWVV.js +15 -0
  53. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-7OSEI5TF.js +249 -0
  54. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-E7PWTRFO.js +91 -0
  55. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-M2ZVBPWL.js +101 -0
  56. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-Q4ULU6ER.js +68 -0
  57. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-VITL2Z45.js +2772 -0
  58. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-ZNJWARTM.js +449 -0
  59. package/dist/node_modules/@glrs-dev/autopilot/dist/index.d.ts +1765 -0
  60. package/dist/node_modules/@glrs-dev/autopilot/dist/index.js +688 -0
  61. package/dist/node_modules/@glrs-dev/autopilot/dist/logger-UITJGIZE.js +8 -0
  62. package/dist/node_modules/@glrs-dev/autopilot/dist/loop-session-XKL3NHUA.js +8 -0
  63. package/dist/node_modules/@glrs-dev/autopilot/dist/plan-enrichment-D3RPJR2J.js +14 -0
  64. package/dist/node_modules/@glrs-dev/autopilot/package.json +8 -0
  65. package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +7 -0
  66. package/dist/vendor/harness-opencode/dist/chunk-GILWWWMB.js +66 -0
  67. package/dist/vendor/harness-opencode/dist/cli.js +335 -639
  68. package/dist/vendor/harness-opencode/dist/index.js +35 -8
  69. package/dist/vendor/harness-opencode/dist/plugin-check-GJRD2OK6.js +14 -0
  70. package/dist/vendor/harness-opencode/package.json +1 -1
  71. package/package.json +14 -6
  72. package/dist/vendor/harness-opencode/dist/autopilot/prompt-template.md +0 -104
  73. package/dist/vendor/harness-opencode/dist/chunk-GCWHRUOK.js +0 -259
  74. package/dist/vendor/harness-opencode/dist/chunk-MJSMBY2Y.js +0 -87
  75. package/dist/vendor/harness-opencode/dist/chunk-NIFAVPNN.js +0 -544
  76. package/dist/vendor/harness-opencode/dist/loop-session-J35NILUZ.js +0 -30
  77. package/dist/vendor/harness-opencode/dist/opencode-server-KPCDFYAX.js +0 -22
  78. package/dist/vendor/harness-opencode/dist/plan-parser-TMHEKT22.js +0 -6
  79. package/dist/vendor/harness-opencode/dist/plan-session-7VS32P52.js +0 -117
@@ -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 };
@@ -0,0 +1,9 @@
1
+ import {
2
+ runDebrief,
3
+ shouldRunDebrief
4
+ } from "../chunk-5ZVUFNCP.js";
5
+ import "../chunk-3RG5ZIWI.js";
6
+ export {
7
+ runDebrief,
8
+ shouldRunDebrief
9
+ };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  del
3
- } from "../chunk-RZWOWTKF.js";
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-SPULDN7P.js";
7
+ import "../chunk-YY7EWHMA.js";
8
8
  import "../chunk-YBCA3IP6.js";
9
9
  import "../chunk-3RG5ZIWI.js";
10
10
  export {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  go
3
- } from "../chunk-E2UNZIZT.js";
3
+ } from "../chunk-R2WXQ54P.js";
4
4
  import "../chunk-P7PRH4I3.js";
5
5
  import "../chunk-LMRDQ4GW.js";
6
- import "../chunk-SPULDN7P.js";
6
+ import "../chunk-YY7EWHMA.js";
7
7
  import "../chunk-YBCA3IP6.js";
8
8
  import "../chunk-3RG5ZIWI.js";
9
9
  export {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  list
3
- } from "../chunk-I2KUXY3I.js";
4
- import "../chunk-E2UNZIZT.js";
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-SPULDN7P.js";
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 };
@@ -1,13 +1,14 @@
1
- import {
2
- createSession,
3
- getLastAssistantMessage,
4
- sendAndWait,
5
- startServer
6
- } from "./chunk-GCWHRUOK.js";
1
+ import "../chunk-3RG5ZIWI.js";
7
2
 
8
- // src/autopilot/scoper.ts
3
+ // src/commands/scoper.ts
9
4
  import * as fs from "fs";
10
5
  import * as path from "path";
6
+ import {
7
+ startServer,
8
+ createSession,
9
+ sendAndWait,
10
+ getLastAssistantMessage
11
+ } from "@glrs-dev/adapter-opencode";
11
12
  var ANSI_RESET = "\x1B[0m\x1B[2K\r";
12
13
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
13
14
  function createSpinner() {
@@ -61,12 +62,13 @@ var FORCED_FINALIZE_MESSAGE = "You have asked enough questions. Present a SCOPE_
61
62
  var PARSE_RETRY_REMINDER = "Your last response did not follow the strict contract. Respond with EXACTLY one of: (a) a single question (\u2264200 chars, ending with '?'), (b) a scope summary starting with 'SCOPE_SUMMARY:', or (c) the sentinel 'SCOPE_COMPLETE: <absolute-path>'. Nothing else.";
62
63
  async function runScoperSession(opts) {
63
64
  const timeoutMs = opts.timeoutMs ?? DEFAULT_SCOPER_TIMEOUT_MS;
64
- const _startServer = opts._deps?.startServer ?? startServer;
65
- const _createSession = opts._deps?.createSession ?? createSession;
66
- const _sendAndWait = opts._deps?.sendAndWait ?? sendAndWait;
67
- const _getLastAssistantMessage = opts._deps?.getLastAssistantMessage ?? getLastAssistantMessage;
68
- const _existsSync = opts._deps?.existsSync ?? fs.existsSync;
69
- const _promptUser = opts._deps?.promptUser ?? (async (question) => {
65
+ const deps = opts._deps;
66
+ const _startServer = deps?.startServer ?? startServer;
67
+ const _createSession = deps?.createSession ?? createSession;
68
+ const _sendAndWait = deps?.sendAndWait ?? sendAndWait;
69
+ const _getLastAssistantMessage = deps?.getLastAssistantMessage ?? getLastAssistantMessage;
70
+ const _existsSync = deps?.existsSync ?? fs.existsSync;
71
+ const _promptUser = deps?.promptUser ?? (async (question) => {
70
72
  const { input } = await import("@inquirer/prompts");
71
73
  return input({ message: question });
72
74
  });
@@ -77,7 +79,7 @@ async function runScoperSession(opts) {
77
79
  cwd: opts.planDir,
78
80
  agentName: "scoper"
79
81
  });
80
- const initialPrompt = [
82
+ const initialPromptParts = [
81
83
  "You are running in an inquirer-driven wizard. Follow the strict response contract:",
82
84
  "- Every response must be EXACTLY one of:",
83
85
  " (a) A single question (\u2264200 chars, ending with '?')",
@@ -89,7 +91,20 @@ async function runScoperSession(opts) {
89
91
  `The user wants to build: ${opts.initialGoal}`,
90
92
  "",
91
93
  "Begin by asking your first clarifying question about the problem being solved."
92
- ].join("\n");
94
+ ];
95
+ if (opts.existingPlanContent) {
96
+ initialPromptParts.push(
97
+ "",
98
+ "The user has an existing plan. Use it as context for your scoping questions:",
99
+ "",
100
+ "---",
101
+ opts.existingPlanContent,
102
+ "---",
103
+ "",
104
+ "Validate this plan against the codebase and ask clarifying questions about gaps or stale assumptions."
105
+ );
106
+ }
107
+ const initialPrompt = initialPromptParts.join("\n");
93
108
  spinner.start("Scoper is thinking");
94
109
  const firstResult = await _sendAndWait(server.client, {
95
110
  sessionId,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  switchCmd
3
- } from "../chunk-OABVEBWW.js";
4
- import "../chunk-E2UNZIZT.js";
3
+ } from "../chunk-MBEVC327.js";
4
+ import "../chunk-R2WXQ54P.js";
5
5
  import "../chunk-P7PRH4I3.js";
6
6
  import "../chunk-LMRDQ4GW.js";
7
- import "../chunk-SPULDN7P.js";
7
+ import "../chunk-YY7EWHMA.js";
8
8
  import "../chunk-YBCA3IP6.js";
9
9
  import "../chunk-3RG5ZIWI.js";
10
10
  export {
package/dist/index.d.ts CHANGED
@@ -24,7 +24,7 @@ interface ResolvedBin {
24
24
  }
25
25
  declare function resolveSubcommand(sub: Subcommand): ResolvedBin;
26
26
  declare const SUBCOMMANDS: Subcommand[];
27
- declare const HELP_TEXT = "glrs \u2014 unified CLI for the @glrs-dev ecosystem\n\nUSAGE\n glrs <subcommand> [args...]\n\nSUBCOMMANDS\n oc OpenCode agent harness (install, pilot, etc.)\n wt Worktree management (create, list, switch, delete, cleanup)\n\nRun 'glrs <subcommand> --help' for per-command help.\n\nEXAMPLES\n glrs oc install\n glrs wt new\n glrs wt list\n glrs wt switch\n\nREQUIREMENTS\n Bun >= 1.2.0 on PATH (install: https://bun.sh)\n\nDOCS https://glrs.dev\nISSUES https://github.com/iceglober/glrs/issues\n";
28
- declare const WORKTREE_HELP_TEXT = "glrs wt \u2014 worktree management\n\nUSAGE\n glrs wt <command> [args...]\n\nCOMMANDS\n new Create a new worktree (auto-named from origin/default)\n list, ls List all worktrees across repos\n switch, sw Interactively select and switch to a worktree\n delete, rm Remove worktrees (interactive or by name)\n cleanup Delete merged/stale worktrees\n\nEXAMPLES\n glrs wt new # Create worktree in current repo\n glrs wt new myrepo # Create worktree for named repo\n glrs wt list # Show all worktrees\n glrs wt list -i # Interactive picker\n glrs wt switch # Interactive switcher\n glrs wt delete my-branch # Delete specific worktree\n glrs wt cleanup # Clean up merged worktrees\n\nWorktrees are stored in ~/.glorious/worktrees/<repo>/<name>/\n";
27
+ declare const HELP_TEXT = "glrs \u2014 unified CLI for the @glrs-dev ecosystem\n\nUSAGE\n glrs <subcommand> [args...]\n\nSUBCOMMANDS\n oc OpenCode agent harness (install, pilot, etc.)\n wt Worktree management (create, list, switch, delete, cleanup)\n dashboard Live TUI dashboard for all running autopilot sessions\n\nRun 'glrs <subcommand> --help' for per-command help.\n\nEXAMPLES\n glrs oc install\n glrs wt new\n glrs wt list\n glrs wt switch\n glrs dashboard\n\nREQUIREMENTS\n Bun >= 1.2.0 on PATH (install: https://bun.sh)\n\nDOCS https://glrs.dev\nISSUES https://github.com/iceglober/glrs/issues\n";
28
+ declare const WORKTREE_HELP_TEXT = "glrs wt \u2014 worktree management\n\nUSAGE\n glrs wt <command> [args...]\n\nCOMMANDS\n new Create a new worktree (auto-named from origin/default)\n list, ls List all worktrees across repos\n switch, sw Interactively select and switch to a worktree\n delete, rm Remove worktrees (interactive or by name)\n cleanup Delete merged/stale worktrees\n\nEXAMPLES\n glrs wt new # Create worktree in current repo\n glrs wt new myrepo # Create worktree for named repo\n glrs wt list # Show all worktrees\n glrs wt list -i # Interactive picker\n glrs wt switch # Interactive switcher\n glrs wt delete my-branch # Delete specific worktree\n glrs wt cleanup # Clean up merged worktrees\n\nWorktrees are stored in ~/.glrs/worktrees/<repo>/<name>/\n";
29
29
 
30
30
  export { HELP_TEXT, type ResolvedBin, SUBCOMMANDS, type Subcommand, WORKTREE_HELP_TEXT, resolveSubcommand };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  SUBCOMMANDS,
4
4
  WORKTREE_HELP_TEXT,
5
5
  resolveSubcommand
6
- } from "./chunk-YGNDPKIW.js";
6
+ } from "./chunk-HQUCVJ4G.js";
7
7
  import "./chunk-3RG5ZIWI.js";
8
8
  export {
9
9
  HELP_TEXT,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  autoUpdate
3
- } from "../chunk-MIWZLETC.js";
3
+ } from "../chunk-MCM47HH4.js";
4
4
  import "../chunk-3RG5ZIWI.js";
5
5
  export {
6
6
  autoUpdate
@@ -6,8 +6,9 @@ declare function worktreesRoot(repo: string): string;
6
6
  /**
7
7
  * Resolve where a worktree should live.
8
8
  *
9
- * Default: ~/.glorious/worktrees/<repo>/<name>
10
- * If GLORIOUS_DIR is set: $GLORIOUS_DIR/<repo>/<name>
9
+ * Default: ~/.glrs/worktrees/<repo>/<name>
10
+ * If GLRS_DIR is set: $GLRS_DIR/<repo>/<name>
11
+ * If GLORIOUS_DIR is set (legacy): $GLORIOUS_DIR/<repo>/<name>
11
12
  */
12
13
  declare function worktreePath(name: string, repo?: string): string;
13
14
 
@@ -3,7 +3,7 @@ import {
3
3
  repoName,
4
4
  worktreePath,
5
5
  worktreesRoot
6
- } from "../chunk-W37UX3U2.js";
6
+ } from "../chunk-6Y27RQQL.js";
7
7
  import "../chunk-LMRDQ4GW.js";
8
8
  import "../chunk-3RG5ZIWI.js";
9
9
  export {
@@ -6,6 +6,8 @@ interface RegistryEntry {
6
6
  createdAt: string;
7
7
  }
8
8
  /** Load registry, pruning entries whose worktree paths no longer exist. */
9
+ /** Load registry, pruning entries whose worktree paths no longer exist.
10
+ * Checks ~/.glrs/worktrees.json first; falls back to ~/.glorious/worktrees.json. */
9
11
  declare function loadRegistry(): RegistryEntry[];
10
12
  declare function saveRegistry(entries: RegistryEntry[]): void;
11
13
  declare function registerWorktree(entry: RegistryEntry): void;
@@ -3,7 +3,7 @@ import {
3
3
  registerWorktree,
4
4
  saveRegistry,
5
5
  unregisterWorktree
6
- } from "../chunk-SPULDN7P.js";
6
+ } from "../chunk-YY7EWHMA.js";
7
7
  import "../chunk-3RG5ZIWI.js";
8
8
  export {
9
9
  loadRegistry,
@@ -3,10 +3,10 @@ import {
3
3
  autoName,
4
4
  createWorktree,
5
5
  ensureWorktree
6
- } from "../chunk-F3AFRUT2.js";
7
- import "../chunk-W37UX3U2.js";
6
+ } from "../chunk-PTIO556V.js";
7
+ import "../chunk-6Y27RQQL.js";
8
8
  import "../chunk-LMRDQ4GW.js";
9
- import "../chunk-SPULDN7P.js";
9
+ import "../chunk-YY7EWHMA.js";
10
10
  import "../chunk-YBCA3IP6.js";
11
11
  import "../chunk-3RG5ZIWI.js";
12
12
  export {