@glrs-dev/cli 2.4.0 → 2.6.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/{chunk-HQUCVJ4G.js → chunk-FBXSGZAA.js} +4 -0
  3. package/dist/chunk-J3FXSHMA.js +263 -0
  4. package/dist/{chunk-5ZVUFNCP.js → chunk-S6N5E2GG.js} +8 -1
  5. package/dist/{chunk-2VMFXAJH.js → chunk-UO7WHIKY.js} +18 -5
  6. package/dist/cli.js +10 -3
  7. package/dist/commands/autopilot-tui.d.ts +11 -1
  8. package/dist/commands/autopilot-tui.js +2 -1
  9. package/dist/commands/autopilot.d.ts +2 -0
  10. package/dist/commands/autopilot.js +62 -21
  11. package/dist/commands/debrief.d.ts +2 -0
  12. package/dist/commands/debrief.js +1 -1
  13. package/dist/commands/loop.d.ts +2 -0
  14. package/dist/commands/loop.js +33 -12
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/node_modules/@glrs-dev/adapter-opencode/dist/index.d.ts +270 -0
  18. package/dist/node_modules/@glrs-dev/adapter-opencode/dist/index.js +506 -0
  19. package/dist/node_modules/@glrs-dev/adapter-opencode/package.json +8 -0
  20. package/dist/node_modules/@glrs-dev/autopilot/dist/auto-ship-EVLBKHUZ.js +7 -0
  21. package/dist/node_modules/@glrs-dev/autopilot/dist/changeset-generator-HAHYSSUR.js +15 -0
  22. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-2X3CWH47.js +3288 -0
  23. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-2ZQ6SBV3.js +70 -0
  24. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-6JZQLIRP.js +781 -0
  25. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-AWRK6S6G.js +91 -0
  26. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-BLEIZHET.js +101 -0
  27. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-GXXCEGDD.js +251 -0
  28. package/dist/node_modules/@glrs-dev/autopilot/dist/chunk-S34HOCZ4.js +44 -0
  29. package/dist/node_modules/@glrs-dev/autopilot/dist/index.d.ts +1915 -0
  30. package/dist/node_modules/@glrs-dev/autopilot/dist/index.js +768 -0
  31. package/dist/node_modules/@glrs-dev/autopilot/dist/logger-3XLFMXLN.js +8 -0
  32. package/dist/node_modules/@glrs-dev/autopilot/dist/loop-session-YLCVJGPV.js +9 -0
  33. package/dist/node_modules/@glrs-dev/autopilot/dist/plan-enrichment-4SQYV5FC.js +17 -0
  34. package/dist/node_modules/@glrs-dev/autopilot/package.json +8 -0
  35. package/dist/vendor/harness-opencode/dist/agents/prompts/agents-md-writer.md +1 -1
  36. package/dist/vendor/harness-opencode/dist/agents/prompts/architecture-advisor.md +1 -1
  37. package/dist/vendor/harness-opencode/dist/agents/prompts/code-searcher.md +1 -1
  38. package/dist/vendor/harness-opencode/dist/agents/prompts/docs-maintainer.md +0 -8
  39. package/dist/vendor/harness-opencode/dist/agents/prompts/gap-analyzer.md +1 -3
  40. package/dist/vendor/harness-opencode/dist/agents/prompts/lib-reader.md +1 -1
  41. package/dist/vendor/harness-opencode/dist/agents/prompts/plan-reviewer.md +0 -2
  42. package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +1 -1
  43. package/dist/vendor/harness-opencode/dist/agents/prompts/prime.md +78 -262
  44. package/dist/vendor/harness-opencode/dist/agents/prompts/research.md +5 -14
  45. package/dist/vendor/harness-opencode/dist/agents/prompts/scoper.md +7 -2
  46. package/dist/vendor/harness-opencode/dist/autopilot/strategies/default.md +29 -0
  47. package/dist/vendor/harness-opencode/dist/index.js +112 -82
  48. package/dist/vendor/harness-opencode/package.json +1 -1
  49. package/package.json +9 -7
@@ -0,0 +1,91 @@
1
+ import {
2
+ hasSpec,
3
+ readSpecGoal,
4
+ readSpecTitle
5
+ } from "./chunk-GXXCEGDD.js";
6
+
7
+ // src/changeset-generator.ts
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ var TARGET_PACKAGE = "@glrs-dev/harness-plugin-opencode";
11
+ function readPlanTitle(planPath) {
12
+ try {
13
+ const stat = fs.statSync(planPath);
14
+ if (stat.isDirectory() && hasSpec(planPath)) {
15
+ const yamlTitle = readSpecTitle(planPath);
16
+ if (yamlTitle) return yamlTitle;
17
+ }
18
+ const target = stat.isDirectory() ? path.join(planPath, "main.md") : planPath;
19
+ const content = fs.readFileSync(target, "utf-8");
20
+ const match = content.match(/^#\s+(.+?)\s*$/m);
21
+ return match ? match[1].trim() : "";
22
+ } catch {
23
+ return "";
24
+ }
25
+ }
26
+ function readPlanGoal(planPath) {
27
+ try {
28
+ const stat = fs.statSync(planPath);
29
+ if (stat.isDirectory() && hasSpec(planPath)) {
30
+ const yamlGoal = readSpecGoal(planPath);
31
+ if (yamlGoal) return yamlGoal;
32
+ }
33
+ const target = stat.isDirectory() ? path.join(planPath, "main.md") : planPath;
34
+ const content = fs.readFileSync(target, "utf-8");
35
+ const re = /^##\s+Goal\s*\n([\s\S]*?)(?=^##\s|$)/m;
36
+ const match = content.match(re);
37
+ if (match) {
38
+ return match[1].trim().replace(/\s+/g, " ");
39
+ }
40
+ return readPlanTitle(planPath);
41
+ } catch {
42
+ return "";
43
+ }
44
+ }
45
+ function inferBumpLevel(title) {
46
+ const t = title.toLowerCase();
47
+ if (t.includes("remove ") || t.includes("removal") || t.includes("breaking") || t.includes("break ") || /\bv2\b/.test(t) || /\bv\d+\b/.test(t.replace(/v1\b/, ""))) {
48
+ return "major";
49
+ }
50
+ if (/\bfix\b/.test(t) || /\bbug(s|fix)?\b/.test(t) || t.includes("hotfix")) {
51
+ return "patch";
52
+ }
53
+ return "minor";
54
+ }
55
+ function slugifyTitle(title) {
56
+ const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
57
+ return slug.length > 0 ? slug : "autopilot";
58
+ }
59
+ function defaultRandomSuffix() {
60
+ return Math.random().toString(36).slice(2, 8);
61
+ }
62
+ async function generateChangeset(planPath, repoRoot, opts = {}) {
63
+ const packageName = opts.packageName ?? TARGET_PACKAGE;
64
+ const randomSuffix = opts._randomSuffix ?? defaultRandomSuffix;
65
+ const title = readPlanTitle(planPath) || "Autopilot run";
66
+ const goal = readPlanGoal(planPath) || title;
67
+ const bumpLevel = opts.bumpLevel ?? inferBumpLevel(title);
68
+ const slug = slugifyTitle(title);
69
+ const content = `---
70
+ "${packageName}": ${bumpLevel}
71
+ ---
72
+
73
+ ${goal}
74
+ `;
75
+ const changesetDir = path.join(repoRoot, ".changeset");
76
+ if (!fs.existsSync(changesetDir)) {
77
+ fs.mkdirSync(changesetDir, { recursive: true });
78
+ }
79
+ const filename = `${slug}-${randomSuffix()}.md`;
80
+ const filePath = path.join(changesetDir, filename);
81
+ fs.writeFileSync(filePath, content, "utf-8");
82
+ return { path: filePath, content, bumpLevel };
83
+ }
84
+
85
+ export {
86
+ readPlanTitle,
87
+ readPlanGoal,
88
+ inferBumpLevel,
89
+ slugifyTitle,
90
+ generateChangeset
91
+ };
@@ -0,0 +1,101 @@
1
+ import {
2
+ hasSpec,
3
+ readSpecTitle
4
+ } from "./chunk-GXXCEGDD.js";
5
+
6
+ // src/auto-ship.ts
7
+ import { execFile as execFileCb } from "child_process";
8
+ import { promisify } from "util";
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ var execFileDefault = promisify(execFileCb);
12
+ var FORBIDDEN_BRANCHES = /* @__PURE__ */ new Set(["main", "master"]);
13
+ function resolvePlanMainPath(planPath) {
14
+ try {
15
+ if (fs.statSync(planPath).isDirectory()) {
16
+ return path.join(planPath, "main.md");
17
+ }
18
+ } catch {
19
+ }
20
+ return planPath;
21
+ }
22
+ function readPlanH1(planPath) {
23
+ try {
24
+ if (fs.statSync(planPath).isDirectory() && hasSpec(planPath)) {
25
+ const yamlTitle = readSpecTitle(planPath);
26
+ if (yamlTitle) return yamlTitle;
27
+ }
28
+ } catch {
29
+ }
30
+ const target = resolvePlanMainPath(planPath);
31
+ try {
32
+ const content = fs.readFileSync(target, "utf-8");
33
+ const match = content.match(/^#\s+(.+?)\s*$/m);
34
+ if (match) return match[1].trim();
35
+ } catch {
36
+ }
37
+ return "Autopilot run";
38
+ }
39
+ async function autoShip(opts) {
40
+ const execFile = opts._deps?.execFile ?? execFileDefault;
41
+ const cwd = opts.repoRoot;
42
+ let branch;
43
+ try {
44
+ const { stdout } = await execFile(
45
+ "git",
46
+ ["rev-parse", "--abbrev-ref", "HEAD"],
47
+ { cwd }
48
+ );
49
+ branch = (typeof stdout === "string" ? stdout : String(stdout)).trim();
50
+ } catch (err) {
51
+ const msg = err instanceof Error ? err.message : String(err);
52
+ throw new Error(`auto-ship: failed to resolve current branch: ${msg}`);
53
+ }
54
+ if (!branch || branch === "HEAD") {
55
+ throw new Error(
56
+ `auto-ship: refusing to ship from a detached HEAD (branch="${branch}")`
57
+ );
58
+ }
59
+ if (FORBIDDEN_BRANCHES.has(branch)) {
60
+ throw new Error(
61
+ `auto-ship: refusing to push to forbidden branch "${branch}". Create a feature branch first.`
62
+ );
63
+ }
64
+ try {
65
+ await execFile("git", ["push", "-u", "origin", branch], { cwd });
66
+ } catch (err) {
67
+ const msg = err instanceof Error ? err.message : String(err);
68
+ throw new Error(`auto-ship: git push failed: ${msg}`);
69
+ }
70
+ const title = readPlanH1(opts.planPath);
71
+ const bodyFile = resolvePlanMainPath(opts.planPath);
72
+ if (!fs.existsSync(bodyFile)) {
73
+ throw new Error(`auto-ship: plan body file not found: ${bodyFile}`);
74
+ }
75
+ let prUrl;
76
+ try {
77
+ const { stdout } = await execFile(
78
+ "gh",
79
+ [
80
+ "pr",
81
+ "create",
82
+ "--title",
83
+ title,
84
+ "--body-file",
85
+ bodyFile
86
+ ],
87
+ { cwd }
88
+ );
89
+ const text = typeof stdout === "string" ? stdout : String(stdout);
90
+ const urlMatch = text.match(/https?:\/\/\S+/);
91
+ prUrl = urlMatch ? urlMatch[0] : text.trim();
92
+ } catch (err) {
93
+ const msg = err instanceof Error ? err.message : String(err);
94
+ throw new Error(`auto-ship: gh pr create failed: ${msg}`);
95
+ }
96
+ return { prUrl, branch, title };
97
+ }
98
+
99
+ export {
100
+ autoShip
101
+ };
@@ -0,0 +1,251 @@
1
+ // src/spec-schema.ts
2
+ function validateMainSpec(raw) {
3
+ const errors = [];
4
+ if (typeof raw !== "object" || raw === null) {
5
+ return { valid: false, errors: ["main spec must be an object"] };
6
+ }
7
+ const obj = raw;
8
+ if (!("phases" in obj)) {
9
+ errors.push("main spec missing required field: phases");
10
+ } else if (!Array.isArray(obj["phases"])) {
11
+ errors.push("main spec field 'phases' must be an array");
12
+ } else {
13
+ const phases = obj["phases"];
14
+ for (let i = 0; i < phases.length; i++) {
15
+ const phase = phases[i];
16
+ if (typeof phase !== "object" || phase === null) {
17
+ errors.push(`phases[${i}] must be an object`);
18
+ continue;
19
+ }
20
+ const p = phase;
21
+ if (!("file" in p) || typeof p["file"] !== "string") {
22
+ errors.push(`phases[${i}] missing required field: file`);
23
+ }
24
+ if (!("completed" in p) || typeof p["completed"] !== "boolean") {
25
+ errors.push(`phases[${i}] missing required field: completed (boolean)`);
26
+ }
27
+ }
28
+ }
29
+ return { valid: errors.length === 0, errors };
30
+ }
31
+ function validatePhaseSpec(raw) {
32
+ const errors = [];
33
+ if (typeof raw !== "object" || raw === null) {
34
+ return { valid: false, errors: ["phase spec must be an object"] };
35
+ }
36
+ const obj = raw;
37
+ if (!("items" in obj)) {
38
+ errors.push("phase spec missing required field: items");
39
+ return { valid: false, errors };
40
+ }
41
+ if (!Array.isArray(obj["items"])) {
42
+ errors.push("phase spec field 'items' must be an array");
43
+ return { valid: false, errors };
44
+ }
45
+ const items = obj["items"];
46
+ for (let i = 0; i < items.length; i++) {
47
+ const item = items[i];
48
+ if (typeof item !== "object" || item === null) {
49
+ errors.push(`items[${i}] must be an object`);
50
+ continue;
51
+ }
52
+ const it = item;
53
+ if (!("id" in it) || typeof it["id"] !== "string" || !it["id"]) {
54
+ errors.push(`items[${i}] missing required field: id`);
55
+ }
56
+ if (!("intent" in it) || typeof it["intent"] !== "string" || !it["intent"]) {
57
+ errors.push(`items[${i}] missing required field: intent`);
58
+ }
59
+ }
60
+ return { valid: errors.length === 0, errors };
61
+ }
62
+
63
+ // src/spec-parser.ts
64
+ import * as fs from "fs";
65
+ import * as path from "path";
66
+ import { parse as yamlParse } from "yaml";
67
+ var DEGRADED = {
68
+ type: "single",
69
+ totalItems: 0,
70
+ checkedItems: 0,
71
+ phaseCount: 0,
72
+ phasesCompleted: 0,
73
+ phases: []
74
+ };
75
+ function hasSpec(planDir) {
76
+ try {
77
+ return fs.existsSync(path.join(planDir, "spec", "main.yaml"));
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+ function specItemToPlanItem(item) {
83
+ const files = (item.files ?? []).map((f) => ({
84
+ path: f.path,
85
+ isNew: f.isNew ?? false,
86
+ change: f.change ?? ""
87
+ }));
88
+ return {
89
+ id: item.id,
90
+ intent: item.intent,
91
+ checked: item.checked ?? false,
92
+ files,
93
+ tests: item.tests ?? [],
94
+ verify: item.verify ?? "",
95
+ ...item.mirror !== void 0 ? { mirror: item.mirror } : {},
96
+ ...item.context !== void 0 ? { context: item.context } : {},
97
+ ...item.conventions !== void 0 ? { conventions: item.conventions } : {},
98
+ ...item.proof !== void 0 ? { proof: item.proof } : {},
99
+ ...item.proof_type !== void 0 ? { proof_type: item.proof_type } : {}
100
+ };
101
+ }
102
+ function parseSpecItems(phasePath) {
103
+ try {
104
+ const content = fs.readFileSync(phasePath, "utf-8");
105
+ const raw = yamlParse(content);
106
+ const validation = validatePhaseSpec(raw);
107
+ if (!validation.valid) {
108
+ return [];
109
+ }
110
+ const spec = raw;
111
+ return spec.items.map(specItemToPlanItem);
112
+ } catch {
113
+ return [];
114
+ }
115
+ }
116
+ function parseSpecState(planDir) {
117
+ try {
118
+ const mainPath = path.join(planDir, "spec", "main.yaml");
119
+ if (!fs.existsSync(mainPath)) {
120
+ return { ...DEGRADED };
121
+ }
122
+ const mainContent = fs.readFileSync(mainPath, "utf-8");
123
+ const rawMain = yamlParse(mainContent);
124
+ const mainValidation = validateMainSpec(rawMain);
125
+ if (!mainValidation.valid) {
126
+ return { ...DEGRADED, type: "multi" };
127
+ }
128
+ const mainSpec = rawMain;
129
+ const phases = [];
130
+ let totalItems = 0;
131
+ let checkedItems = 0;
132
+ let phasesCompleted = 0;
133
+ for (const phaseRef of mainSpec.phases) {
134
+ const phasePath = path.join(planDir, "spec", phaseRef.file);
135
+ const items = parseSpecItems(phasePath);
136
+ const phaseTotal = items.length;
137
+ const phaseChecked = items.filter((it) => it.checked).length;
138
+ phases.push({
139
+ file: phaseRef.file,
140
+ totalItems: phaseTotal,
141
+ checkedItems: phaseChecked
142
+ });
143
+ totalItems += phaseTotal;
144
+ checkedItems += phaseChecked;
145
+ if (phaseRef.completed) {
146
+ phasesCompleted++;
147
+ }
148
+ }
149
+ return {
150
+ type: "multi",
151
+ totalItems,
152
+ checkedItems,
153
+ phaseCount: mainSpec.phases.length,
154
+ phasesCompleted,
155
+ phases
156
+ };
157
+ } catch {
158
+ return { ...DEGRADED };
159
+ }
160
+ }
161
+ function detectSpecPhases(planDir) {
162
+ try {
163
+ const mainPath = path.join(planDir, "spec", "main.yaml");
164
+ if (!fs.existsSync(mainPath)) {
165
+ return [];
166
+ }
167
+ const content = fs.readFileSync(mainPath, "utf-8");
168
+ const raw = yamlParse(content);
169
+ const validation = validateMainSpec(raw);
170
+ if (!validation.valid) {
171
+ return [];
172
+ }
173
+ const spec = raw;
174
+ return spec.phases.map((p) => p.file);
175
+ } catch {
176
+ return [];
177
+ }
178
+ }
179
+ function readSpecGoal(planDir) {
180
+ try {
181
+ const mainPath = path.join(planDir, "spec", "main.yaml");
182
+ const content = fs.readFileSync(mainPath, "utf-8");
183
+ const raw = yamlParse(content);
184
+ if (typeof raw === "object" && raw !== null) {
185
+ const obj = raw;
186
+ if (typeof obj["goal"] === "string") return obj["goal"];
187
+ }
188
+ return "";
189
+ } catch {
190
+ return "";
191
+ }
192
+ }
193
+ function readSpecTitle(planDir) {
194
+ try {
195
+ const mainPath = path.join(planDir, "spec", "main.yaml");
196
+ const content = fs.readFileSync(mainPath, "utf-8");
197
+ const raw = yamlParse(content);
198
+ if (typeof raw === "object" && raw !== null) {
199
+ const obj = raw;
200
+ if (typeof obj["title"] === "string") return obj["title"];
201
+ }
202
+ return "";
203
+ } catch {
204
+ return "";
205
+ }
206
+ }
207
+ function readSpecConstraints(planDir) {
208
+ try {
209
+ const mainPath = path.join(planDir, "spec", "main.yaml");
210
+ const content = fs.readFileSync(mainPath, "utf-8");
211
+ const raw = yamlParse(content);
212
+ if (typeof raw === "object" && raw !== null) {
213
+ const obj = raw;
214
+ if (typeof obj["constraints"] === "string") return obj["constraints"];
215
+ }
216
+ return "";
217
+ } catch {
218
+ return "";
219
+ }
220
+ }
221
+ function filterUncheckedSpecPhases(phaseFiles, planDir) {
222
+ try {
223
+ const mainPath = path.join(planDir, "spec", "main.yaml");
224
+ const content = fs.readFileSync(mainPath, "utf-8");
225
+ const raw = yamlParse(content);
226
+ const validation = validateMainSpec(raw);
227
+ if (!validation.valid) {
228
+ return phaseFiles;
229
+ }
230
+ const spec = raw;
231
+ const completedSet = new Set(
232
+ spec.phases.filter((p) => p.completed === true).map((p) => p.file)
233
+ );
234
+ return phaseFiles.filter((f) => !completedSet.has(f));
235
+ } catch {
236
+ return phaseFiles;
237
+ }
238
+ }
239
+
240
+ export {
241
+ validateMainSpec,
242
+ validatePhaseSpec,
243
+ hasSpec,
244
+ parseSpecItems,
245
+ parseSpecState,
246
+ detectSpecPhases,
247
+ readSpecGoal,
248
+ readSpecTitle,
249
+ readSpecConstraints,
250
+ filterUncheckedSpecPhases
251
+ };
@@ -0,0 +1,44 @@
1
+ // src/model-resolver.ts
2
+ var CLAUDE_TIER_ALIASES = {
3
+ deep: "claude-opus-4-7",
4
+ prime: "claude-opus-4-7",
5
+ mid: "claude-sonnet-4-6",
6
+ "mid-execute": "claude-sonnet-4-6",
7
+ "autopilot-execute": "claude-haiku-4-5-20251001",
8
+ fast: "claude-haiku-4-5-20251001"
9
+ };
10
+ var warnedOnce = null;
11
+ function warn(message) {
12
+ if (!warnedOnce) warnedOnce = /* @__PURE__ */ new Set();
13
+ if (warnedOnce.has(message)) return;
14
+ warnedOnce.add(message);
15
+ console.warn(`[model-resolver] ${message}`);
16
+ }
17
+ function resolveModel(specifier, adapterName, opencodeTiers) {
18
+ if (specifier.includes("/")) {
19
+ return specifier;
20
+ }
21
+ if (adapterName === "claude-code-cli") {
22
+ if (specifier in CLAUDE_TIER_ALIASES) {
23
+ return CLAUDE_TIER_ALIASES[specifier];
24
+ }
25
+ return specifier;
26
+ }
27
+ if (!opencodeTiers) {
28
+ return specifier;
29
+ }
30
+ const resolved = opencodeTiers[specifier];
31
+ if (resolved !== void 0) {
32
+ return Array.isArray(resolved) ? resolved[0] : resolved;
33
+ }
34
+ const fallback = opencodeTiers["deep"];
35
+ if (fallback !== void 0) {
36
+ warn(`Unknown tier "${specifier}"; falling back to "deep"`);
37
+ return Array.isArray(fallback) ? fallback[0] : fallback;
38
+ }
39
+ return specifier;
40
+ }
41
+
42
+ export {
43
+ resolveModel
44
+ };