goalbuddy 0.2.13 → 0.2.15

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.
@@ -11,7 +11,7 @@
11
11
  "path": "./plugins/goalbuddy"
12
12
  },
13
13
  "policy": {
14
- "installation": "AVAILABLE",
14
+ "installation": "INSTALLED_BY_DEFAULT",
15
15
  "authentication": "ON_INSTALL"
16
16
  },
17
17
  "category": "Coding"
package/README.md CHANGED
@@ -22,7 +22,13 @@ GoalBuddy is a local Codex companion for work that is too broad to trust to a si
22
22
  npx goalbuddy
23
23
  ```
24
24
 
25
- Then invoke the installed skill inside Codex:
25
+ Or install it globally:
26
+
27
+ ```bash
28
+ npm i -g goalbuddy
29
+ ```
30
+
31
+ Then restart Codex and invoke the installed skill:
26
32
 
27
33
  ```text
28
34
  $goalbuddy
@@ -72,10 +78,17 @@ The default agents are installed with the skill:
72
78
 
73
79
  ## Install And Check Readiness
74
80
 
75
- Install or refresh the Codex skill and bundled agents:
81
+ Install and enable the native Codex plugin:
76
82
 
77
83
  ```bash
78
84
  npx goalbuddy
85
+ npm i -g goalbuddy
86
+ ```
87
+
88
+ Use the skill-only fallback if your Codex build does not support plugins:
89
+
90
+ ```bash
91
+ npx goalbuddy install
79
92
  npx goalbuddy update
80
93
  ```
81
94
 
@@ -102,10 +115,10 @@ npx goalbuddy doctor
102
115
  Use a non-default Codex home:
103
116
 
104
117
  ```bash
105
- npx goalbuddy install --codex-home /path/to/.codex
118
+ npx goalbuddy --codex-home /path/to/.codex
106
119
  ```
107
120
 
108
- `install`, `update`, and `doctor` also support `--json` when an agent or script needs structured output.
121
+ `plugin install`, `install`, `update`, and `doctor` also support `--json` when an agent or script needs structured output.
109
122
 
110
123
  ## Run A Goal
111
124
 
@@ -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);
@@ -43,7 +44,7 @@ const command = args[0] === "--help" || args[0] === "-h"
43
44
  ? "help"
44
45
  : args[0] && !args[0].startsWith("-")
45
46
  ? args[0]
46
- : "install";
47
+ : "default";
47
48
  const invokedAs = invokedCommandName();
48
49
 
49
50
  main().catch((error) => {
@@ -54,6 +55,9 @@ main().catch((error) => {
54
55
  async function main() {
55
56
  maybePrintLegacyNotice();
56
57
  switch (command) {
58
+ case "default":
59
+ installPlugin();
60
+ break;
57
61
  case "install":
58
62
  case "update":
59
63
  await installAll();
@@ -64,6 +68,9 @@ async function main() {
64
68
  case "doctor":
65
69
  doctor();
66
70
  break;
71
+ case "plugin":
72
+ plugin();
73
+ break;
67
74
  case "extend":
68
75
  await extend();
69
76
  break;
@@ -129,6 +136,8 @@ function usage() {
129
136
  console.log(`Codex ${canonicalProductName}
130
137
 
131
138
  Usage:
139
+ ${canonicalCliName} [--codex-home <path>] [--json]
140
+ ${canonicalCliName} plugin install [--source <marketplace-source>] [--codex-home <path>] [--json]
132
141
  ${canonicalCliName} install [--codex-home <path>] [--force] [--json]
133
142
  ${canonicalCliName} update [--codex-home <path>] [--json]
134
143
  ${canonicalCliName} agents [--codex-home <path>] [--force]
@@ -140,7 +149,10 @@ Usage:
140
149
  ${canonicalCliName} extend doctor [<id>] [--codex-home <path>] [--json]
141
150
 
142
151
  Default:
143
- ${canonicalCliName} Installs the skill and bundled agent definitions.
152
+ ${canonicalCliName} Installs and enables the native Codex plugin.
153
+
154
+ Skill-only fallback:
155
+ ${canonicalCliName} install Installs the legacy skill payload and bundled agent definitions.
144
156
 
145
157
  Compatibility:
146
158
  ${legacyCliName} remains a temporary alias and prints the new npx command for human-facing use.
@@ -321,6 +333,123 @@ function doctor() {
321
333
  process.exit(installOk && goalReadyOk ? 0 : 1);
322
334
  }
323
335
 
336
+ function plugin() {
337
+ const subcommand = positional(1) || "";
338
+ switch (subcommand) {
339
+ case "install":
340
+ installPlugin();
341
+ break;
342
+ case "help":
343
+ case "--help":
344
+ case "-h":
345
+ pluginUsage();
346
+ break;
347
+ default:
348
+ console.error(`Unknown plugin command: ${subcommand || "<missing>"}`);
349
+ pluginUsage();
350
+ process.exit(2);
351
+ }
352
+ }
353
+
354
+ function pluginUsage() {
355
+ console.log(`${canonicalProductName} Plugin
356
+
357
+ Usage:
358
+ ${canonicalCliName} plugin install [--source <marketplace-source>] [--codex-home <path>] [--json]
359
+
360
+ Default source:
361
+ tolibear/goalbuddy
362
+ `);
363
+ }
364
+
365
+ function installPlugin() {
366
+ const source = optionValue("--source") || "tolibear/goalbuddy";
367
+ const pluginSource = join(packageRoot, "plugins", canonicalSkillName);
368
+ const pluginManifestPath = join(pluginSource, ".codex-plugin", "plugin.json");
369
+ if (!existsSync(pluginManifestPath)) {
370
+ throw new Error(`Plugin manifest not found: ${pluginManifestPath}`);
371
+ }
372
+
373
+ const pluginManifest = JSON.parse(readFileSync(pluginManifestPath, "utf8"));
374
+ const pluginCachePath = pluginCacheRoot(pluginManifest.version);
375
+ const marketplace = runCodex(["plugin", "marketplace", "add", source]);
376
+ if (!marketplace.ok) {
377
+ throw new Error(`Failed to add Codex plugin marketplace: ${firstLine(marketplace.stderr || marketplace.stdout)}`);
378
+ }
379
+
380
+ mkdirSync(dirname(pluginCachePath), { recursive: true });
381
+ rmSync(pluginCachePath, { recursive: true, force: true });
382
+ cpSync(pluginSource, pluginCachePath, { recursive: true });
383
+ const configPath = enablePluginConfig();
384
+
385
+ const report = {
386
+ installed: true,
387
+ plugin: `${canonicalSkillName}@${canonicalSkillName}`,
388
+ version: pluginManifest.version,
389
+ codex_home: codexHome(),
390
+ marketplace_source: source,
391
+ cache_path: pluginCachePath,
392
+ config_path: configPath,
393
+ };
394
+
395
+ if (hasFlag("--json")) {
396
+ printJson(report);
397
+ return;
398
+ }
399
+
400
+ console.log(`Installed ${canonicalProductName} Codex plugin ${pluginManifest.version}`);
401
+ console.log(`Marketplace: ${source}`);
402
+ console.log(`Cache: ${pluginCachePath}`);
403
+ console.log(`Config: ${configPath}`);
404
+ console.log("");
405
+ console.log("Restart Codex, then use:");
406
+ console.log(` $${canonicalSkillName}`);
407
+ }
408
+
409
+ function pluginCacheRoot(version) {
410
+ return join(codexHome(), "plugins", "cache", canonicalSkillName, canonicalSkillName, version);
411
+ }
412
+
413
+ function enablePluginConfig() {
414
+ const configPath = join(codexHome(), "config.toml");
415
+ mkdirSync(dirname(configPath), { recursive: true });
416
+ const header = `[plugins."${canonicalSkillName}@${canonicalSkillName}"]`;
417
+ const existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
418
+ const updated = upsertTomlEnabled(existing, header);
419
+ writeFileSync(configPath, updated);
420
+ return configPath;
421
+ }
422
+
423
+ function upsertTomlEnabled(text, header) {
424
+ const normalized = text.endsWith("\n") || text.length === 0 ? text : `${text}\n`;
425
+ const lines = normalized.split("\n");
426
+ const start = lines.findIndex((line) => line.trim() === header);
427
+ if (start === -1) {
428
+ const prefix = normalized.trim() ? `${normalized}\n` : "";
429
+ return `${prefix}${header}\nenabled = true\n`;
430
+ }
431
+
432
+ let end = lines.length;
433
+ for (let index = start + 1; index < lines.length; index += 1) {
434
+ if (/^\s*\[/.test(lines[index])) {
435
+ end = index;
436
+ break;
437
+ }
438
+ }
439
+
440
+ let sawEnabled = false;
441
+ for (let index = start + 1; index < end; index += 1) {
442
+ if (/^\s*enabled\s*=/.test(lines[index])) {
443
+ lines[index] = "enabled = true";
444
+ sawEnabled = true;
445
+ break;
446
+ }
447
+ }
448
+ if (!sawEnabled) lines.splice(start + 1, 0, "enabled = true");
449
+
450
+ return lines.join("\n").replace(/\n*$/, "\n");
451
+ }
452
+
324
453
  function codexGoalRuntimeStatus() {
325
454
  const version = runCodex(["--version"]);
326
455
  const login = version.ok ? runCodex(["login", "status"]) : { ok: false, stdout: "", stderr: "codex CLI unavailable" };
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const cliPath = join(__dirname, "goal-maker.mjs");
8
+ const globalInstall = process.env.npm_config_global === "true"
9
+ || process.env.npm_config_location === "global";
10
+
11
+ if (!globalInstall || process.env.GOALBUDDY_SKIP_POSTINSTALL) {
12
+ process.exit(0);
13
+ }
14
+
15
+ const result = spawnSync(process.execPath, [cliPath, "plugin", "install"], {
16
+ encoding: "utf8",
17
+ env: process.env,
18
+ stdio: "inherit",
19
+ });
20
+
21
+ if (result.status === 0) {
22
+ process.exit(0);
23
+ }
24
+
25
+ console.error("");
26
+ console.error("GoalBuddy installed globally, but Codex plugin setup did not complete.");
27
+ console.error("Run this after Codex is available:");
28
+ console.error(" goalbuddy");
29
+ process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goalbuddy",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Turn open-ended Codex goals into a GoalBuddy Scout/Judge/Worker board with receipts, verification, and optional extensions.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,9 +21,10 @@
21
21
  "goalbuddy/templates"
22
22
  ],
23
23
  "scripts": {
24
- "check": "node --check internal/cli/goal-maker.mjs goalbuddy/scripts/*.mjs && node --test internal/test/*.test.mjs",
24
+ "check": "node --check internal/cli/*.mjs goalbuddy/scripts/*.mjs && node --test internal/test/*.test.mjs",
25
25
  "test": "node --test internal/test/*.test.mjs",
26
26
  "pack:dry-run": "npm pack --dry-run",
27
+ "postinstall": "node internal/cli/postinstall.mjs",
27
28
  "publish:check": "node internal/cli/check-publish-version.mjs && npm run pack:dry-run",
28
29
  "prepublishOnly": "node internal/cli/check-publish-version.mjs"
29
30
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goalbuddy",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Turn broad Codex work into verified GoalBuddy boards with Scout, Judge, Worker, receipts, and optional extensions.",
5
5
  "author": {
6
6
  "name": "tolibear",
@@ -19,18 +19,24 @@ npx goalbuddy doctor
19
19
 
20
20
  ## Native Codex Install
21
21
 
22
- Add the repository as a Codex plugin marketplace:
22
+ Install and enable GoalBuddy:
23
23
 
24
24
  ```bash
25
- codex plugin marketplace add tolibear/goalbuddy
25
+ npx goalbuddy
26
26
  ```
27
27
 
28
- Then enable the `goalbuddy` plugin from that marketplace in Codex. The npm CLI remains useful for `doctor`, project-local agent setup, and optional GoalBuddy extension management.
28
+ Or install the npm package globally:
29
+
30
+ ```bash
31
+ npm i -g goalbuddy
32
+ ```
33
+
34
+ The marketplace manifest is included for Codex discovery, but current Codex CLI builds only register the marketplace with `codex plugin marketplace add`; the npm CLI also caches and enables the plugin.
29
35
 
30
36
  For local CLI testing before npm publish:
31
37
 
32
38
  ```bash
33
- node internal/cli/goal-maker.mjs install --catalog-url extend/catalog.json
39
+ node internal/cli/goal-maker.mjs --catalog-url extend/catalog.json
34
40
  node internal/cli/goal-maker.mjs doctor
35
41
  ```
36
42