@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,140 @@
|
|
|
1
|
+
// src/commands/debrief.ts
|
|
2
|
+
function shouldRunDebrief(opts) {
|
|
3
|
+
if (opts.noDebrief) return false;
|
|
4
|
+
const envVal = opts.env["GLRS_AUTOPILOT_DEBRIEF"];
|
|
5
|
+
if (envVal !== void 0 && envVal.toLowerCase() === "off") return false;
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
async function defaultExecGitDiffStat(cwd) {
|
|
9
|
+
const { execFile: execFileCb } = await import("child_process");
|
|
10
|
+
const { promisify } = await import("util");
|
|
11
|
+
const execFile = promisify(execFileCb);
|
|
12
|
+
try {
|
|
13
|
+
const { stdout } = await execFile("git", ["diff", "--stat", "HEAD~1", "HEAD"], { cwd });
|
|
14
|
+
return stdout.trim();
|
|
15
|
+
} catch {
|
|
16
|
+
try {
|
|
17
|
+
const { stdout } = await execFile("git", ["diff", "--stat"], { cwd });
|
|
18
|
+
return stdout.trim() || "(no uncommitted changes)";
|
|
19
|
+
} catch {
|
|
20
|
+
return "(git diff unavailable)";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function buildContextMessage(loopResult, prompt, gitDiffStat) {
|
|
25
|
+
const cost = loopResult.cumulativeCostUsd !== void 0 ? `$${loopResult.cumulativeCostUsd.toFixed(4)}` : "not available";
|
|
26
|
+
const sessionId = loopResult.sessionId ?? "not available";
|
|
27
|
+
const lines = [
|
|
28
|
+
"## Autopilot session context",
|
|
29
|
+
"",
|
|
30
|
+
`**Exit reason:** ${loopResult.exitReason}`,
|
|
31
|
+
`**Iterations completed:** ${loopResult.iterations}`,
|
|
32
|
+
`**Exit message:** ${loopResult.message}`,
|
|
33
|
+
`**Cumulative cost:** ${cost}`,
|
|
34
|
+
`**Session ID:** ${sessionId}`
|
|
35
|
+
];
|
|
36
|
+
if (loopResult.phaseBreakdown && loopResult.phaseBreakdown.length > 0) {
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push("## Per-phase cost breakdown");
|
|
39
|
+
lines.push("");
|
|
40
|
+
for (const phase of loopResult.phaseBreakdown) {
|
|
41
|
+
const phaseCost = phase.costUsd > 0 ? `$${phase.costUsd.toFixed(4)}` : "n/a";
|
|
42
|
+
lines.push(`- **${phase.phaseFile}**: ${phase.iterations} iteration(s), ${phaseCost}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (loopResult.laneCosts && loopResult.laneCosts.size > 1) {
|
|
46
|
+
lines.push("");
|
|
47
|
+
lines.push("## Per-lane cost breakdown");
|
|
48
|
+
lines.push("");
|
|
49
|
+
const sortedLanes = [...loopResult.laneCosts.entries()].sort(
|
|
50
|
+
([a], [b]) => a.localeCompare(b)
|
|
51
|
+
);
|
|
52
|
+
let total = 0;
|
|
53
|
+
for (const [laneId, laneCost] of sortedLanes) {
|
|
54
|
+
total += laneCost;
|
|
55
|
+
const fmt = laneCost > 0 ? `$${laneCost.toFixed(4)}` : "n/a";
|
|
56
|
+
lines.push(`- **${laneId}**: ${fmt}`);
|
|
57
|
+
}
|
|
58
|
+
lines.push(`- **total**: $${total.toFixed(4)}`);
|
|
59
|
+
}
|
|
60
|
+
if (loopResult.orphanedWorktrees && loopResult.orphanedWorktrees.length > 0) {
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push("## Orphaned worktrees");
|
|
63
|
+
lines.push("");
|
|
64
|
+
lines.push(
|
|
65
|
+
"The following worktrees survived the run because their merge failed."
|
|
66
|
+
);
|
|
67
|
+
lines.push("Resolve manually with `git worktree remove --force <path>`.");
|
|
68
|
+
lines.push("");
|
|
69
|
+
for (const wt of loopResult.orphanedWorktrees) {
|
|
70
|
+
lines.push(`- ${wt}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (loopResult.verifyResults && loopResult.verifyResults.length > 0) {
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("## Verify command results");
|
|
76
|
+
lines.push("");
|
|
77
|
+
for (const phase of loopResult.verifyResults) {
|
|
78
|
+
const passed = phase.results.filter((r) => r.passed).length;
|
|
79
|
+
const total = phase.results.length;
|
|
80
|
+
lines.push(`### ${phase.phaseFile} \u2014 ${passed}/${total} passed`);
|
|
81
|
+
lines.push("");
|
|
82
|
+
lines.push("| Item | Command | Result | Duration |");
|
|
83
|
+
lines.push("| --- | --- | --- | --- |");
|
|
84
|
+
for (const r of phase.results) {
|
|
85
|
+
const cmd = r.command.length > 60 ? r.command.slice(0, 57) + "..." : r.command;
|
|
86
|
+
const status = r.passed ? "\u2713 pass" : "\u2717 fail";
|
|
87
|
+
const dur = r.durationMs < 1e3 ? `${r.durationMs}ms` : `${(r.durationMs / 1e3).toFixed(1)}s`;
|
|
88
|
+
lines.push(`| ${r.itemId} | \`${cmd}\` | ${status} | ${dur} |`);
|
|
89
|
+
}
|
|
90
|
+
lines.push("");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
lines.push(
|
|
94
|
+
"",
|
|
95
|
+
"## Original prompt",
|
|
96
|
+
"",
|
|
97
|
+
prompt,
|
|
98
|
+
"",
|
|
99
|
+
"## Git diff stat (last commit vs HEAD~1)",
|
|
100
|
+
"",
|
|
101
|
+
gitDiffStat || "(no changes)",
|
|
102
|
+
"",
|
|
103
|
+
"---",
|
|
104
|
+
"",
|
|
105
|
+
"Please produce the five-section debrief as instructed in your system prompt."
|
|
106
|
+
);
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
async function runDebrief(opts) {
|
|
110
|
+
const _execGitDiffStat = opts._deps?.execGitDiffStat ?? defaultExecGitDiffStat;
|
|
111
|
+
const { adapter, handle } = opts.agentHandle;
|
|
112
|
+
try {
|
|
113
|
+
const gitDiffStat = await _execGitDiffStat(opts.cwd).catch(() => "(git diff unavailable)");
|
|
114
|
+
const contextMessage = buildContextMessage(opts.loopResult, opts.prompt, gitDiffStat);
|
|
115
|
+
const sessionId = await adapter.createSession(handle, {
|
|
116
|
+
agentName: "debriefer"
|
|
117
|
+
});
|
|
118
|
+
await adapter.sendAndWait(handle, {
|
|
119
|
+
sessionId,
|
|
120
|
+
message: contextMessage,
|
|
121
|
+
stallMs: 5 * 60 * 1e3
|
|
122
|
+
// 5 min stall timeout for debrief
|
|
123
|
+
});
|
|
124
|
+
const debriefOutput = await adapter.getLastResponse(handle, sessionId);
|
|
125
|
+
if (debriefOutput) {
|
|
126
|
+
process.stdout.write("\n\x1B[1m\u2500\u2500\u2500 Autopilot Debrief \u2500\u2500\u2500\x1B[0m\n\n");
|
|
127
|
+
process.stdout.write(debriefOutput);
|
|
128
|
+
process.stdout.write("\n\n");
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
132
|
+
process.stderr.write(`\x1B[33m\u26A0 Debrief failed (non-fatal): ${msg}\x1B[0m
|
|
133
|
+
`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export {
|
|
138
|
+
shouldRunDebrief,
|
|
139
|
+
runDebrief
|
|
140
|
+
};
|
|
@@ -18,9 +18,9 @@ function repoName() {
|
|
|
18
18
|
return path.basename(gitRoot());
|
|
19
19
|
}
|
|
20
20
|
function worktreesRoot(repo) {
|
|
21
|
-
const override = process.env.GLORIOUS_DIR;
|
|
21
|
+
const override = process.env.GLRS_DIR ?? process.env.GLORIOUS_DIR;
|
|
22
22
|
if (override) return path.resolve(override, repo);
|
|
23
|
-
return path.join(os.homedir(), ".
|
|
23
|
+
return path.join(os.homedir(), ".glrs", "worktrees", repo);
|
|
24
24
|
}
|
|
25
25
|
function worktreePath(name, repo) {
|
|
26
26
|
const repoKey = repo ?? repoName();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
worktreePath
|
|
3
|
-
} from "./chunk-W37UX3U2.js";
|
|
4
1
|
import {
|
|
5
2
|
multiSelect
|
|
6
3
|
} from "./chunk-P7PRH4I3.js";
|
|
4
|
+
import {
|
|
5
|
+
worktreePath
|
|
6
|
+
} from "./chunk-6Y27RQQL.js";
|
|
7
7
|
import {
|
|
8
8
|
gitIn,
|
|
9
9
|
gitInSafe,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
loadRegistry,
|
|
15
15
|
unregisterWorktree
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YY7EWHMA.js";
|
|
17
17
|
import {
|
|
18
18
|
bold,
|
|
19
19
|
dim,
|
|
@@ -52,6 +52,7 @@ USAGE
|
|
|
52
52
|
SUBCOMMANDS
|
|
53
53
|
oc OpenCode agent harness (install, pilot, etc.)
|
|
54
54
|
wt Worktree management (create, list, switch, delete, cleanup)
|
|
55
|
+
dashboard Live TUI dashboard for all running autopilot sessions
|
|
55
56
|
|
|
56
57
|
Run 'glrs <subcommand> --help' for per-command help.
|
|
57
58
|
|
|
@@ -60,6 +61,7 @@ EXAMPLES
|
|
|
60
61
|
glrs wt new
|
|
61
62
|
glrs wt list
|
|
62
63
|
glrs wt switch
|
|
64
|
+
glrs dashboard
|
|
63
65
|
|
|
64
66
|
REQUIREMENTS
|
|
65
67
|
Bun >= 1.2.0 on PATH (install: https://bun.sh)
|
|
@@ -88,7 +90,7 @@ EXAMPLES
|
|
|
88
90
|
glrs wt delete my-branch # Delete specific worktree
|
|
89
91
|
glrs wt cleanup # Clean up merged worktrees
|
|
90
92
|
|
|
91
|
-
Worktrees are stored in ~/.
|
|
93
|
+
Worktrees are stored in ~/.glrs/worktrees/<repo>/<name>/
|
|
92
94
|
`;
|
|
93
95
|
|
|
94
96
|
export {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// src/lib/auto-update.ts
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
3
|
+
import { join, sep } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { execFileSync } from "child_process";
|
|
6
6
|
var PACKAGE_NAME = "@glrs-dev/cli";
|
|
7
7
|
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
8
8
|
var REGISTRY_TIMEOUT_MS = 3e3;
|
|
9
9
|
function getStateDir() {
|
|
10
|
-
const dir = join(homedir(), ".
|
|
10
|
+
const dir = join(homedir(), ".glrs", "cli");
|
|
11
11
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
12
12
|
return dir;
|
|
13
13
|
}
|
|
@@ -63,10 +63,15 @@ function isNewer(current, latest) {
|
|
|
63
63
|
if (lMin < cMin) return false;
|
|
64
64
|
return lPat > cPat;
|
|
65
65
|
}
|
|
66
|
+
function isRunningFromDevCheckout() {
|
|
67
|
+
const resolvedDir = realpathSync(import.meta.dir);
|
|
68
|
+
return !resolvedDir.includes(`${sep}node_modules${sep}`);
|
|
69
|
+
}
|
|
66
70
|
async function autoUpdate() {
|
|
67
71
|
if (process.env["GLRS_AUTO_UPDATE"] === "0") return false;
|
|
68
72
|
if (process.env["CI"]) return false;
|
|
69
73
|
if (process.env["GLRS_UPDATING"] === "1") return false;
|
|
74
|
+
if (isRunningFromDevCheckout()) return false;
|
|
70
75
|
const currentVersion = getCurrentVersion();
|
|
71
76
|
if (!currentVersion) return false;
|
|
72
77
|
const state = readState();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
repoName,
|
|
3
3
|
worktreePath
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6Y27RQQL.js";
|
|
5
5
|
import {
|
|
6
6
|
defaultBranchIn,
|
|
7
7
|
gitIn,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-LMRDQ4GW.js";
|
|
11
11
|
import {
|
|
12
12
|
registerWorktree
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YY7EWHMA.js";
|
|
14
14
|
import {
|
|
15
15
|
bold,
|
|
16
16
|
info,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
go
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-R2WXQ54P.js";
|
|
4
4
|
import {
|
|
5
5
|
currentBranchIn,
|
|
6
6
|
gitInSafe,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-LMRDQ4GW.js";
|
|
11
11
|
import {
|
|
12
12
|
loadRegistry
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YY7EWHMA.js";
|
|
14
14
|
import {
|
|
15
15
|
bold,
|
|
16
16
|
dim
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import * as os from "os";
|
|
4
4
|
import * as fs from "fs";
|
|
5
|
-
var REGISTRY_DIR = path.join(os.homedir(), ".
|
|
5
|
+
var REGISTRY_DIR = path.join(os.homedir(), ".glrs");
|
|
6
6
|
var REGISTRY_FILE = path.join(REGISTRY_DIR, "worktrees.json");
|
|
7
|
+
var LEGACY_REGISTRY_FILE = path.join(os.homedir(), ".glorious", "worktrees.json");
|
|
7
8
|
function ensureDir() {
|
|
8
9
|
fs.mkdirSync(REGISTRY_DIR, { recursive: true });
|
|
9
10
|
}
|
|
@@ -21,9 +22,10 @@ function writeTextSync(filePath, content) {
|
|
|
21
22
|
fs.writeFileSync(filePath, content, "utf8");
|
|
22
23
|
}
|
|
23
24
|
function loadRegistry() {
|
|
24
|
-
|
|
25
|
+
const fileToRead = existsSync2(REGISTRY_FILE) ? REGISTRY_FILE : existsSync2(LEGACY_REGISTRY_FILE) ? LEGACY_REGISTRY_FILE : null;
|
|
26
|
+
if (!fileToRead) return [];
|
|
25
27
|
try {
|
|
26
|
-
const raw = readTextSync(
|
|
28
|
+
const raw = readTextSync(fileToRead);
|
|
27
29
|
if (!raw) return [];
|
|
28
30
|
const entries = JSON.parse(raw);
|
|
29
31
|
const valid = entries.filter((e) => existsSync2(e.wtPath));
|
package/dist/cli.js
CHANGED
|
@@ -1,36 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import {
|
|
3
|
+
switchCmd
|
|
4
|
+
} from "./chunk-MBEVC327.js";
|
|
2
5
|
import {
|
|
3
6
|
autoUpdate
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MCM47HH4.js";
|
|
8
|
+
import {
|
|
9
|
+
del
|
|
10
|
+
} from "./chunk-EKNRKZWR.js";
|
|
11
|
+
import {
|
|
12
|
+
list
|
|
13
|
+
} from "./chunk-SMDIOB5B.js";
|
|
14
|
+
import {
|
|
15
|
+
go
|
|
16
|
+
} from "./chunk-R2WXQ54P.js";
|
|
17
|
+
import "./chunk-P7PRH4I3.js";
|
|
5
18
|
import {
|
|
6
19
|
HELP_TEXT,
|
|
7
20
|
SUBCOMMANDS,
|
|
8
21
|
WORKTREE_HELP_TEXT,
|
|
9
22
|
resolveSubcommand
|
|
10
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-HQUCVJ4G.js";
|
|
24
|
+
import {
|
|
25
|
+
runAutopilot
|
|
26
|
+
} from "./chunk-2VMFXAJH.js";
|
|
11
27
|
import {
|
|
12
28
|
cleanup
|
|
13
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-2P3ETOT2.js";
|
|
14
30
|
import {
|
|
15
31
|
create
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import
|
|
19
|
-
del
|
|
20
|
-
} from "./chunk-RZWOWTKF.js";
|
|
21
|
-
import "./chunk-W37UX3U2.js";
|
|
22
|
-
import {
|
|
23
|
-
list
|
|
24
|
-
} from "./chunk-I2KUXY3I.js";
|
|
25
|
-
import {
|
|
26
|
-
switchCmd
|
|
27
|
-
} from "./chunk-OABVEBWW.js";
|
|
28
|
-
import {
|
|
29
|
-
go
|
|
30
|
-
} from "./chunk-E2UNZIZT.js";
|
|
31
|
-
import "./chunk-P7PRH4I3.js";
|
|
32
|
+
} from "./chunk-2AZKRWC6.js";
|
|
33
|
+
import "./chunk-PTIO556V.js";
|
|
34
|
+
import "./chunk-6Y27RQQL.js";
|
|
32
35
|
import "./chunk-LMRDQ4GW.js";
|
|
33
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-YY7EWHMA.js";
|
|
34
37
|
import "./chunk-YBCA3IP6.js";
|
|
35
38
|
import "./chunk-3RG5ZIWI.js";
|
|
36
39
|
|
|
@@ -94,6 +97,14 @@ if (sub === "wt" || sub === "worktree") {
|
|
|
94
97
|
await run(wt, wtArgs);
|
|
95
98
|
process.exit(0);
|
|
96
99
|
}
|
|
100
|
+
if (sub === "autopilot") {
|
|
101
|
+
await runAutopilot();
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
if (sub === "dashboard") {
|
|
105
|
+
await runAutopilot();
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
97
108
|
if (!SUBCOMMANDS.includes(sub)) {
|
|
98
109
|
process.stderr.write(
|
|
99
110
|
`[glrs] Unknown subcommand '${sub}'. Run 'glrs --help' for usage.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ScoperSessionOptions, ScoperSessionResult, PlanSessionOptions, PlanSessionResult, LoopSessionOptions, LoopResult, AutopilotLogger } from '@glrs-dev/autopilot';
|
|
2
|
+
export { LoopSessionOptions, PlanSessionOptions, PlanSessionResult } from '@glrs-dev/autopilot';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Interactive autopilot entry point.
|
|
6
|
+
*
|
|
7
|
+
* Two paths:
|
|
8
|
+
* A. Plan-path provided: read the file, extract goal from title/## Goal,
|
|
9
|
+
* pass content to the scoper as context, then scope → plan → loop.
|
|
10
|
+
* B. No plan path: prompt for goal interactively, then scope → plan → loop.
|
|
11
|
+
*
|
|
12
|
+
* The scoper always runs — a provided plan is context for scoping, not a bypass.
|
|
13
|
+
* Each phase prints a structured status banner to the terminal.
|
|
14
|
+
* Dependency-injected for testability.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface AutopilotOrchestrationOptions {
|
|
18
|
+
slug: string;
|
|
19
|
+
planDir: string;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
/** The user's initial goal text, passed to the @scoper wizard. */
|
|
22
|
+
initialGoal: string;
|
|
23
|
+
/** When provided, passed to the scoper so it can ground questions in the existing plan. */
|
|
24
|
+
existingPlanContent?: string;
|
|
25
|
+
}
|
|
26
|
+
interface AutopilotOrchestrationResult {
|
|
27
|
+
scopePath: string;
|
|
28
|
+
planPath: string;
|
|
29
|
+
loopResult: LoopResult;
|
|
30
|
+
}
|
|
31
|
+
interface AutopilotOrchestrationDeps {
|
|
32
|
+
runScoper: (opts: ScoperSessionOptions) => Promise<ScoperSessionResult>;
|
|
33
|
+
runPlan: (opts: PlanSessionOptions) => Promise<PlanSessionResult>;
|
|
34
|
+
runLoop: (opts: LoopSessionOptions) => Promise<LoopResult>;
|
|
35
|
+
onBanner?: (message: string) => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Orchestrate the three-phase interactive autopilot workflow.
|
|
39
|
+
*
|
|
40
|
+
* @param opts - Orchestration options (slug, planDir, cwd)
|
|
41
|
+
* @param deps - Injected dependencies (for testing)
|
|
42
|
+
*/
|
|
43
|
+
declare function orchestrateAutopilot(opts: AutopilotOrchestrationOptions, deps: AutopilotOrchestrationDeps): Promise<AutopilotOrchestrationResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Derive a URL-safe slug from a free-form goal string.
|
|
46
|
+
* Lowercase, replace non-alphanumeric runs with `-`, truncate to 40 chars.
|
|
47
|
+
* Falls back to `feature-<timestamp>` if the result is empty.
|
|
48
|
+
*/
|
|
49
|
+
declare function deriveSlug(goal: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Injectable dependencies for runInteractiveAutopilot.
|
|
52
|
+
* Allows tests to mock inquirer prompts, runner functions, and fs.
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
interface InteractiveAutopilotDeps {
|
|
56
|
+
/** Mock for @inquirer/prompts input() */
|
|
57
|
+
promptGoal?: () => Promise<string>;
|
|
58
|
+
/** Mock for @inquirer/prompts input() (ticket ref) */
|
|
59
|
+
promptTicketRef?: () => Promise<string>;
|
|
60
|
+
/** Override getPlanDir */
|
|
61
|
+
getPlanDir?: (cwd: string) => Promise<string>;
|
|
62
|
+
/** Override fs.mkdirSync */
|
|
63
|
+
mkdirSync?: (p: string, opts?: {
|
|
64
|
+
recursive?: boolean;
|
|
65
|
+
}) => void;
|
|
66
|
+
/** Override fs.writeFileSync */
|
|
67
|
+
writeFileSync?: (p: string, content: string) => void;
|
|
68
|
+
/** Runner overrides */
|
|
69
|
+
runScoper?: (opts: ScoperSessionOptions) => Promise<ScoperSessionResult>;
|
|
70
|
+
runPlan?: (opts: PlanSessionOptions) => Promise<PlanSessionResult>;
|
|
71
|
+
runLoop?: (opts: LoopSessionOptions) => Promise<LoopResult>;
|
|
72
|
+
onBanner?: (message: string) => void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* CLI entry point for `glrs oc autopilot`.
|
|
76
|
+
*
|
|
77
|
+
* When planPath is provided: read the file, extract goal, pass content to scoper.
|
|
78
|
+
* When omitted: prompt for goal interactively, then scope → plan → loop.
|
|
79
|
+
*/
|
|
80
|
+
declare function runInteractiveAutopilot(cwd: string, planPath?: string, _deps?: InteractiveAutopilotDeps, options?: {
|
|
81
|
+
fast?: boolean;
|
|
82
|
+
resume?: boolean;
|
|
83
|
+
maxIterationsPerPhase?: number;
|
|
84
|
+
parallel?: number;
|
|
85
|
+
ship?: boolean;
|
|
86
|
+
logger?: AutopilotLogger;
|
|
87
|
+
}): Promise<AutopilotOrchestrationResult>;
|
|
88
|
+
|
|
89
|
+
export { type AutopilotOrchestrationDeps, type AutopilotOrchestrationOptions, type AutopilotOrchestrationResult, type InteractiveAutopilotDeps, deriveSlug, orchestrateAutopilot, runInteractiveAutopilot };
|