@mmnto/cli 0.14.0 → 0.15.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.
Files changed (44) hide show
  1. package/dist/adapters/github-cli.d.ts +9 -0
  2. package/dist/adapters/github-cli.d.ts.map +1 -1
  3. package/dist/adapters/github-cli.js +34 -0
  4. package/dist/adapters/github-cli.js.map +1 -1
  5. package/dist/assets/universal-lessons.d.ts +9 -0
  6. package/dist/assets/universal-lessons.d.ts.map +1 -0
  7. package/dist/assets/universal-lessons.js +71 -0
  8. package/dist/assets/universal-lessons.js.map +1 -0
  9. package/dist/commands/docs.d.ts +11 -0
  10. package/dist/commands/docs.d.ts.map +1 -0
  11. package/dist/commands/docs.js +210 -0
  12. package/dist/commands/docs.js.map +1 -0
  13. package/dist/commands/docs.test.d.ts +2 -0
  14. package/dist/commands/docs.test.d.ts.map +1 -0
  15. package/dist/commands/docs.test.js +188 -0
  16. package/dist/commands/docs.test.js.map +1 -0
  17. package/dist/commands/init.d.ts +7 -0
  18. package/dist/commands/init.d.ts.map +1 -1
  19. package/dist/commands/init.js +35 -1
  20. package/dist/commands/init.js.map +1 -1
  21. package/dist/commands/init.test.js +100 -1
  22. package/dist/commands/init.test.js.map +1 -1
  23. package/dist/commands/wrap.d.ts.map +1 -1
  24. package/dist/commands/wrap.js +23 -4
  25. package/dist/commands/wrap.js.map +1 -1
  26. package/dist/commands/wrap.test.js +30 -2
  27. package/dist/commands/wrap.test.js.map +1 -1
  28. package/dist/git.d.ts +19 -0
  29. package/dist/git.d.ts.map +1 -1
  30. package/dist/git.js +72 -0
  31. package/dist/git.js.map +1 -1
  32. package/dist/git.test.d.ts +2 -0
  33. package/dist/git.test.d.ts.map +1 -0
  34. package/dist/git.test.js +74 -0
  35. package/dist/git.test.js.map +1 -0
  36. package/dist/index.js +22 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/utils.d.ts +5 -0
  39. package/dist/utils.d.ts.map +1 -1
  40. package/dist/utils.js +37 -0
  41. package/dist/utils.js.map +1 -1
  42. package/dist/utils.test.js +58 -1
  43. package/dist/utils.test.js.map +1 -1
  44. package/package.json +2 -2
@@ -1,8 +1,17 @@
1
1
  import type { IssueAdapter, StandardIssue, StandardIssueListItem } from './issue-adapter.js';
2
+ export interface ClosedIssueListItem {
3
+ number: number;
4
+ title: string;
5
+ closedAt: string;
6
+ }
2
7
  export declare class GitHubCliAdapter implements IssueAdapter {
3
8
  private cwd;
4
9
  constructor(cwd: string);
5
10
  fetchIssue(issueNumber: number): StandardIssue;
11
+ /**
12
+ * Fetch recently closed issues, optionally filtered by search query (e.g., "closed:>2026-01-01").
13
+ */
14
+ fetchClosedIssues(limit?: number, sinceTag?: string): ClosedIssueListItem[];
6
15
  fetchOpenIssues(limit?: number): StandardIssueListItem[];
7
16
  }
8
17
  //# sourceMappingURL=github-cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"github-cli.d.ts","sourceRoot":"","sources":["../../src/adapters/github-cli.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAuB7F,qBAAa,gBAAiB,YAAW,YAAY;IACvC,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,MAAM;IAE/B,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAgB9C,eAAe,CAAC,KAAK,GAAE,MAA4B,GAAG,qBAAqB,EAAE;CAuB9E"}
1
+ {"version":3,"file":"github-cli.d.ts","sourceRoot":"","sources":["../../src/adapters/github-cli.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE7F,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6BD,qBAAa,gBAAiB,YAAW,YAAY;IACvC,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,MAAM;IAE/B,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAgB9C;;OAEG;IACH,iBAAiB,CAAC,KAAK,GAAE,MAA4B,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAiChG,eAAe,CAAC,KAAK,GAAE,MAA4B,GAAG,qBAAqB,EAAE;CAuB9E"}
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { getTagDate } from '../git.js';
2
3
  import { ghFetchAndParse } from './gh-utils.js';
3
4
  // ─── Zod schemas for GitHub CLI JSON output ─────────────
4
5
  const GhIssueSchema = z.object({
@@ -14,6 +15,11 @@ const GhIssueListItemSchema = z.object({
14
15
  labels: z.array(z.object({ name: z.string() })),
15
16
  updatedAt: z.string().datetime(),
16
17
  });
18
+ const GhClosedIssueListItemSchema = z.object({
19
+ number: z.number(),
20
+ title: z.string(),
21
+ closedAt: z.string().datetime(),
22
+ });
17
23
  // ─── Adapter implementation ─────────────────────────────
18
24
  const DEFAULT_ISSUE_LIMIT = 100;
19
25
  export class GitHubCliAdapter {
@@ -31,6 +37,34 @@ export class GitHubCliAdapter {
31
37
  labels: issue.labels.map((l) => l.name),
32
38
  };
33
39
  }
40
+ /**
41
+ * Fetch recently closed issues, optionally filtered by search query (e.g., "closed:>2026-01-01").
42
+ */
43
+ fetchClosedIssues(limit = DEFAULT_ISSUE_LIMIT, sinceTag) {
44
+ const args = [
45
+ 'issue',
46
+ 'list',
47
+ '--state',
48
+ 'closed',
49
+ '--json',
50
+ 'number,title,closedAt',
51
+ '--limit',
52
+ String(limit),
53
+ ];
54
+ // If we have a tag, use --search to filter by close date
55
+ if (sinceTag) {
56
+ const tagDate = getTagDate(this.cwd, sinceTag);
57
+ if (tagDate) {
58
+ args.push('--search', `closed:>=${tagDate}`);
59
+ }
60
+ }
61
+ const issues = ghFetchAndParse(args, z.array(GhClosedIssueListItemSchema), 'closed issues', this.cwd);
62
+ return issues.map((i) => ({
63
+ number: i.number,
64
+ title: i.title,
65
+ closedAt: i.closedAt,
66
+ }));
67
+ }
34
68
  fetchOpenIssues(limit = DEFAULT_ISSUE_LIMIT) {
35
69
  const issues = ghFetchAndParse([
36
70
  'issue',
@@ -1 +1 @@
1
- {"version":3,"file":"github-cli.js","sourceRoot":"","sources":["../../src/adapters/github-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,2DAA2D;AAE3D,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAEH,2DAA2D;AAE3D,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,OAAO,gBAAgB;IACP;IAApB,YAAoB,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;IAAG,CAAC;IAEnC,UAAU,CAAC,WAAmB;QAC5B,MAAM,KAAK,GAAG,eAAe,CAC3B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,gCAAgC,CAAC,EAClF,aAAa,EACb,UAAU,WAAW,EAAE,EACvB,IAAI,CAAC,GAAG,CACT,CAAC;QACF,OAAO;YACL,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACxC,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,QAAgB,mBAAmB;QACjD,MAAM,MAAM,GAAG,eAAe,CAC5B;YACE,OAAO;YACP,MAAM;YACN,SAAS;YACT,MAAM;YACN,QAAQ;YACR,+BAA+B;YAC/B,SAAS;YACT,MAAM,CAAC,KAAK,CAAC;SACd,EACD,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAC9B,aAAa,EACb,IAAI,CAAC,GAAG,CACT,CAAC;QACF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACnC,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;CACF"}
1
+ {"version":3,"file":"github-cli.js","sourceRoot":"","sources":["../../src/adapters/github-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Universal AI Developer Baseline — curated lessons installed during `totem init`.
3
+ *
4
+ * These lessons provide immediate Day-1 value for any AI-assisted project.
5
+ * Format matches what `add_lesson` produces so the markdown chunker indexes them correctly.
6
+ */
7
+ export declare const BASELINE_MARKER = "<!-- totem:baseline -->";
8
+ export declare const UNIVERSAL_LESSONS_MARKDOWN = "\n<!-- totem:baseline -->\n\n## Lesson \u2014 Prompt Injection Prevention\n\n**Tags:** security, prompt-injection, trap\n\nNever trust raw text from external sources (PR comments, issue bodies, user input) when feeding it to an AI agent. Always sanitize or escape untrusted content before persisting it to memory files or passing it as context. Indirect prompt injection can cause agents to execute unintended actions.\n\n## Lesson \u2014 Secret Management\n\n**Tags:** security, secrets, trap\n\nNever commit API keys, tokens, or credentials to version control \u2014 even in `.env.example` files. Use environment variables loaded at runtime. If a secret is accidentally committed, rotate it immediately; removing it from git history alone is not sufficient.\n\n## Lesson \u2014 AI Hallucination Traps\n\n**Tags:** ai-behavior, hallucination, trap\n\nAI agents will confidently reference APIs, functions, database tables, and configuration options that do not exist. Always verify AI-generated code against the actual codebase and documentation before merging. Prefer semantic search over asking the agent to \"remember\" prior context.\n\n## Lesson \u2014 Scope Creep Prevention\n\n**Tags:** ai-behavior, scope-creep, architecture\n\nWhen an AI agent proposes a \"small improvement\" or \"quick refactor\" alongside the requested change, reject it. Unrelated changes in the same commit obscure code review diffs, introduce untested side effects, and make git bisect useless.\n\n## Lesson \u2014 Dependency Verification\n\n**Tags:** architecture, dependencies, trap\n\nBefore an AI agent adds a new dependency, verify it exists, is actively maintained, and matches your project's license. AI agents frequently hallucinate package names or suggest deprecated libraries. Check the npm/PyPI registry directly.\n\n## Lesson \u2014 Meaningful Test Assertions\n\n**Tags:** testing, ai-behavior, trap\n\nAI-generated tests often pass trivially \u2014 asserting that a mock returns the value it was told to return, or testing implementation details rather than behavior. Review test assertions for meaningful coverage: does the test fail when the feature breaks?\n\n## Lesson \u2014 No Empty Catch Blocks\n\n**Tags:** architecture, error-handling, design-decision\n\nCatch blocks should never be empty. At minimum, log the error or re-throw with added context. Silent failures cause cascading bugs that are extremely difficult to diagnose. If an error truly can be ignored, add a comment explaining why.\n\n## Lesson \u2014 Shell Injection Prevention\n\n**Tags:** security, shell, trap\n\nNever interpolate user-controlled strings directly into shell commands. Use parameterized APIs or write inputs to temp files. This applies to CI/CD pipelines (GitHub Actions `run:` blocks), CLI tools, and any code that calls `exec` or `spawn`.\n\n## Lesson \u2014 Context Window Management\n\n**Tags:** ai-behavior, context-window, design-decision\n\nWhen an AI agent's context window fills up, it loses earlier instructions and begins contradicting its own prior outputs. Break long tasks into smaller, well-scoped steps. Use handoff artifacts (like `totem bridge` or `totem handoff`) to preserve context across session boundaries.\n\n## Lesson \u2014 Idempotent Scaffolding\n\n**Tags:** architecture, idempotency, design-decision\n\nScaffolding commands (init, setup, install) must be idempotent \u2014 running them twice should not duplicate content, overwrite user changes, or corrupt state. Always check for existing files/content before writing, and use markers to detect prior runs.\n";
9
+ //# sourceMappingURL=universal-lessons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"universal-lessons.d.ts","sourceRoot":"","sources":["../../src/assets/universal-lessons.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD,eAAO,MAAM,0BAA0B,0/GA8DtC,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Universal AI Developer Baseline — curated lessons installed during `totem init`.
3
+ *
4
+ * These lessons provide immediate Day-1 value for any AI-assisted project.
5
+ * Format matches what `add_lesson` produces so the markdown chunker indexes them correctly.
6
+ */
7
+ export const BASELINE_MARKER = '<!-- totem:baseline -->';
8
+ export const UNIVERSAL_LESSONS_MARKDOWN = `
9
+ ${BASELINE_MARKER}
10
+
11
+ ## Lesson — Prompt Injection Prevention
12
+
13
+ **Tags:** security, prompt-injection, trap
14
+
15
+ Never trust raw text from external sources (PR comments, issue bodies, user input) when feeding it to an AI agent. Always sanitize or escape untrusted content before persisting it to memory files or passing it as context. Indirect prompt injection can cause agents to execute unintended actions.
16
+
17
+ ## Lesson — Secret Management
18
+
19
+ **Tags:** security, secrets, trap
20
+
21
+ Never commit API keys, tokens, or credentials to version control — even in \`.env.example\` files. Use environment variables loaded at runtime. If a secret is accidentally committed, rotate it immediately; removing it from git history alone is not sufficient.
22
+
23
+ ## Lesson — AI Hallucination Traps
24
+
25
+ **Tags:** ai-behavior, hallucination, trap
26
+
27
+ AI agents will confidently reference APIs, functions, database tables, and configuration options that do not exist. Always verify AI-generated code against the actual codebase and documentation before merging. Prefer semantic search over asking the agent to "remember" prior context.
28
+
29
+ ## Lesson — Scope Creep Prevention
30
+
31
+ **Tags:** ai-behavior, scope-creep, architecture
32
+
33
+ When an AI agent proposes a "small improvement" or "quick refactor" alongside the requested change, reject it. Unrelated changes in the same commit obscure code review diffs, introduce untested side effects, and make git bisect useless.
34
+
35
+ ## Lesson — Dependency Verification
36
+
37
+ **Tags:** architecture, dependencies, trap
38
+
39
+ Before an AI agent adds a new dependency, verify it exists, is actively maintained, and matches your project's license. AI agents frequently hallucinate package names or suggest deprecated libraries. Check the npm/PyPI registry directly.
40
+
41
+ ## Lesson — Meaningful Test Assertions
42
+
43
+ **Tags:** testing, ai-behavior, trap
44
+
45
+ AI-generated tests often pass trivially — asserting that a mock returns the value it was told to return, or testing implementation details rather than behavior. Review test assertions for meaningful coverage: does the test fail when the feature breaks?
46
+
47
+ ## Lesson — No Empty Catch Blocks
48
+
49
+ **Tags:** architecture, error-handling, design-decision
50
+
51
+ Catch blocks should never be empty. At minimum, log the error or re-throw with added context. Silent failures cause cascading bugs that are extremely difficult to diagnose. If an error truly can be ignored, add a comment explaining why.
52
+
53
+ ## Lesson — Shell Injection Prevention
54
+
55
+ **Tags:** security, shell, trap
56
+
57
+ Never interpolate user-controlled strings directly into shell commands. Use parameterized APIs or write inputs to temp files. This applies to CI/CD pipelines (GitHub Actions \`run:\` blocks), CLI tools, and any code that calls \`exec\` or \`spawn\`.
58
+
59
+ ## Lesson — Context Window Management
60
+
61
+ **Tags:** ai-behavior, context-window, design-decision
62
+
63
+ When an AI agent's context window fills up, it loses earlier instructions and begins contradicting its own prior outputs. Break long tasks into smaller, well-scoped steps. Use handoff artifacts (like \`totem bridge\` or \`totem handoff\`) to preserve context across session boundaries.
64
+
65
+ ## Lesson — Idempotent Scaffolding
66
+
67
+ **Tags:** architecture, idempotency, design-decision
68
+
69
+ Scaffolding commands (init, setup, install) must be idempotent — running them twice should not duplicate content, overwrite user changes, or corrupt state. Always check for existing files/content before writing, and use markers to detect prior runs.
70
+ `;
71
+ //# sourceMappingURL=universal-lessons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"universal-lessons.js","sourceRoot":"","sources":["../../src/assets/universal-lessons.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD,MAAM,CAAC,MAAM,0BAA0B,GAAG;EACxC,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DhB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface DocsOptions {
2
+ raw?: boolean;
3
+ out?: string;
4
+ model?: string;
5
+ fresh?: boolean;
6
+ only?: string;
7
+ dryRun?: boolean;
8
+ yes?: boolean;
9
+ }
10
+ export declare function docsCommand(options: DocsOptions): Promise<void>;
11
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AA8JA,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoHrE"}
@@ -0,0 +1,210 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { GitHubCliAdapter } from '../adapters/github-cli.js';
4
+ import { getGitLogSince, getLatestTag, isFileDirty } from '../git.js';
5
+ import { log } from '../ui.js';
6
+ import { getSystemPrompt, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, wrapXml, writeOutput, } from '../utils.js';
7
+ // ─── Constants ──────────────────────────────────────────
8
+ const TAG = 'Docs';
9
+ const MAX_DOC_CHARS = 80_000;
10
+ const MAX_LOG_CHARS = 20_000;
11
+ const GH_CLOSED_ISSUE_LIMIT = 50;
12
+ // ─── System prompt ──────────────────────────────────────
13
+ const SYSTEM_PROMPT = `# Docs System Prompt — Automated Documentation Sync
14
+
15
+ ## Identity & Role
16
+ You are a meticulous Technical Writer responsible for keeping project documentation accurate and up-to-date. You rewrite documentation files to reflect the latest project state.
17
+
18
+ ## Core Mission
19
+ Given a documentation file, its purpose, and recent project changes (git log, closed issues), produce an updated version of the entire file that accurately reflects the current state.
20
+
21
+ ## Critical Rules
22
+ - **Full Rewrite:** Output the ENTIRE updated file content — not a diff, not a patch, the complete file.
23
+ - **Preserve Structure:** Maintain the existing document's structure, tone, and formatting conventions unless changes require restructuring.
24
+ - **Evidence-Based:** Only update information that is supported by the provided git log, closed issues, or active work context. Do NOT invent features or status changes.
25
+ - **Phase Numbering:** If the document references phases, use ONLY the phase numbering from the provided active_work.md context. Do NOT change or renumber phases.
26
+ - **Conservative Updates:** When in doubt, keep the existing text. Only change what the evidence supports.
27
+ - **No Preamble:** Output ONLY the updated file content. No commentary, no explanation, no markdown code fences wrapping the output.
28
+ `;
29
+ function gatherReleaseContext(cwd) {
30
+ const tag = getLatestTag(cwd);
31
+ const gitLog = getGitLogSince(cwd, tag ?? undefined);
32
+ let closedIssues = '';
33
+ try {
34
+ const adapter = new GitHubCliAdapter(cwd);
35
+ const issues = adapter.fetchClosedIssues(GH_CLOSED_ISSUE_LIMIT, tag ?? undefined);
36
+ if (issues.length > 0) {
37
+ closedIssues = issues
38
+ .map((i) => `#${i.number} — ${i.title} (closed ${i.closedAt?.slice(0, 10) ?? 'unknown'})`)
39
+ .join('\n');
40
+ }
41
+ }
42
+ catch {
43
+ log.dim(TAG, 'Could not fetch closed issues (gh CLI unavailable or no remote).');
44
+ }
45
+ return { tag, gitLog, closedIssues };
46
+ }
47
+ // ─── Prompt assembly ────────────────────────────────────
48
+ function assemblePrompt(doc, currentContent, releaseContext, activeWork, systemPrompt) {
49
+ const sections = [systemPrompt];
50
+ // Document metadata
51
+ sections.push('=== DOCUMENT TO UPDATE ===');
52
+ sections.push(`Path: ${doc.path}`);
53
+ sections.push(`Purpose: ${doc.description}`);
54
+ sections.push('');
55
+ // Current content
56
+ const truncatedContent = currentContent.length > MAX_DOC_CHARS
57
+ ? currentContent.slice(0, MAX_DOC_CHARS) + '\n... [truncated] ...'
58
+ : currentContent;
59
+ sections.push(wrapXml('current_document', truncatedContent));
60
+ // Release context
61
+ sections.push('\n=== CHANGES SINCE LAST RELEASE ===');
62
+ if (releaseContext.tag) {
63
+ sections.push(`Last release tag: ${releaseContext.tag}`);
64
+ }
65
+ else {
66
+ sections.push('No release tags found — showing recent commits.');
67
+ }
68
+ if (releaseContext.gitLog) {
69
+ const truncatedLog = releaseContext.gitLog.length > MAX_LOG_CHARS
70
+ ? releaseContext.gitLog.slice(0, MAX_LOG_CHARS) + '\n... [truncated] ...'
71
+ : releaseContext.gitLog;
72
+ sections.push(wrapXml('git_log', truncatedLog));
73
+ }
74
+ else {
75
+ sections.push('(No commits found since last release)');
76
+ }
77
+ if (releaseContext.closedIssues) {
78
+ sections.push(wrapXml('closed_issues', releaseContext.closedIssues));
79
+ }
80
+ // Active work context
81
+ if (activeWork) {
82
+ sections.push('\n=== ACTIVE WORK (SOURCE OF TRUTH FOR PHASES & PRIORITIES) ===');
83
+ sections.push(wrapXml('active_work', activeWork));
84
+ }
85
+ return sections.join('\n');
86
+ }
87
+ // ─── Diff display ───────────────────────────────────────
88
+ function showDiff(filePath, original, updated) {
89
+ if (original === updated) {
90
+ log.dim(TAG, `No changes for ${filePath}.`);
91
+ return false;
92
+ }
93
+ const originalLines = original.split('\n');
94
+ const updatedLines = updated.split('\n');
95
+ let added = 0;
96
+ let removed = 0;
97
+ // Simple line-level diff summary
98
+ const originalSet = new Set(originalLines);
99
+ const updatedSet = new Set(updatedLines);
100
+ for (const line of updatedLines) {
101
+ if (!originalSet.has(line))
102
+ added++;
103
+ }
104
+ for (const line of originalLines) {
105
+ if (!updatedSet.has(line))
106
+ removed++;
107
+ }
108
+ log.info(TAG, `${filePath}: +${added} / -${removed} lines changed`);
109
+ return true;
110
+ }
111
+ export async function docsCommand(options) {
112
+ const cwd = process.cwd();
113
+ const configPath = resolveConfigPath(cwd);
114
+ loadEnv(cwd);
115
+ const config = await loadConfig(configPath);
116
+ // Validate docs are configured
117
+ if (!config.docs || config.docs.length === 0) {
118
+ const err = new Error(`[Totem Error] No docs configured.\n` +
119
+ `Add a 'docs' array to totem.config.ts. Example:\n` +
120
+ ` docs: [\n` +
121
+ ` { path: 'README.md', description: 'Public-facing README', trigger: 'post-release' },\n` +
122
+ ` ]`);
123
+ err.name = 'NoDocsConfiguredError';
124
+ throw err;
125
+ }
126
+ // Filter by --only
127
+ let targets = config.docs;
128
+ if (options.only) {
129
+ const onlyNames = options.only.split(',').map((s) => s.trim().toLowerCase());
130
+ targets = config.docs.filter((d) => {
131
+ const basename = path.basename(d.path, path.extname(d.path)).toLowerCase();
132
+ const fullPath = d.path.toLowerCase();
133
+ return onlyNames.some((name) => basename.includes(name) || fullPath.includes(name));
134
+ });
135
+ if (targets.length === 0) {
136
+ throw new Error(`[Totem Error] --only '${options.only}' matched no configured docs.\n` +
137
+ `Available: ${config.docs.map((d) => d.path).join(', ')}`);
138
+ }
139
+ }
140
+ log.info(TAG, `Updating ${targets.length} doc(s): ${targets.map((d) => d.path).join(', ')}`);
141
+ // Check for dirty files (data loss protection)
142
+ const dirtyFiles = targets.filter((d) => isFileDirty(cwd, d.path));
143
+ if (dirtyFiles.length > 0 && !options.dryRun) {
144
+ throw new Error(`[Totem Error] The following doc(s) have uncommitted changes:\n` +
145
+ dirtyFiles.map((d) => ` - ${d.path}`).join('\n') +
146
+ `\nCommit or stash changes before running \`totem docs\` to prevent data loss.`);
147
+ }
148
+ // Gather release context (shared across all docs)
149
+ log.info(TAG, 'Gathering release context...');
150
+ const releaseContext = gatherReleaseContext(cwd);
151
+ if (releaseContext.tag) {
152
+ log.dim(TAG, `Last release: ${releaseContext.tag}`);
153
+ }
154
+ // Load active_work.md for phase/priority context
155
+ let activeWork = '';
156
+ const activeWorkPath = path.join(cwd, 'docs', 'active_work.md');
157
+ try {
158
+ activeWork = fs.readFileSync(activeWorkPath, 'utf-8');
159
+ }
160
+ catch {
161
+ log.dim(TAG, 'No docs/active_work.md found — proceeding without active work context.');
162
+ }
163
+ // Resolve system prompt (allow .totem/prompts/docs.md override)
164
+ const systemPrompt = getSystemPrompt('docs', SYSTEM_PROMPT, cwd, config.totemDir);
165
+ // Process each doc sequentially (separate orchestrator call per doc)
166
+ let updated = 0;
167
+ for (const doc of targets) {
168
+ const filePath = path.join(cwd, doc.path);
169
+ // Read current content
170
+ let currentContent;
171
+ try {
172
+ currentContent = fs.readFileSync(filePath, 'utf-8');
173
+ }
174
+ catch {
175
+ log.warn(TAG, `Skipping ${doc.path} — file not found.`);
176
+ continue;
177
+ }
178
+ log.info(TAG, `Processing ${doc.path}...`);
179
+ // Assemble prompt for this doc
180
+ const prompt = assemblePrompt(doc, currentContent, releaseContext, activeWork, systemPrompt);
181
+ log.dim(TAG, `Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
182
+ const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd });
183
+ if (content == null)
184
+ continue; // --raw mode
185
+ // Check if anything changed
186
+ const trimmedContent = content.trimEnd() + '\n';
187
+ const hasChanges = showDiff(doc.path, currentContent, trimmedContent);
188
+ if (!hasChanges)
189
+ continue;
190
+ if (options.dryRun) {
191
+ log.dim(TAG, `[dry-run] Would update ${doc.path}`);
192
+ if (options.out) {
193
+ writeOutput(trimmedContent, options.out);
194
+ log.success(TAG, `[dry-run] Preview written to ${options.out}`);
195
+ }
196
+ continue;
197
+ }
198
+ // Write the updated content
199
+ fs.writeFileSync(filePath, trimmedContent, 'utf-8');
200
+ log.success(TAG, `Updated ${doc.path}`);
201
+ updated++;
202
+ }
203
+ if (updated > 0) {
204
+ log.success(TAG, `Done — ${updated} doc(s) updated.`);
205
+ }
206
+ else if (!options.raw && !options.dryRun) {
207
+ log.dim(TAG, 'No docs needed updating.');
208
+ }
209
+ }
210
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=docs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.test.d.ts","sourceRoot":"","sources":["../../src/commands/docs.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,188 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import { docsCommand } from './docs.js';
6
+ // ─── Mocks ──────────────────────────────────────────────
7
+ vi.mock('../utils.js', async (importOriginal) => {
8
+ const actual = (await importOriginal());
9
+ return {
10
+ ...actual,
11
+ resolveConfigPath: vi.fn().mockReturnValue('/fake/totem.config.ts'),
12
+ loadEnv: vi.fn(),
13
+ loadConfig: vi.fn(),
14
+ runOrchestrator: vi.fn().mockReturnValue('# Updated README\n\nNew content here.\n'),
15
+ getSystemPrompt: vi.fn().mockReturnValue('system prompt'),
16
+ writeOutput: vi.fn(),
17
+ };
18
+ });
19
+ vi.mock('../git.js', () => ({
20
+ getLatestTag: vi.fn().mockReturnValue('v0.14.0'),
21
+ getGitLogSince: vi.fn().mockReturnValue('abc1234 feat: new feature\ndef5678 fix: bug fix'),
22
+ isFileDirty: vi.fn().mockReturnValue(false),
23
+ }));
24
+ vi.mock('../adapters/github-cli.js', () => ({
25
+ GitHubCliAdapter: vi.fn().mockImplementation(() => ({
26
+ fetchClosedIssues: vi
27
+ .fn()
28
+ .mockReturnValue([
29
+ { number: 108, title: 'Clean up temp files', closedAt: '2026-03-06T00:00:00Z' },
30
+ ]),
31
+ })),
32
+ }));
33
+ import { isFileDirty } from '../git.js';
34
+ import { loadConfig, runOrchestrator } from '../utils.js';
35
+ // ─── Helpers ────────────────────────────────────────────
36
+ let tmpDir;
37
+ function setupTmpDir() {
38
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-docs-test-'));
39
+ // Create docs directory and active_work.md
40
+ fs.mkdirSync(path.join(dir, 'docs'), { recursive: true });
41
+ fs.writeFileSync(path.join(dir, 'docs', 'active_work.md'), '# Active Work\n', 'utf-8');
42
+ return dir;
43
+ }
44
+ function writeDoc(dir, relPath, content) {
45
+ const fullPath = path.join(dir, relPath);
46
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
47
+ fs.writeFileSync(fullPath, content, 'utf-8');
48
+ }
49
+ // ─── Tests ──────────────────────────────────────────────
50
+ describe('docsCommand', () => {
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ // Reset return values (clearAllMocks only clears call records, not implementations)
54
+ vi.mocked(isFileDirty).mockReturnValue(false);
55
+ vi.mocked(runOrchestrator).mockReturnValue('# Updated README\n\nNew content here.\n');
56
+ tmpDir = setupTmpDir();
57
+ vi.spyOn(process, 'cwd').mockReturnValue(tmpDir);
58
+ });
59
+ afterEach(() => {
60
+ vi.restoreAllMocks();
61
+ fs.rmSync(tmpDir, { recursive: true, force: true });
62
+ });
63
+ it('throws when no docs configured', async () => {
64
+ vi.mocked(loadConfig).mockResolvedValue({
65
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
66
+ totemDir: '.totem',
67
+ lanceDir: '.lancedb',
68
+ ignorePatterns: [],
69
+ contextWarningThreshold: 40_000,
70
+ });
71
+ await expect(docsCommand({})).rejects.toThrow('No docs configured');
72
+ });
73
+ it('throws when docs array is empty', async () => {
74
+ vi.mocked(loadConfig).mockResolvedValue({
75
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
76
+ docs: [],
77
+ totemDir: '.totem',
78
+ lanceDir: '.lancedb',
79
+ ignorePatterns: [],
80
+ contextWarningThreshold: 40_000,
81
+ });
82
+ await expect(docsCommand({})).rejects.toThrow('No docs configured');
83
+ });
84
+ it('throws when --only matches no docs', async () => {
85
+ vi.mocked(loadConfig).mockResolvedValue({
86
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
87
+ docs: [{ path: 'README.md', description: 'readme', trigger: 'post-release' }],
88
+ totemDir: '.totem',
89
+ lanceDir: '.lancedb',
90
+ ignorePatterns: [],
91
+ contextWarningThreshold: 40_000,
92
+ });
93
+ await expect(docsCommand({ only: 'nonexistent' })).rejects.toThrow("--only 'nonexistent' matched no configured docs");
94
+ });
95
+ it('filters docs with --only', async () => {
96
+ vi.mocked(loadConfig).mockResolvedValue({
97
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
98
+ docs: [
99
+ { path: 'README.md', description: 'readme', trigger: 'post-release' },
100
+ { path: 'docs/roadmap.md', description: 'roadmap', trigger: 'post-release' },
101
+ ],
102
+ totemDir: '.totem',
103
+ lanceDir: '.lancedb',
104
+ ignorePatterns: [],
105
+ contextWarningThreshold: 40_000,
106
+ });
107
+ writeDoc(tmpDir, 'README.md', '# Old README\n');
108
+ writeDoc(tmpDir, 'docs/roadmap.md', '# Old Roadmap\n');
109
+ await docsCommand({ only: 'readme' });
110
+ // Only one orchestrator call (for README.md)
111
+ expect(runOrchestrator).toHaveBeenCalledTimes(1);
112
+ });
113
+ it('throws when target file has uncommitted changes', async () => {
114
+ vi.mocked(loadConfig).mockResolvedValue({
115
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
116
+ docs: [{ path: 'README.md', description: 'readme', trigger: 'post-release' }],
117
+ totemDir: '.totem',
118
+ lanceDir: '.lancedb',
119
+ ignorePatterns: [],
120
+ contextWarningThreshold: 40_000,
121
+ });
122
+ vi.mocked(isFileDirty).mockReturnValue(true);
123
+ await expect(docsCommand({})).rejects.toThrow('uncommitted changes');
124
+ });
125
+ it('allows dirty files in --dry-run mode', async () => {
126
+ vi.mocked(loadConfig).mockResolvedValue({
127
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
128
+ docs: [{ path: 'README.md', description: 'readme', trigger: 'post-release' }],
129
+ totemDir: '.totem',
130
+ lanceDir: '.lancedb',
131
+ ignorePatterns: [],
132
+ contextWarningThreshold: 40_000,
133
+ });
134
+ vi.mocked(isFileDirty).mockReturnValue(true);
135
+ writeDoc(tmpDir, 'README.md', '# Old README\n');
136
+ // Should not throw
137
+ await docsCommand({ dryRun: true });
138
+ expect(runOrchestrator).toHaveBeenCalledTimes(1);
139
+ // File should NOT be modified in dry-run
140
+ const content = fs.readFileSync(path.join(tmpDir, 'README.md'), 'utf-8');
141
+ expect(content).toBe('# Old README\n');
142
+ });
143
+ it('writes updated content to disk', async () => {
144
+ vi.mocked(loadConfig).mockResolvedValue({
145
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
146
+ docs: [{ path: 'README.md', description: 'readme', trigger: 'post-release' }],
147
+ totemDir: '.totem',
148
+ lanceDir: '.lancedb',
149
+ ignorePatterns: [],
150
+ contextWarningThreshold: 40_000,
151
+ });
152
+ writeDoc(tmpDir, 'README.md', '# Old README\n');
153
+ await docsCommand({});
154
+ const content = fs.readFileSync(path.join(tmpDir, 'README.md'), 'utf-8');
155
+ expect(content).toContain('Updated README');
156
+ });
157
+ it('skips files that do not exist', async () => {
158
+ vi.mocked(loadConfig).mockResolvedValue({
159
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
160
+ docs: [{ path: 'nonexistent.md', description: 'missing', trigger: 'post-release' }],
161
+ totemDir: '.totem',
162
+ lanceDir: '.lancedb',
163
+ ignorePatterns: [],
164
+ contextWarningThreshold: 40_000,
165
+ });
166
+ // Should not throw — just skip
167
+ await docsCommand({});
168
+ expect(runOrchestrator).not.toHaveBeenCalled();
169
+ });
170
+ it('processes multiple docs sequentially', async () => {
171
+ vi.mocked(loadConfig).mockResolvedValue({
172
+ targets: [{ glob: '**/*.ts', type: 'code', strategy: 'typescript-ast' }],
173
+ docs: [
174
+ { path: 'README.md', description: 'readme', trigger: 'post-release' },
175
+ { path: 'docs/roadmap.md', description: 'roadmap', trigger: 'post-release' },
176
+ ],
177
+ totemDir: '.totem',
178
+ lanceDir: '.lancedb',
179
+ ignorePatterns: [],
180
+ contextWarningThreshold: 40_000,
181
+ });
182
+ writeDoc(tmpDir, 'README.md', '# Old README\n');
183
+ writeDoc(tmpDir, 'docs/roadmap.md', '# Old Roadmap\n');
184
+ await docsCommand({});
185
+ expect(runOrchestrator).toHaveBeenCalledTimes(2);
186
+ });
187
+ });
188
+ //# sourceMappingURL=docs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.test.js","sourceRoot":"","sources":["../../src/commands/docs.test.ts"],"names":[],"mappings":"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"}