@slowcook-ai/cli 0.25.0 → 0.27.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 (30) hide show
  1. package/dist/commands/check/index.d.ts.map +1 -1
  2. package/dist/commands/check/index.js +10 -0
  3. package/dist/commands/check/index.js.map +1 -1
  4. package/dist/commands/check/surface-parity.d.ts +123 -0
  5. package/dist/commands/check/surface-parity.d.ts.map +1 -0
  6. package/dist/commands/check/surface-parity.js +328 -0
  7. package/dist/commands/check/surface-parity.js.map +1 -0
  8. package/dist/commands/extract/as-built-cli.d.ts +6 -0
  9. package/dist/commands/extract/as-built-cli.d.ts.map +1 -0
  10. package/dist/commands/extract/as-built-cli.js +67 -0
  11. package/dist/commands/extract/as-built-cli.js.map +1 -0
  12. package/dist/commands/extract/as-built.d.ts +21 -0
  13. package/dist/commands/extract/as-built.d.ts.map +1 -0
  14. package/dist/commands/extract/as-built.js +113 -0
  15. package/dist/commands/extract/as-built.js.map +1 -0
  16. package/dist/commands/extract/index.d.ts.map +1 -1
  17. package/dist/commands/extract/index.js +50 -3
  18. package/dist/commands/extract/index.js.map +1 -1
  19. package/dist/commands/extract/survey.d.ts +17 -0
  20. package/dist/commands/extract/survey.d.ts.map +1 -0
  21. package/dist/commands/extract/survey.js +176 -0
  22. package/dist/commands/extract/survey.js.map +1 -0
  23. package/dist/commands/vibe/as-built.d.ts +25 -0
  24. package/dist/commands/vibe/as-built.d.ts.map +1 -0
  25. package/dist/commands/vibe/as-built.js +111 -0
  26. package/dist/commands/vibe/as-built.js.map +1 -0
  27. package/dist/commands/vibe/index.d.ts.map +1 -1
  28. package/dist/commands/vibe/index.js +47 -0
  29. package/dist/commands/vibe/index.js.map +1 -1
  30. package/package.json +5 -5
@@ -0,0 +1,21 @@
1
+ import type { LlmClient } from "@slowcook-ai/core";
2
+ import type { SurveyOutput } from "./survey.js";
3
+ export declare const AS_BUILT_SYSTEM = "You are slowcook's brownfield extraction agent. You produce AS-BUILT\ndocumentation of an EXISTING product from its repository: what IS, as\nobserved in the code \u2014 never what docs promise, never invented intent.\n\nRules, non-negotiable:\n- Output ONLY the markdown document, no preamble.\n- Structure EXACTLY: a single \"# <repo name> \u2014 as-built\" title line, then the\n sections \"## What the product is\", \"## Map\", \"## Data model (as-built)\",\n \"## Honesty notes\", \"## Founder questions (intake queue)\".\n- Every bullet in every section EXCEPT the questions section MUST end with a\n citation in parentheses naming the file(s) it was observed in, e.g.\n (src/lib/emotions/index.ts:1-14) or (supabase/migrations/00013.sql). No\n citation = the bullet will be rejected by a validator.\n- When repo documents CONTRADICT the code, the code is truth: state the code's\n behaviour and flag the contradiction in \"Honesty notes\" citing both sides.\n- \"Founder questions\" = numbered questions only a human can answer (unclear\n intent, missing infra facts, dead features to rule on). No citations needed.\n- Be dense and specific. 40-70 bullets total. Never pad, never speculate \u2014\n what you cannot see, you either omit or turn into a founder question.";
4
+ export interface Dossier {
5
+ userPrompt: string;
6
+ filesIncluded: string[];
7
+ }
8
+ /** assemble the model's evidence pack: survey + key files (truncated) + route inventory. */
9
+ export declare function buildDossier(repoRoot: string, survey: SurveyOutput, allPaths: string[]): Dossier;
10
+ export interface CitationReport {
11
+ bullets: number;
12
+ uncited: string[];
13
+ }
14
+ /** deterministic post-check: bullets outside the questions section need (path…) citations. */
15
+ export declare function validateCitations(md: string): CitationReport;
16
+ export declare function validateSections(md: string): string[];
17
+ export declare function generateAsBuilt(llm: LlmClient, model: string, dossier: Dossier): Promise<{
18
+ md: string;
19
+ usage: unknown;
20
+ }>;
21
+ //# sourceMappingURL=as-built.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-built.d.ts","sourceRoot":"","sources":["../../../src/commands/extract/as-built.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,eAAe,uwCAkB4C,CAAC;AAEzE,MAAM,WAAW,OAAO;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE;AAWxE,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAsBhG;AAED,MAAM,WAAW,cAAc;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE;AAEtE,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,CAmB5D;AAID,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAErD;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAWzC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * `slowcook extract --as-built` — tier 1 of #262: the LLM pass that turns an
3
+ * existing repo into `.brewing/as-built.md`: what the product IS, as observed,
4
+ * every statement citing its source. Section contract mirrors the hand-made
5
+ * originals (dash's brownfield intake ingests these sections directly):
6
+ *
7
+ * ## What the product is
8
+ * ## Map
9
+ * ## Data model (as-built)
10
+ * ## Honesty notes (docs-vs-code lies, stubs, dead features)
11
+ * ## Founder questions (intake queue)
12
+ *
13
+ * CITATION DISCIPLINE is enforced deterministically after generation: every
14
+ * bullet outside the questions section must carry a `(path[:line…])` citation;
15
+ * violations are reported and the run fails without --allow-uncited. This is
16
+ * verify-before-spec's foundation — an uncited claim is a guess.
17
+ */
18
+ import { readFileSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ export const AS_BUILT_SYSTEM = `You are slowcook's brownfield extraction agent. You produce AS-BUILT
21
+ documentation of an EXISTING product from its repository: what IS, as
22
+ observed in the code — never what docs promise, never invented intent.
23
+
24
+ Rules, non-negotiable:
25
+ - Output ONLY the markdown document, no preamble.
26
+ - Structure EXACTLY: a single "# <repo name> — as-built" title line, then the
27
+ sections "## What the product is", "## Map", "## Data model (as-built)",
28
+ "## Honesty notes", "## Founder questions (intake queue)".
29
+ - Every bullet in every section EXCEPT the questions section MUST end with a
30
+ citation in parentheses naming the file(s) it was observed in, e.g.
31
+ (src/lib/emotions/index.ts:1-14) or (supabase/migrations/00013.sql). No
32
+ citation = the bullet will be rejected by a validator.
33
+ - When repo documents CONTRADICT the code, the code is truth: state the code's
34
+ behaviour and flag the contradiction in "Honesty notes" citing both sides.
35
+ - "Founder questions" = numbered questions only a human can answer (unclear
36
+ intent, missing infra facts, dead features to rule on). No citations needed.
37
+ - Be dense and specific. 40-70 bullets total. Never pad, never speculate —
38
+ what you cannot see, you either omit or turn into a founder question.`;
39
+ const KEY_DOC = /^(readme|claude)\.md$/i;
40
+ const INTERESTING = [
41
+ /^docs\/[^/]+\.md$/i,
42
+ /^(package|pnpm-workspace|foundry|cargo|go)\.(json|yaml|toml|mod)$/i,
43
+ /migrations?\/[^/]+\.(sql|ts|js)$/i,
44
+ /schema[^/]*\.(ts|sql|prisma)$/i,
45
+ ];
46
+ const ROUTEISH = /(app|pages|routes|src\/app)\/.*\.(tsx?|jsx?|vue|svelte)$/i;
47
+ /** assemble the model's evidence pack: survey + key files (truncated) + route inventory. */
48
+ export function buildDossier(repoRoot, survey, allPaths) {
49
+ const parts = [];
50
+ const included = [];
51
+ parts.push(`# Deterministic survey (tier 0)\n${JSON.stringify({ repo_head: survey.repo_head, claims: survey.claims.map((c) => c.statement), skipped: survey.skipped }, null, 1)}`);
52
+ const read = (p, cap) => {
53
+ try {
54
+ const body = readFileSync(join(repoRoot, p), "utf8");
55
+ included.push(p);
56
+ parts.push(`\n===== FILE: ${p} =====\n${body.slice(0, cap)}${body.length > cap ? "\n…(truncated)" : ""}`);
57
+ }
58
+ catch { /* unreadable */ }
59
+ };
60
+ for (const p of allPaths)
61
+ if (KEY_DOC.test(p))
62
+ read(p, 6000);
63
+ for (const p of allPaths.filter((p) => INTERESTING.some((re) => re.test(p))).sort().slice(0, 25))
64
+ read(p, 4000);
65
+ const routes = allPaths.filter((p) => ROUTEISH.test(p) && !/test|spec|stories/.test(p)).sort().slice(0, 120);
66
+ parts.push(`\n===== ROUTE/SURFACE FILE INVENTORY (${routes.length}) =====\n${routes.join("\n")}`);
67
+ // a few route files in full — the product's actual behaviour lives here.
68
+ for (const p of routes.filter((p) => /route\.|page\.|index\./i.test(p)).slice(0, 8))
69
+ read(p, 3000);
70
+ return { userPrompt: parts.join("\n"), filesIncluded: included };
71
+ }
72
+ /** deterministic post-check: bullets outside the questions section need (path…) citations. */
73
+ export function validateCitations(md) {
74
+ const lines = md.split("\n");
75
+ let inQuestions = false;
76
+ let bullets = 0;
77
+ const uncited = [];
78
+ for (const l of lines) {
79
+ if (/^##\s/.test(l))
80
+ inQuestions = /founder questions/i.test(l);
81
+ if (inQuestions)
82
+ continue;
83
+ const t = l.trim();
84
+ if (!/^[-*]\s/.test(t))
85
+ continue;
86
+ bullets++;
87
+ // a citation is a paren group naming a path or file — allowing ONE level
88
+ // of nested parens because real paths contain them (Next.js route groups
89
+ // like src/app/(landing)/page.tsx — found by the rewo dogfood).
90
+ const groups = t.match(/\((?:[^()]|\([^()]*\))*\)/g) ?? [];
91
+ const cited = groups.some((g) => /[\w)\].-]\/[\w(.-]/.test(g) || /\.(ts|tsx|js|jsx|sql|md|mdx|ya?ml|toml|json|sol|py|go|rs|css|prisma)\b/.test(g));
92
+ if (!cited)
93
+ uncited.push(t.slice(0, 110));
94
+ }
95
+ return { bullets, uncited };
96
+ }
97
+ const REQUIRED_SECTIONS = ["## What the product is", "## Map", "## Data model (as-built)", "## Honesty notes", "## Founder questions (intake queue)"];
98
+ export function validateSections(md) {
99
+ return REQUIRED_SECTIONS.filter((s) => !md.includes(s));
100
+ }
101
+ export async function generateAsBuilt(llm, model, dossier) {
102
+ const res = await llm.complete({
103
+ system: AS_BUILT_SYSTEM,
104
+ cacheSystem: false,
105
+ model,
106
+ messages: [{ role: "user", content: dossier.userPrompt }],
107
+ maxTokens: 16000,
108
+ });
109
+ // strip accidental fences
110
+ const md = res.text.replace(/^```(?:markdown|md)?\n/, "").replace(/\n```\s*$/, "").trim() + "\n";
111
+ return { md, usage: res.usage };
112
+ }
113
+ //# sourceMappingURL=as-built.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-built.js","sourceRoot":"","sources":["../../../src/commands/extract/as-built.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/extract/index.ts"],"names":[],"mappings":"AA4GA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/extract/index.ts"],"names":[],"mappings":"AAgJA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ChF"}
@@ -1,10 +1,16 @@
1
1
  import { emitSchemaDiagram, emitTokensCatalog, emitEntitiesDiagram, } from "../map/index.js";
2
+ import { runSurvey, writeSurvey } from "./survey.js";
3
+ import { runAsBuiltCli } from "./as-built-cli.js";
2
4
  function parseArgs(argv) {
3
5
  const args = {
4
6
  repoRoot: process.cwd(),
5
7
  schema: false,
6
8
  tokens: false,
7
9
  entities: false,
10
+ survey: false,
11
+ asBuilt: false,
12
+ allowUncited: false,
13
+ model: null,
8
14
  };
9
15
  let any = false;
10
16
  for (let i = 0; i < argv.length; i++) {
@@ -26,6 +32,21 @@ function parseArgs(argv) {
26
32
  args.entities = true;
27
33
  any = true;
28
34
  }
35
+ else if (a === "--survey") {
36
+ args.survey = true;
37
+ any = true;
38
+ }
39
+ else if (a === "--as-built") {
40
+ args.asBuilt = true;
41
+ any = true;
42
+ }
43
+ else if (a === "--allow-uncited") {
44
+ args.allowUncited = true;
45
+ }
46
+ else if (a === "--model" && next) {
47
+ args.model = next;
48
+ i++;
49
+ }
29
50
  else if (a === "--help" || a === "-h") {
30
51
  printHelp();
31
52
  process.exit(0);
@@ -54,10 +75,13 @@ investigate so their proposals align with the project's existing
54
75
  schema + design tokens instead of inventing.
55
76
 
56
77
  Usage:
57
- slowcook extract [--schema] [--tokens] [--cwd <path>]
78
+ slowcook extract [--schema] [--tokens] [--entities] [--cwd <path>]
79
+ slowcook extract --survey [--cwd <path>]
80
+ slowcook extract --as-built [--cwd <path>] [--model <id>] [--allow-uncited]
58
81
 
59
- No flag = extract everything (currently --schema + --tokens).
60
- Outputs are gitignored; regenerate per refine run.
82
+ No flag = the diagram extracts (--schema + --tokens + --entities).
83
+ Diagram outputs are gitignored; regenerate per refine run.
84
+ --survey / --as-built outputs are INTAKE ARTIFACTS — commit them.
61
85
 
62
86
  Targets:
63
87
  --schema .brewing/diagrams/schema.mmd
@@ -75,12 +99,35 @@ Targets:
75
99
  by default; the init gitignore template carves out an
76
100
  exception for this file.
77
101
 
102
+ --survey .brewing/extract-survey.json (#262 tier 0 — deterministic).
103
+ Doc catalog dated via git (stale-honest), story-spec
104
+ aggregate, commit/branch evidence, issues/PRs via gh when
105
+ available. Entries are knowledge-claim shaped for direct
106
+ ingestion by §7.18-style intakes.
107
+ --as-built .brewing/as-built.md (#262 tier 1 — LLM, key-less capable
108
+ via SLOWCOOK_LLM=claude-cli). AS-OBSERVED product truth in
109
+ five fixed sections; every bullet must carry a (path)
110
+ citation — enforced by a validator; founder questions
111
+ close the doc. Fails on uncited bullets unless
112
+ --allow-uncited.
113
+
78
114
  This command does NOT run the ts-morph code-map scan; for that,
79
115
  use \`slowcook map generate\`.
80
116
  `);
81
117
  }
82
118
  export async function extract(argv, _cliVersion) {
83
119
  const args = parseArgs(argv);
120
+ if (args.survey || args.asBuilt) {
121
+ const survey = runSurvey(args.repoRoot);
122
+ if (args.survey) {
123
+ const file = writeSurvey(args.repoRoot, survey);
124
+ console.log(`Wrote ${file} (${survey.claims.length} claims${survey.skipped.length ? `; skipped: ${survey.skipped.join("; ")}` : ""}).`);
125
+ }
126
+ if (args.asBuilt) {
127
+ await runAsBuiltCli(args.repoRoot, survey, { model: args.model, allowUncited: args.allowUncited });
128
+ }
129
+ return;
130
+ }
84
131
  if (args.schema) {
85
132
  const r = emitSchemaDiagram(args.repoRoot);
86
133
  if (r.written) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/extract/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/extract/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface SurveyClaim {
2
+ source: "doc" | "extraction";
3
+ area: "product" | "behaviour" | "brand" | "architecture" | "data";
4
+ statement: string;
5
+ status: "unverified" | "verified";
6
+ evidence: Record<string, unknown>;
7
+ doc_name?: string;
8
+ }
9
+ export interface SurveyOutput {
10
+ generated_at: string;
11
+ repo_head: string | null;
12
+ claims: SurveyClaim[];
13
+ skipped: string[];
14
+ }
15
+ export declare function runSurvey(repoRoot: string, now?: Date): SurveyOutput;
16
+ export declare function writeSurvey(repoRoot: string, out: SurveyOutput): string;
17
+ //# sourceMappingURL=survey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey.d.ts","sourceRoot":"","sources":["../../../src/commands/extract/survey.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,YAAY,CAAC;IAC7B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,CAAC;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,GAAG,UAAU,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAmDD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,YAAY,CAmF1E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAMvE"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * `slowcook extract --survey` — tier 0 of #262: the deterministic brownfield
3
+ * survey. What a founder expects the moment an existing repo is connected:
4
+ * the documents it already holds (dated — stale ones stay honest), its story
5
+ * history, and the work evidence git/GitHub carry. No LLM, no network beyond
6
+ * optional `gh` (skipped honestly when unavailable).
7
+ *
8
+ * Emits `.brewing/extract-survey.json` whose entries are knowledge-claim
9
+ * shaped ({source, area, statement, status, evidence}) so consumers (dash's
10
+ * knowledge sync, or any §7.18-style intake) can ingest them directly.
11
+ */
12
+ import { execFileSync } from "node:child_process";
13
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
14
+ import { join, relative } from "node:path";
15
+ const DOC_AREA = [
16
+ { re: /brand|design|theme|style/i, area: "brand" },
17
+ { re: /architec|deploy|infra|stack|engineering|supabase|setup|operations|ops\b/i, area: "architecture" },
18
+ { re: /schema|migration|data\b|ddl/i, area: "data" },
19
+ { re: /prd|readme|product|vision|stories|spec|roadmap|changelog/i, area: "product" },
20
+ ];
21
+ const areaFor = (path) => DOC_AREA.find((d) => d.re.test(path))?.area ?? "product";
22
+ const isDocPath = (p) => (/\.(md|mdx|txt|rst)$/i.test(p) || /^\.brewing\/[^/]+\.ya?ml$/i.test(p) || /brand[^/]*\.ya?ml$/i.test(p)) &&
23
+ !/node_modules|^\.github\/|CODE_OF_CONDUCT|LICENSE/i.test(p) && p.split("/").length <= 4;
24
+ function walk(dir, root, acc = []) {
25
+ let entries;
26
+ try {
27
+ entries = readdirSync(dir);
28
+ }
29
+ catch {
30
+ return acc;
31
+ }
32
+ for (const name of entries) {
33
+ if (name === "node_modules" || name === ".git" || name === "dist")
34
+ continue;
35
+ const full = join(dir, name);
36
+ let st;
37
+ try {
38
+ st = statSync(full);
39
+ }
40
+ catch {
41
+ continue;
42
+ }
43
+ if (st.isDirectory())
44
+ walk(full, root, acc);
45
+ else
46
+ acc.push(relative(root, full).replace(/\\/g, "/"));
47
+ }
48
+ return acc;
49
+ }
50
+ function git(root, args) {
51
+ try {
52
+ return execFileSync("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ function gh(root, args) {
59
+ try {
60
+ return execFileSync("gh", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ }
66
+ const firstHeading = (body) => body.split("\n").find((l) => l.startsWith("# "))?.slice(2).trim() ?? null;
67
+ function datedSuffix(iso, now) {
68
+ if (!iso)
69
+ return "";
70
+ const months = Math.floor((now.getTime() - Date.parse(iso)) / (30 * 86_400_000));
71
+ if (Number.isNaN(months))
72
+ return "";
73
+ return months >= 1
74
+ ? ` — last touched ${months} month${months === 1 ? "" : "s"} ago${months >= 6 ? " (may be stale)" : ""}`
75
+ : " — recently updated";
76
+ }
77
+ export function runSurvey(repoRoot, now = new Date()) {
78
+ const claims = [];
79
+ const skipped = [];
80
+ const paths = walk(repoRoot, repoRoot);
81
+ const head = git(repoRoot, ["rev-parse", "--short", "HEAD"]);
82
+ // 1) document catalog, dated via git.
83
+ for (const p of paths.filter(isDocPath).sort().slice(0, 60)) {
84
+ let title = null;
85
+ try {
86
+ title = firstHeading(readFileSync(join(repoRoot, p), "utf8"));
87
+ }
88
+ catch { /* binary/unreadable */ }
89
+ const iso = git(repoRoot, ["log", "-1", "--format=%cI", "--", p]);
90
+ claims.push({
91
+ source: "doc", area: areaFor(p), status: "unverified",
92
+ statement: `Repo document: ${p}${title ? ` — “${title}”` : ""}${datedSuffix(iso, now)}`,
93
+ evidence: { path: p, last_commit: iso, kind: "doc-catalog" },
94
+ doc_name: p,
95
+ });
96
+ }
97
+ // 2) story specs — one aggregate claim.
98
+ const specs = paths.filter((p) => /^specs\/story-\d+\.ya?ml$/.test(p)).sort();
99
+ if (specs.length > 0) {
100
+ const titles = [];
101
+ for (const p of specs.slice(0, 25)) {
102
+ try {
103
+ const t = readFileSync(join(repoRoot, p), "utf8").split("\n").find((l) => /^title:/.test(l))
104
+ ?.replace(/^title:\s*/, "").replace(/^["']|["']$/g, "").trim();
105
+ if (t)
106
+ titles.push(`${p.replace(/^specs\//, "").replace(/\.ya?ml$/, "")}: ${t}`);
107
+ }
108
+ catch { /* skip */ }
109
+ }
110
+ let statusBit = "";
111
+ try {
112
+ const index = readFileSync(join(repoRoot, "specs/_index.yaml"), "utf8");
113
+ const active = (index.match(/status:\s*active/g) ?? []).length;
114
+ const superseded = (index.match(/status:\s*superseded/g) ?? []).length;
115
+ statusBit = ` (${active} active, ${superseded} superseded per specs/_index.yaml)`;
116
+ }
117
+ catch { /* no index */ }
118
+ const sample = titles.slice(0, 3).map((t) => `“${t.split(": ").slice(1).join(": ").slice(0, 60)}”`).join(" · ");
119
+ claims.push({
120
+ source: "extraction", area: "product", status: "verified",
121
+ statement: `Story history: ${specs.length} committed story specs${statusBit}${sample ? ` — e.g. ${sample}` : ""}.`,
122
+ evidence: { kind: "story-specs", titles },
123
+ });
124
+ }
125
+ // 3) work evidence — git always; GitHub via `gh` when available.
126
+ const commitCount = git(repoRoot, ["rev-list", "--count", "HEAD"]);
127
+ const recent = git(repoRoot, ["log", "-20", "--format=%s"])?.split("\n").filter(Boolean) ?? [];
128
+ const lastIso = git(repoRoot, ["log", "-1", "--format=%cI"]);
129
+ const branches = git(repoRoot, ["branch", "-r", "--format=%(refname:short)"])?.split("\n")
130
+ .map((b) => b.replace(/^origin\//, "")).filter((b) => b && b !== "HEAD") ?? [];
131
+ const conventions = {};
132
+ for (const b of branches) {
133
+ const prefix = b.includes("/") ? `${b.split("/")[0]}/*` : "(bare)";
134
+ conventions[prefix] = (conventions[prefix] ?? 0) + 1;
135
+ }
136
+ const conv = Object.entries(conventions).sort((a, b) => b[1] - a[1]).slice(0, 2).map(([k, n]) => `${k} ×${n}`).join(", ");
137
+ if (commitCount) {
138
+ claims.push({
139
+ source: "extraction", area: "architecture", status: "verified",
140
+ statement: `Commit history: ${commitCount} commits${lastIso ? `, last${datedSuffix(lastIso, now).replace(" — last touched", "")}` : ""}; ${branches.length} remote branches${conv ? ` (mostly ${conv})` : ""}. Recent: ${recent.slice(0, 2).map((m) => `“${m}”`).join(" · ")}`,
141
+ evidence: { kind: "commit-sample", messages: recent, branches: conventions, last_commit: lastIso },
142
+ });
143
+ }
144
+ else {
145
+ skipped.push("git history (not a git checkout)");
146
+ }
147
+ const issueJson = gh(repoRoot, ["issue", "list", "--state", "all", "--limit", "100", "--json", "state,title"]);
148
+ const prJson = gh(repoRoot, ["pr", "list", "--state", "all", "--limit", "100", "--json", "state,title"]);
149
+ if (issueJson && prJson) {
150
+ try {
151
+ const issues = JSON.parse(issueJson);
152
+ const prs = JSON.parse(prJson);
153
+ claims.push({
154
+ source: "extraction", area: "product", status: "verified",
155
+ statement: `Work evidence: ${issues.length} issues (${issues.filter((i) => i.state === "OPEN").length} open), ${prs.length} PRs (${prs.filter((p) => p.state === "MERGED").length} merged).`,
156
+ evidence: { kind: "work-evidence", issues: issues.slice(0, 8), pulls: prs.slice(0, 8) },
157
+ });
158
+ }
159
+ catch {
160
+ skipped.push("GitHub issues/PRs (gh output unparseable)");
161
+ }
162
+ }
163
+ else {
164
+ skipped.push("GitHub issues/PRs (gh unavailable or no remote access)");
165
+ }
166
+ return { generated_at: now.toISOString(), repo_head: head, claims, skipped };
167
+ }
168
+ export function writeSurvey(repoRoot, out) {
169
+ const dir = join(repoRoot, ".brewing");
170
+ if (!existsSync(dir))
171
+ mkdirSync(dir, { recursive: true });
172
+ const file = join(dir, "extract-survey.json");
173
+ writeFileSync(file, JSON.stringify(out, null, 2) + "\n", "utf8");
174
+ return file;
175
+ }
176
+ //# sourceMappingURL=survey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"survey.js","sourceRoot":"","sources":["../../../src/commands/extract/survey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { LlmClient } from "@slowcook-ai/core";
2
+ import { type VibeFileBlock } from "./emit.js";
3
+ export declare const AS_BUILT_VIBE_SYSTEM = "You are slowcook's as-built vibe agent. You are given the PRODUCTION\nsource of ONE existing surface. Produce a FAITHFUL, self-contained mock\nre-render of it for design review.\n\nRules, non-negotiable:\n- Output ONLY <file path=\"mock/src/apps/<surface>/...\">\u2026</file> blocks. No prose.\n- FAITHFUL means: same structure, same copy, same states as the source \u2014\n you are transcribing what IS, not designing. Do not improve, rename,\n restyle or add features. Uncertain behaviour becomes a code comment\n \"AS-BUILT-UNCLEAR: \u2026\", never an invention.\n- Self-contained: react only; no imports from the production tree or any\n package the mock app does not already use. Data the source fetches\n becomes inline fixtures marked \"@slowcook-honest: as-built fixture,\n shaped from <source path>\".\n- The FIRST line of every file must be a comment IN THAT FILE TYPE'S native\n comment syntax (// for ts/tsx, /* \u2026 */ for css, <!-- \u2026 --> for html):\n @slowcook-as-built-from <source path>@<sha> \u2014 prod-first: this mock\n mirrors production; edits here are PROPOSALS, not truth.\n- Use the design tokens provided (brand.yaml) via inline styles or the\n mock app's existing CSS variables; do not invent a palette.";
4
+ export interface AsBuiltVibeInput {
5
+ repoRoot: string;
6
+ fromPath: string;
7
+ surface: string;
8
+ sha: string | null;
9
+ sources: {
10
+ path: string;
11
+ body: string;
12
+ }[];
13
+ brandYaml: string | null;
14
+ }
15
+ export declare function collectAsBuiltInput(repoRoot: string, fromPath: string, surface?: string): AsBuiltVibeInput;
16
+ export declare function buildAsBuiltVibePrompt(input: AsBuiltVibeInput): string;
17
+ export interface AsBuiltVibeResult {
18
+ written: string[];
19
+ files: VibeFileBlock[];
20
+ violations: string[];
21
+ }
22
+ export declare function runAsBuiltVibe(llm: LlmClient, model: string, input: AsBuiltVibeInput, opts?: {
23
+ dryRun?: boolean;
24
+ }): Promise<AsBuiltVibeResult>;
25
+ //# sourceMappingURL=as-built.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-built.d.ts","sourceRoot":"","sources":["../../../src/commands/vibe/as-built.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAmC,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAEhF,eAAO,MAAM,oBAAoB,ouCAmB6B,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CA0B1G;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAQtE;AAED,MAAM,WAAW,iBAAiB;IAAG,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE;AAEtG,wBAAsB,cAAc,CAClC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,gBAAgB,EACvB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAyB5B"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * `slowcook vibe --as-built --from <srcPath>` — #263: generate a FAITHFUL
3
+ * mock of an EXISTING surface from its production source (lazy brownfield
4
+ * mocking). Where normal vibe designs from a spec (mock-first), as-built
5
+ * vibe transcribes from code (prod-first): the mock is a reviewable
6
+ * re-render of what IS, stamped with its provenance so the parity baseline
7
+ * can tell staleness (prod moved) from mutation (mock edited).
8
+ *
9
+ * Uses the shared LlmClient (key-less capable via SLOWCOOK_LLM=claude-cli)
10
+ * and vibe's existing XML file-block emit path — including the hard
11
+ * mock/-only write guard.
12
+ */
13
+ import { existsSync, readFileSync } from "node:fs";
14
+ import { dirname, join, normalize } from "node:path";
15
+ import { execFileSync } from "node:child_process";
16
+ import { parseVibeOutput, writeVibeFiles } from "./emit.js";
17
+ export const AS_BUILT_VIBE_SYSTEM = `You are slowcook's as-built vibe agent. You are given the PRODUCTION
18
+ source of ONE existing surface. Produce a FAITHFUL, self-contained mock
19
+ re-render of it for design review.
20
+
21
+ Rules, non-negotiable:
22
+ - Output ONLY <file path="mock/src/apps/<surface>/...">…</file> blocks. No prose.
23
+ - FAITHFUL means: same structure, same copy, same states as the source —
24
+ you are transcribing what IS, not designing. Do not improve, rename,
25
+ restyle or add features. Uncertain behaviour becomes a code comment
26
+ "AS-BUILT-UNCLEAR: …", never an invention.
27
+ - Self-contained: react only; no imports from the production tree or any
28
+ package the mock app does not already use. Data the source fetches
29
+ becomes inline fixtures marked "@slowcook-honest: as-built fixture,
30
+ shaped from <source path>".
31
+ - The FIRST line of every file must be a comment IN THAT FILE TYPE'S native
32
+ comment syntax (// for ts/tsx, /* … */ for css, <!-- … --> for html):
33
+ @slowcook-as-built-from <source path>@<sha> — prod-first: this mock
34
+ mirrors production; edits here are PROPOSALS, not truth.
35
+ - Use the design tokens provided (brand.yaml) via inline styles or the
36
+ mock app's existing CSS variables; do not invent a palette.`;
37
+ export function collectAsBuiltInput(repoRoot, fromPath, surface) {
38
+ const norm = normalize(fromPath).replace(/\\/g, "/");
39
+ const abs = join(repoRoot, norm);
40
+ if (!existsSync(abs))
41
+ throw new Error(`--from source not found: ${norm}`);
42
+ const main = readFileSync(abs, "utf8");
43
+ const sources = [{ path: norm, body: main }];
44
+ // one hop of same-directory relative imports — the surface's local parts.
45
+ const dir = dirname(norm);
46
+ const rel = [...main.matchAll(/from\s+["']\.\/([\w./-]+)["']/g)].map((m) => m[1]).slice(0, 6);
47
+ for (const r of rel) {
48
+ for (const ext of ["", ".ts", ".tsx", ".js", ".jsx"]) {
49
+ const p = join(repoRoot, dir, r + ext);
50
+ if (existsSync(p) && !p.endsWith("/")) {
51
+ try {
52
+ sources.push({ path: join(dir, r + ext).replace(/\\/g, "/"), body: readFileSync(p, "utf8").slice(0, 8000) });
53
+ }
54
+ catch { /* skip */ }
55
+ break;
56
+ }
57
+ }
58
+ }
59
+ let brandYaml = null;
60
+ try {
61
+ brandYaml = readFileSync(join(repoRoot, ".brewing/brand.yaml"), "utf8").slice(0, 3000);
62
+ }
63
+ catch { /* none */ }
64
+ let sha = null;
65
+ try {
66
+ sha = execFileSync("git", ["rev-parse", "--short", "HEAD"], { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
67
+ }
68
+ catch { /* not git */ }
69
+ const surfaceName = surface ?? (norm.split("/").pop() ?? "surface").replace(/\.(tsx?|jsx?)$/, "").replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
70
+ return { repoRoot, fromPath: norm, surface: surfaceName, sha, sources, brandYaml };
71
+ }
72
+ export function buildAsBuiltVibePrompt(input) {
73
+ const parts = [];
74
+ parts.push(`Surface name: ${input.surface}`);
75
+ parts.push(`Provenance to stamp: ${input.fromPath}@${input.sha ?? "HEAD"}`);
76
+ parts.push(`Target directory for ALL files: mock/src/apps/${input.surface}/`);
77
+ if (input.brandYaml)
78
+ parts.push(`===== .brewing/brand.yaml (design tokens) =====\n${input.brandYaml}`);
79
+ for (const s of input.sources)
80
+ parts.push(`===== PRODUCTION SOURCE: ${s.path} =====\n${s.body}`);
81
+ return parts.join("\n\n");
82
+ }
83
+ export async function runAsBuiltVibe(llm, model, input, opts = {}) {
84
+ const res = await llm.complete({
85
+ system: AS_BUILT_VIBE_SYSTEM,
86
+ cacheSystem: false,
87
+ model,
88
+ messages: [{ role: "user", content: buildAsBuiltVibePrompt(input) }],
89
+ maxTokens: 12000,
90
+ });
91
+ const out = parseVibeOutput(res.text);
92
+ const violations = [];
93
+ if (out.files.length === 0)
94
+ violations.push("model emitted no <file> blocks");
95
+ for (const f of out.files) {
96
+ // stamp must open the file in the file-type's native comment syntax
97
+ // (// for ts/js, /* for css, <!-- for html/md — the landing dogfood's
98
+ // css emission caught the //-only assumption).
99
+ if (!/^(\/\/|\/\*|<!--|#)\s*@slowcook-as-built-from/.test(f.contents)) {
100
+ violations.push(`${f.path}: missing @slowcook-as-built-from provenance stamp on line 1`);
101
+ }
102
+ if (!f.path.startsWith(`mock/src/apps/${input.surface}/`)) {
103
+ violations.push(`${f.path}: outside the surface directory mock/src/apps/${input.surface}/`);
104
+ }
105
+ }
106
+ if (violations.length > 0 || opts.dryRun)
107
+ return { written: [], files: out.files, violations };
108
+ const written = writeVibeFiles(input.repoRoot, out.files); // hard mock/-only guard inside
109
+ return { written, files: out.files, violations: [] };
110
+ }
111
+ //# sourceMappingURL=as-built.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-built.js","sourceRoot":"","sources":["../../../src/commands/vibe/as-built.ts"],"names":[],"mappings":"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"}