goalbuddy 0.2.13 → 0.2.14
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/README.md
CHANGED
|
@@ -30,6 +30,12 @@ $goalbuddy
|
|
|
30
30
|
|
|
31
31
|
`$goalbuddy` prepares the board and prints the `/goal` command to run next. It does not start `/goal` automatically.
|
|
32
32
|
|
|
33
|
+
For native Codex plugin install instead of the skill-only installer:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx goalbuddy plugin install
|
|
37
|
+
```
|
|
38
|
+
|
|
33
39
|
## Why GoalBuddy Exists
|
|
34
40
|
|
|
35
41
|
Long Codex goals drift. A request like "improve this project" can turn into unbounded edits, stale verification, and premature completion claims.
|
|
@@ -79,6 +85,12 @@ npx goalbuddy
|
|
|
79
85
|
npx goalbuddy update
|
|
80
86
|
```
|
|
81
87
|
|
|
88
|
+
Install and enable the native Codex plugin:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx goalbuddy plugin install
|
|
92
|
+
```
|
|
93
|
+
|
|
82
94
|
Native Codex `/goal` is still an under-development Codex feature. Before relying on the printed command, confirm your local Codex runtime is logged in and has goals enabled:
|
|
83
95
|
|
|
84
96
|
```bash
|
|
@@ -36,6 +36,7 @@ const optionsWithValues = new Set([
|
|
|
36
36
|
"--catalog-url",
|
|
37
37
|
"--codex-home",
|
|
38
38
|
"--kind",
|
|
39
|
+
"--source",
|
|
39
40
|
]);
|
|
40
41
|
|
|
41
42
|
const args = process.argv.slice(2);
|
|
@@ -64,6 +65,9 @@ async function main() {
|
|
|
64
65
|
case "doctor":
|
|
65
66
|
doctor();
|
|
66
67
|
break;
|
|
68
|
+
case "plugin":
|
|
69
|
+
plugin();
|
|
70
|
+
break;
|
|
67
71
|
case "extend":
|
|
68
72
|
await extend();
|
|
69
73
|
break;
|
|
@@ -133,6 +137,7 @@ Usage:
|
|
|
133
137
|
${canonicalCliName} update [--codex-home <path>] [--json]
|
|
134
138
|
${canonicalCliName} agents [--codex-home <path>] [--force]
|
|
135
139
|
${canonicalCliName} doctor [--codex-home <path>] [--goal-ready]
|
|
140
|
+
${canonicalCliName} plugin install [--source <marketplace-source>] [--codex-home <path>] [--json]
|
|
136
141
|
${canonicalCliName} extend [--catalog-url <url-or-path>] [--kind <kind>] [--json]
|
|
137
142
|
${canonicalCliName} extend <id> [--catalog-url <url-or-path>] [--json]
|
|
138
143
|
${canonicalCliName} extend install <id> [--catalog-url <url-or-path>] [--dry-run] [--force] [--json]
|
|
@@ -321,6 +326,123 @@ function doctor() {
|
|
|
321
326
|
process.exit(installOk && goalReadyOk ? 0 : 1);
|
|
322
327
|
}
|
|
323
328
|
|
|
329
|
+
function plugin() {
|
|
330
|
+
const subcommand = positional(1) || "";
|
|
331
|
+
switch (subcommand) {
|
|
332
|
+
case "install":
|
|
333
|
+
installPlugin();
|
|
334
|
+
break;
|
|
335
|
+
case "help":
|
|
336
|
+
case "--help":
|
|
337
|
+
case "-h":
|
|
338
|
+
pluginUsage();
|
|
339
|
+
break;
|
|
340
|
+
default:
|
|
341
|
+
console.error(`Unknown plugin command: ${subcommand || "<missing>"}`);
|
|
342
|
+
pluginUsage();
|
|
343
|
+
process.exit(2);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function pluginUsage() {
|
|
348
|
+
console.log(`${canonicalProductName} Plugin
|
|
349
|
+
|
|
350
|
+
Usage:
|
|
351
|
+
${canonicalCliName} plugin install [--source <marketplace-source>] [--codex-home <path>] [--json]
|
|
352
|
+
|
|
353
|
+
Default source:
|
|
354
|
+
tolibear/goalbuddy
|
|
355
|
+
`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function installPlugin() {
|
|
359
|
+
const source = optionValue("--source") || "tolibear/goalbuddy";
|
|
360
|
+
const pluginSource = join(packageRoot, "plugins", canonicalSkillName);
|
|
361
|
+
const pluginManifestPath = join(pluginSource, ".codex-plugin", "plugin.json");
|
|
362
|
+
if (!existsSync(pluginManifestPath)) {
|
|
363
|
+
throw new Error(`Plugin manifest not found: ${pluginManifestPath}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const pluginManifest = JSON.parse(readFileSync(pluginManifestPath, "utf8"));
|
|
367
|
+
const pluginCachePath = pluginCacheRoot(pluginManifest.version);
|
|
368
|
+
const marketplace = runCodex(["plugin", "marketplace", "add", source]);
|
|
369
|
+
if (!marketplace.ok) {
|
|
370
|
+
throw new Error(`Failed to add Codex plugin marketplace: ${firstLine(marketplace.stderr || marketplace.stdout)}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
mkdirSync(dirname(pluginCachePath), { recursive: true });
|
|
374
|
+
rmSync(pluginCachePath, { recursive: true, force: true });
|
|
375
|
+
cpSync(pluginSource, pluginCachePath, { recursive: true });
|
|
376
|
+
const configPath = enablePluginConfig();
|
|
377
|
+
|
|
378
|
+
const report = {
|
|
379
|
+
installed: true,
|
|
380
|
+
plugin: `${canonicalSkillName}@${canonicalSkillName}`,
|
|
381
|
+
version: pluginManifest.version,
|
|
382
|
+
codex_home: codexHome(),
|
|
383
|
+
marketplace_source: source,
|
|
384
|
+
cache_path: pluginCachePath,
|
|
385
|
+
config_path: configPath,
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
if (hasFlag("--json")) {
|
|
389
|
+
printJson(report);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
console.log(`Installed ${canonicalProductName} Codex plugin ${pluginManifest.version}`);
|
|
394
|
+
console.log(`Marketplace: ${source}`);
|
|
395
|
+
console.log(`Cache: ${pluginCachePath}`);
|
|
396
|
+
console.log(`Config: ${configPath}`);
|
|
397
|
+
console.log("");
|
|
398
|
+
console.log("Restart Codex, then use:");
|
|
399
|
+
console.log(` $${canonicalSkillName}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function pluginCacheRoot(version) {
|
|
403
|
+
return join(codexHome(), "plugins", "cache", canonicalSkillName, canonicalSkillName, version);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function enablePluginConfig() {
|
|
407
|
+
const configPath = join(codexHome(), "config.toml");
|
|
408
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
409
|
+
const header = `[plugins."${canonicalSkillName}@${canonicalSkillName}"]`;
|
|
410
|
+
const existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
411
|
+
const updated = upsertTomlEnabled(existing, header);
|
|
412
|
+
writeFileSync(configPath, updated);
|
|
413
|
+
return configPath;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function upsertTomlEnabled(text, header) {
|
|
417
|
+
const normalized = text.endsWith("\n") || text.length === 0 ? text : `${text}\n`;
|
|
418
|
+
const lines = normalized.split("\n");
|
|
419
|
+
const start = lines.findIndex((line) => line.trim() === header);
|
|
420
|
+
if (start === -1) {
|
|
421
|
+
const prefix = normalized.trim() ? `${normalized}\n` : "";
|
|
422
|
+
return `${prefix}${header}\nenabled = true\n`;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
let end = lines.length;
|
|
426
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
427
|
+
if (/^\s*\[/.test(lines[index])) {
|
|
428
|
+
end = index;
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let sawEnabled = false;
|
|
434
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
435
|
+
if (/^\s*enabled\s*=/.test(lines[index])) {
|
|
436
|
+
lines[index] = "enabled = true";
|
|
437
|
+
sawEnabled = true;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (!sawEnabled) lines.splice(start + 1, 0, "enabled = true");
|
|
442
|
+
|
|
443
|
+
return lines.join("\n").replace(/\n*$/, "\n");
|
|
444
|
+
}
|
|
445
|
+
|
|
324
446
|
function codexGoalRuntimeStatus() {
|
|
325
447
|
const version = runCodex(["--version"]);
|
|
326
448
|
const login = version.ok ? runCodex(["login", "status"]) : { ok: false, stdout: "", stderr: "codex CLI unavailable" };
|
package/package.json
CHANGED
|
@@ -19,13 +19,13 @@ npx goalbuddy doctor
|
|
|
19
19
|
|
|
20
20
|
## Native Codex Install
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Install and enable the plugin with the GoalBuddy CLI:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
|
|
25
|
+
npx goalbuddy plugin install
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
This adds the `tolibear/goalbuddy` marketplace, caches the packaged plugin, and enables `goalbuddy@goalbuddy` for Codex. The npm CLI remains useful for `doctor`, project-local agent setup, and optional GoalBuddy extension management.
|
|
29
29
|
|
|
30
30
|
For local CLI testing before npm publish:
|
|
31
31
|
|