@forwardimpact/libwiki 0.2.19 → 0.2.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libwiki",
3
- "version": "0.2.19",
3
+ "version": "0.2.21",
4
4
  "description": "Wiki lifecycle primitives — stable memory for agent teams so coordination persists across sessions.",
5
5
  "keywords": [
6
6
  "wiki",
@@ -254,7 +254,7 @@ export const RULES = [
254
254
  remediation: "rotate",
255
255
  check: lineBudget(WEEKLY_LOG_LINE_BUDGET),
256
256
  message: (_s, r) => `${r.value} lines (limit ${WEEKLY_LOG_LINE_BUDGET})`,
257
- hint: "run `bunx fit-wiki rotate` to seal this file as a sealed part and start a fresh weekly log",
257
+ hint: "run `bunx fit-wiki rotate --agent <agent>` (agent = this filename's prefix) to seal this file as a sealed part and start a fresh weekly log",
258
258
  },
259
259
  {
260
260
  id: "weekly-log.word-budget",
@@ -263,7 +263,7 @@ export const RULES = [
263
263
  remediation: "rotate",
264
264
  check: wordBudget(WEEKLY_LOG_WORD_BUDGET),
265
265
  message: (_s, r) => `${r.value} words (limit ${WEEKLY_LOG_WORD_BUDGET})`,
266
- hint: "run `bunx fit-wiki rotate` to seal this file as a sealed part and start a fresh weekly log",
266
+ hint: "run `bunx fit-wiki rotate --agent <agent>` (agent = this filename's prefix) to seal this file as a sealed part and start a fresh weekly log",
267
267
  },
268
268
  {
269
269
  id: "weekly-log.h1-agent-matches-filename",
@@ -48,9 +48,10 @@ function invariantContract(findings) {
48
48
  }
49
49
 
50
50
  /**
51
- * The opening task: the findings, the invariant contract, and the two things
52
- * the rule hints don't cover — where trimmed history goes, and to prefer a
53
- * single Write.
51
+ * The opening task: the findings, the invariant contract, and the things the
52
+ * rule hints don't cover — where trimmed history goes (only existing
53
+ * weekly-log files; rotation owns minting new ones), and to prefer a single
54
+ * Write.
54
55
  */
55
56
  function composeTask(findings, wikiRoot, projectRoot) {
56
57
  return [
@@ -62,9 +63,13 @@ function composeTask(findings, wikiRoot, projectRoot) {
62
63
  `by breaking another:`,
63
64
  ...invariantContract(findings),
64
65
  ``,
65
- `Move history out of an over-budget summary into the agent's weekly-log`,
66
- `file (wiki/<agent>-YYYY-Www.md), never a new summary section. Prefer a`,
67
- `single Write over many Edits.`,
66
+ `Move history out of an over-budget summary into the agent's existing`,
67
+ `weekly-log file or its current part (wiki/<agent>-YYYY-Www[-partN].md) —`,
68
+ `never a new summary section, and never a new file: rotation tooling owns`,
69
+ `when part files are created, so do not mint filenames yourself. If the`,
70
+ `trimmed narrative already exists in the weekly log, replace it in the`,
71
+ `summary with a pointer to that file instead of copying it anywhere.`,
72
+ `Prefer a single Write over many Edits.`,
68
73
  ].join("\n");
69
74
  }
70
75
 
@@ -1,4 +1,4 @@
1
- import { rotateIfOverBudget } from "../weekly-log.js";
1
+ import { rotateIfOverBudget, weeklyLogPath } from "../weekly-log.js";
2
2
  import { currentDayIso } from "../util/clock.js";
3
3
  import { resolveWikiRoot } from "../util/wiki-dir.js";
4
4
 
@@ -16,6 +16,12 @@ export function runRotateCommand(ctx) {
16
16
  }
17
17
  const wikiRoot = resolveWikiRoot(runtime, options);
18
18
  const today = options.today || currentDayIso(runtime);
19
+ // Name the resolved target before any seal: the file follows from agent +
20
+ // current week, not from any audit finding, so an env-default agent can
21
+ // silently select a different file than the one the operator has in mind.
22
+ runtime.proc.stdout.write(
23
+ `target → ${weeklyLogPath(wikiRoot, agent, today)}\n`,
24
+ );
19
25
 
20
26
  let result;
21
27
  try {
package/src/weekly-log.js CHANGED
@@ -281,6 +281,13 @@ export function rotateIfOverBudget(
281
281
  const { force = false } = options;
282
282
  if (!fs.existsSync(filePath)) return { status: "noop", fromPath: filePath };
283
283
  const text = fs.readFileSync(filePath, "utf-8");
284
+ // A header-only (or empty) log has nothing to seal. Without this floor,
285
+ // force-rotating a freshly-reset main would mint an empty `(part 1 of 1)`
286
+ // file and reset the main again — once per invocation, forever.
287
+ const nl = text.indexOf("\n");
288
+ if ((nl === -1 ? "" : text.slice(nl + 1)).trim() === "") {
289
+ return { status: "noop", fromPath: filePath };
290
+ }
284
291
  const current = countLines(text);
285
292
  if (!force && current + appendLines <= WEEKLY_LOG_LINE_BUDGET) {
286
293
  return { status: "noop", fromPath: filePath };