@forwardimpact/libwiki 0.2.35 → 0.3.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/README.md CHANGED
@@ -14,15 +14,15 @@ storyboards. `libwiki` keeps that wiki coherent across sessions — agents boot
14
14
  from it, write decisions back, send memos to each other, and audit the
15
15
  result against a declarative rule set.
16
16
 
17
- The primary interface is the `fit-wiki` CLI. The library also exposes a few
17
+ The primary interface is the `gemba-wiki` CLI. The library also exposes a few
18
18
  helpers for programmatic use.
19
19
 
20
20
  ## Getting started
21
21
 
22
22
  ```sh
23
- npx fit-wiki init
24
- npx fit-wiki boot --agent staff-engineer
25
- npx fit-wiki audit
23
+ npx gemba-wiki init
24
+ npx gemba-wiki boot --agent staff-engineer
25
+ npx gemba-wiki audit
26
26
  ```
27
27
 
28
28
  ## CLI
@@ -36,7 +36,7 @@ sweep that runs without `--agent`.
36
36
  ### `boot` — start a session
37
37
 
38
38
  ```sh
39
- npx fit-wiki boot --agent staff-engineer [--format json|markdown]
39
+ npx gemba-wiki boot --agent staff-engineer [--format json|markdown]
40
40
  ```
41
41
 
42
42
  Print the on-boot digest for the agent: own priorities, cross-cutting
@@ -45,9 +45,9 @@ priorities, active claims, storyboard items, inbox count.
45
45
  ### `log` — record decisions, notes, done
46
46
 
47
47
  ```sh
48
- npx fit-wiki log decision --agent X --surveyed "..." --chosen "..." --rationale "..."
49
- npx fit-wiki log note --agent X --field "PR Status" --body "merged"
50
- npx fit-wiki log done --agent X
48
+ npx gemba-wiki log decision --agent X --surveyed "..." --chosen "..." --rationale "..."
49
+ npx gemba-wiki log note --agent X --field "PR Status" --body "merged"
50
+ npx gemba-wiki log done --agent X
51
51
  ```
52
52
 
53
53
  Appends to `wiki/<agent>-YYYY-WVV.md`. Auto-rotates to `*-partN.md` when the
@@ -56,9 +56,9 @@ line budget would be exceeded.
56
56
  ### `claim` / `release` — coordinate work
57
57
 
58
58
  ```sh
59
- npx fit-wiki claim --agent X --target spec-NNNN --branch claude/spec-NNNN
60
- npx fit-wiki release --agent X --target spec-NNNN
61
- npx fit-wiki release --expired
59
+ npx gemba-wiki claim --agent X --target spec-NNNN --branch claude/spec-NNNN
60
+ npx gemba-wiki release --agent X --target spec-NNNN
61
+ npx gemba-wiki release --expired
62
62
  ```
63
63
 
64
64
  Maintains the `## Active Claims` table in `MEMORY.md`. Duplicates refused;
@@ -68,10 +68,10 @@ claim is a short-lived "shipping this now" assertion, not a lease.
68
68
  ### `inbox` — triage memos
69
69
 
70
70
  ```sh
71
- npx fit-wiki inbox list --agent X
72
- npx fit-wiki inbox ack --agent X --index 0
73
- npx fit-wiki inbox promote --agent X --index 0 [--owner X]
74
- npx fit-wiki inbox drop --agent X --index 0
71
+ npx gemba-wiki inbox list --agent X
72
+ npx gemba-wiki inbox ack --agent X --index 0
73
+ npx gemba-wiki inbox promote --agent X --index 0 [--owner X]
74
+ npx gemba-wiki inbox drop --agent X --index 0
75
75
  ```
76
76
 
77
77
  Reads bullets under the `<!-- memo:inbox -->` marker in the agent's summary.
@@ -80,8 +80,8 @@ Reads bullets under the `<!-- memo:inbox -->` marker in the agent's summary.
80
80
  ### `memo` — cross-team coordination
81
81
 
82
82
  ```sh
83
- npx fit-wiki memo --from X --to Y --message "audit d642ff0c"
84
- npx fit-wiki memo --from X --to all --message "new XmR baseline"
83
+ npx gemba-wiki memo --from X --to Y --message "audit d642ff0c"
84
+ npx gemba-wiki memo --from X --to all --message "new XmR baseline"
85
85
  ```
86
86
 
87
87
  Inserts a bullet `- YYYY-MM-DD from **X**: ...` after the recipient's
@@ -90,7 +90,7 @@ Inserts a bullet `- YYYY-MM-DD from **X**: ...` after the recipient's
90
90
  ### `audit` — verify wiki state
91
91
 
92
92
  ```sh
93
- npx fit-wiki audit [--format text|json]
93
+ npx gemba-wiki audit [--format text|json]
94
94
  ```
95
95
 
96
96
  Runs a declarative catalogue of rules across the wiki. Exits 0 on pass, 1
@@ -107,7 +107,7 @@ Each finding carries a stable `id` for filtering. The catalogue lives in
107
107
  ### `rotate` — force a part split
108
108
 
109
109
  ```sh
110
- npx fit-wiki rotate --agent X
110
+ npx gemba-wiki rotate --agent X
111
111
  ```
112
112
 
113
113
  Renames the current weekly log to the next `-partN.md` and starts a fresh
@@ -116,7 +116,7 @@ main file.
116
116
  ### `refresh` — re-render storyboard blocks
117
117
 
118
118
  ```sh
119
- npx fit-wiki refresh [storyboard-path]
119
+ npx gemba-wiki refresh [storyboard-path]
120
120
  ```
121
121
 
122
122
  Re-renders `<!-- xmr:metric:csv-path -->` and `<!-- obstacles:open[:Nd] -->`
@@ -128,9 +128,9 @@ deterministic refresh.
128
128
  ### `init` / `push` / `pull` — wiki working tree
129
129
 
130
130
  ```sh
131
- npx fit-wiki init [--wiki-root wiki] [--skills-dir .claude/skills]
132
- npx fit-wiki push
133
- npx fit-wiki pull
131
+ npx gemba-wiki init [--wiki-root wiki] [--skills-dir .claude/skills]
132
+ npx gemba-wiki push
133
+ npx gemba-wiki pull
134
134
  ```
135
135
 
136
136
  `init` clones the wiki repo if missing, scaffolds Active Claims in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libwiki",
3
- "version": "0.2.35",
3
+ "version": "0.3.0",
4
4
  "description": "Wiki lifecycle for agent teams — persistent memory, declarative integrity audits, and a collision ledger so coordination survives across sessions and parallel work.",
5
5
  "keywords": [
6
6
  "wiki",
@@ -31,14 +31,12 @@
31
31
  "main": "./src/index.js",
32
32
  "exports": {
33
33
  ".": "./src/index.js",
34
- "./bin/fit-wiki.js": "./bin/fit-wiki.js"
35
- },
36
- "bin": {
37
- "fit-wiki": "./bin/fit-wiki.js"
34
+ "./wiki-sync.js": "./src/wiki-sync.js",
35
+ "./util/wiki-dir.js": "./src/util/wiki-dir.js",
36
+ "./cli-definition.js": "./src/cli-definition.js"
38
37
  },
39
38
  "files": [
40
39
  "src/**/*.js",
41
- "bin/**/*.js",
42
40
  "README.md"
43
41
  ],
44
42
  "scripts": {
@@ -47,11 +45,11 @@
47
45
  "dependencies": {
48
46
  "@forwardimpact/libcli": "^0.1.0",
49
47
  "@forwardimpact/libconfig": "^0.1.77",
50
- "@forwardimpact/libharness": "^2.0.0",
48
+ "@forwardimpact/libharness": "^3.0.0",
51
49
  "@forwardimpact/libpreflight": "^0.1.0",
52
50
  "@forwardimpact/libtelemetry": "^0.1.47",
53
51
  "@forwardimpact/libutil": "^0.1.0",
54
- "@forwardimpact/libxmr": "^2.0.0"
52
+ "@forwardimpact/libxmr": "^3.0.0"
55
53
  },
56
54
  "devDependencies": {
57
55
  "@forwardimpact/libmock": "^0.1.0"
@@ -94,7 +94,7 @@ export const RULES = [
94
94
  when: (s) => s.h2s.includes("Message Inbox"),
95
95
  check: containsLine(MEMO_INBOX_MARKER),
96
96
  message: () => `Missing ${MEMO_INBOX_MARKER} marker`,
97
- hint: "add the marker directly below the '## Message Inbox' heading so `fit-wiki memo` can find it",
97
+ hint: "add the marker directly below the '## Message Inbox' heading so `gemba-wiki memo` can find it",
98
98
  },
99
99
  {
100
100
  id: "summary.open-blockers-last",
@@ -148,7 +148,7 @@ export const RULES = [
148
148
  check: lineBudget(WEEKLY_LOG_LINE_BUDGET),
149
149
  message: (_s, r) => `${r.value} lines (limit ${WEEKLY_LOG_LINE_BUDGET})`,
150
150
  hint: (s) =>
151
- `run \`bunx fit-wiki rotate --agent ${s.agentPrefix}\` to seal this file as a sealed part and start a fresh weekly log`,
151
+ `run \`bunx gemba-wiki rotate --agent ${s.agentPrefix}\` to seal this file as a sealed part and start a fresh weekly log`,
152
152
  },
153
153
  {
154
154
  id: "weekly-log.word-budget",
@@ -158,7 +158,7 @@ export const RULES = [
158
158
  check: wordBudget(WEEKLY_LOG_WORD_BUDGET),
159
159
  message: (_s, r) => `${r.value} words (limit ${WEEKLY_LOG_WORD_BUDGET})`,
160
160
  hint: (s) =>
161
- `run \`bunx fit-wiki rotate --agent ${s.agentPrefix}\` to seal this file as a sealed part and start a fresh weekly log`,
161
+ `run \`bunx gemba-wiki rotate --agent ${s.agentPrefix}\` to seal this file as a sealed part and start a fresh weekly log`,
162
162
  },
163
163
  {
164
164
  id: "weekly-log.h1-agent-matches-filename",
@@ -176,7 +176,7 @@ export const RULES = [
176
176
  check: headingGrammarDrift,
177
177
  message: (_s, r) =>
178
178
  `Entry heading '${r.observed}' does not match the dated grammar`,
179
- hint: "weekly-log entry headings must be '## YYYY-MM-DD'; open entries with `fit-wiki log decision/note`, which emit a conforming heading the rotation seam-finder can split",
179
+ hint: "weekly-log entry headings must be '## YYYY-MM-DD'; open entries with `gemba-wiki log decision/note`, which emit a conforming heading the rotation seam-finder can split",
180
180
  },
181
181
  {
182
182
  id: "decision-block.heading-within-5",
@@ -191,7 +191,7 @@ export const RULES = [
191
191
  r.nearMiss
192
192
  ? `Entry opens with '${r.nearMiss}'; the heading must be exactly '${DECISION_HEADING}' — move the suffix into the body`
193
193
  : `Entry lacks a line that is exactly '${DECISION_HEADING}'`,
194
- hint: `open each '## YYYY-MM-DD' entry with \`fit-wiki log decision\`, which emits a line containing exactly '${DECISION_HEADING}' (no suffix — the check is an exact match); put the one-line summary in the body below it, drawn from the entry's own narrative — do not invent rationale the entry does not support`,
194
+ hint: `open each '## YYYY-MM-DD' entry with \`gemba-wiki log decision\`, which emits a line containing exactly '${DECISION_HEADING}' (no suffix — the check is an exact match); put the one-line summary in the body below it, drawn from the entry's own narrative — do not invent rationale the entry does not support`,
195
195
  },
196
196
 
197
197
  // -- Weekly logs (sealed parts) --
@@ -211,7 +211,7 @@ export const RULES = [
211
211
  check: headingGrammarDrift,
212
212
  message: (_s, r) =>
213
213
  `Entry heading '${r.observed}' does not match the dated grammar`,
214
- hint: "weekly-log entry headings must be '## YYYY-MM-DD'; open entries with `fit-wiki log decision/note`, which emit a conforming heading the rotation seam-finder can split",
214
+ hint: "weekly-log entry headings must be '## YYYY-MM-DD'; open entries with `gemba-wiki log decision/note`, which emit a conforming heading the rotation seam-finder can split",
215
215
  },
216
216
  {
217
217
  id: "weekly-log-part.line-budget",
@@ -220,7 +220,7 @@ export const RULES = [
220
220
  remediation: "rotate",
221
221
  check: lineBudget(WEEKLY_LOG_LINE_BUDGET),
222
222
  message: (_s, r) => `${r.value} lines (limit ${WEEKLY_LOG_LINE_BUDGET})`,
223
- hint: "`bunx fit-wiki fix` re-bisects an over-budget part at its day-section seams and, for a lone over-cap day, at its '### ' block seams; only a single '### ' block that alone exceeds the budget remains for a human to shorten",
223
+ hint: "`bunx gemba-wiki fix` re-bisects an over-budget part at its day-section seams and, for a lone over-cap day, at its '### ' block seams; only a single '### ' block that alone exceeds the budget remains for a human to shorten",
224
224
  },
225
225
  {
226
226
  id: "weekly-log-part.word-budget",
@@ -229,7 +229,7 @@ export const RULES = [
229
229
  remediation: "rotate",
230
230
  check: wordBudget(WEEKLY_LOG_WORD_BUDGET),
231
231
  message: (_s, r) => `${r.value} words (limit ${WEEKLY_LOG_WORD_BUDGET})`,
232
- hint: "`bunx fit-wiki fix` re-bisects an over-budget part at its day-section seams and, for a lone over-cap day, at its '### ' block seams; only a single '### ' block that alone exceeds the budget remains for a human to shorten",
232
+ hint: "`bunx gemba-wiki fix` re-bisects an over-budget part at its day-section seams and, for a lone over-cap day, at its '### ' block seams; only a single '### ' block that alone exceeds the budget remains for a human to shorten",
233
233
  },
234
234
  {
235
235
  id: "weekly-log-part.h1-agent-matches-filename",
@@ -273,7 +273,7 @@ export const RULES = [
273
273
  severity: "fail",
274
274
  check: exists,
275
275
  message: () => "MEMORY.md not found",
276
- hint: "run `bunx fit-wiki init` to scaffold the canonical sections",
276
+ hint: "run `bunx gemba-wiki init` to scaffold the canonical sections",
277
277
  },
278
278
  {
279
279
  id: "memory.line-budget",
@@ -371,7 +371,7 @@ export const RULES = [
371
371
  severity: "warn",
372
372
  check: expired,
373
373
  message: (s) => `${s.agent}/${s.target} expired ${s.expires_at}`,
374
- hint: "run `bunx fit-wiki refresh` (or `release --expired`) to clear expired claims",
374
+ hint: "run `bunx gemba-wiki refresh` (or `release --expired`) to clear expired claims",
375
375
  },
376
376
 
377
377
  // -- Storyboards --
@@ -27,7 +27,7 @@ const NON_SUMMARY_PREFIXES = [
27
27
  "downstream-",
28
28
  "memory-protocol-",
29
29
  "kata-interview-",
30
- "fit-trace-",
30
+ "gemba-trace-",
31
31
  ];
32
32
 
33
33
  function listMdFiles(wikiRoot, fs) {
@@ -14,7 +14,7 @@ import { runFixCommand } from "./commands/fix.js";
14
14
  import { runLedgerCommand } from "./commands/ledger.js";
15
15
 
16
16
  /**
17
- * Build the `fit-wiki` libcli definition. Agent identity is never resolved from
17
+ * Build the `gemba-wiki` libcli definition. Agent identity is never resolved from
18
18
  * the environment: agent-scoped subcommands require an explicit `--agent`
19
19
  * (`--from` for `memo`) and fail closed without it, so this module carries no
20
20
  * ambient agent identity. The version is resolved by libcli's `createCli` from
@@ -47,7 +47,7 @@ export function createDefinition() {
47
47
  };
48
48
 
49
49
  return {
50
- name: "fit-wiki",
50
+ name: "gemba-wiki",
51
51
  description: "Wiki lifecycle management for the Kata agent system",
52
52
  commands: [
53
53
  {
@@ -348,21 +348,21 @@ export function createDefinition() {
348
348
  },
349
349
  },
350
350
  examples: [
351
- "fit-wiki boot --agent staff-engineer",
352
- 'fit-wiki log decision --agent staff-engineer --surveyed "..." --chosen "..." --rationale "..."',
353
- "fit-wiki claim --agent staff-engineer --target spec-NNNN --branch claude/...",
354
- "fit-wiki release --agent staff-engineer --target spec-NNNN",
355
- "fit-wiki inbox list --agent staff-engineer",
356
- "fit-wiki rotate --agent staff-engineer",
357
- "fit-wiki audit",
358
- "fit-wiki curate",
359
- "fit-wiki fix",
360
- 'fit-wiki memo --from staff-engineer --to security-engineer --message "audit d642ff0c"',
361
- "fit-wiki refresh",
362
- "fit-wiki product-mix",
363
- "fit-wiki init",
364
- "fit-wiki push",
365
- "fit-wiki pull",
351
+ "gemba-wiki boot --agent staff-engineer",
352
+ 'gemba-wiki log decision --agent staff-engineer --surveyed "..." --chosen "..." --rationale "..."',
353
+ "gemba-wiki claim --agent staff-engineer --target spec-NNNN --branch claude/...",
354
+ "gemba-wiki release --agent staff-engineer --target spec-NNNN",
355
+ "gemba-wiki inbox list --agent staff-engineer",
356
+ "gemba-wiki rotate --agent staff-engineer",
357
+ "gemba-wiki audit",
358
+ "gemba-wiki curate",
359
+ "gemba-wiki fix",
360
+ 'gemba-wiki memo --from staff-engineer --to security-engineer --message "audit d642ff0c"',
361
+ "gemba-wiki refresh",
362
+ "gemba-wiki product-mix",
363
+ "gemba-wiki init",
364
+ "gemba-wiki push",
365
+ "gemba-wiki pull",
366
366
  ],
367
367
  documentation: [
368
368
  {
@@ -46,7 +46,7 @@ export function runBootCommand(ctx) {
46
46
  const options = ctx.options;
47
47
  const resolved = requireAgentFlag(options, {
48
48
  command: "boot",
49
- example: "fit-wiki boot --agent staff-engineer",
49
+ example: "gemba-wiki boot --agent staff-engineer",
50
50
  });
51
51
  if (!resolved.ok) return resolved;
52
52
  const agent = resolved.agent;
@@ -150,7 +150,7 @@ export async function runClaimCommand(ctx) {
150
150
  const resolved = requireAgentFlag(options, {
151
151
  command: "claim",
152
152
  example:
153
- "fit-wiki claim --agent staff-engineer --target spec-NNNN --branch claude/...",
153
+ "gemba-wiki claim --agent staff-engineer --target spec-NNNN --branch claude/...",
154
154
  });
155
155
  if (!resolved.ok) return resolved;
156
156
  const agent = resolved.agent;
@@ -245,7 +245,7 @@ export async function runReleaseCommand(ctx) {
245
245
 
246
246
  const resolved = requireAgentFlag(options, {
247
247
  command: "release",
248
- example: "fit-wiki release --agent staff-engineer --target spec-NNNN",
248
+ example: "gemba-wiki release --agent staff-engineer --target spec-NNNN",
249
249
  });
250
250
  if (!resolved.ok) return resolved;
251
251
  const agent = resolved.agent;
@@ -19,7 +19,7 @@ const TITLE = "Wiki curation: shared-state audit findings";
19
19
  // GitHub rejects an issue or comment body over 65536 characters. Keep the whole
20
20
  // body under a margin below that so the preamble, JSON fence, and truncation
21
21
  // notice always fit. When the findings overflow, the body carries the first N
22
- // that fit plus a count; the full list stays reproducible via `fit-wiki audit`.
22
+ // that fit plus a count; the full list stays reproducible via `gemba-wiki audit`.
23
23
  const MAX_BODY = 65000;
24
24
 
25
25
  /**
@@ -39,7 +39,7 @@ function buildBody(findingsJson, { shown, total } = {}) {
39
39
  ];
40
40
  if (total != null && shown != null && shown < total) {
41
41
  lines.push(
42
- `Showing ${shown} of ${total} findings — the body was truncated to fit GitHub's comment limit. Run \`fit-wiki audit\` for the full list.`,
42
+ `Showing ${shown} of ${total} findings — the body was truncated to fit GitHub's comment limit. Run \`gemba-wiki audit\` for the full list.`,
43
43
  "",
44
44
  );
45
45
  }
@@ -122,7 +122,7 @@ function sealMainLog(agent, { wikiRoot, today, projectRoot, fs, out, err }) {
122
122
  );
123
123
  }
124
124
  } catch (e) {
125
- err(`fit-wiki fix: rotate failed for ${agent}: ${e.message}\n`);
125
+ err(`gemba-wiki fix: rotate failed for ${agent}: ${e.message}\n`);
126
126
  }
127
127
  }
128
128
 
@@ -164,7 +164,7 @@ function resealPart(partPath, { fs, projectRoot, out, err }) {
164
164
  }
165
165
  } catch (e) {
166
166
  err(
167
- `fit-wiki fix: rebisect failed for ` +
167
+ `gemba-wiki fix: rebisect failed for ` +
168
168
  `${path.relative(projectRoot, partPath)}: ${e.message}\n`,
169
169
  );
170
170
  }
@@ -193,7 +193,7 @@ function rebisectOverBudgetParts(findings, deps) {
193
193
  /** Report findings that need human judgment — never auto-fixed. */
194
194
  function reportFlags(err, flagFindings, projectRoot) {
195
195
  err(
196
- `fit-wiki fix: ${flagFindings.length} finding(s) need human judgment ` +
196
+ `gemba-wiki fix: ${flagFindings.length} finding(s) need human judgment ` +
197
197
  `(not auto-fixable):\n` +
198
198
  emitFindingsText(flagFindings, { cwd: projectRoot }),
199
199
  );
@@ -209,10 +209,10 @@ function reportFlags(err, flagFindings, projectRoot) {
209
209
  function isFatalError(result, round, err) {
210
210
  if (!result.error) return false;
211
211
  if (!result.sessionId) {
212
- err(`fit-wiki fix: agent run failed: ${result.error.message}\n`);
212
+ err(`gemba-wiki fix: agent run failed: ${result.error.message}\n`);
213
213
  return true;
214
214
  }
215
- err(`fit-wiki fix: round ${round} agent error: ${result.error.message}\n`);
215
+ err(`gemba-wiki fix: round ${round} agent error: ${result.error.message}\n`);
216
216
  return false;
217
217
  }
218
218
 
@@ -265,7 +265,7 @@ async function runAgentRounds(runner, agentFindings, deps) {
265
265
  }
266
266
 
267
267
  err(
268
- `fit-wiki fix: ${agentFindings.length} finding(s) remain after ` +
268
+ `gemba-wiki fix: ${agentFindings.length} finding(s) remain after ` +
269
269
  `${MAX_ROUNDS} round(s):\n` +
270
270
  emitFindingsText(agentFindings, { cwd: projectRoot }),
271
271
  );
@@ -13,7 +13,7 @@ function paths(runtime, options) {
13
13
  const wikiRoot = resolveWikiRoot(runtime, options);
14
14
  const resolved = requireAgentFlag(options, {
15
15
  command: "inbox",
16
- example: "fit-wiki inbox list --agent staff-engineer",
16
+ example: "gemba-wiki inbox list --agent staff-engineer",
17
17
  });
18
18
  if (!resolved.ok) return { error: resolved };
19
19
  const agent = resolved.agent;
@@ -32,7 +32,7 @@ function scaffoldActiveClaims(runtime, memoryPath) {
32
32
  ACTIVE_CLAIMS_HEADING,
33
33
  "",
34
34
  "In-flight work claimed by an agent. Row present = active; row absent = settled.",
35
- "Writers: `fit-wiki claim`, `fit-wiki release`. Reader: `fit-wiki boot`.",
35
+ "Writers: `gemba-wiki claim`, `gemba-wiki release`. Reader: `gemba-wiki boot`.",
36
36
  "",
37
37
  ACTIVE_CLAIMS_TABLE_HEADER,
38
38
  ACTIVE_CLAIMS_TABLE_SEPARATOR,
@@ -181,7 +181,7 @@ async function verify(env, options) {
181
181
  const SUBS = { allocate, rebuild, verify };
182
182
 
183
183
  /**
184
- * `fit-wiki ledger <allocate|rebuild|verify>` — the allocation procedure that
184
+ * `gemba-wiki ledger <allocate|rebuild|verify>` — the allocation procedure that
185
185
  * keeps identity off the merge-contested page. Allocation publishes an anchor
186
186
  * comment to the obstacle issue with no projection write at allocation time;
187
187
  * rebuild and verify project the anchor record onto the ledger page and MEMORY
@@ -19,7 +19,7 @@ function commonContext(runtime, options) {
19
19
  const resolved = requireAgentFlag(options, {
20
20
  command: "log",
21
21
  example:
22
- 'fit-wiki log decision --agent staff-engineer --chosen "..." --rationale "..."',
22
+ 'gemba-wiki log decision --agent staff-engineer --chosen "..." --rationale "..."',
23
23
  });
24
24
  if (!resolved.ok) return { error: resolved };
25
25
  const wikiRoot = resolveWikiRoot(runtime, options);
@@ -72,7 +72,7 @@ export function runMemoCommand(ctx) {
72
72
  command: "memo",
73
73
  flag: "--from",
74
74
  example:
75
- 'fit-wiki memo --from staff-engineer --to security-engineer --message "..."',
75
+ 'gemba-wiki memo --from staff-engineer --to security-engineer --message "..."',
76
76
  });
77
77
  if (!resolved.ok) return resolved;
78
78
  const sender = resolved.agent;
@@ -76,7 +76,7 @@ function countByLabel(prs) {
76
76
  * Emit the product-vs-internal mix of merged PRs as a `product_share` metric
77
77
  * row. Counts PRs merged in `[since, until]` by their `product` / `internal`
78
78
  * label and appends `product_share = round(product / (product + internal) *
79
- * 100)` to `wiki/metrics/product-mix/<YYYY>.csv` via the `fit-xmr record` write
79
+ * 100)` to `wiki/metrics/product-mix/<YYYY>.csv` via the `gemba-xmr record` write
80
80
  * path. Deterministic — re-running over the same merged PRs yields the same
81
81
  * value. A window with no labeled merged PRs emits no row (avoids a 0/0 ratio).
82
82
  */
@@ -117,7 +117,7 @@ export async function runProductMixCommand(ctx) {
117
117
 
118
118
  const share = Math.round((product / total) * 100);
119
119
  const recordArgs = [
120
- "fit-xmr",
120
+ "gemba-xmr",
121
121
  "record",
122
122
  "--skill",
123
123
  "product-mix",
@@ -142,7 +142,7 @@ export async function runProductMixCommand(ctx) {
142
142
 
143
143
  const recordResult = await runtime.subprocess.run("npx", recordArgs, { cwd });
144
144
  if (recordResult.exitCode !== 0) {
145
- logger.warn("product-mix", "fit-xmr record failed");
145
+ logger.warn("product-mix", "gemba-xmr record failed");
146
146
  }
147
147
  return { ok: true };
148
148
  }
@@ -15,7 +15,7 @@ export function runRotateCommand(ctx) {
15
15
  const options = ctx.options;
16
16
  const resolved = requireAgentFlag(options, {
17
17
  command: "rotate",
18
- example: "fit-wiki rotate --agent staff-engineer",
18
+ example: "gemba-wiki rotate --agent staff-engineer",
19
19
  });
20
20
  if (!resolved.ok) return resolved;
21
21
  const agent = resolved.agent;
package/src/constants.js CHANGED
@@ -94,7 +94,7 @@ export const CARRY_SURFACE_H1_RE = /^# (.+) — Carries$/;
94
94
  export const CARRY_CLEARANCE_MARKER_RE = /\*\*Carry-clearance:\*\*/;
95
95
 
96
96
  // Storyboard marker syntax. An open or close marker tolerates optional trailing
97
- // text after the tag (typically an inline "Do not edit. Generated from fit-wiki
97
+ // text after the tag (typically an inline "Do not edit. Generated from gemba-wiki
98
98
  // refresh." notice). One home so the marker scanner (marker-scanner.js) and the
99
99
  // audit's balance check (audit/rules.js) cannot drift on the syntax.
100
100
  // Capture groups: 1 metric, 2 csvPath, 3 optional prior-read anchor date. The
@@ -110,7 +110,7 @@ export const ISSUE_CLOSE_RE =
110
110
 
111
111
  // Materialized per-agent experiments surface. A distinct marker
112
112
  // kind from `experiments:open` — it carries attributed, sanitized items plus a
113
- // last-successful-sync stamp, and is read offline by `fit-wiki boot`. One home
113
+ // last-successful-sync stamp, and is read offline by `gemba-wiki boot`. One home
114
114
  // so the scanner (marker-scanner.js), the refresh renderer (commands/refresh.js),
115
115
  // the boot parser (boot.js), and the audit balance check (audit/rules.js) cannot
116
116
  // drift on the syntax.
@@ -72,7 +72,7 @@ export function renderLedgerPage(
72
72
  const lines = [
73
73
  "# Parallel-Collision Ledger",
74
74
  "",
75
- "Derived projection of the allocation-anchor record. Rebuilt by `fit-wiki ledger rebuild`; do not hand-edit identifiers here — allocate at an anchor.",
75
+ "Derived projection of the allocation-anchor record. Rebuilt by `gemba-wiki ledger rebuild`; do not hand-edit identifiers here — allocate at an anchor.",
76
76
  "",
77
77
  ...renderKindSections(fold),
78
78
  ...renderConflicts(fold, labelMode),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Storyboard skeleton — the minimal, valid storyboard file `fit-wiki refresh`
2
+ * Storyboard skeleton — the minimal, valid storyboard file `gemba-wiki refresh`
3
3
  * writes when the current-month board does not yet exist. It carries only the
4
4
  * structural surface libwiki owns: the five Toyota Kata sections and the
5
5
  * generic `obstacles`/`experiments` issue-list marker blocks that refresh
package/src/wiki-sync.js CHANGED
@@ -319,7 +319,7 @@ export class WikiSync {
319
319
  *
320
320
  * The commit is always pathspec-scoped: with `paths` the scope is the
321
321
  * caller's declared write-set, and without `paths` it is the session's own
322
- * dirty set (`#dirtyPaths`, the `fit-wiki push` contract under per-session
322
+ * dirty set (`#dirtyPaths`, the `gemba-wiki push` contract under per-session
323
323
  * checkout isolation). The whole-tree `add -A` sweep is gone, so foreign
324
324
  * content on undeclared paths is never staged and the stale fast-forward
325
325
  * eraser it carried no longer exists; the rebase runs with --autostash
@@ -465,7 +465,7 @@ export class WikiSync {
465
465
  ).changed;
466
466
  // Attribute the commit's write-set. A caller that knows
467
467
  // its narrower write-set passes `paths` (the claim/release path, scoped to
468
- // MEMORY.md). The session-close `fit-wiki push` passes none and the
468
+ // MEMORY.md). The session-close `gemba-wiki push` passes none and the
469
469
  // write-set is the session's own dirty set, read from the working tree —
470
470
  // correct because the canonical mechanism runs it in a per-session isolated
471
471
  // checkout where the dirty set holds no foreign content. The whole-tree
@@ -638,7 +638,7 @@ export class WikiSync {
638
638
  const files = [...new Set(gate.refusals.map((r) => r.file))].join(", ");
639
639
  return new WikiPushFailure(
640
640
  PUSH_REASONS.BUDGET,
641
- "fit-wiki: refusing to push — it would introduce or deepen a budget " +
641
+ "gemba-wiki: refusing to push — it would introduce or deepen a budget " +
642
642
  `breach in ${files} (${lead.ruleId}: ${lead.value} vs baseline ` +
643
643
  `${lead.baseline}). Trim your own content or surface the carried ` +
644
644
  "content to its owner, then re-push; your work is committed locally.",
@@ -682,7 +682,7 @@ export class WikiSync {
682
682
  });
683
683
  throw new WikiPushFailure(
684
684
  PUSH_REASONS.RESIDUE_CONFLICT,
685
- "fit-wiki: refusing to push — a foreign writer's residue conflicted " +
685
+ "gemba-wiki: refusing to push — a foreign writer's residue conflicted " +
686
686
  "on the autostash pop; your stash is preserved at " +
687
687
  `${stashSha || "refs/stash"} (git stash list). Resolve or pop it ` +
688
688
  "from the true tip.",
@@ -736,8 +736,8 @@ export class WikiSync {
736
736
  // No-intent path: fail loud rather than discard the remote side (D2).
737
737
  throw new WikiPushFailure(
738
738
  PUSH_REASONS.CONFLICT,
739
- "fit-wiki: refusing to push — rebase conflict with the remote. " +
740
- "Resolve or retry from the true tip (fit-wiki pull, then push).",
739
+ "gemba-wiki: refusing to push — rebase conflict with the remote. " +
740
+ "Resolve or retry from the true tip (gemba-wiki pull, then push).",
741
741
  );
742
742
  }
743
743
 
@@ -923,7 +923,7 @@ export class WikiSync {
923
923
  if (this.#rebaseInProgress()) {
924
924
  throw new WikiPushFailure(
925
925
  PUSH_REASONS.PRECONDITION,
926
- "fit-wiki: refusing to act — a rebase is in progress. Resolve or " +
926
+ "gemba-wiki: refusing to act — a rebase is in progress. Resolve or " +
927
927
  "abort it before retrying; your uncommitted edit is preserved.",
928
928
  );
929
929
  }
@@ -1061,7 +1061,7 @@ export class WikiSync {
1061
1061
  this.#reportConservation("refusal");
1062
1062
  throw new WikiPushFailure(
1063
1063
  PUSH_REASONS.CONSERVATION,
1064
- "fit-wiki: refusing to push — it would drop another writer's " +
1064
+ "gemba-wiki: refusing to push — it would drop another writer's " +
1065
1065
  `content in ${file} that is present on the remote. Pull and ` +
1066
1066
  "re-apply, or declare the removal if it is deliberate.",
1067
1067
  );
@@ -1176,7 +1176,7 @@ export class WikiSync {
1176
1176
  }
1177
1177
 
1178
1178
  #sidecarPath() {
1179
- return path.join(this.#wikiDir, ".git", "fit-wiki-removal-intent");
1179
+ return path.join(this.#wikiDir, ".git", "gemba-wiki-removal-intent");
1180
1180
  }
1181
1181
 
1182
1182
  /** Read the clone-local removal-intent sidecar (declared deliberate removals). */
@@ -1226,7 +1226,7 @@ export class WikiSync {
1226
1226
  reason: PUSH_REASONS.TRANSPORT,
1227
1227
  error: new WikiPushFailure(
1228
1228
  PUSH_REASONS.TRANSPORT,
1229
- "fit-wiki: push failed at transport (network or credentials). " +
1229
+ "gemba-wiki: push failed at transport (network or credentials). " +
1230
1230
  "Your work is committed locally; retry when connectivity returns.",
1231
1231
  ),
1232
1232
  };
@@ -1240,7 +1240,7 @@ export class WikiSync {
1240
1240
  reason: PUSH_REASONS.TRANSPORT,
1241
1241
  error: new WikiPushFailure(
1242
1242
  PUSH_REASONS.TRANSPORT,
1243
- "fit-wiki: push did not land and the remote could not be observed " +
1243
+ "gemba-wiki: push did not land and the remote could not be observed " +
1244
1244
  "(network or credentials). Your work is committed locally.",
1245
1245
  ),
1246
1246
  };
@@ -1250,8 +1250,8 @@ export class WikiSync {
1250
1250
  reason: PUSH_REASONS.REJECTED,
1251
1251
  error: new WikiPushFailure(
1252
1252
  PUSH_REASONS.REJECTED,
1253
- "fit-wiki: push rejected — the remote advanced. Rerun from the true " +
1254
- "tip (fit-wiki pull, then push).",
1253
+ "gemba-wiki: push rejected — the remote advanced. Rerun from the true " +
1254
+ "tip (gemba-wiki pull, then push).",
1255
1255
  ),
1256
1256
  };
1257
1257
  }
@@ -1309,7 +1309,7 @@ export class WikiSync {
1309
1309
  if ((await this.#git.headBranch({ cwd })) !== BRANCH) {
1310
1310
  throw new AncestryRefusal(
1311
1311
  "unverifiable",
1312
- "fit-wiki: refusing to publish — HEAD is detached, so the configured " +
1312
+ "gemba-wiki: refusing to publish — HEAD is detached, so the configured " +
1313
1313
  "branch would be pushed instead of your work. Re-clone the wiki.",
1314
1314
  );
1315
1315
  }
@@ -1325,7 +1325,7 @@ export class WikiSync {
1325
1325
  } catch {
1326
1326
  throw new AncestryRefusal(
1327
1327
  "unverifiable",
1328
- "fit-wiki: refusing to publish — could not observe the remote to " +
1328
+ "gemba-wiki: refusing to publish — could not observe the remote to " +
1329
1329
  "verify ancestry; the local change is not published.",
1330
1330
  );
1331
1331
  }
@@ -1345,7 +1345,7 @@ export class WikiSync {
1345
1345
  } catch {
1346
1346
  throw new AncestryRefusal(
1347
1347
  "unverifiable",
1348
- "fit-wiki: refusing to publish — could not fetch the remote branch " +
1348
+ "gemba-wiki: refusing to publish — could not fetch the remote branch " +
1349
1349
  "to verify ancestry; the local change is not published.",
1350
1350
  );
1351
1351
  }
@@ -1355,7 +1355,7 @@ export class WikiSync {
1355
1355
  if (!(await this.#git.refExists("HEAD", { cwd }))) {
1356
1356
  throw new AncestryRefusal(
1357
1357
  "unrelated",
1358
- "fit-wiki: refusing to publish — HEAD is unborn but the remote " +
1358
+ "gemba-wiki: refusing to publish — HEAD is unborn but the remote " +
1359
1359
  "branch exists. Re-clone the wiki.",
1360
1360
  );
1361
1361
  }
@@ -1367,7 +1367,7 @@ export class WikiSync {
1367
1367
  if (!this.#isShallow()) {
1368
1368
  throw new AncestryRefusal(
1369
1369
  "unrelated",
1370
- "fit-wiki: refusing to publish — local history is unrelated to the " +
1370
+ "gemba-wiki: refusing to publish — local history is unrelated to the " +
1371
1371
  "remote branch. Re-clone the wiki.",
1372
1372
  );
1373
1373
  }
@@ -1377,14 +1377,14 @@ export class WikiSync {
1377
1377
  if (deepen.exitCode !== 0) {
1378
1378
  throw new AncestryRefusal(
1379
1379
  "unverifiable",
1380
- "fit-wiki: refusing to publish — could not deepen history to verify " +
1380
+ "gemba-wiki: refusing to publish — could not deepen history to verify " +
1381
1381
  "ancestry; the local change is not published.",
1382
1382
  );
1383
1383
  }
1384
1384
  if (await this.#git.mergeBaseExists(REMOTE_BRANCH, "HEAD", { cwd })) return;
1385
1385
  throw new AncestryRefusal(
1386
1386
  "unrelated",
1387
- "fit-wiki: refusing to publish — local history is unrelated to the " +
1387
+ "gemba-wiki: refusing to publish — local history is unrelated to the " +
1388
1388
  "remote branch (confirmed against full history). Re-clone the wiki.",
1389
1389
  );
1390
1390
  }
package/bin/fit-wiki.js DELETED
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import "@forwardimpact/libpreflight/node22";
4
-
5
- import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
6
- import { GitClient } from "@forwardimpact/libutil/git-client";
7
- import { GhClient } from "@forwardimpact/libutil/gh-client";
8
- import { createScriptConfig } from "@forwardimpact/libconfig";
9
- import { createCli } from "@forwardimpact/libcli";
10
- import { createLogger } from "@forwardimpact/libtelemetry";
11
- import { WikiSync } from "../src/wiki-sync.js";
12
- import {
13
- resolveProjectRoot,
14
- resolveWikiRoot,
15
- wikiExists,
16
- } from "../src/util/wiki-dir.js";
17
- import { createDefinition } from "../src/cli-definition.js";
18
-
19
- // Commands that mutate or sync the remote wiki need a constructed WikiSync
20
- // (and its config-backed token resolver); the rest run against the local tree.
21
- const NEEDS_WIKI_SYNC = new Set(["claim", "release", "push", "pull", "init"]);
22
-
23
- // The ledger command reads and writes the allocation-anchor surface (the
24
- // obstacle issue's comments) over the GitHub API, so it needs a GhClient.
25
- const NEEDS_GH_CLIENT = new Set(["ledger"]);
26
-
27
- async function main() {
28
- const runtime = createDefaultRuntime();
29
- const definition = createDefinition();
30
- const cli = createCli(definition, {
31
- runtime,
32
- packageJsonUrl: new URL("../package.json", import.meta.url),
33
- });
34
-
35
- const parsed = cli.parse(runtime.proc.argv.slice(2));
36
- if (!parsed) return runtime.proc.exit(0); // --help / --version already printed
37
-
38
- const { positionals } = parsed;
39
- if (positionals.length === 0) {
40
- cli.showHelp();
41
- return runtime.proc.exit(0);
42
- }
43
-
44
- const command = positionals[0];
45
- if (!definition.commands.some((c) => c.name === command)) {
46
- cli.usageError(`unknown command "${command}"`);
47
- return runtime.proc.exit(2);
48
- }
49
-
50
- // Every command except `init` operates on an existing wiki tree. When it is
51
- // absent (e.g. a fresh worktree where bootstrap.sh never ran), degrade
52
- // gracefully: warn and exit 0 so the session Stop hook and other callers do
53
- // not fail loudly. `init` is exempt — it creates the tree.
54
- if (command !== "init") {
55
- const wikiDir = resolveWikiRoot(runtime, parsed.values);
56
- if (!wikiExists(runtime, wikiDir)) {
57
- createLogger("wiki", runtime).warn(
58
- command,
59
- `no wiki at ${wikiDir}; skipping (run \`fit-wiki init\` to create one)`,
60
- );
61
- return runtime.proc.exit(0);
62
- }
63
- }
64
-
65
- const gitClient = new GitClient({ runtime });
66
- let wikiSync;
67
- if (NEEDS_WIKI_SYNC.has(command)) {
68
- const projectRoot = resolveProjectRoot(runtime);
69
- const wikiDir = resolveWikiRoot(runtime, parsed.values);
70
- const config = await createScriptConfig("wiki");
71
- wikiSync = new WikiSync({
72
- runtime,
73
- gitClient,
74
- wikiDir,
75
- parentDir: projectRoot,
76
- resolveToken: () => config.ghToken(),
77
- });
78
- }
79
-
80
- let ghClient;
81
- if (NEEDS_GH_CLIENT.has(command)) {
82
- ghClient = new GhClient({ runtime });
83
- }
84
-
85
- const result = await cli.dispatch(parsed, {
86
- deps: { runtime, wikiSync, gitClient, ghClient },
87
- });
88
-
89
- const envelope = result ?? { ok: true };
90
- if (!envelope.ok && envelope.error) cli.usageError(envelope.error);
91
- runtime.proc.exit(envelope.ok ? 0 : (envelope.code ?? 1));
92
- }
93
-
94
- main();