toga-ai 1.0.45 → 1.0.46

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/knowledge.js CHANGED
@@ -170,6 +170,82 @@ function cmdManifest() {
170
170
  console.log(JSON.stringify({ repos, clients }));
171
171
  }
172
172
 
173
+ /* ------------------------------------------------------------------ */
174
+ /* command: publish — capture's deterministic finish (validate, index, */
175
+ /* optional mirror, commit knowledge/, rebase-before-push with retry). */
176
+ /* Replaces ~80 lines of skill prose + 6 model-orchestrated git calls. */
177
+ /* Flags: --msg=<commit msg> --mirror=<project .claude dir> --branch= */
178
+ /* Prints one PUBLISH: <STATUS> line the skill can branch on. */
179
+ /* ------------------------------------------------------------------ */
180
+
181
+ function copyDir(src, dest) {
182
+ fs.mkdirSync(dest, { recursive: true });
183
+ for (const e of fs.readdirSync(src, { withFileTypes: true })) {
184
+ const s = path.join(src, e.name), d = path.join(dest, e.name);
185
+ if (e.isDirectory()) copyDir(s, d);
186
+ else fs.copyFileSync(s, d);
187
+ }
188
+ }
189
+
190
+ function cmdPublish(args) {
191
+ const cp = require('child_process');
192
+ const TEAM = __dirname;
193
+ const node = process.argv[0];
194
+ const self = __filename;
195
+ const branch = args.branch || '_main';
196
+ const run = (cmd) => cp.execSync(cmd, { cwd: TEAM, encoding: 'utf8', stdio: 'pipe' });
197
+
198
+ // 0. must be a git clone
199
+ try { run('git rev-parse --git-dir'); }
200
+ catch { console.log('PUBLISH: NOT_GIT — knowledge written locally only; run `npx toga-ai` to create a pushable clone'); return; }
201
+
202
+ // 1. validate (inherit output so any ERROR: lines are visible); abort on failure
203
+ try { cp.execSync(`"${node}" "${self}" validate`, { cwd: TEAM, stdio: 'inherit' }); }
204
+ catch { console.log('PUBLISH: VALIDATE_FAILED — fix the errors above; nothing pushed'); process.exitCode = 1; return; }
205
+
206
+ // 2. rebuild indexes
207
+ cp.execSync(`"${node}" "${self}" index`, { cwd: TEAM, stdio: 'inherit' });
208
+
209
+ // 3. optional mirror back to the project bundle (keeps local reads fresh)
210
+ if (args.mirror && typeof args.mirror === 'string') {
211
+ const dest = path.join(args.mirror, 'knowledge');
212
+ if (path.resolve(dest) !== path.resolve(ROOT)) { copyDir(ROOT, dest); console.log('PUBLISH: mirrored knowledge/ -> ' + dest); }
213
+ }
214
+
215
+ // 4. stage knowledge/ ONLY; bail if anything else slipped in
216
+ run('git add knowledge/');
217
+ const staged = run('git diff --cached --name-only').split('\n').map(s => s.trim()).filter(Boolean);
218
+ if (staged.length === 0) { console.log('PUBLISH: NO_CHANGES — nothing new to push'); return; }
219
+ const outside = staged.filter(f => !f.startsWith('knowledge/'));
220
+ if (outside.length) { run('git reset -q'); console.log('PUBLISH: ABORT_OUTSIDE_KNOWLEDGE — refusing to commit non-knowledge files: ' + outside.join(', ')); process.exitCode = 1; return; }
221
+
222
+ // 5. commit
223
+ const msg = String(args.msg || 'knowledge: capture session updates').replace(/["\\]/g, "'").slice(0, 200);
224
+ run(`git commit -m "${msg}"`);
225
+
226
+ // 6. rebase-before-push, retrying the CI version-bump race up to 3x
227
+ for (let attempt = 1; attempt <= 3; attempt++) {
228
+ try {
229
+ run('git fetch origin');
230
+ run(`git rebase origin/${branch}`);
231
+ run(`git push origin HEAD:${branch}`);
232
+ console.log(`PUBLISH: PUSHED to ${branch} — CI publishes a new npm version; teammates get it on \`npx toga-ai\``);
233
+ return;
234
+ } catch (e) {
235
+ let status = '';
236
+ try { status = run('git status --porcelain'); } catch { /* ignore */ }
237
+ if (/^(UU|AA|DD|AU|UA|DU|UD) /m.test(status)) {
238
+ try { run('git rebase --abort'); } catch { /* ignore */ }
239
+ console.log(`PUBLISH: CONFLICT — rebase onto origin/${branch} hit a real conflict; resolve manually, then re-run publish`);
240
+ process.exitCode = 1; return;
241
+ }
242
+ // else: almost certainly a fresh CI bump (non-fast-forward) — loop and retry
243
+ }
244
+ }
245
+ console.log(`PUBLISH: PUSH_FAILED after 3 attempts — run manually: git -C "${TEAM}" push origin HEAD:${branch}`);
246
+ process.exitCode = 1;
247
+ }
248
+
173
249
  /* ------------------------------------------------------------------ */
174
250
  /* command: deps */
175
251
  /* ------------------------------------------------------------------ */
@@ -405,8 +481,9 @@ function main() {
405
481
  case 'deps': return cmdDeps(args);
406
482
  case 'validate': return cmdValidate();
407
483
  case 'manifest': return cmdManifest();
484
+ case 'publish': return cmdPublish(args);
408
485
  default:
409
- console.log('Usage: node knowledge.js <search|index|deps|validate|manifest> [--flags]');
486
+ console.log('Usage: node knowledge.js <search|index|deps|validate|manifest|publish> [--flags]');
410
487
  process.exitCode = 1;
411
488
  }
412
489
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -53,8 +53,8 @@ done
53
53
  **`~/toga-tech` must be probed first** — `npx toga-ai` runs `initLocalRepo` there, which
54
54
  creates a proper git repo seeded from the bundle even when the remote is private.
55
55
 
56
- **If `IS_GIT_CLONE` is false** (only `.claude/` bundle found): warn immediately and skip
57
- Steps 5–7 for git operations:
56
+ **If `IS_GIT_CLONE` is false** (only `.claude/` bundle found): you can still write docs
57
+ locally (Step 5), but the Step 6 publish will report `NOT_GIT` instead of pushing. Warn:
58
58
  > "⚠ No git clone found at standard paths. Docs will be written locally only.
59
59
  > Run `npx toga-ai` first (it creates `~/toga-tech` as a pushable git repo),
60
60
  > then re-run /capture to push to GitHub."
@@ -143,94 +143,34 @@ For a client `profile.md`, the `title:` **is** the client's formal name (e.g. "C
143
143
  there is no separate name field; `validate` requires `title`. See New-client onboarding.
144
144
  Add `related:` cross-links. Append new repos to `<TEAM_REPO>/knowledge/registry.json`.
145
145
 
146
- ## Step 6 — Validate, index, mirror back (mandatory)
146
+ ## Step 6 — Publish (validate → index mirror rebase-push, one command)
147
147
 
148
- ```bash
149
- node "<TEAM_REPO>/knowledge.js" validate
150
- node "<TEAM_REPO>/knowledge.js" index
151
- ```
152
-
153
- If `validate` reports any ERROR — stop and fix before continuing.
154
-
155
- After both pass, **mirror back** to keep the project's local reads fresh:
156
- ```bash
157
- # Only when TEAM_REPO != <project>/.claude
158
- cp -r "<TEAM_REPO>/knowledge/" "<project>/.claude/knowledge/"
159
- ```
160
- Skip mirror-back if the paths are the same directory.
161
-
162
- ## Step 7 — Push (only when IS_GIT_CLONE is true)
163
-
164
- **This push is pre-authorized and mandatory — never ask the developer to confirm it.**
165
- Running `/capture` IS the authorization to publish. After validate + index pass and the
166
- staged set is confined to `knowledge/`, commit and push automatically as the final step of
167
- every capture. Do not pause, do not present a "ready to push?" prompt, do not offer to "leave
168
- it staged locally." The only reasons to stop are the guardrails already listed below: nothing
169
- new to push (Check B empty), files staged outside `knowledge/`, or a push that errors.
170
-
171
- If `IS_GIT_CLONE` is false — skip this step entirely and show:
172
- > "⚠ Docs written to `.claude/knowledge/` only (no git clone). Run `npx toga-ai`
173
- > to create `~/toga-tech`, then re-run /capture to push."
174
-
175
- Otherwise:
176
-
177
- **Check A — origin URL correct?**
178
- ```bash
179
- git -C "<TEAM_REPO>" remote get-url origin
180
- ```
181
- If wrong or missing: `git -C "<TEAM_REPO>" remote set-url origin https://github.com/agilantsolutions/claude`
182
-
183
- **Check B — anything new to push?**
184
- ```bash
185
- git -C "<TEAM_REPO>" status --short knowledge/
186
- ```
187
- If empty — report "No new knowledge to push" and exit cleanly.
188
-
189
- **Commit:**
190
- ```bash
191
- git -C "<TEAM_REPO>" add knowledge/
192
- git -C "<TEAM_REPO>" diff --cached --quiet || \
193
- git -C "<TEAM_REPO>" commit -m "knowledge: <one-line summary>"
194
- ```
195
-
196
- Never stage files outside `knowledge/`. If `git diff --cached` includes anything outside
197
- `knowledge/`, abort and warn before committing.
198
-
199
- **Sync, then push (rebase BEFORE pushing — this prevents the version-bump conflict):**
200
-
201
- Every push to this branch triggers a CI job that commits a `chore: bump version [skip ci]`
202
- back to the branch. So after *any* prior push (e.g. an earlier capture in the same session),
203
- your local branch is one commit behind the remote, and a naive push is rejected as a
204
- non-fast-forward. Rebase your fresh commit onto the remote **before** pushing — this pulls in
205
- commits that already exist (no waiting on CI), so the push fast-forwards cleanly:
148
+ Finish every capture with the deterministic publisher — **do not** run validate/index/git
149
+ by hand. The push is **pre-authorized and mandatory**: running `/capture` IS the
150
+ authorization, so never ask "ready to push?".
206
151
 
207
152
  ```bash
208
- git -C "<TEAM_REPO>" fetch origin
209
- git -C "<TEAM_REPO>" rebase origin/_main
210
- git -C "<TEAM_REPO>" push origin HEAD:_main
153
+ node "<TEAM_REPO>/knowledge.js" publish --msg="knowledge: <one-line summary>" --mirror="<project>/.claude"
211
154
  ```
212
155
 
213
- > **Do NOT "pull after push" instead** the bump commit for *this* push is created
214
- > asynchronously by CI a few seconds later, so pulling immediately afterward races CI and
215
- > usually grabs nothing. Rebasing *before* the push is what reliably avoids the conflict,
216
- > with zero dependency on npm build/publish timing.
217
-
218
- **If the push is still rejected** (a bump commit landed in the brief window between your
219
- rebase and push), simply repeat `fetch` → `rebase` → `push`, up to 2 more times. This is an
220
- expected occasional race, not an error — do not report it as a failure unless all retries are
221
- exhausted.
222
-
223
- **If push succeeds:**
224
- > "✓ Pushed to `_main` — CI publishes new npm version. Teammates get it on `npx toga-ai`."
156
+ This validates, rebuilds indexes, mirrors `knowledge/` back to the project bundle, then
157
+ stages **only** `knowledge/`, commits, and rebase-pushes to `_main` (auto-retrying the CI
158
+ version-bump race). Omit `--mirror` if TEAM_REPO already *is* the project bundle. Read the
159
+ final `PUBLISH:` line and act on it:
225
160
 
226
- **If push fails**show exact git error, then:
227
- > "⚠ Push failed: `<error>`. Run manually: `git -C <TEAM_REPO> push origin HEAD:_main`"
161
+ - **`PUSHED`** done. Report: "✓ Pushed to `_main` teammates get it on `npx toga-ai`."
162
+ - **`NO_CHANGES`** report "No new knowledge to push" and finish.
163
+ - **`VALIDATE_FAILED`** — fix the printed `ERROR:` lines, then re-run publish. Never push around it.
164
+ - **`CONFLICT`** — a real rebase conflict; resolve manually, then re-run publish.
165
+ - **`ABORT_OUTSIDE_KNOWLEDGE`** — non-`knowledge/` files were staged; investigate before retrying.
166
+ - **`NOT_GIT`** — no git clone; docs are local only. Tell the dev to run `npx toga-ai` first.
167
+ - **`PUSH_FAILED`** — show the printed manual-push command.
228
168
 
229
- ## Step 8 — Report
169
+ ## Step 7 — Report
230
170
 
231
171
  List exactly what changed (clickable relative paths), and note any ⚠ ELEVATED docs the
232
172
  developer approved so they remember those touched senior-owned standards/architecture.
233
- If Step 7 pushed successfully, include the push confirmation in the report.
173
+ If Step 6 published successfully (`PUSHED`), include the push confirmation in the report.
234
174
 
235
175
  ---
236
176
 
@@ -396,4 +336,4 @@ Suggest a slug from the work, e.g. `/session-save clickup-deploy-worker`.
396
336
 
397
337
  `.claude/settings.json` runs `node knowledge.js validate` after every write to `knowledge/`,
398
338
  so `ERROR:`/`OK` output appears inline as each doc is written — fix any error before writing
399
- the next. Step 6's explicit `validate` is still required as the final global-consistency gate.
339
+ the next. Step 6's `publish` re-runs `validate` as the final global-consistency gate before pushing.