@glrs-dev/harness-plugin-opencode 2.4.1 → 2.7.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 +51 -0
- package/dist/agents/prompts/agents-md-writer.md +1 -1
- package/dist/agents/prompts/architecture-advisor.md +1 -1
- package/dist/agents/prompts/code-searcher.md +1 -1
- package/dist/agents/prompts/docs-maintainer.md +0 -8
- package/dist/agents/prompts/gap-analyzer.md +1 -3
- package/dist/agents/prompts/lib-reader.md +1 -1
- package/dist/agents/prompts/plan-reviewer.md +0 -2
- package/dist/agents/prompts/plan.md +1 -1
- package/dist/agents/prompts/prime.md +79 -263
- package/dist/agents/prompts/research.md +5 -14
- package/dist/agents/prompts/scoper.md +7 -2
- package/dist/autopilot/strategies/default.md +29 -0
- package/dist/cli-exports.d.ts +49 -0
- package/dist/{cli.js → cli-exports.js} +21 -282
- package/dist/index.js +114 -85
- package/package.json +11 -6
- package/dist/cli.d.ts +0 -1
|
@@ -24,22 +24,13 @@ Every cognitive task is a subagent. You launch subagents and pass their outputs
|
|
|
24
24
|
|
|
25
25
|
## How to Invoke Research Agents
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Dispatch research subagents via the task tool:
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
4. **`@research-auto`** — autonomous experimentation with `.lab/` directory
|
|
29
|
+
- **`@research-local`** — deep codebase research using parallel Explore subagents
|
|
30
|
+
- **`@research-web`** — multi-agent web research with skeleton-file pattern
|
|
31
|
+
- **`@research-auto`** — autonomous experimentation with `.lab/` directory
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
task tool:
|
|
38
|
-
agent: "research-web"
|
|
39
|
-
prompt: "Research the competitive landscape for X. Focus on: {specific angle}."
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
The research agents are thin shims that load their matching bundled skill and follow it end-to-end. Trust the brief — the task-tool arguments ARE the research query.
|
|
33
|
+
Each is a thin shim that loads its matching bundled skill. The task-tool arguments ARE the research query.
|
|
43
34
|
|
|
44
35
|
## 7-Phase Flow
|
|
45
36
|
|
|
@@ -73,7 +73,12 @@ After the user approves the summary, use Serena MCP tools and file-reading tools
|
|
|
73
73
|
Resolve the plan directory:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
76
|
+
PLAN_BASE="${GLORIOUS_PLAN_DIR:-$HOME/.glorious/opencode}"
|
|
77
|
+
GIT_COMMON="$(git rev-parse --git-common-dir)"
|
|
78
|
+
[[ "$GIT_COMMON" != /* ]] && GIT_COMMON="$PWD/$GIT_COMMON"
|
|
79
|
+
REPO_FOLDER="$(basename "$(dirname "$GIT_COMMON")")"
|
|
80
|
+
PLAN_DIR="$PLAN_BASE/$REPO_FOLDER/plans"
|
|
81
|
+
mkdir -p "$PLAN_DIR"
|
|
77
82
|
```
|
|
78
83
|
|
|
79
84
|
Write `$PLAN_DIR/<slug>/scope.md` (create the slug directory if needed). Use this structure:
|
|
@@ -122,7 +127,7 @@ If you have been asked 8 questions and the wizard sends: "You have asked enough
|
|
|
122
127
|
- **Always present a scope summary for user approval before writing scope.md.** Never skip the approval gate.
|
|
123
128
|
- **Do NOT call the `question` tool.** Emit questions as plain assistant text per the strict contract.
|
|
124
129
|
- Every response is EXACTLY a question (≤200 chars, ends with `?`), a scope summary (starts with `SCOPE_SUMMARY:`), or the SCOPE_COMPLETE sentinel. Nothing else.
|
|
125
|
-
- Write scope.md to the plan directory resolved via
|
|
130
|
+
- Write scope.md to the plan directory resolved via the bash snippet in Phase 4. Do not write to any other path.
|
|
126
131
|
- The `SCOPE_COMPLETE:` sentinel must be the entire content of your response, with the absolute path.
|
|
127
132
|
- Do not begin implementation. Do not write code. Do not modify any file except scope.md.
|
|
128
133
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
You are generating a YAML spec file from a markdown plan phase, enriched with codebase context.
|
|
2
|
+
|
|
3
|
+
Read the markdown plan content below and write `${specPath}` (relative to the plan directory: ${planDir}) using the write/edit tool.
|
|
4
|
+
|
|
5
|
+
The output file should follow this schema:
|
|
6
|
+
|
|
7
|
+
${schemaExample}
|
|
8
|
+
|
|
9
|
+
For each acceptance-criteria item in the plan:
|
|
10
|
+
1. Extract `id`, `intent`, `files`, `tests`, `verify` from the markdown.
|
|
11
|
+
2. Set `checked: false` for all items.
|
|
12
|
+
3. Add enrichment fields by reading the actual codebase:
|
|
13
|
+
- **mirror**: Find the most similar existing file in the codebase and set `mirror: <path>`. This is the pattern-match target the executor will follow.
|
|
14
|
+
- **context**: For each file being MODIFIED (not NEW), read the relevant function/section and add 10-20 lines of the current code. For NEW files, add the key function signatures the file should export.
|
|
15
|
+
- **conventions**: List project-specific patterns: import style (named vs default), export pattern, test framework (vitest/jest/bun:test), naming conventions, error handling pattern.
|
|
16
|
+
|
|
17
|
+
Rules:
|
|
18
|
+
- Read actual files from the codebase to get accurate code pointers. Do not hallucinate file contents.
|
|
19
|
+
- Be concise — 10-20 lines of context per file, not the whole file.
|
|
20
|
+
- Only add enrichment fields you can verify from the codebase.
|
|
21
|
+
|
|
22
|
+
Here is the plan file to convert:
|
|
23
|
+
|
|
24
|
+
### {{file}}
|
|
25
|
+
```markdown
|
|
26
|
+
{{content}}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Write the file `${planDir}/${specPath}` using the write/edit tool, then respond with "SPEC_COMPLETE" when done.
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
interface InstallOptions {
|
|
6
|
+
dryRun?: boolean;
|
|
7
|
+
pin?: boolean;
|
|
8
|
+
nonInteractive?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function install(opts?: InstallOptions): Promise<void>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* `bunx @glrs-dev/harness-plugin-opencode uninstall`
|
|
14
|
+
*
|
|
15
|
+
* Removes "@glrs-dev/harness-plugin-opencode" from the user's opencode.json plugin
|
|
16
|
+
* array. Writes a .bak backup before mutation. Does NOT touch skills (they
|
|
17
|
+
* live in node_modules, removed by `bun remove`). Does NOT touch ~/.claude/.
|
|
18
|
+
*/
|
|
19
|
+
interface UninstallOptions {
|
|
20
|
+
dryRun?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare function uninstall(opts?: UninstallOptions): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `bunx @glrs-dev/harness-plugin-opencode doctor`
|
|
26
|
+
*
|
|
27
|
+
* Checks the installation health and reports per-check green/yellow/red.
|
|
28
|
+
*/
|
|
29
|
+
declare function doctor(): void;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `glrs oc configure` — Interactive configuration editor.
|
|
33
|
+
*
|
|
34
|
+
* Shows the current opencode.json config as a navigable menu.
|
|
35
|
+
* The user selects a setting to change, picks from available options
|
|
36
|
+
* (no free-text for model selection), and saves.
|
|
37
|
+
*
|
|
38
|
+
* Unlike `install`, this command:
|
|
39
|
+
* - Never re-prompts for settings you don't want to change
|
|
40
|
+
* - Shows model choices from the Models.dev API (not free-text)
|
|
41
|
+
* - Supports changing a single tier without touching others
|
|
42
|
+
*/
|
|
43
|
+
declare const configureCmd: Partial<cmd_ts_dist_cjs_argparser_js.Register> & {
|
|
44
|
+
parse(context: cmd_ts_dist_cjs_argparser_js.ParseContext): Promise<cmd_ts_dist_cjs_argparser_js.ParsingResult<{}>>;
|
|
45
|
+
} & 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<{}, Promise<void>> & {
|
|
46
|
+
run(context: cmd_ts_dist_cjs_argparser_js.ParseContext): Promise<cmd_ts_dist_cjs_argparser_js.ParsingResult<Promise<void>>>;
|
|
47
|
+
} & Partial<cmd_ts_dist_cjs_helpdoc_js.Versioned & cmd_ts_dist_cjs_helpdoc_js.Descriptive & cmd_ts_dist_cjs_helpdoc_js.Aliased>;
|
|
48
|
+
|
|
49
|
+
export { type InstallOptions, type UninstallOptions, configureCmd, doctor, install, uninstall };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
1
|
import {
|
|
3
2
|
getOpenCodeCachePackageDir,
|
|
4
3
|
inspectCachePin,
|
|
@@ -11,16 +10,6 @@ import {
|
|
|
11
10
|
promptMulti
|
|
12
11
|
} from "./chunk-GILWWWMB.js";
|
|
13
12
|
|
|
14
|
-
// src/cli.ts
|
|
15
|
-
import {
|
|
16
|
-
binary,
|
|
17
|
-
command as command2,
|
|
18
|
-
flag,
|
|
19
|
-
positional,
|
|
20
|
-
subcommands,
|
|
21
|
-
run
|
|
22
|
-
} from "cmd-ts";
|
|
23
|
-
|
|
24
13
|
// src/cli/install.ts
|
|
25
14
|
import * as fs2 from "fs";
|
|
26
15
|
import * as path2 from "path";
|
|
@@ -977,17 +966,17 @@ function getOpencodeConfigPath2() {
|
|
|
977
966
|
function uninstall(opts = {}) {
|
|
978
967
|
const { dryRun = false } = opts;
|
|
979
968
|
const configPath = getOpencodeConfigPath2();
|
|
980
|
-
const
|
|
969
|
+
const c3 = {
|
|
981
970
|
reset: "\x1B[0m",
|
|
982
971
|
green: "\x1B[32m",
|
|
983
972
|
yellow: "\x1B[33m",
|
|
984
973
|
blue: "\x1B[34m"
|
|
985
974
|
};
|
|
986
|
-
const ok3 = (msg) => console.log(`${
|
|
987
|
-
const info3 = (msg) => console.log(`${
|
|
988
|
-
const warn2 = (msg) => console.log(`${
|
|
975
|
+
const ok3 = (msg) => console.log(`${c3.green}\u2713${c3.reset} ${msg}`);
|
|
976
|
+
const info3 = (msg) => console.log(`${c3.blue}\u2022${c3.reset} ${msg}`);
|
|
977
|
+
const warn2 = (msg) => console.log(`${c3.yellow}!${c3.reset} ${msg}`);
|
|
989
978
|
console.log(`
|
|
990
|
-
${
|
|
979
|
+
${c3.blue}Uninstalling ${PLUGIN_NAME2}${c3.reset}
|
|
991
980
|
`);
|
|
992
981
|
if (!fs3.existsSync(configPath)) {
|
|
993
982
|
warn2(`No opencode.json found at ${configPath} \u2014 nothing to do`);
|
|
@@ -1057,9 +1046,9 @@ function getOpencodeConfigPath3() {
|
|
|
1057
1046
|
const configHome = process.env["XDG_CONFIG_HOME"] ?? path4.join(os3.homedir(), ".config");
|
|
1058
1047
|
return path4.join(configHome, "opencode", "opencode.json");
|
|
1059
1048
|
}
|
|
1060
|
-
function cmd(
|
|
1049
|
+
function cmd(command2) {
|
|
1061
1050
|
try {
|
|
1062
|
-
return execSync(
|
|
1051
|
+
return execSync(command2, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
1063
1052
|
} catch {
|
|
1064
1053
|
return null;
|
|
1065
1054
|
}
|
|
@@ -1068,18 +1057,18 @@ function which(bin) {
|
|
|
1068
1057
|
return cmd(`which ${bin}`) !== null;
|
|
1069
1058
|
}
|
|
1070
1059
|
function doctor() {
|
|
1071
|
-
const
|
|
1060
|
+
const c3 = {
|
|
1072
1061
|
reset: "\x1B[0m",
|
|
1073
1062
|
green: "\x1B[32m",
|
|
1074
1063
|
yellow: "\x1B[33m",
|
|
1075
1064
|
red: "\x1B[31m",
|
|
1076
1065
|
bold: "\x1B[1m"
|
|
1077
1066
|
};
|
|
1078
|
-
const ok3 = (msg) => console.log(`${
|
|
1079
|
-
const warn2 = (msg) => console.log(`${
|
|
1080
|
-
const fail = (msg) => console.log(`${
|
|
1067
|
+
const ok3 = (msg) => console.log(`${c3.green}\u2713${c3.reset} ${msg}`);
|
|
1068
|
+
const warn2 = (msg) => console.log(`${c3.yellow}!${c3.reset} ${msg}`);
|
|
1069
|
+
const fail = (msg) => console.log(`${c3.red}\u2717${c3.reset} ${msg}`);
|
|
1081
1070
|
console.log(`
|
|
1082
|
-
${
|
|
1071
|
+
${c3.bold}Doctor \u2014 ${PLUGIN_NAME3}${c3.reset}
|
|
1083
1072
|
`);
|
|
1084
1073
|
const ocVersion = cmd("opencode --version 2>/dev/null | head -1");
|
|
1085
1074
|
if (ocVersion) {
|
|
@@ -1150,15 +1139,15 @@ ${c4.bold}Doctor \u2014 ${PLUGIN_NAME3}${c4.reset}
|
|
|
1150
1139
|
for (const entry of invalid) {
|
|
1151
1140
|
fail(`invalid model override at ${entry.keyPath}: "${entry.value}"`);
|
|
1152
1141
|
if (entry.reason) {
|
|
1153
|
-
console.log(` ${
|
|
1142
|
+
console.log(` ${c3.yellow}reason:${c3.reset} ${entry.reason}`);
|
|
1154
1143
|
}
|
|
1155
1144
|
if (entry.suggestion) {
|
|
1156
1145
|
console.log(
|
|
1157
|
-
` ${
|
|
1146
|
+
` ${c3.yellow}fix:${c3.reset} remove this key, or replace with \`${entry.suggestion}\``
|
|
1158
1147
|
);
|
|
1159
1148
|
} else {
|
|
1160
1149
|
console.log(
|
|
1161
|
-
` ${
|
|
1150
|
+
` ${c3.yellow}fix:${c3.reset} remove this key, or run \`bunx ${PLUGIN_NAME3} install\` to pick a current preset`
|
|
1162
1151
|
);
|
|
1163
1152
|
}
|
|
1164
1153
|
}
|
|
@@ -1384,7 +1373,7 @@ var configureCmd = command({
|
|
|
1384
1373
|
const configPath = getOpencodeConfigPath4();
|
|
1385
1374
|
const config = readConfig(configPath);
|
|
1386
1375
|
if (!config) {
|
|
1387
|
-
console.log(`No config found at ${configPath}. Run ${c2.green}glrs
|
|
1376
|
+
console.log(`No config found at ${configPath}. Run ${c2.green}glrs harness install${c2.reset} first.`);
|
|
1388
1377
|
process.exit(1);
|
|
1389
1378
|
}
|
|
1390
1379
|
const opts = extractPluginOptions2(config);
|
|
@@ -1447,259 +1436,9 @@ ${c2.bold}Done.${c2.reset} Restart opencode to pick up changes.
|
|
|
1447
1436
|
}
|
|
1448
1437
|
}
|
|
1449
1438
|
});
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
import { spawn } from "child_process";
|
|
1456
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1457
|
-
var PACKAGE_NAME = "@glrs-dev/harness-plugin-opencode";
|
|
1458
|
-
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
1459
|
-
var c3 = {
|
|
1460
|
-
reset: "\x1B[0m",
|
|
1461
|
-
green: "\x1B[32m",
|
|
1462
|
-
yellow: "\x1B[33m",
|
|
1463
|
-
blue: "\x1B[34m",
|
|
1464
|
-
dim: "\x1B[2m",
|
|
1465
|
-
bold: "\x1B[1m"
|
|
1439
|
+
export {
|
|
1440
|
+
configureCmd,
|
|
1441
|
+
doctor,
|
|
1442
|
+
install,
|
|
1443
|
+
uninstall
|
|
1466
1444
|
};
|
|
1467
|
-
function parseSemver(v) {
|
|
1468
|
-
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
|
|
1469
|
-
if (!m) return null;
|
|
1470
|
-
return { major: +m[1], minor: +m[2], patch: +m[3] };
|
|
1471
|
-
}
|
|
1472
|
-
function isNewer(current, latest) {
|
|
1473
|
-
if (latest.major !== current.major) return latest.major > current.major;
|
|
1474
|
-
if (latest.minor !== current.minor) return latest.minor > current.minor;
|
|
1475
|
-
return latest.patch > current.patch;
|
|
1476
|
-
}
|
|
1477
|
-
function isMajorBump(current, latest) {
|
|
1478
|
-
return latest.major > current.major;
|
|
1479
|
-
}
|
|
1480
|
-
function getStateFilePath() {
|
|
1481
|
-
const cacheHome = process.env["XDG_CACHE_HOME"] ?? path6.join(os5.homedir(), ".cache");
|
|
1482
|
-
return path6.join(cacheHome, "harness-opencode", "cli-update.json");
|
|
1483
|
-
}
|
|
1484
|
-
function readState() {
|
|
1485
|
-
try {
|
|
1486
|
-
const raw = fs6.readFileSync(getStateFilePath(), "utf8");
|
|
1487
|
-
return JSON.parse(raw);
|
|
1488
|
-
} catch {
|
|
1489
|
-
return null;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
function writeState(state) {
|
|
1493
|
-
try {
|
|
1494
|
-
const statePath = getStateFilePath();
|
|
1495
|
-
fs6.mkdirSync(path6.dirname(statePath), { recursive: true });
|
|
1496
|
-
fs6.writeFileSync(statePath, JSON.stringify(state));
|
|
1497
|
-
} catch {
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
function readInstalledVersion() {
|
|
1501
|
-
const here = path6.dirname(fileURLToPath2(import.meta.url));
|
|
1502
|
-
const candidates = [
|
|
1503
|
-
path6.join(here, "..", "package.json"),
|
|
1504
|
-
path6.join(here, "..", "..", "package.json"),
|
|
1505
|
-
path6.join(here, "package.json")
|
|
1506
|
-
];
|
|
1507
|
-
for (const candidate of candidates) {
|
|
1508
|
-
try {
|
|
1509
|
-
const raw = fs6.readFileSync(candidate, "utf8");
|
|
1510
|
-
const parsed = JSON.parse(raw);
|
|
1511
|
-
if (parsed.name === PACKAGE_NAME && typeof parsed.version === "string") {
|
|
1512
|
-
return parsed.version;
|
|
1513
|
-
}
|
|
1514
|
-
} catch {
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
return "0.0.0";
|
|
1518
|
-
}
|
|
1519
|
-
async function fetchLatestVersion() {
|
|
1520
|
-
try {
|
|
1521
|
-
const controller = new AbortController();
|
|
1522
|
-
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
1523
|
-
const res = await fetch(
|
|
1524
|
-
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
1525
|
-
{ signal: controller.signal }
|
|
1526
|
-
);
|
|
1527
|
-
clearTimeout(timer);
|
|
1528
|
-
if (!res.ok) return null;
|
|
1529
|
-
const data = await res.json();
|
|
1530
|
-
return data.version ?? null;
|
|
1531
|
-
} catch {
|
|
1532
|
-
return null;
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
function spawnBackgroundUpdate() {
|
|
1536
|
-
try {
|
|
1537
|
-
const child = spawn("bun", ["update", "-g", PACKAGE_NAME], {
|
|
1538
|
-
detached: true,
|
|
1539
|
-
stdio: "ignore"
|
|
1540
|
-
});
|
|
1541
|
-
child.unref();
|
|
1542
|
-
} catch {
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
function startUpdateCheck() {
|
|
1546
|
-
if (process.env["HARNESS_OPENCODE_UPDATE_CHECK"] === "0") {
|
|
1547
|
-
return () => {
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
const currentVersionStr = readInstalledVersion();
|
|
1551
|
-
const current = parseSemver(currentVersionStr);
|
|
1552
|
-
if (!current) return () => {
|
|
1553
|
-
};
|
|
1554
|
-
const state = readState();
|
|
1555
|
-
if (state && Date.now() - state.last_check_ts < CHECK_INTERVAL_MS) {
|
|
1556
|
-
if (state.latest_version) {
|
|
1557
|
-
const cached = parseSemver(state.latest_version);
|
|
1558
|
-
if (cached && isNewer(current, cached) && isMajorBump(current, cached)) {
|
|
1559
|
-
return () => printMajorNotice(currentVersionStr, state.latest_version);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
return () => {
|
|
1563
|
-
};
|
|
1564
|
-
}
|
|
1565
|
-
let action = null;
|
|
1566
|
-
fetchLatestVersion().then((latestStr) => {
|
|
1567
|
-
writeState({
|
|
1568
|
-
last_check_ts: Date.now(),
|
|
1569
|
-
latest_version: latestStr ?? void 0
|
|
1570
|
-
});
|
|
1571
|
-
if (!latestStr) return;
|
|
1572
|
-
const latest = parseSemver(latestStr);
|
|
1573
|
-
if (!latest || !isNewer(current, latest)) return;
|
|
1574
|
-
if (isMajorBump(current, latest)) {
|
|
1575
|
-
action = () => printMajorNotice(currentVersionStr, latestStr);
|
|
1576
|
-
} else {
|
|
1577
|
-
action = () => {
|
|
1578
|
-
process.stderr.write(
|
|
1579
|
-
`
|
|
1580
|
-
${c3.blue}\u2022${c3.reset} Updating ${PACKAGE_NAME} ${c3.dim}${currentVersionStr}${c3.reset} \u2192 ${c3.green}${latestStr}${c3.reset} in the background...
|
|
1581
|
-
`
|
|
1582
|
-
);
|
|
1583
|
-
spawnBackgroundUpdate();
|
|
1584
|
-
};
|
|
1585
|
-
}
|
|
1586
|
-
}).catch(() => {
|
|
1587
|
-
});
|
|
1588
|
-
return () => {
|
|
1589
|
-
if (action) action();
|
|
1590
|
-
};
|
|
1591
|
-
}
|
|
1592
|
-
function printMajorNotice(current, latest) {
|
|
1593
|
-
process.stderr.write(
|
|
1594
|
-
`
|
|
1595
|
-
${c3.yellow}${c3.bold}Major update available:${c3.reset} ${current} \u2192 ${c3.green}${latest}${c3.reset}
|
|
1596
|
-
${c3.dim}Review the changelog before upgrading:${c3.reset}
|
|
1597
|
-
bun update -g ${PACKAGE_NAME}
|
|
1598
|
-
`
|
|
1599
|
-
);
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
// src/cli.ts
|
|
1603
|
-
{
|
|
1604
|
-
const dispatched = process.env["GLRS_CLI_DISPATCHED"];
|
|
1605
|
-
if (!dispatched || dispatched === "") {
|
|
1606
|
-
const argv1 = process.argv[1] ?? "harness-opencode";
|
|
1607
|
-
const invoke = argv1.replace(/\\/g, "/").split("/").pop() ?? "harness-opencode";
|
|
1608
|
-
process.stderr.write(`[${invoke}] This binary is deprecated when invoked standalone.
|
|
1609
|
-
`);
|
|
1610
|
-
process.stderr.write(`[${invoke}] Install @glrs-dev/cli and use 'glrs oc' instead:
|
|
1611
|
-
`);
|
|
1612
|
-
process.stderr.write(`[${invoke}] npm i -g @glrs-dev/cli
|
|
1613
|
-
`);
|
|
1614
|
-
process.stderr.write(`[${invoke}] glrs oc <args>
|
|
1615
|
-
`);
|
|
1616
|
-
process.stderr.write(`[${invoke}] Docs: https://glrs.dev/install
|
|
1617
|
-
`);
|
|
1618
|
-
process.exit(1);
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
if (!process.versions.bun) {
|
|
1622
|
-
const [majorStr = "0", minorStr = "0"] = (process.versions.node ?? "0.0").split(".");
|
|
1623
|
-
const major = Number(majorStr);
|
|
1624
|
-
const minor = Number(minorStr);
|
|
1625
|
-
if (major < 20 || major === 20 && minor < 10) {
|
|
1626
|
-
process.stderr.write(
|
|
1627
|
-
`harness-opencode requires Node.js >= 20.10 (you are on ${process.versions.node}).
|
|
1628
|
-
Upgrade Node or run via a compatible Bun runtime. See the "engines" field in package.json.
|
|
1629
|
-
`
|
|
1630
|
-
);
|
|
1631
|
-
process.exit(1);
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
var VERSION = "0.1.0";
|
|
1635
|
-
var installCmd = command2({
|
|
1636
|
-
name: "install",
|
|
1637
|
-
description: 'Add "@glrs-dev/harness-plugin-opencode" to your opencode.json plugin array.',
|
|
1638
|
-
args: {
|
|
1639
|
-
dryRun: flag({
|
|
1640
|
-
long: "dry-run",
|
|
1641
|
-
description: "Preview changes without writing."
|
|
1642
|
-
}),
|
|
1643
|
-
pin: flag({
|
|
1644
|
-
long: "pin",
|
|
1645
|
-
description: "Pin to the current exact version (e.g. @0.1.0)."
|
|
1646
|
-
})
|
|
1647
|
-
},
|
|
1648
|
-
handler: async ({ dryRun, pin }) => {
|
|
1649
|
-
await install({ dryRun, pin });
|
|
1650
|
-
}
|
|
1651
|
-
});
|
|
1652
|
-
var uninstallCmd = command2({
|
|
1653
|
-
name: "uninstall",
|
|
1654
|
-
description: 'Remove "@glrs-dev/harness-plugin-opencode" from your opencode.json plugin array.',
|
|
1655
|
-
args: {
|
|
1656
|
-
dryRun: flag({
|
|
1657
|
-
long: "dry-run",
|
|
1658
|
-
description: "Preview changes without writing."
|
|
1659
|
-
})
|
|
1660
|
-
},
|
|
1661
|
-
handler: ({ dryRun }) => {
|
|
1662
|
-
uninstall({ dryRun });
|
|
1663
|
-
}
|
|
1664
|
-
});
|
|
1665
|
-
var doctorCmd = command2({
|
|
1666
|
-
name: "doctor",
|
|
1667
|
-
description: "Check installation health (OpenCode CLI, plugin registration, MCP backends).",
|
|
1668
|
-
args: {},
|
|
1669
|
-
handler: () => {
|
|
1670
|
-
doctor();
|
|
1671
|
-
}
|
|
1672
|
-
});
|
|
1673
|
-
var installPluginCmd = command2({
|
|
1674
|
-
name: "install-plugin",
|
|
1675
|
-
description: 'Add "@glrs-dev/harness-plugin-opencode" to your opencode.json plugin array.',
|
|
1676
|
-
args: {
|
|
1677
|
-
dryRun: flag({
|
|
1678
|
-
long: "dry-run",
|
|
1679
|
-
description: "Preview changes without writing."
|
|
1680
|
-
}),
|
|
1681
|
-
pin: flag({
|
|
1682
|
-
long: "pin",
|
|
1683
|
-
description: "Pin to the current exact version (e.g. @0.1.0)."
|
|
1684
|
-
})
|
|
1685
|
-
},
|
|
1686
|
-
handler: async ({ dryRun, pin }) => {
|
|
1687
|
-
await install({ dryRun, pin });
|
|
1688
|
-
}
|
|
1689
|
-
});
|
|
1690
|
-
var cli = subcommands({
|
|
1691
|
-
name: "glrs-oc",
|
|
1692
|
-
description: "OpenCode agent harness CLI.",
|
|
1693
|
-
version: VERSION,
|
|
1694
|
-
cmds: {
|
|
1695
|
-
"install-plugin": installPluginCmd,
|
|
1696
|
-
install: installCmd,
|
|
1697
|
-
uninstall: uninstallCmd,
|
|
1698
|
-
configure: configureCmd,
|
|
1699
|
-
doctor: doctorCmd
|
|
1700
|
-
// Note: `loop` and `autopilot` commands have moved to @glrs-dev/cli.
|
|
1701
|
-
}
|
|
1702
|
-
});
|
|
1703
|
-
var printUpdate = startUpdateCheck();
|
|
1704
|
-
process.on("exit", printUpdate);
|
|
1705
|
-
void run(binary(cli), process.argv);
|