@percepta/kaizen 0.6.0 → 0.8.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 (139) hide show
  1. package/README.md +54 -126
  2. package/agent/claude-command.md +23 -0
  3. package/agent/evals.md +41 -0
  4. package/agent/overview.md +53 -0
  5. package/agent/variant-builder.md +22 -0
  6. package/agent/views.md +51 -0
  7. package/dashboard/.next/standalone/package.json +1 -1
  8. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/BUILD_ID +1 -1
  9. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/build-manifest.json +22 -22
  10. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/prerender-manifest.json +3 -3
  11. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/routes-manifest.json +36 -10
  12. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/chunks/169.js +1 -0
  13. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/chunks/588.js +8 -0
  14. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/middleware-build-manifest.js +1 -1
  15. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/404.html +1 -1
  16. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/500.html +1 -1
  17. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/benchmarks.html +1 -1
  18. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/benchmarks.js.nft.json +1 -1
  19. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/data/[[...path]].html +1 -0
  20. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/data/[[...path]].js.nft.json +1 -0
  21. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/eval.html +1 -1
  22. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/eval.js.nft.json +1 -1
  23. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/experiments/[[...path]].html +1 -0
  24. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/experiments/[[...path]].js.nft.json +1 -0
  25. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/ideas.html +1 -1
  26. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/ideas.js.nft.json +1 -1
  27. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-action.js +1 -0
  28. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-action.js.nft.json +1 -0
  29. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset-item.js +1 -1
  30. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset-item.js.nft.json +1 -1
  31. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset-mutation.js +1 -0
  32. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset-mutation.js.nft.json +1 -0
  33. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset.js +1 -1
  34. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-dataset.js.nft.json +1 -1
  35. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-datasets.js +1 -1
  36. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-datasets.js.nft.json +1 -1
  37. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-trace-memberships.js +1 -0
  38. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-trace-memberships.js.nft.json +1 -0
  39. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-trace.js +1 -1
  40. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-trace.js.nft.json +1 -1
  41. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-traces.js +1 -0
  42. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/langfuse-traces.js.nft.json +1 -0
  43. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/linear-ideas.js +2 -2
  44. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/linear-ideas.js.nft.json +1 -1
  45. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-events.js +1 -1
  46. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-events.js.nft.json +1 -1
  47. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-failures.js +1 -1
  48. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-failures.js.nft.json +1 -1
  49. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-traces.js +1 -1
  50. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/run-traces.js.nft.json +1 -1
  51. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/runs.js +2 -2
  52. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/runs.js.nft.json +1 -1
  53. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/systems.js +2 -2
  54. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/systems.js.nft.json +1 -1
  55. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/trace-renderer.js +1 -1
  56. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/api/trace-renderer.js.nft.json +1 -1
  57. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/index.html +1 -1
  58. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/index.js.nft.json +1 -1
  59. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages-manifest.json +10 -6
  60. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/9JQIPpJv6qWldYoYMHZAl/_buildManifest.js +1 -0
  61. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/53-795fe9d662eaacfe.js +8 -0
  62. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/{benchmarks-559dc9df52db3af4.js → benchmarks-bc38d751890170d0.js} +1 -1
  63. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/data/[[...path]]-8afe5a733bdde0f4.js +1 -0
  64. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/{eval-3c911ea8744631fd.js → eval-ab900515b5b18b4d.js} +1 -1
  65. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/experiments/[[...path]]-7198800378ce98dc.js +1 -0
  66. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/{ideas-6829a271003150a9.js → ideas-d8fd592d7cd21bb9.js} +1 -1
  67. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/{index-1d8b6719f49e4ae0.js → index-842f5332939fc510.js} +1 -1
  68. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/css/d97fcd1d34ebab98.css +1 -0
  69. package/dashboard/.next/standalone/packages/kaizen/package.json +8 -3
  70. package/dashboard/.next/standalone/packages/kaizen/shared/workspace-paths.js +84 -0
  71. package/dist/commands/create-view.js +58 -0
  72. package/dist/commands/create-view.js.map +1 -0
  73. package/dist/commands/guide.js +66 -0
  74. package/dist/commands/guide.js.map +1 -0
  75. package/dist/commands/ideas.js +4 -8
  76. package/dist/commands/ideas.js.map +1 -1
  77. package/dist/commands/init-system.js +22 -20
  78. package/dist/commands/init-system.js.map +1 -1
  79. package/dist/commands/init.js +28 -64
  80. package/dist/commands/init.js.map +1 -1
  81. package/dist/commands/log.js +5 -11
  82. package/dist/commands/log.js.map +1 -1
  83. package/dist/commands/rebuild.js +7 -9
  84. package/dist/commands/rebuild.js.map +1 -1
  85. package/dist/commands/run.js +5 -9
  86. package/dist/commands/run.js.map +1 -1
  87. package/dist/commands/studio.js +3 -3
  88. package/dist/commands/studio.js.map +1 -1
  89. package/dist/index.js +17 -21
  90. package/dist/index.js.map +1 -1
  91. package/dist/lib/cli.js +20 -0
  92. package/dist/lib/cli.js.map +1 -0
  93. package/dist/lib/events.js.map +1 -1
  94. package/dist/lib/fs-utils.js +3 -27
  95. package/dist/lib/fs-utils.js.map +1 -1
  96. package/dist/lib/leaderboard.js +1 -1
  97. package/dist/lib/leaderboard.js.map +1 -1
  98. package/dist/lib/paths.js +3 -3
  99. package/dist/lib/paths.js.map +1 -1
  100. package/dist/lib/promotion.js.map +1 -1
  101. package/dist/lib/run-dir.js +1 -1
  102. package/dist/lib/run-dir.js.map +1 -1
  103. package/dist/lib/runner.js +6 -5
  104. package/dist/lib/runner.js.map +1 -1
  105. package/dist/lib/system.js +4 -2
  106. package/dist/lib/system.js.map +1 -1
  107. package/dist/package.js +6 -3
  108. package/dist/shared/view-types.d.ts +67 -0
  109. package/dist/shared/view-types.d.ts.map +1 -0
  110. package/dist/shared/workspace-paths.js +84 -0
  111. package/dist/shared/workspace-paths.js.map +1 -0
  112. package/dist/types.d.ts +3 -30
  113. package/dist/types.d.ts.map +1 -1
  114. package/package.json +8 -3
  115. package/shared/view-types.d.ts +69 -0
  116. package/shared/view-types.js +1 -0
  117. package/shared/workspace-paths.d.ts +19 -0
  118. package/shared/workspace-paths.js +84 -0
  119. package/templates/system/eval.py +13 -6
  120. package/templates/system/eval.ts +11 -5
  121. package/templates/system/rubric.md +1 -1
  122. package/templates/system/system.md +6 -5
  123. package/templates/view/dataset-item.tsx +63 -0
  124. package/templates/view/trace.tsx +10 -0
  125. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/chunks/715.js +0 -6
  126. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/data.html +0 -1
  127. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/data.js.nft.json +0 -1
  128. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/experiments.html +0 -1
  129. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/server/pages/[system]/experiments.js.nft.json +0 -1
  130. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/YpQ-I4VL-aEdQrM5uN7_3/_buildManifest.js +0 -1
  131. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/673-ed4be46027ae7a37.js +0 -6
  132. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/data-644e4280b4c86fe0.js +0 -1
  133. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/chunks/pages/[system]/experiments-42f31600c2bb47ad.js +0 -1
  134. package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/css/b18a6732b96168e1.css +0 -1
  135. package/dist/lib/env.js +0 -2
  136. package/dist/shared/env.js +0 -4
  137. package/templates/workspace/.claude/agents/variant-builder.md +0 -51
  138. package/templates/workspace/.claude/commands/kaizen.md +0 -65
  139. /package/dashboard/.next/standalone/packages/kaizen/dashboard/.next/static/{YpQ-I4VL-aEdQrM5uN7_3 → 9JQIPpJv6qWldYoYMHZAl}/_ssgManifest.js +0 -0
@@ -0,0 +1,58 @@
1
+ import { kaizenSystemDir, kaizenSystemPath } from "../shared/workspace-paths.js";
2
+ import { templatesDir, workspaceRoot } from "../lib/paths.js";
3
+ import { isSystemId, requireKaizenWorkspace } from "../lib/cli.js";
4
+ import { applyVars, ensureDir, writeFileSafely } from "../lib/fs-utils.js";
5
+ import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
6
+ import { existsSync, readFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ //#region src/commands/create-view.ts
9
+ const VIEW_TYPES = ["trace", "dataset-item"];
10
+ async function runCreateView(argv) {
11
+ const { positional, flags } = parseFlags(argv);
12
+ const root = workspaceRoot();
13
+ const force = boolFlag(flags, "force");
14
+ if (!requireKaizenWorkspace(root)) return 1;
15
+ const systemId = strFlag(flags, "system") ?? positional[0];
16
+ if (!systemId || !isSystemId(systemId)) {
17
+ process.stderr.write(`invalid system name: "${systemId ?? ""}". use kebab-case (e.g. cost-savings).\n`);
18
+ return 1;
19
+ }
20
+ if (!existsSync(kaizenSystemPath(root, systemId))) {
21
+ process.stderr.write(`system "${systemId}" not found at kaizen/systems/${systemId}/system.md.\nrun \`kaizen create system ${systemId}\` first.\n`);
22
+ return 1;
23
+ }
24
+ const typeFlag = strFlag(flags, "type");
25
+ if (!typeFlag) {
26
+ process.stderr.write(`kaizen create view: --type <${VIEW_TYPES.join("|")}> is required.\n`);
27
+ return 1;
28
+ }
29
+ const type = normalizeType(typeFlag);
30
+ if (!type) {
31
+ process.stderr.write(`invalid view type. use one of: ${VIEW_TYPES.join(", ")}.\n`);
32
+ return 1;
33
+ }
34
+ const dir = kaizenSystemDir(root, systemId);
35
+ const viewPath = join(dir, `${type}.tsx`);
36
+ if (existsSync(viewPath) && !force) {
37
+ process.stderr.write(`refusing to overwrite ${viewPath}. pass --force to replace.\n`);
38
+ return 1;
39
+ }
40
+ ensureDir(dir);
41
+ writeFileSafely(viewPath, applyVars(readFileSync(join(templatesDir(), "view", `${type}.tsx`), "utf-8"), { system_id: systemId }), { overwrite: force });
42
+ process.stdout.write(`scaffolded ${type} view for "${systemId}":\n`);
43
+ process.stdout.write(` kaizen/systems/${systemId}/${type}.tsx\n`);
44
+ process.stdout.write([
45
+ "",
46
+ "Kaizen Studio loads this file by convention beside system.md.",
47
+ "Refresh the browser or focus the Studio window after edits to reload the view.",
48
+ ""
49
+ ].join("\n"));
50
+ return 0;
51
+ }
52
+ function normalizeType(value) {
53
+ return VIEW_TYPES.includes(value) ? value : null;
54
+ }
55
+ //#endregion
56
+ export { runCreateView };
57
+
58
+ //# sourceMappingURL=create-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-view.js","names":[],"sources":["../../src/commands/create-view.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isSystemId, requireKaizenWorkspace } from \"../lib/cli.js\";\nimport { applyVars, ensureDir, writeFileSafely } from \"../lib/fs-utils.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport {\n kaizenSystemDir,\n kaizenSystemPath,\n templatesDir,\n workspaceRoot,\n} from \"../lib/paths.js\";\n\nconst VIEW_TYPES = [\"trace\", \"dataset-item\"] as const;\ntype ViewType = (typeof VIEW_TYPES)[number];\n\nexport async function runCreateView(argv: string[]): Promise<number> {\n const { positional, flags } = parseFlags(argv);\n const root = workspaceRoot();\n const force = boolFlag(flags, \"force\");\n\n if (!requireKaizenWorkspace(root)) return 1;\n\n const systemId = strFlag(flags, \"system\") ?? positional[0];\n if (!systemId || !isSystemId(systemId)) {\n process.stderr.write(\n `invalid system name: \"${systemId ?? \"\"}\". use kebab-case (e.g. cost-savings).\\n`,\n );\n return 1;\n }\n\n const systemPath = kaizenSystemPath(root, systemId);\n if (!existsSync(systemPath)) {\n process.stderr.write(\n `system \"${systemId}\" not found at kaizen/systems/${systemId}/system.md.\\n` +\n `run \\`kaizen create system ${systemId}\\` first.\\n`,\n );\n return 1;\n }\n\n const typeFlag = strFlag(flags, \"type\");\n if (!typeFlag) {\n process.stderr.write(\n `kaizen create view: --type <${VIEW_TYPES.join(\"|\")}> is required.\\n`,\n );\n return 1;\n }\n const type = normalizeType(typeFlag);\n if (!type) {\n process.stderr.write(\n `invalid view type. use one of: ${VIEW_TYPES.join(\", \")}.\\n`,\n );\n return 1;\n }\n\n const dir = kaizenSystemDir(root, systemId);\n const viewPath = join(dir, `${type}.tsx`);\n if (existsSync(viewPath) && !force) {\n process.stderr.write(\n `refusing to overwrite ${viewPath}. pass --force to replace.\\n`,\n );\n return 1;\n }\n\n ensureDir(dir);\n const templatePath = join(templatesDir(), \"view\", `${type}.tsx`);\n const template = readFileSync(templatePath, \"utf-8\");\n writeFileSafely(viewPath, applyVars(template, { system_id: systemId }), {\n overwrite: force,\n });\n\n process.stdout.write(`scaffolded ${type} view for \"${systemId}\":\\n`);\n process.stdout.write(` kaizen/systems/${systemId}/${type}.tsx\\n`);\n process.stdout.write(\n [\n \"\",\n \"Kaizen Studio loads this file by convention beside system.md.\",\n \"Refresh the browser or focus the Studio window after edits to reload the view.\",\n \"\",\n ].join(\"\\n\"),\n );\n\n return 0;\n}\n\nfunction normalizeType(value: string): ViewType | null {\n return (VIEW_TYPES as readonly string[]).includes(value)\n ? (value as ViewType)\n : null;\n}\n"],"mappings":";;;;;;;;AAYA,MAAM,aAAa,CAAC,SAAS,eAAe;AAG5C,eAAsB,cAAc,MAAiC;CACnE,MAAM,EAAE,YAAY,UAAU,WAAW,KAAK;CAC9C,MAAM,OAAO,eAAe;CAC5B,MAAM,QAAQ,SAAS,OAAO,QAAQ;AAEtC,KAAI,CAAC,uBAAuB,KAAK,CAAE,QAAO;CAE1C,MAAM,WAAW,QAAQ,OAAO,SAAS,IAAI,WAAW;AACxD,KAAI,CAAC,YAAY,CAAC,WAAW,SAAS,EAAE;AACtC,UAAQ,OAAO,MACb,yBAAyB,YAAY,GAAG,0CACzC;AACD,SAAO;;AAIT,KAAI,CAAC,WADc,iBAAiB,MAAM,SAChB,CAAC,EAAE;AAC3B,UAAQ,OAAO,MACb,WAAW,SAAS,gCAAgC,SAAS,0CAC7B,SAAS,aAC1C;AACD,SAAO;;CAGT,MAAM,WAAW,QAAQ,OAAO,OAAO;AACvC,KAAI,CAAC,UAAU;AACb,UAAQ,OAAO,MACb,+BAA+B,WAAW,KAAK,IAAI,CAAC,kBACrD;AACD,SAAO;;CAET,MAAM,OAAO,cAAc,SAAS;AACpC,KAAI,CAAC,MAAM;AACT,UAAQ,OAAO,MACb,kCAAkC,WAAW,KAAK,KAAK,CAAC,KACzD;AACD,SAAO;;CAGT,MAAM,MAAM,gBAAgB,MAAM,SAAS;CAC3C,MAAM,WAAW,KAAK,KAAK,GAAG,KAAK,MAAM;AACzC,KAAI,WAAW,SAAS,IAAI,CAAC,OAAO;AAClC,UAAQ,OAAO,MACb,yBAAyB,SAAS,8BACnC;AACD,SAAO;;AAGT,WAAU,IAAI;AAGd,iBAAgB,UAAU,UADT,aADI,KAAK,cAAc,EAAE,QAAQ,GAAG,KAAK,MAChB,EAAE,QACA,EAAE,EAAE,WAAW,UAAU,CAAC,EAAE,EACtE,WAAW,OACZ,CAAC;AAEF,SAAQ,OAAO,MAAM,cAAc,KAAK,aAAa,SAAS,MAAM;AACpE,SAAQ,OAAO,MAAM,oBAAoB,SAAS,GAAG,KAAK,QAAQ;AAClE,SAAQ,OAAO,MACb;EACE;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAED,QAAO;;AAGT,SAAS,cAAc,OAAgC;AACrD,QAAQ,WAAiC,SAAS,MAAM,GACnD,QACD"}
@@ -0,0 +1,66 @@
1
+ import { packageRoot } from "../lib/paths.js";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ //#region src/commands/guide.ts
5
+ const TOPICS = {
6
+ overview: {
7
+ file: "overview.md",
8
+ description: "canonical agent workflow, commands, files, evals, and views"
9
+ },
10
+ evals: {
11
+ file: "evals.md",
12
+ description: "eval script invocation, NDJSON events, and baseline runs"
13
+ },
14
+ views: {
15
+ file: "views.md",
16
+ description: "custom trace and dataset item view paths, props, and actions"
17
+ },
18
+ "claude-command": {
19
+ file: "claude-command.md",
20
+ description: "Claude Code slash-command instructions"
21
+ },
22
+ "variant-builder": {
23
+ file: "variant-builder.md",
24
+ description: "single-variant worktree agent instructions"
25
+ }
26
+ };
27
+ function runGuide(argv) {
28
+ const [rawTopic] = argv.filter((arg) => !arg.startsWith("-"));
29
+ const topic = rawTopic ?? "overview";
30
+ if (topic === "topics" || topic === "list") {
31
+ process.stdout.write(renderTopicList());
32
+ return 0;
33
+ }
34
+ if (topic === "all") {
35
+ process.stdout.write(Object.keys(TOPICS).map((name) => readGuide(name)).join("\n\n---\n\n"));
36
+ process.stdout.write("\n");
37
+ return 0;
38
+ }
39
+ if (!isGuideTopic(topic)) {
40
+ process.stderr.write(`unknown guide topic: ${topic}\n\n${renderTopicList()}`);
41
+ return 1;
42
+ }
43
+ process.stdout.write(readGuide(topic));
44
+ process.stdout.write("\n");
45
+ return 0;
46
+ }
47
+ function readGuide(topic) {
48
+ const guide = TOPICS[topic];
49
+ return readFileSync(join(packageRoot(), "agent", guide.file), "utf-8");
50
+ }
51
+ function isGuideTopic(topic) {
52
+ return Object.prototype.hasOwnProperty.call(TOPICS, topic);
53
+ }
54
+ function renderTopicList() {
55
+ return [
56
+ "kaizen guide topics:",
57
+ "",
58
+ ...Object.entries(TOPICS).map(([name, guide]) => ` ${name.padEnd(15)} ${guide.description}`),
59
+ " all print every guide topic",
60
+ ""
61
+ ].join("\n");
62
+ }
63
+ //#endregion
64
+ export { runGuide };
65
+
66
+ //# sourceMappingURL=guide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guide.js","names":[],"sources":["../../src/commands/guide.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { packageRoot } from \"../lib/paths.js\";\n\ninterface GuideTopic {\n file: string;\n description: string;\n}\n\nconst TOPICS: Record<string, GuideTopic> = {\n overview: {\n file: \"overview.md\",\n description: \"canonical agent workflow, commands, files, evals, and views\",\n },\n evals: {\n file: \"evals.md\",\n description: \"eval script invocation, NDJSON events, and baseline runs\",\n },\n views: {\n file: \"views.md\",\n description: \"custom trace and dataset item view paths, props, and actions\",\n },\n \"claude-command\": {\n file: \"claude-command.md\",\n description: \"Claude Code slash-command instructions\",\n },\n \"variant-builder\": {\n file: \"variant-builder.md\",\n description: \"single-variant worktree agent instructions\",\n },\n};\n\nexport function runGuide(argv: string[]): number {\n const [rawTopic] = argv.filter((arg) => !arg.startsWith(\"-\"));\n const topic = rawTopic ?? \"overview\";\n\n if (topic === \"topics\" || topic === \"list\") {\n process.stdout.write(renderTopicList());\n return 0;\n }\n\n if (topic === \"all\") {\n process.stdout.write(\n Object.keys(TOPICS)\n .map((name) => readGuide(name))\n .join(\"\\n\\n---\\n\\n\"),\n );\n process.stdout.write(\"\\n\");\n return 0;\n }\n\n if (!isGuideTopic(topic)) {\n process.stderr.write(\n `unknown guide topic: ${topic}\\n\\n${renderTopicList()}`,\n );\n return 1;\n }\n\n process.stdout.write(readGuide(topic));\n process.stdout.write(\"\\n\");\n return 0;\n}\n\nfunction readGuide(topic: string): string {\n const guide = TOPICS[topic];\n return readFileSync(join(packageRoot(), \"agent\", guide.file), \"utf-8\");\n}\n\nfunction isGuideTopic(topic: string): boolean {\n return Object.prototype.hasOwnProperty.call(TOPICS, topic);\n}\n\nfunction renderTopicList(): string {\n return [\n \"kaizen guide topics:\",\n \"\",\n ...Object.entries(TOPICS).map(\n ([name, guide]) => ` ${name.padEnd(15)} ${guide.description}`,\n ),\n \" all print every guide topic\",\n \"\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;AASA,MAAM,SAAqC;CACzC,UAAU;EACR,MAAM;EACN,aAAa;EACd;CACD,OAAO;EACL,MAAM;EACN,aAAa;EACd;CACD,OAAO;EACL,MAAM;EACN,aAAa;EACd;CACD,kBAAkB;EAChB,MAAM;EACN,aAAa;EACd;CACD,mBAAmB;EACjB,MAAM;EACN,aAAa;EACd;CACF;AAED,SAAgB,SAAS,MAAwB;CAC/C,MAAM,CAAC,YAAY,KAAK,QAAQ,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC;CAC7D,MAAM,QAAQ,YAAY;AAE1B,KAAI,UAAU,YAAY,UAAU,QAAQ;AAC1C,UAAQ,OAAO,MAAM,iBAAiB,CAAC;AACvC,SAAO;;AAGT,KAAI,UAAU,OAAO;AACnB,UAAQ,OAAO,MACb,OAAO,KAAK,OAAO,CAChB,KAAK,SAAS,UAAU,KAAK,CAAC,CAC9B,KAAK,cAAc,CACvB;AACD,UAAQ,OAAO,MAAM,KAAK;AAC1B,SAAO;;AAGT,KAAI,CAAC,aAAa,MAAM,EAAE;AACxB,UAAQ,OAAO,MACb,wBAAwB,MAAM,MAAM,iBAAiB,GACtD;AACD,SAAO;;AAGT,SAAQ,OAAO,MAAM,UAAU,MAAM,CAAC;AACtC,SAAQ,OAAO,MAAM,KAAK;AAC1B,QAAO;;AAGT,SAAS,UAAU,OAAuB;CACxC,MAAM,QAAQ,OAAO;AACrB,QAAO,aAAa,KAAK,aAAa,EAAE,SAAS,MAAM,KAAK,EAAE,QAAQ;;AAGxE,SAAS,aAAa,OAAwB;AAC5C,QAAO,OAAO,UAAU,eAAe,KAAK,QAAQ,MAAM;;AAG5D,SAAS,kBAA0B;AACjC,QAAO;EACL;EACA;EACA,GAAG,OAAO,QAAQ,OAAO,CAAC,KACvB,CAAC,MAAM,WAAW,KAAK,KAAK,OAAO,GAAG,CAAC,GAAG,MAAM,cAClD;EACD;EACA;EACD,CAAC,KAAK,KAAK"}
@@ -1,8 +1,8 @@
1
- import { ISSUE_QUERY, KAIZEN_LINEAR_LABEL, buildIssueFilter, linearHttpMessage, linearProjectRefFromFields, parseLinearBody, resolveLinearEnv, resolveLinearProject } from "../shared/linear-ideas.js";
2
- import { readEnvFile } from "../shared/env-file.js";
3
- import "../lib/env.js";
4
- import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
5
1
  import { workspaceRoot } from "../lib/paths.js";
2
+ import { pad } from "../lib/cli.js";
3
+ import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
4
+ import { readEnvFile } from "../shared/env-file.js";
5
+ import { ISSUE_QUERY, KAIZEN_LINEAR_LABEL, buildIssueFilter, linearHttpMessage, linearProjectRefFromFields, parseLinearBody, resolveLinearEnv, resolveLinearProject } from "../shared/linear-ideas.js";
6
6
  import { loadSystem } from "../lib/system.js";
7
7
  import { join } from "node:path";
8
8
  //#region src/commands/ideas.ts
@@ -127,10 +127,6 @@ function formatDate(value) {
127
127
  if (Number.isNaN(date.getTime())) return value.slice(0, 10);
128
128
  return date.toISOString().slice(0, 10);
129
129
  }
130
- function pad(s, w) {
131
- if (s.length >= w) return s.slice(0, w - 1) + " ";
132
- return s + " ".repeat(w - s.length);
133
- }
134
130
  //#endregion
135
131
  export { runIdeas };
136
132
 
@@ -1 +1 @@
1
- {"version":3,"file":"ideas.js","names":[],"sources":["../../src/commands/ideas.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport {\n buildIssueFilter,\n ISSUE_QUERY,\n KAIZEN_LINEAR_LABEL,\n linearProjectRefFromFields,\n linearHttpMessage,\n parseLinearBody,\n resolveLinearEnv,\n resolveLinearProject,\n type LinearIdea,\n type LinearProject,\n type LinearProjectRef,\n} from \"../../shared/linear-ideas.js\";\nimport { readEnvFile } from \"../lib/env.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { workspaceRoot } from \"../lib/paths.js\";\nimport { loadSystem } from \"../lib/system.js\";\n\nexport async function runIdeas(argv: string[]): Promise<number> {\n const { flags } = parseFlags(argv);\n const root = workspaceRoot();\n const systemId = strFlag(flags, \"system\");\n const json = boolFlag(flags, \"json\");\n const limit = parseLimit(strFlag(flags, \"limit\") ?? strFlag(flags, \"n\"));\n\n if (!systemId) {\n process.stderr.write(\"kaizen ideas: --system <id> is required\\n\");\n return 1;\n }\n if (limit === null) {\n process.stderr.write(\"kaizen ideas: --limit must be a positive integer\\n\");\n return 1;\n }\n\n const system = loadSystem(root, systemId);\n const projectRef = linearProjectRefFromFields({\n project: stringFrontmatter(system.frontmatter.linear_project),\n projectId: stringFrontmatter(system.frontmatter.linear_project_id),\n projectUrl: stringFrontmatter(system.frontmatter.linear_project_url),\n });\n if (!projectRef) {\n process.stderr.write(\n `kaizen ideas: system \"${systemId}\" is missing linear_project in frontmatter.\\n` +\n \"Add the Linear project URL or project ID to scope ideas for this system.\\n\",\n );\n return 1;\n }\n\n const envPath = join(root, \".env.local\");\n const linearEnv = resolveLinearEnv(readEnvFile(envPath), {});\n const token = linearEnv.apiKey;\n if (!token) {\n process.stderr.write(\n `kaizen ideas: LINEAR_API_KEY is missing. Add it to ${envPath}.\\n`,\n );\n return 1;\n }\n\n const config = {\n system: systemId,\n projectRef,\n team:\n stringFrontmatter(system.frontmatter.linear_team) ?? linearEnv.teamKey,\n label: KAIZEN_LINEAR_LABEL,\n limit,\n };\n\n const { project, ideas } = await fetchLinearIdeas(token, config);\n const outputConfig = {\n ...config,\n project,\n };\n\n if (json) {\n process.stdout.write(\n JSON.stringify({ config: outputConfig, ideas }, null, 2) + \"\\n\",\n );\n return 0;\n }\n\n printIdeas(outputConfig, ideas);\n return 0;\n}\n\nfunction parseLimit(raw: string | undefined): number | null {\n if (!raw) return 50;\n const n = Number(raw);\n return Number.isInteger(n) && n > 0 ? n : null;\n}\n\nasync function fetchLinearIdeas(\n token: string,\n config: {\n projectRef: LinearProjectRef;\n team: string | null;\n label: string;\n limit: number;\n },\n): Promise<{ project: LinearProject; ideas: LinearIdea[] }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const project = await resolveLinearProject(\n token,\n config.projectRef,\n controller.signal,\n );\n if (!project) {\n throw new Error(\n `Linear project ${config.projectRef.value} was not found`,\n );\n }\n\n const res = await fetch(\"https://api.linear.app/graphql\", {\n method: \"POST\",\n headers: {\n Authorization: token,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: ISSUE_QUERY,\n variables: {\n first: config.limit,\n filter: buildIssueFilter({\n projectId: project.id,\n teamKey: config.team,\n label: config.label,\n }),\n },\n }),\n signal: controller.signal,\n });\n\n const text = await res.text();\n const body = parseLinearBody(text);\n if (!res.ok || body.errors?.length) {\n throw new Error(linearHttpMessage(res, body.errors));\n }\n return { project, ideas: body.data?.issues?.nodes ?? [] };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction printIdeas(\n config: {\n system: string;\n project: LinearProject;\n team: string | null;\n label: string;\n },\n ideas: LinearIdea[],\n): void {\n process.stdout.write(\n `system: ${config.system} project: ${config.project.name} label: ${config.label}\\n`,\n );\n if (config.team) process.stdout.write(`team: ${config.team}\\n`);\n if (ideas.length === 0) {\n process.stdout.write(\"no ideas found.\\n\");\n return;\n }\n\n process.stdout.write(\"\\n\");\n process.stdout.write(\n pad(\"issue\", 12) +\n pad(\"priority\", 10) +\n pad(\"status\", 18) +\n pad(\"assignee\", 18) +\n pad(\"updated\", 13) +\n \"title\\n\",\n );\n for (const idea of ideas) {\n process.stdout.write(\n pad(idea.identifier, 12) +\n pad(priorityLabel(idea.priority), 10) +\n pad(idea.state?.name ?? \"No status\", 18) +\n pad(idea.assignee?.name ?? \"Unassigned\", 18) +\n pad(formatDate(idea.updatedAt), 13) +\n idea.title +\n \"\\n\",\n );\n }\n process.stdout.write(\n \"\\nUse `kaizen ideas --system \" +\n config.system +\n \" --json` for URLs and full issue details.\\n\",\n );\n}\n\nfunction stringFrontmatter(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\nfunction priorityLabel(priority: number): string {\n if (priority === 1) return \"Urgent\";\n if (priority === 2) return \"High\";\n if (priority === 3) return \"Normal\";\n if (priority === 4) return \"Low\";\n return \"None\";\n}\n\nfunction formatDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value.slice(0, 10);\n return date.toISOString().slice(0, 10);\n}\n\nfunction pad(s: string, w: number): string {\n if (s.length >= w) return s.slice(0, w - 1) + \" \";\n return s + \" \".repeat(w - s.length);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ideas.js","names":[],"sources":["../../src/commands/ideas.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { readEnvFile } from \"../../shared/env-file.js\";\nimport {\n buildIssueFilter,\n ISSUE_QUERY,\n KAIZEN_LINEAR_LABEL,\n linearProjectRefFromFields,\n linearHttpMessage,\n parseLinearBody,\n resolveLinearEnv,\n resolveLinearProject,\n type LinearIdea,\n type LinearProject,\n type LinearProjectRef,\n} from \"../../shared/linear-ideas.js\";\nimport { pad } from \"../lib/cli.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { workspaceRoot } from \"../lib/paths.js\";\nimport { loadSystem } from \"../lib/system.js\";\n\nexport async function runIdeas(argv: string[]): Promise<number> {\n const { flags } = parseFlags(argv);\n const root = workspaceRoot();\n const systemId = strFlag(flags, \"system\");\n const json = boolFlag(flags, \"json\");\n const limit = parseLimit(strFlag(flags, \"limit\") ?? strFlag(flags, \"n\"));\n\n if (!systemId) {\n process.stderr.write(\"kaizen ideas: --system <id> is required\\n\");\n return 1;\n }\n if (limit === null) {\n process.stderr.write(\"kaizen ideas: --limit must be a positive integer\\n\");\n return 1;\n }\n\n const system = loadSystem(root, systemId);\n const projectRef = linearProjectRefFromFields({\n project: stringFrontmatter(system.frontmatter.linear_project),\n projectId: stringFrontmatter(system.frontmatter.linear_project_id),\n projectUrl: stringFrontmatter(system.frontmatter.linear_project_url),\n });\n if (!projectRef) {\n process.stderr.write(\n `kaizen ideas: system \"${systemId}\" is missing linear_project in frontmatter.\\n` +\n \"Add the Linear project URL or project ID to scope ideas for this system.\\n\",\n );\n return 1;\n }\n\n const envPath = join(root, \".env.local\");\n const linearEnv = resolveLinearEnv(readEnvFile(envPath), {});\n const token = linearEnv.apiKey;\n if (!token) {\n process.stderr.write(\n `kaizen ideas: LINEAR_API_KEY is missing. Add it to ${envPath}.\\n`,\n );\n return 1;\n }\n\n const config = {\n system: systemId,\n projectRef,\n team:\n stringFrontmatter(system.frontmatter.linear_team) ?? linearEnv.teamKey,\n label: KAIZEN_LINEAR_LABEL,\n limit,\n };\n\n const { project, ideas } = await fetchLinearIdeas(token, config);\n const outputConfig = {\n ...config,\n project,\n };\n\n if (json) {\n process.stdout.write(\n JSON.stringify({ config: outputConfig, ideas }, null, 2) + \"\\n\",\n );\n return 0;\n }\n\n printIdeas(outputConfig, ideas);\n return 0;\n}\n\nfunction parseLimit(raw: string | undefined): number | null {\n if (!raw) return 50;\n const n = Number(raw);\n return Number.isInteger(n) && n > 0 ? n : null;\n}\n\nasync function fetchLinearIdeas(\n token: string,\n config: {\n projectRef: LinearProjectRef;\n team: string | null;\n label: string;\n limit: number;\n },\n): Promise<{ project: LinearProject; ideas: LinearIdea[] }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const project = await resolveLinearProject(\n token,\n config.projectRef,\n controller.signal,\n );\n if (!project) {\n throw new Error(\n `Linear project ${config.projectRef.value} was not found`,\n );\n }\n\n const res = await fetch(\"https://api.linear.app/graphql\", {\n method: \"POST\",\n headers: {\n Authorization: token,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: ISSUE_QUERY,\n variables: {\n first: config.limit,\n filter: buildIssueFilter({\n projectId: project.id,\n teamKey: config.team,\n label: config.label,\n }),\n },\n }),\n signal: controller.signal,\n });\n\n const text = await res.text();\n const body = parseLinearBody(text);\n if (!res.ok || body.errors?.length) {\n throw new Error(linearHttpMessage(res, body.errors));\n }\n return { project, ideas: body.data?.issues?.nodes ?? [] };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction printIdeas(\n config: {\n system: string;\n project: LinearProject;\n team: string | null;\n label: string;\n },\n ideas: LinearIdea[],\n): void {\n process.stdout.write(\n `system: ${config.system} project: ${config.project.name} label: ${config.label}\\n`,\n );\n if (config.team) process.stdout.write(`team: ${config.team}\\n`);\n if (ideas.length === 0) {\n process.stdout.write(\"no ideas found.\\n\");\n return;\n }\n\n process.stdout.write(\"\\n\");\n process.stdout.write(\n pad(\"issue\", 12) +\n pad(\"priority\", 10) +\n pad(\"status\", 18) +\n pad(\"assignee\", 18) +\n pad(\"updated\", 13) +\n \"title\\n\",\n );\n for (const idea of ideas) {\n process.stdout.write(\n pad(idea.identifier, 12) +\n pad(priorityLabel(idea.priority), 10) +\n pad(idea.state?.name ?? \"No status\", 18) +\n pad(idea.assignee?.name ?? \"Unassigned\", 18) +\n pad(formatDate(idea.updatedAt), 13) +\n idea.title +\n \"\\n\",\n );\n }\n process.stdout.write(\n \"\\nUse `kaizen ideas --system \" +\n config.system +\n \" --json` for URLs and full issue details.\\n\",\n );\n}\n\nfunction stringFrontmatter(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\nfunction priorityLabel(priority: number): string {\n if (priority === 1) return \"Urgent\";\n if (priority === 2) return \"High\";\n if (priority === 3) return \"Normal\";\n if (priority === 4) return \"Low\";\n return \"None\";\n}\n\nfunction formatDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value.slice(0, 10);\n return date.toISOString().slice(0, 10);\n}\n"],"mappings":"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"}
@@ -1,9 +1,11 @@
1
- import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
1
+ import { kaizenSystemDir } from "../shared/workspace-paths.js";
2
2
  import { templatesDir, workspaceRoot } from "../lib/paths.js";
3
+ import { isSystemId, requireKaizenWorkspace } from "../lib/cli.js";
3
4
  import { applyVars, ensureDir, writeFileSafely } from "../lib/fs-utils.js";
5
+ import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
4
6
  import { prompt, promptChoice } from "../lib/prompt.js";
5
- import { join } from "node:path";
6
7
  import { existsSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
7
9
  //#region src/commands/init-system.ts
8
10
  const EVAL_STYLES = [
9
11
  "ground-truth",
@@ -15,12 +17,9 @@ async function runInitSystem(argv) {
15
17
  const { positional, flags } = parseFlags(argv);
16
18
  const root = workspaceRoot();
17
19
  const force = boolFlag(flags, "force");
18
- if (!existsSync(join(root, "kaizen.config.ts"))) {
19
- process.stderr.write(`no kaizen.config.ts in ${root}.\nrun \`kaizen init\` first.\n`);
20
- return 1;
21
- }
20
+ if (!requireKaizenWorkspace(root)) return 1;
22
21
  const name = strFlag(flags, "name") ?? positional[0] ?? await prompt("system name (kebab-case)");
23
- if (!name || !/^[a-z][a-z0-9-]*$/.test(name)) {
22
+ if (!name || !isSystemId(name)) {
24
23
  process.stderr.write(`invalid system name: "${name}". use kebab-case (e.g. cost-savings).\n`);
25
24
  return 1;
26
25
  }
@@ -38,30 +37,33 @@ async function runInitSystem(argv) {
38
37
  primary_metric: strFlag(flags, "metric") ?? await prompt("primary metric name", evalStyle === "ground-truth" ? "accuracy" : "score"),
39
38
  target: strFlag(flags, "target") ?? await prompt("target score (0-1)", "0.90"),
40
39
  eval_ext: evalLanguage === "typescript" ? "ts" : "py",
40
+ eval_file: `eval.${evalLanguage === "typescript" ? "ts" : "py"}`,
41
+ rubric_frontmatter: evalStyle === "ground-truth" ? "" : `rubric: kaizen/systems/${name}/rubric.md\n`,
41
42
  iso_now: (/* @__PURE__ */ new Date()).toISOString()
42
43
  };
43
- const systemPath = join(root, "systems", `${name}.md`);
44
- const evalPath = join(root, "eval", `${name}.${vars.eval_ext}`);
45
- const rubricPath = join(root, "rubrics", `${name}.md`);
44
+ const systemDir = kaizenSystemDir(root, name);
45
+ const systemPath = join(systemDir, "system.md");
46
+ const evalPath = join(systemDir, vars.eval_file);
47
+ const rubricPath = join(systemDir, "rubric.md");
46
48
  if (!force) {
47
- for (const p of [systemPath, evalPath]) if (existsSync(p)) {
49
+ for (const p of [
50
+ systemPath,
51
+ evalPath,
52
+ ...evalStyle !== "ground-truth" ? [rubricPath] : []
53
+ ]) if (existsSync(p)) {
48
54
  process.stderr.write(`refusing to overwrite ${p}. pass --force to replace.\n`);
49
55
  return 1;
50
56
  }
51
57
  }
52
- ensureDir(join(root, "systems"));
53
- ensureDir(join(root, "eval"));
58
+ ensureDir(systemDir);
54
59
  const tpl = templatesDir();
55
60
  writeFileSafely(systemPath, applyVars(readFileSync(join(tpl, "system", "system.md"), "utf-8"), vars), { overwrite: force });
56
61
  writeFileSafely(evalPath, applyVars(readFileSync(join(tpl, "system", evalLanguage === "typescript" ? "eval.ts" : "eval.py"), "utf-8"), vars), { overwrite: force });
57
- if (evalStyle !== "ground-truth") {
58
- ensureDir(join(root, "rubrics"));
59
- writeFileSafely(rubricPath, applyVars(readFileSync(join(tpl, "system", "rubric.md"), "utf-8"), vars), { overwrite: force });
60
- }
62
+ if (evalStyle !== "ground-truth") writeFileSafely(rubricPath, applyVars(readFileSync(join(tpl, "system", "rubric.md"), "utf-8"), vars), { overwrite: force });
61
63
  process.stdout.write(`scaffolded system "${name}":\n`);
62
- process.stdout.write(` systems/${name}.md\n`);
63
- process.stdout.write(` eval/${name}.${vars.eval_ext}\n`);
64
- if (evalStyle !== "ground-truth") process.stdout.write(` rubrics/${name}.md\n`);
64
+ process.stdout.write(` kaizen/systems/${name}/system.md\n`);
65
+ process.stdout.write(` kaizen/systems/${name}/${vars.eval_file}\n`);
66
+ if (evalStyle !== "ground-truth") process.stdout.write(` kaizen/systems/${name}/rubric.md\n`);
65
67
  process.stdout.write([
66
68
  "",
67
69
  "the starter eval emits a working NDJSON event stream against 3 dummy items.",
@@ -1 +1 @@
1
- {"version":3,"file":"init-system.js","names":[],"sources":["../../src/commands/init-system.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { applyVars, ensureDir, writeFileSafely } from \"../lib/fs-utils.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { templatesDir, workspaceRoot } from \"../lib/paths.js\";\nimport { prompt, promptChoice } from \"../lib/prompt.js\";\n\nconst EVAL_STYLES = [\"ground-truth\", \"llm-as-judge\", \"hybrid\"] as const;\ntype EvalStyle = (typeof EVAL_STYLES)[number];\nconst EVAL_LANGUAGES = [\"python\", \"typescript\"] as const;\ntype EvalLanguage = (typeof EVAL_LANGUAGES)[number];\n\nexport async function runInitSystem(argv: string[]): Promise<number> {\n const { positional, flags } = parseFlags(argv);\n const root = workspaceRoot();\n const force = boolFlag(flags, \"force\");\n\n if (!existsSync(join(root, \"kaizen.config.ts\"))) {\n process.stderr.write(\n `no kaizen.config.ts in ${root}.\\nrun \\`kaizen init\\` first.\\n`,\n );\n return 1;\n }\n\n const name =\n strFlag(flags, \"name\") ??\n positional[0] ??\n (await prompt(\"system name (kebab-case)\"));\n if (!name || !/^[a-z][a-z0-9-]*$/.test(name)) {\n process.stderr.write(\n `invalid system name: \"${name}\". use kebab-case (e.g. cost-savings).\\n`,\n );\n return 1;\n }\n\n const description =\n strFlag(flags, \"description\") ??\n (await prompt(\"one-line description\", `${name} system`));\n\n const evalStyle = (strFlag(flags, \"eval-style\") ??\n (await promptChoice(\n \"eval style\",\n [...EVAL_STYLES],\n \"ground-truth\",\n ))) as EvalStyle;\n\n const evalLanguage = normalizeEvalLanguage(\n strFlag(flags, \"eval-language\") ?? strFlag(flags, \"language\") ?? \"python\",\n );\n if (!evalLanguage) {\n process.stderr.write(\n `invalid eval language. use one of: ${EVAL_LANGUAGES.join(\", \")}, py, ts.\\n`,\n );\n return 1;\n }\n\n const primaryMetric =\n strFlag(flags, \"metric\") ??\n (await prompt(\n \"primary metric name\",\n evalStyle === \"ground-truth\" ? \"accuracy\" : \"score\",\n ));\n\n const target =\n strFlag(flags, \"target\") ?? (await prompt(\"target score (0-1)\", \"0.90\"));\n\n const vars: Record<string, string> = {\n name,\n description,\n eval_style: evalStyle,\n primary_metric: primaryMetric,\n target,\n eval_ext: evalLanguage === \"typescript\" ? \"ts\" : \"py\",\n iso_now: new Date().toISOString(),\n };\n\n const systemPath = join(root, \"systems\", `${name}.md`);\n const evalPath = join(root, \"eval\", `${name}.${vars.eval_ext}`);\n const rubricPath = join(root, \"rubrics\", `${name}.md`);\n\n if (!force) {\n for (const p of [systemPath, evalPath]) {\n if (existsSync(p)) {\n process.stderr.write(\n `refusing to overwrite ${p}. pass --force to replace.\\n`,\n );\n return 1;\n }\n }\n }\n\n ensureDir(join(root, \"systems\"));\n ensureDir(join(root, \"eval\"));\n\n const tpl = templatesDir();\n writeFileSafely(\n systemPath,\n applyVars(readFileSync(join(tpl, \"system\", \"system.md\"), \"utf-8\"), vars),\n { overwrite: force },\n );\n writeFileSafely(\n evalPath,\n applyVars(\n readFileSync(\n join(\n tpl,\n \"system\",\n evalLanguage === \"typescript\" ? \"eval.ts\" : \"eval.py\",\n ),\n \"utf-8\",\n ),\n vars,\n ),\n { overwrite: force },\n );\n\n if (evalStyle !== \"ground-truth\") {\n ensureDir(join(root, \"rubrics\"));\n writeFileSafely(\n rubricPath,\n applyVars(readFileSync(join(tpl, \"system\", \"rubric.md\"), \"utf-8\"), vars),\n { overwrite: force },\n );\n }\n\n process.stdout.write(`scaffolded system \"${name}\":\\n`);\n process.stdout.write(` systems/${name}.md\\n`);\n process.stdout.write(` eval/${name}.${vars.eval_ext}\\n`);\n if (evalStyle !== \"ground-truth\")\n process.stdout.write(` rubrics/${name}.md\\n`);\n process.stdout.write(\n [\n \"\",\n \"the starter eval emits a working NDJSON event stream against 3 dummy items.\",\n \"edit it to load your dataset and produce real scores, then:\",\n \"\",\n ` kaizen run --system ${name} --variant baseline --hypothesis \"starting baseline\"`,\n \"\",\n ].join(\"\\n\"),\n );\n\n return 0;\n}\n\nfunction normalizeEvalLanguage(raw: string): EvalLanguage | null {\n const normalized = raw.toLowerCase();\n if (normalized === \"python\" || normalized === \"py\") return \"python\";\n if (normalized === \"typescript\" || normalized === \"ts\") return \"typescript\";\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"init-system.js","names":[],"sources":["../../src/commands/init-system.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isSystemId, requireKaizenWorkspace } from \"../lib/cli.js\";\nimport { applyVars, ensureDir, writeFileSafely } from \"../lib/fs-utils.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { kaizenSystemDir, templatesDir, workspaceRoot } from \"../lib/paths.js\";\nimport { prompt, promptChoice } from \"../lib/prompt.js\";\n\nconst EVAL_STYLES = [\"ground-truth\", \"llm-as-judge\", \"hybrid\"] as const;\ntype EvalStyle = (typeof EVAL_STYLES)[number];\nconst EVAL_LANGUAGES = [\"python\", \"typescript\"] as const;\ntype EvalLanguage = (typeof EVAL_LANGUAGES)[number];\n\nexport async function runInitSystem(argv: string[]): Promise<number> {\n const { positional, flags } = parseFlags(argv);\n const root = workspaceRoot();\n const force = boolFlag(flags, \"force\");\n\n if (!requireKaizenWorkspace(root)) return 1;\n\n const name =\n strFlag(flags, \"name\") ??\n positional[0] ??\n (await prompt(\"system name (kebab-case)\"));\n if (!name || !isSystemId(name)) {\n process.stderr.write(\n `invalid system name: \"${name}\". use kebab-case (e.g. cost-savings).\\n`,\n );\n return 1;\n }\n\n const description =\n strFlag(flags, \"description\") ??\n (await prompt(\"one-line description\", `${name} system`));\n\n const evalStyle = (strFlag(flags, \"eval-style\") ??\n (await promptChoice(\n \"eval style\",\n [...EVAL_STYLES],\n \"ground-truth\",\n ))) as EvalStyle;\n\n const evalLanguage = normalizeEvalLanguage(\n strFlag(flags, \"eval-language\") ?? strFlag(flags, \"language\") ?? \"python\",\n );\n if (!evalLanguage) {\n process.stderr.write(\n `invalid eval language. use one of: ${EVAL_LANGUAGES.join(\", \")}, py, ts.\\n`,\n );\n return 1;\n }\n\n const primaryMetric =\n strFlag(flags, \"metric\") ??\n (await prompt(\n \"primary metric name\",\n evalStyle === \"ground-truth\" ? \"accuracy\" : \"score\",\n ));\n\n const target =\n strFlag(flags, \"target\") ?? (await prompt(\"target score (0-1)\", \"0.90\"));\n\n const vars: Record<string, string> = {\n name,\n description,\n eval_style: evalStyle,\n primary_metric: primaryMetric,\n target,\n eval_ext: evalLanguage === \"typescript\" ? \"ts\" : \"py\",\n eval_file: `eval.${evalLanguage === \"typescript\" ? \"ts\" : \"py\"}`,\n rubric_frontmatter:\n evalStyle === \"ground-truth\"\n ? \"\"\n : `rubric: kaizen/systems/${name}/rubric.md\\n`,\n iso_now: new Date().toISOString(),\n };\n\n const systemDir = kaizenSystemDir(root, name);\n const systemPath = join(systemDir, \"system.md\");\n const evalPath = join(systemDir, vars.eval_file);\n const rubricPath = join(systemDir, \"rubric.md\");\n\n if (!force) {\n for (const p of [\n systemPath,\n evalPath,\n ...(evalStyle !== \"ground-truth\" ? [rubricPath] : []),\n ]) {\n if (existsSync(p)) {\n process.stderr.write(\n `refusing to overwrite ${p}. pass --force to replace.\\n`,\n );\n return 1;\n }\n }\n }\n\n ensureDir(systemDir);\n\n const tpl = templatesDir();\n writeFileSafely(\n systemPath,\n applyVars(readFileSync(join(tpl, \"system\", \"system.md\"), \"utf-8\"), vars),\n { overwrite: force },\n );\n writeFileSafely(\n evalPath,\n applyVars(\n readFileSync(\n join(\n tpl,\n \"system\",\n evalLanguage === \"typescript\" ? \"eval.ts\" : \"eval.py\",\n ),\n \"utf-8\",\n ),\n vars,\n ),\n { overwrite: force },\n );\n\n if (evalStyle !== \"ground-truth\") {\n writeFileSafely(\n rubricPath,\n applyVars(readFileSync(join(tpl, \"system\", \"rubric.md\"), \"utf-8\"), vars),\n { overwrite: force },\n );\n }\n\n process.stdout.write(`scaffolded system \"${name}\":\\n`);\n process.stdout.write(` kaizen/systems/${name}/system.md\\n`);\n process.stdout.write(` kaizen/systems/${name}/${vars.eval_file}\\n`);\n if (evalStyle !== \"ground-truth\")\n process.stdout.write(` kaizen/systems/${name}/rubric.md\\n`);\n process.stdout.write(\n [\n \"\",\n \"the starter eval emits a working NDJSON event stream against 3 dummy items.\",\n \"edit it to load your dataset and produce real scores, then:\",\n \"\",\n ` kaizen run --system ${name} --variant baseline --hypothesis \"starting baseline\"`,\n \"\",\n ].join(\"\\n\"),\n );\n\n return 0;\n}\n\nfunction normalizeEvalLanguage(raw: string): EvalLanguage | null {\n const normalized = raw.toLowerCase();\n if (normalized === \"python\" || normalized === \"py\") return \"python\";\n if (normalized === \"typescript\" || normalized === \"ts\") return \"typescript\";\n return null;\n}\n"],"mappings":"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"}
@@ -1,39 +1,33 @@
1
+ import { kaizenConfigPath, kaizenDir, kaizenSystemsDir } from "../shared/workspace-paths.js";
2
+ import { resolveStateDir, workspaceRoot } from "../lib/paths.js";
3
+ import { appendIfMissing, ensureDir, writeFileSafely } from "../lib/fs-utils.js";
1
4
  import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
2
- import { templatesDir, workspaceRoot } from "../lib/paths.js";
3
- import { appendIfMissing, copyTreeIfMissing, ensureDir, writeFileSafely } from "../lib/fs-utils.js";
4
5
  import { prompt } from "../lib/prompt.js";
6
+ import { existsSync } from "node:fs";
5
7
  import { join } from "node:path";
6
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
7
8
  //#region src/commands/init.ts
8
9
  async function runInit(argv) {
9
- const { flags } = parseFlags(argv);
10
+ const { positional, flags } = parseFlags(argv);
11
+ if (positional.length > 0) {
12
+ process.stderr.write(`kaizen init does not take positional arguments. Run \`kaizen create system <name>\` to add a system.\n`);
13
+ return 1;
14
+ }
10
15
  const force = boolFlag(flags, "force");
11
16
  const root = workspaceRoot();
12
- const configPath = join(root, "kaizen.config.ts");
17
+ const configPath = kaizenConfigPath(root);
18
+ const stateDir = resolveStateDir(root);
13
19
  if (existsSync(configPath) && !force) {
14
- process.stdout.write(`kaizen.config.ts already exists at ${configPath}\nre-run with --force to overwrite, or run \`kaizen create system <name>\` to add a system.\n`);
20
+ process.stdout.write(`kaizen/config.ts already exists at ${configPath}\nre-run with --force to overwrite, or run \`kaizen create system <name>\` to add a system.\n`);
15
21
  return 1;
16
22
  }
17
23
  process.stdout.write("kaizen init — scaffolding a workspace\n\n");
18
- const customer = strFlag(flags, "customer") ?? await prompt("customer slug (e.g. tc, cbh, janus)", inferCustomerSlug(root));
19
- const vars = {
20
- customer,
21
- customer_name: strFlag(flags, "customer-name") ?? await prompt("customer display name", customer),
22
- langfuse_host: strFlag(flags, "langfuse-host") ?? await prompt("langfuse host URL", "https://langfuse.example.com")
23
- };
24
+ const vars = { customer_name: strFlag(flags, "customer-name") ?? strFlag(flags, "customer") ?? await prompt("customer display name", inferCustomerName(root)) };
25
+ ensureDir(kaizenDir(root));
24
26
  writeFileSafely(configPath, renderConfig(vars), { overwrite: force });
25
- for (const dir of [
26
- "systems",
27
- "rubrics",
28
- "eval",
29
- "views"
30
- ]) {
31
- ensureDir(join(root, dir));
32
- writeFileSafely(join(root, dir, ".gitkeep"), "");
33
- }
34
- ensureDir(join(root, ".kaizen"));
35
- const claudeWritten = copyTreeIfMissing(join(templatesDir(), "workspace", ".claude"), join(root, ".claude"), vars);
36
- writeFileSafely(join(root, ".kaizen", ".gitignore"), [
27
+ ensureDir(kaizenSystemsDir(root));
28
+ writeFileSafely(join(kaizenSystemsDir(root), ".gitkeep"), "");
29
+ ensureDir(stateDir);
30
+ writeFileSafely(join(stateDir, ".gitignore"), [
37
31
  "# Kaizen-managed run state. Runs are large and per-machine; commit only the durable summaries.",
38
32
  "runs/",
39
33
  "dist/",
@@ -41,25 +35,27 @@ async function runInit(argv) {
41
35
  ""
42
36
  ].join("\n"));
43
37
  appendIfMissing(join(root, ".gitignore"), "# Kaizen");
44
- appendIfMissing(join(root, ".gitignore"), ".kaizen/runs/");
45
- appendIfMissing(join(root, ".gitignore"), ".kaizen/dist/");
46
- appendClaudeSection(join(root, "CLAUDE.md"), vars);
38
+ appendIfMissing(join(root, ".gitignore"), "kaizen/.kaizen/runs/");
39
+ appendIfMissing(join(root, ".gitignore"), "kaizen/.kaizen/dist/");
47
40
  process.stdout.write("\nscaffolded:\n");
48
41
  process.stdout.write(` ${rel(root, configPath)}\n`);
49
- process.stdout.write(` systems/, rubrics/, eval/, views/\n`);
50
- process.stdout.write(` .kaizen/.gitignore\n`);
51
- for (const f of claudeWritten) process.stdout.write(` .claude/${f}\n`);
42
+ process.stdout.write(` kaizen/systems/\n`);
43
+ process.stdout.write(` ${rel(root, join(stateDir, ".gitignore"))}\n`);
44
+ process.stdout.write(` package-owned agent guide available via \`kaizen guide\`\n`);
52
45
  process.stdout.write([
53
46
  "",
54
47
  "next:",
48
+ " kaizen guide # print agent instructions from the installed package",
55
49
  " kaizen create system <name> # add your first system",
50
+ " kaizen create view <name> --type trace",
51
+ " kaizen create view <name> --type dataset-item",
56
52
  " kaizen studio # open the dashboard",
57
53
  ""
58
54
  ].join("\n"));
59
55
  return 0;
60
56
  }
61
- function inferCustomerSlug(root) {
62
- return (root.split("/").pop() ?? "").replace(/[^a-z0-9-]/gi, "").toLowerCase() || "customer";
57
+ function inferCustomerName(root) {
58
+ return (root.split("/").pop() ?? "") || "Customer";
63
59
  }
64
60
  function rel(root, p) {
65
61
  return p.startsWith(root) ? p.slice(root.length + 1) : p;
@@ -69,45 +65,13 @@ function renderConfig(vars) {
69
65
 
70
66
  const config: KaizenConfig = {
71
67
  customer: {
72
- slug: ${JSON.stringify(vars.customer)},
73
68
  name: ${JSON.stringify(vars.customer_name)},
74
69
  },
75
- langfuse: {
76
- host: ${JSON.stringify(vars.langfuse_host)},
77
- // Read keys from env. Never commit credentials.
78
- publicKeyEnv: "LANGFUSE_PUBLIC_KEY",
79
- secretKeyEnv: "LANGFUSE_SECRET_KEY",
80
- },
81
- studio: {
82
- port: 6789,
83
- },
84
70
  };
85
71
 
86
72
  export default config;
87
73
  `;
88
74
  }
89
- function appendClaudeSection(path, vars) {
90
- const cur = existsSync(path) ? readFileSync(path, "utf-8") : "";
91
- if (cur.includes("## Kaizen")) return;
92
- const section = [
93
- "## Kaizen",
94
- "",
95
- "This repo uses Kaizen — an automated AI researcher — to evaluate and improve systems.",
96
- "",
97
- "- System definitions live in `systems/*.md`.",
98
- "- Each system has an eval script under `eval/` that emits NDJSON events.",
99
- "- Real Langfuse-backed eval scripts should also link each dataset item to the fresh run trace in a Langfuse dataset run and write the primary metric as a trace score.",
100
- "- Record runs via the supervisor: `kaizen run --system <s> --variant <v>`.",
101
- "- Open the dashboard with `kaizen studio` (default port 6789).",
102
- "- Custom per-system UIs go in `views/<system>/index.tsx`.",
103
- "- Run state lives under `.kaizen/runs/` (gitignored).",
104
- "- The `/kaizen` slash command and the `variant-builder` agent are in `.claude/`.",
105
- "",
106
- `Customer: ${vars.customer_name} (slug: \`${vars.customer}\`)`,
107
- ""
108
- ].join("\n");
109
- writeFileSync(path, cur + (cur.length === 0 || cur.endsWith("\n") ? "" : "\n") + (cur.length > 0 ? "\n" : "") + section);
110
- }
111
75
  //#endregion
112
76
  export { runInit };
113
77
 
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","names":[],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n appendIfMissing,\n copyTreeIfMissing,\n ensureDir,\n writeFileSafely,\n} from \"../lib/fs-utils.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { templatesDir, workspaceRoot } from \"../lib/paths.js\";\nimport { prompt } from \"../lib/prompt.js\";\n\nexport async function runInit(argv: string[]): Promise<number> {\n const { flags } = parseFlags(argv);\n const force = boolFlag(flags, \"force\");\n const root = workspaceRoot();\n const configPath = join(root, \"kaizen.config.ts\");\n\n if (existsSync(configPath) && !force) {\n process.stdout.write(\n `kaizen.config.ts already exists at ${configPath}\\n` +\n `re-run with --force to overwrite, or run \\`kaizen create system <name>\\` to add a system.\\n`,\n );\n return 1;\n }\n\n process.stdout.write(\"kaizen init — scaffolding a workspace\\n\\n\");\n\n const customer =\n strFlag(flags, \"customer\") ??\n (await prompt(\n \"customer slug (e.g. tc, cbh, janus)\",\n inferCustomerSlug(root),\n ));\n const customerName =\n strFlag(flags, \"customer-name\") ??\n (await prompt(\"customer display name\", customer));\n const langfuseHost =\n strFlag(flags, \"langfuse-host\") ??\n (await prompt(\"langfuse host URL\", \"https://langfuse.example.com\"));\n\n const vars: Record<string, string> = {\n customer,\n customer_name: customerName,\n langfuse_host: langfuseHost,\n };\n\n // 1) kaizen.config.ts\n writeFileSafely(configPath, renderConfig(vars), { overwrite: force });\n\n // 2) directory tree\n for (const dir of [\"systems\", \"rubrics\", \"eval\", \"views\"]) {\n ensureDir(join(root, dir));\n writeFileSafely(join(root, dir, \".gitkeep\"), \"\");\n }\n ensureDir(join(root, \".kaizen\"));\n\n // 3) copy .claude templates (skill + agent)\n const claudeWritten = copyTreeIfMissing(\n join(templatesDir(), \"workspace\", \".claude\"),\n join(root, \".claude\"),\n vars,\n );\n\n // 4) .kaizen/.gitignore — ignore bulky generated state but keep durable summaries.\n writeFileSafely(\n join(root, \".kaizen\", \".gitignore\"),\n [\n \"# Kaizen-managed run state. Runs are large and per-machine; commit only the durable summaries.\",\n \"runs/\",\n \"dist/\",\n \"!hypotheses/\",\n \"\",\n ].join(\"\\n\"),\n );\n\n // 5) project .gitignore additions\n appendIfMissing(join(root, \".gitignore\"), \"# Kaizen\");\n appendIfMissing(join(root, \".gitignore\"), \".kaizen/runs/\");\n appendIfMissing(join(root, \".gitignore\"), \".kaizen/dist/\");\n\n // 6) CLAUDE.md note (append a section if not already present)\n appendClaudeSection(join(root, \"CLAUDE.md\"), vars);\n\n process.stdout.write(\"\\nscaffolded:\\n\");\n process.stdout.write(` ${rel(root, configPath)}\\n`);\n process.stdout.write(` systems/, rubrics/, eval/, views/\\n`);\n process.stdout.write(` .kaizen/.gitignore\\n`);\n for (const f of claudeWritten) process.stdout.write(` .claude/${f}\\n`);\n\n process.stdout.write(\n [\n \"\",\n \"next:\",\n \" kaizen create system <name> # add your first system\",\n \" kaizen studio # open the dashboard\",\n \"\",\n ].join(\"\\n\"),\n );\n\n return 0;\n}\n\nfunction inferCustomerSlug(root: string): string {\n const name = root.split(\"/\").pop() ?? \"\";\n return name.replace(/[^a-z0-9-]/gi, \"\").toLowerCase() || \"customer\";\n}\n\nfunction rel(root: string, p: string): string {\n return p.startsWith(root) ? p.slice(root.length + 1) : p;\n}\n\nfunction renderConfig(vars: Record<string, string>): string {\n // JSON.stringify escapes quotes/backslashes/newlines correctly so user input\n // with characters like O'Brien or paths with backslashes don't produce\n // invalid TypeScript.\n return `import type { KaizenConfig } from \"@percepta/kaizen\";\n\nconst config: KaizenConfig = {\n customer: {\n slug: ${JSON.stringify(vars.customer)},\n name: ${JSON.stringify(vars.customer_name)},\n },\n langfuse: {\n host: ${JSON.stringify(vars.langfuse_host)},\n // Read keys from env. Never commit credentials.\n publicKeyEnv: \"LANGFUSE_PUBLIC_KEY\",\n secretKeyEnv: \"LANGFUSE_SECRET_KEY\",\n },\n studio: {\n port: 6789,\n },\n};\n\nexport default config;\n`;\n}\n\nfunction appendClaudeSection(path: string, vars: Record<string, string>): void {\n const cur = existsSync(path) ? readFileSync(path, \"utf-8\") : \"\";\n if (cur.includes(\"## Kaizen\")) return; // already present, leave alone\n const section = [\n \"## Kaizen\",\n \"\",\n \"This repo uses Kaizen — an automated AI researcher — to evaluate and improve systems.\",\n \"\",\n \"- System definitions live in `systems/*.md`.\",\n \"- Each system has an eval script under `eval/` that emits NDJSON events.\",\n \"- Real Langfuse-backed eval scripts should also link each dataset item to the fresh run trace in a Langfuse dataset run and write the primary metric as a trace score.\",\n \"- Record runs via the supervisor: `kaizen run --system <s> --variant <v>`.\",\n \"- Open the dashboard with `kaizen studio` (default port 6789).\",\n \"- Custom per-system UIs go in `views/<system>/index.tsx`.\",\n \"- Run state lives under `.kaizen/runs/` (gitignored).\",\n \"- The `/kaizen` slash command and the `variant-builder` agent are in `.claude/`.\",\n \"\",\n `Customer: ${vars.customer_name} (slug: \\`${vars.customer}\\`)`,\n \"\",\n ].join(\"\\n\");\n const sep = cur.length === 0 || cur.endsWith(\"\\n\") ? \"\" : \"\\n\";\n writeFileSync(path, cur + sep + (cur.length > 0 ? \"\\n\" : \"\") + section);\n}\n"],"mappings":";;;;;;;AAYA,eAAsB,QAAQ,MAAiC;CAC7D,MAAM,EAAE,UAAU,WAAW,KAAK;CAClC,MAAM,QAAQ,SAAS,OAAO,QAAQ;CACtC,MAAM,OAAO,eAAe;CAC5B,MAAM,aAAa,KAAK,MAAM,mBAAmB;AAEjD,KAAI,WAAW,WAAW,IAAI,CAAC,OAAO;AACpC,UAAQ,OAAO,MACb,sCAAsC,WAAW,+FAElD;AACD,SAAO;;AAGT,SAAQ,OAAO,MAAM,4CAA4C;CAEjE,MAAM,WACJ,QAAQ,OAAO,WAAW,IACzB,MAAM,OACL,uCACA,kBAAkB,KAAK,CACxB;CAQH,MAAM,OAA+B;EACnC;EACA,eARA,QAAQ,OAAO,gBAAgB,IAC9B,MAAM,OAAO,yBAAyB,SAAS;EAQhD,eANA,QAAQ,OAAO,gBAAgB,IAC9B,MAAM,OAAO,qBAAqB,+BAA+B;EAMnE;AAGD,iBAAgB,YAAY,aAAa,KAAK,EAAE,EAAE,WAAW,OAAO,CAAC;AAGrE,MAAK,MAAM,OAAO;EAAC;EAAW;EAAW;EAAQ;EAAQ,EAAE;AACzD,YAAU,KAAK,MAAM,IAAI,CAAC;AAC1B,kBAAgB,KAAK,MAAM,KAAK,WAAW,EAAE,GAAG;;AAElD,WAAU,KAAK,MAAM,UAAU,CAAC;CAGhC,MAAM,gBAAgB,kBACpB,KAAK,cAAc,EAAE,aAAa,UAAU,EAC5C,KAAK,MAAM,UAAU,EACrB,KACD;AAGD,iBACE,KAAK,MAAM,WAAW,aAAa,EACnC;EACE;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAGD,iBAAgB,KAAK,MAAM,aAAa,EAAE,WAAW;AACrD,iBAAgB,KAAK,MAAM,aAAa,EAAE,gBAAgB;AAC1D,iBAAgB,KAAK,MAAM,aAAa,EAAE,gBAAgB;AAG1D,qBAAoB,KAAK,MAAM,YAAY,EAAE,KAAK;AAElD,SAAQ,OAAO,MAAM,kBAAkB;AACvC,SAAQ,OAAO,MAAM,KAAK,IAAI,MAAM,WAAW,CAAC,IAAI;AACpD,SAAQ,OAAO,MAAM,wCAAwC;AAC7D,SAAQ,OAAO,MAAM,yBAAyB;AAC9C,MAAK,MAAM,KAAK,cAAe,SAAQ,OAAO,MAAM,aAAa,EAAE,IAAI;AAEvE,SAAQ,OAAO,MACb;EACE;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAED,QAAO;;AAGT,SAAS,kBAAkB,MAAsB;AAE/C,SADa,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,IAC1B,QAAQ,gBAAgB,GAAG,CAAC,aAAa,IAAI;;AAG3D,SAAS,IAAI,MAAc,GAAmB;AAC5C,QAAO,EAAE,WAAW,KAAK,GAAG,EAAE,MAAM,KAAK,SAAS,EAAE,GAAG;;AAGzD,SAAS,aAAa,MAAsC;AAI1D,QAAO;;;;YAIG,KAAK,UAAU,KAAK,SAAS,CAAC;YAC9B,KAAK,UAAU,KAAK,cAAc,CAAC;;;YAGnC,KAAK,UAAU,KAAK,cAAc,CAAC;;;;;;;;;;;;;AAc/C,SAAS,oBAAoB,MAAc,MAAoC;CAC7E,MAAM,MAAM,WAAW,KAAK,GAAG,aAAa,MAAM,QAAQ,GAAG;AAC7D,KAAI,IAAI,SAAS,YAAY,CAAE;CAC/B,MAAM,UAAU;EACd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,KAAK,cAAc,YAAY,KAAK,SAAS;EAC1D;EACD,CAAC,KAAK,KAAK;AAEZ,eAAc,MAAM,OADR,IAAI,WAAW,KAAK,IAAI,SAAS,KAAK,GAAG,KAAK,SACzB,IAAI,SAAS,IAAI,OAAO,MAAM,QAAQ"}
1
+ {"version":3,"file":"init.js","names":[],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n appendIfMissing,\n ensureDir,\n writeFileSafely,\n} from \"../lib/fs-utils.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport {\n kaizenConfigPath,\n kaizenDir,\n kaizenSystemsDir,\n resolveStateDir,\n workspaceRoot,\n} from \"../lib/paths.js\";\nimport { prompt } from \"../lib/prompt.js\";\n\nexport async function runInit(argv: string[]): Promise<number> {\n const { positional, flags } = parseFlags(argv);\n if (positional.length > 0) {\n process.stderr.write(\n `kaizen init does not take positional arguments. Run \\`kaizen create system <name>\\` to add a system.\\n`,\n );\n return 1;\n }\n const force = boolFlag(flags, \"force\");\n const root = workspaceRoot();\n const configPath = kaizenConfigPath(root);\n const stateDir = resolveStateDir(root);\n\n if (existsSync(configPath) && !force) {\n process.stdout.write(\n `kaizen/config.ts already exists at ${configPath}\\n` +\n `re-run with --force to overwrite, or run \\`kaizen create system <name>\\` to add a system.\\n`,\n );\n return 1;\n }\n\n process.stdout.write(\"kaizen init — scaffolding a workspace\\n\\n\");\n\n const customerName =\n strFlag(flags, \"customer-name\") ??\n strFlag(flags, \"customer\") ??\n (await prompt(\"customer display name\", inferCustomerName(root)));\n\n const vars: Record<string, string> = {\n customer_name: customerName,\n };\n\n // 1) kaizen/config.ts\n ensureDir(kaizenDir(root));\n writeFileSafely(configPath, renderConfig(vars), { overwrite: force });\n\n // 2) directory tree\n ensureDir(kaizenSystemsDir(root));\n writeFileSafely(join(kaizenSystemsDir(root), \".gitkeep\"), \"\");\n ensureDir(stateDir);\n\n // 3) kaizen/.kaizen/.gitignore — ignore bulky generated state but keep durable summaries.\n writeFileSafely(\n join(stateDir, \".gitignore\"),\n [\n \"# Kaizen-managed run state. Runs are large and per-machine; commit only the durable summaries.\",\n \"runs/\",\n \"dist/\",\n \"!hypotheses/\",\n \"\",\n ].join(\"\\n\"),\n );\n\n // 4) project .gitignore additions\n appendIfMissing(join(root, \".gitignore\"), \"# Kaizen\");\n appendIfMissing(join(root, \".gitignore\"), \"kaizen/.kaizen/runs/\");\n appendIfMissing(join(root, \".gitignore\"), \"kaizen/.kaizen/dist/\");\n\n process.stdout.write(\"\\nscaffolded:\\n\");\n process.stdout.write(` ${rel(root, configPath)}\\n`);\n process.stdout.write(` kaizen/systems/\\n`);\n process.stdout.write(` ${rel(root, join(stateDir, \".gitignore\"))}\\n`);\n process.stdout.write(\n ` package-owned agent guide available via \\`kaizen guide\\`\\n`,\n );\n\n process.stdout.write(\n [\n \"\",\n \"next:\",\n \" kaizen guide # print agent instructions from the installed package\",\n \" kaizen create system <name> # add your first system\",\n \" kaizen create view <name> --type trace\",\n \" kaizen create view <name> --type dataset-item\",\n \" kaizen studio # open the dashboard\",\n \"\",\n ].join(\"\\n\"),\n );\n\n return 0;\n}\n\nfunction inferCustomerName(root: string): string {\n const name = root.split(\"/\").pop() ?? \"\";\n return name || \"Customer\";\n}\n\nfunction rel(root: string, p: string): string {\n return p.startsWith(root) ? p.slice(root.length + 1) : p;\n}\n\nfunction renderConfig(vars: Record<string, string>): string {\n // JSON.stringify escapes quotes/backslashes/newlines correctly so user input\n // with characters like O'Brien or paths with backslashes don't produce\n // invalid TypeScript.\n return `import type { KaizenConfig } from \"@percepta/kaizen\";\n\nconst config: KaizenConfig = {\n customer: {\n name: ${JSON.stringify(vars.customer_name)},\n },\n};\n\nexport default config;\n`;\n}\n"],"mappings":";;;;;;;;AAiBA,eAAsB,QAAQ,MAAiC;CAC7D,MAAM,EAAE,YAAY,UAAU,WAAW,KAAK;AAC9C,KAAI,WAAW,SAAS,GAAG;AACzB,UAAQ,OAAO,MACb,yGACD;AACD,SAAO;;CAET,MAAM,QAAQ,SAAS,OAAO,QAAQ;CACtC,MAAM,OAAO,eAAe;CAC5B,MAAM,aAAa,iBAAiB,KAAK;CACzC,MAAM,WAAW,gBAAgB,KAAK;AAEtC,KAAI,WAAW,WAAW,IAAI,CAAC,OAAO;AACpC,UAAQ,OAAO,MACb,sCAAsC,WAAW,+FAElD;AACD,SAAO;;AAGT,SAAQ,OAAO,MAAM,4CAA4C;CAOjE,MAAM,OAA+B,EACnC,eALA,QAAQ,OAAO,gBAAgB,IAC/B,QAAQ,OAAO,WAAW,IACzB,MAAM,OAAO,yBAAyB,kBAAkB,KAAK,CAAC,EAIhE;AAGD,WAAU,UAAU,KAAK,CAAC;AAC1B,iBAAgB,YAAY,aAAa,KAAK,EAAE,EAAE,WAAW,OAAO,CAAC;AAGrE,WAAU,iBAAiB,KAAK,CAAC;AACjC,iBAAgB,KAAK,iBAAiB,KAAK,EAAE,WAAW,EAAE,GAAG;AAC7D,WAAU,SAAS;AAGnB,iBACE,KAAK,UAAU,aAAa,EAC5B;EACE;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAGD,iBAAgB,KAAK,MAAM,aAAa,EAAE,WAAW;AACrD,iBAAgB,KAAK,MAAM,aAAa,EAAE,uBAAuB;AACjE,iBAAgB,KAAK,MAAM,aAAa,EAAE,uBAAuB;AAEjE,SAAQ,OAAO,MAAM,kBAAkB;AACvC,SAAQ,OAAO,MAAM,KAAK,IAAI,MAAM,WAAW,CAAC,IAAI;AACpD,SAAQ,OAAO,MAAM,sBAAsB;AAC3C,SAAQ,OAAO,MAAM,KAAK,IAAI,MAAM,KAAK,UAAU,aAAa,CAAC,CAAC,IAAI;AACtE,SAAQ,OAAO,MACb,+DACD;AAED,SAAQ,OAAO,MACb;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,CACb;AAED,QAAO;;AAGT,SAAS,kBAAkB,MAAsB;AAE/C,SADa,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,OACvB;;AAGjB,SAAS,IAAI,MAAc,GAAmB;AAC5C,QAAO,EAAE,WAAW,KAAK,GAAG,EAAE,MAAM,KAAK,SAAS,EAAE,GAAG;;AAGzD,SAAS,aAAa,MAAsC;AAI1D,QAAO;;;;YAIG,KAAK,UAAU,KAAK,cAAc,CAAC"}
@@ -1,18 +1,16 @@
1
- import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
2
1
  import { resolveStateDir, workspaceRoot } from "../lib/paths.js";
2
+ import { pad, requireKaizenWorkspace } from "../lib/cli.js";
3
+ import { boolFlag, parseFlags, strFlag } from "../lib/parse-args.js";
3
4
  import { currentBaseline, listRuns } from "../lib/leaderboard.js";
4
5
  import { reapStaleRuns } from "../lib/runner.js";
5
- import { join } from "node:path";
6
6
  import { existsSync, readdirSync, statSync } from "node:fs";
7
+ import { join } from "node:path";
7
8
  //#region src/commands/log.ts
8
9
  async function runLog(argv) {
9
10
  const { flags } = parseFlags(argv);
10
11
  const root = workspaceRoot();
11
- const stateDir = resolveStateDir(root, strFlag(flags, "state-dir"));
12
- if (!existsSync(join(root, "kaizen.config.ts"))) {
13
- process.stderr.write(`no kaizen.config.ts in ${root}. run \`kaizen init\` first.\n`);
14
- return 1;
15
- }
12
+ const stateDir = resolveStateDir(root);
13
+ if (!requireKaizenWorkspace(root)) return 1;
16
14
  const single = strFlag(flags, "system");
17
15
  const n = Number(strFlag(flags, "n") ?? "10");
18
16
  const json = boolFlag(flags, "json");
@@ -102,10 +100,6 @@ function printSystem(stateDir, systemId, n) {
102
100
  process.stdout.write(pad(String(idx), 4) + pad(r.run_id, 14) + pad(r.variant, 22) + pad(score, 8) + pad(r.status, 11) + pad(promoted, 9) + pad(r.started_at.replace("T", " ").slice(0, 19), 21) + (r.hypothesis || "") + "\n");
103
101
  }
104
102
  }
105
- function pad(s, w) {
106
- if (s.length >= w) return s.slice(0, w - 1) + " ";
107
- return s + " ".repeat(w - s.length);
108
- }
109
103
  //#endregion
110
104
  export { runLog };
111
105
 
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","names":[],"sources":["../../src/commands/log.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type RunSummary,\n currentBaseline,\n listRuns,\n} from \"../lib/leaderboard.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { resolveStateDir, workspaceRoot } from \"../lib/paths.js\";\nimport { reapStaleRuns } from \"../lib/runner.js\";\n\nexport async function runLog(argv: string[]): Promise<number> {\n const { flags } = parseFlags(argv);\n const root = workspaceRoot();\n const stateDir = resolveStateDir(root, strFlag(flags, \"state-dir\"));\n\n if (!existsSync(join(root, \"kaizen.config.ts\"))) {\n process.stderr.write(\n `no kaizen.config.ts in ${root}. run \\`kaizen init\\` first.\\n`,\n );\n return 1;\n }\n\n const single = strFlag(flags, \"system\");\n const n = Number(strFlag(flags, \"n\") ?? \"10\");\n const json = boolFlag(flags, \"json\");\n\n const systems = single ? [single] : discoverSystems(stateDir);\n if (systems.length === 0) {\n process.stdout.write(\"no systems found.\\n\");\n return 0;\n }\n\n if (json) {\n const out = systems.map((s) => buildSystemReport(stateDir, s, n));\n process.stdout.write(JSON.stringify(out, null, 2) + \"\\n\");\n return 0;\n }\n\n for (let i = 0; i < systems.length; i++) {\n if (i > 0) process.stdout.write(\"\\n\");\n printSystem(stateDir, systems[i], n);\n }\n return 0;\n}\n\nfunction discoverSystems(stateDir: string): string[] {\n const runsRoot = join(stateDir, \"runs\");\n if (!existsSync(runsRoot)) return [];\n return readdirSync(runsRoot).filter((d) => {\n try {\n return statSync(join(runsRoot, d)).isDirectory();\n } catch {\n return false;\n }\n });\n}\n\ninterface SystemReport {\n system: string;\n baseline: {\n run_id: string;\n variant: string;\n score: number;\n n: number | null;\n eval_version: number;\n dataset_version: string;\n } | null;\n totals: {\n all: number;\n complete: number;\n crashed: number;\n aborted: number;\n running: number;\n };\n recent: RunSummary[];\n}\n\nfunction buildSystemReport(\n stateDir: string,\n systemId: string,\n n: number,\n): SystemReport {\n reapStaleRuns(stateDir, systemId);\n const runs = listRuns(stateDir, systemId);\n const baseline = pickBaseline(runs);\n const totals = countByStatus(runs);\n const recent = runs.slice(0, n);\n return {\n system: systemId,\n baseline: baseline\n ? {\n run_id: baseline.run_id,\n variant: baseline.variant,\n score: baseline.score!,\n n: baseline.n,\n eval_version: baseline.eval_version,\n dataset_version: baseline.dataset_version,\n }\n : null,\n totals,\n recent,\n };\n}\n\nfunction pickBaseline(runs: RunSummary[]): RunSummary | null {\n // Use the eval/dataset versions of the most recent complete run as the \"current\" anchor.\n const newest = runs.find((r) => r.status === \"complete\");\n if (!newest) return null;\n return currentBaseline(runs, newest.eval_version, newest.dataset_version);\n}\n\nfunction countByStatus(runs: RunSummary[]) {\n const c = {\n all: runs.length,\n complete: 0,\n crashed: 0,\n aborted: 0,\n running: 0,\n };\n for (const r of runs) {\n if (r.status === \"complete\") c.complete++;\n else if (r.status === \"crashed\") c.crashed++;\n else if (r.status === \"aborted\") c.aborted++;\n else if (r.status === \"running\") c.running++;\n }\n return c;\n}\n\nfunction printSystem(stateDir: string, systemId: string, n: number): void {\n const report = buildSystemReport(stateDir, systemId, n);\n const baseHeader = report.baseline\n ? `promoted baseline: ${report.baseline.run_id} ${report.baseline.variant} (score ${report.baseline.score.toFixed(4)}, n=${report.baseline.n ?? \"?\"}, eval_v=${report.baseline.eval_version}, dataset=${report.baseline.dataset_version})`\n : \"promoted baseline: <none>\";\n process.stdout.write(`system: ${systemId} ${baseHeader}\\n`);\n const t = report.totals;\n process.stdout.write(\n `total runs: ${t.all} completed: ${t.complete} crashed: ${t.crashed} aborted: ${t.aborted} running: ${t.running}\\n`,\n );\n if (report.recent.length === 0) {\n process.stdout.write(\"(no runs yet)\\n\");\n return;\n }\n process.stdout.write(\"\\n\");\n process.stdout.write(\n pad(\"#\", 4) +\n pad(\"run_id\", 14) +\n pad(\"variant\", 22) +\n pad(\"score\", 8) +\n pad(\"status\", 11) +\n pad(\"promoted\", 9) +\n pad(\"started_at\", 21) +\n \"hypothesis\\n\",\n );\n for (let i = 0; i < report.recent.length; i++) {\n const r = report.recent[i];\n const idx = report.totals.all - i;\n const score = r.score === null ? \"—\" : r.score.toFixed(3);\n const promoted = r.promoted === null ? \"—\" : r.promoted ? \"yes\" : \"no\";\n process.stdout.write(\n pad(String(idx), 4) +\n pad(r.run_id, 14) +\n pad(r.variant, 22) +\n pad(score, 8) +\n pad(r.status, 11) +\n pad(promoted, 9) +\n pad(r.started_at.replace(\"T\", \" \").slice(0, 19), 21) +\n (r.hypothesis || \"\") +\n \"\\n\",\n );\n }\n}\n\nfunction pad(s: string, w: number): string {\n if (s.length >= w) return s.slice(0, w - 1) + \" \";\n return s + \" \".repeat(w - s.length);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"log.js","names":[],"sources":["../../src/commands/log.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { pad, requireKaizenWorkspace } from \"../lib/cli.js\";\nimport {\n type RunSummary,\n currentBaseline,\n listRuns,\n} from \"../lib/leaderboard.js\";\nimport { boolFlag, parseFlags, strFlag } from \"../lib/parse-args.js\";\nimport { resolveStateDir, workspaceRoot } from \"../lib/paths.js\";\nimport { reapStaleRuns } from \"../lib/runner.js\";\n\nexport async function runLog(argv: string[]): Promise<number> {\n const { flags } = parseFlags(argv);\n const root = workspaceRoot();\n const stateDir = resolveStateDir(root);\n\n if (!requireKaizenWorkspace(root)) return 1;\n\n const single = strFlag(flags, \"system\");\n const n = Number(strFlag(flags, \"n\") ?? \"10\");\n const json = boolFlag(flags, \"json\");\n\n const systems = single ? [single] : discoverSystems(stateDir);\n if (systems.length === 0) {\n process.stdout.write(\"no systems found.\\n\");\n return 0;\n }\n\n if (json) {\n const out = systems.map((s) => buildSystemReport(stateDir, s, n));\n process.stdout.write(JSON.stringify(out, null, 2) + \"\\n\");\n return 0;\n }\n\n for (let i = 0; i < systems.length; i++) {\n if (i > 0) process.stdout.write(\"\\n\");\n printSystem(stateDir, systems[i], n);\n }\n return 0;\n}\n\nfunction discoverSystems(stateDir: string): string[] {\n const runsRoot = join(stateDir, \"runs\");\n if (!existsSync(runsRoot)) return [];\n return readdirSync(runsRoot).filter((d) => {\n try {\n return statSync(join(runsRoot, d)).isDirectory();\n } catch {\n return false;\n }\n });\n}\n\ninterface SystemReport {\n system: string;\n baseline: {\n run_id: string;\n variant: string;\n score: number;\n n: number | null;\n eval_version: number;\n dataset_version: string;\n } | null;\n totals: {\n all: number;\n complete: number;\n crashed: number;\n aborted: number;\n running: number;\n };\n recent: RunSummary[];\n}\n\nfunction buildSystemReport(\n stateDir: string,\n systemId: string,\n n: number,\n): SystemReport {\n reapStaleRuns(stateDir, systemId);\n const runs = listRuns(stateDir, systemId);\n const baseline = pickBaseline(runs);\n const totals = countByStatus(runs);\n const recent = runs.slice(0, n);\n return {\n system: systemId,\n baseline: baseline\n ? {\n run_id: baseline.run_id,\n variant: baseline.variant,\n score: baseline.score!,\n n: baseline.n,\n eval_version: baseline.eval_version,\n dataset_version: baseline.dataset_version,\n }\n : null,\n totals,\n recent,\n };\n}\n\nfunction pickBaseline(runs: RunSummary[]): RunSummary | null {\n // Use the eval/dataset versions of the most recent complete run as the \"current\" anchor.\n const newest = runs.find((r) => r.status === \"complete\");\n if (!newest) return null;\n return currentBaseline(runs, newest.eval_version, newest.dataset_version);\n}\n\nfunction countByStatus(runs: RunSummary[]) {\n const c = {\n all: runs.length,\n complete: 0,\n crashed: 0,\n aborted: 0,\n running: 0,\n };\n for (const r of runs) {\n if (r.status === \"complete\") c.complete++;\n else if (r.status === \"crashed\") c.crashed++;\n else if (r.status === \"aborted\") c.aborted++;\n else if (r.status === \"running\") c.running++;\n }\n return c;\n}\n\nfunction printSystem(stateDir: string, systemId: string, n: number): void {\n const report = buildSystemReport(stateDir, systemId, n);\n const baseHeader = report.baseline\n ? `promoted baseline: ${report.baseline.run_id} ${report.baseline.variant} (score ${report.baseline.score.toFixed(4)}, n=${report.baseline.n ?? \"?\"}, eval_v=${report.baseline.eval_version}, dataset=${report.baseline.dataset_version})`\n : \"promoted baseline: <none>\";\n process.stdout.write(`system: ${systemId} ${baseHeader}\\n`);\n const t = report.totals;\n process.stdout.write(\n `total runs: ${t.all} completed: ${t.complete} crashed: ${t.crashed} aborted: ${t.aborted} running: ${t.running}\\n`,\n );\n if (report.recent.length === 0) {\n process.stdout.write(\"(no runs yet)\\n\");\n return;\n }\n process.stdout.write(\"\\n\");\n process.stdout.write(\n pad(\"#\", 4) +\n pad(\"run_id\", 14) +\n pad(\"variant\", 22) +\n pad(\"score\", 8) +\n pad(\"status\", 11) +\n pad(\"promoted\", 9) +\n pad(\"started_at\", 21) +\n \"hypothesis\\n\",\n );\n for (let i = 0; i < report.recent.length; i++) {\n const r = report.recent[i];\n const idx = report.totals.all - i;\n const score = r.score === null ? \"—\" : r.score.toFixed(3);\n const promoted = r.promoted === null ? \"—\" : r.promoted ? \"yes\" : \"no\";\n process.stdout.write(\n pad(String(idx), 4) +\n pad(r.run_id, 14) +\n pad(r.variant, 22) +\n pad(score, 8) +\n pad(r.status, 11) +\n pad(promoted, 9) +\n pad(r.started_at.replace(\"T\", \" \").slice(0, 19), 21) +\n (r.hypothesis || \"\") +\n \"\\n\",\n );\n }\n}\n"],"mappings":";;;;;;;;AAYA,eAAsB,OAAO,MAAiC;CAC5D,MAAM,EAAE,UAAU,WAAW,KAAK;CAClC,MAAM,OAAO,eAAe;CAC5B,MAAM,WAAW,gBAAgB,KAAK;AAEtC,KAAI,CAAC,uBAAuB,KAAK,CAAE,QAAO;CAE1C,MAAM,SAAS,QAAQ,OAAO,SAAS;CACvC,MAAM,IAAI,OAAO,QAAQ,OAAO,IAAI,IAAI,KAAK;CAC7C,MAAM,OAAO,SAAS,OAAO,OAAO;CAEpC,MAAM,UAAU,SAAS,CAAC,OAAO,GAAG,gBAAgB,SAAS;AAC7D,KAAI,QAAQ,WAAW,GAAG;AACxB,UAAQ,OAAO,MAAM,sBAAsB;AAC3C,SAAO;;AAGT,KAAI,MAAM;EACR,MAAM,MAAM,QAAQ,KAAK,MAAM,kBAAkB,UAAU,GAAG,EAAE,CAAC;AACjE,UAAQ,OAAO,MAAM,KAAK,UAAU,KAAK,MAAM,EAAE,GAAG,KAAK;AACzD,SAAO;;AAGT,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,MAAI,IAAI,EAAG,SAAQ,OAAO,MAAM,KAAK;AACrC,cAAY,UAAU,QAAQ,IAAI,EAAE;;AAEtC,QAAO;;AAGT,SAAS,gBAAgB,UAA4B;CACnD,MAAM,WAAW,KAAK,UAAU,OAAO;AACvC,KAAI,CAAC,WAAW,SAAS,CAAE,QAAO,EAAE;AACpC,QAAO,YAAY,SAAS,CAAC,QAAQ,MAAM;AACzC,MAAI;AACF,UAAO,SAAS,KAAK,UAAU,EAAE,CAAC,CAAC,aAAa;UAC1C;AACN,UAAO;;GAET;;AAuBJ,SAAS,kBACP,UACA,UACA,GACc;AACd,eAAc,UAAU,SAAS;CACjC,MAAM,OAAO,SAAS,UAAU,SAAS;CACzC,MAAM,WAAW,aAAa,KAAK;CACnC,MAAM,SAAS,cAAc,KAAK;CAClC,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE;AAC/B,QAAO;EACL,QAAQ;EACR,UAAU,WACN;GACE,QAAQ,SAAS;GACjB,SAAS,SAAS;GAClB,OAAO,SAAS;GAChB,GAAG,SAAS;GACZ,cAAc,SAAS;GACvB,iBAAiB,SAAS;GAC3B,GACD;EACJ;EACA;EACD;;AAGH,SAAS,aAAa,MAAuC;CAE3D,MAAM,SAAS,KAAK,MAAM,MAAM,EAAE,WAAW,WAAW;AACxD,KAAI,CAAC,OAAQ,QAAO;AACpB,QAAO,gBAAgB,MAAM,OAAO,cAAc,OAAO,gBAAgB;;AAG3E,SAAS,cAAc,MAAoB;CACzC,MAAM,IAAI;EACR,KAAK,KAAK;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,SAAS;EACV;AACD,MAAK,MAAM,KAAK,KACd,KAAI,EAAE,WAAW,WAAY,GAAE;UACtB,EAAE,WAAW,UAAW,GAAE;UAC1B,EAAE,WAAW,UAAW,GAAE;UAC1B,EAAE,WAAW,UAAW,GAAE;AAErC,QAAO;;AAGT,SAAS,YAAY,UAAkB,UAAkB,GAAiB;CACxE,MAAM,SAAS,kBAAkB,UAAU,UAAU,EAAE;CACvD,MAAM,aAAa,OAAO,WACtB,sBAAsB,OAAO,SAAS,OAAO,GAAG,OAAO,SAAS,QAAQ,UAAU,OAAO,SAAS,MAAM,QAAQ,EAAE,CAAC,MAAM,OAAO,SAAS,KAAK,IAAI,WAAW,OAAO,SAAS,aAAa,YAAY,OAAO,SAAS,gBAAgB,KACtO;AACJ,SAAQ,OAAO,MAAM,WAAW,SAAS,KAAK,WAAW,IAAI;CAC7D,MAAM,IAAI,OAAO;AACjB,SAAQ,OAAO,MACb,eAAe,EAAE,IAAI,gBAAgB,EAAE,SAAS,cAAc,EAAE,QAAQ,cAAc,EAAE,QAAQ,cAAc,EAAE,QAAQ,IACzH;AACD,KAAI,OAAO,OAAO,WAAW,GAAG;AAC9B,UAAQ,OAAO,MAAM,kBAAkB;AACvC;;AAEF,SAAQ,OAAO,MAAM,KAAK;AAC1B,SAAQ,OAAO,MACb,IAAI,KAAK,EAAE,GACT,IAAI,UAAU,GAAG,GACjB,IAAI,WAAW,GAAG,GAClB,IAAI,SAAS,EAAE,GACf,IAAI,UAAU,GAAG,GACjB,IAAI,YAAY,EAAE,GAClB,IAAI,cAAc,GAAG,GACrB,eACH;AACD,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,OAAO,QAAQ,KAAK;EAC7C,MAAM,IAAI,OAAO,OAAO;EACxB,MAAM,MAAM,OAAO,OAAO,MAAM;EAChC,MAAM,QAAQ,EAAE,UAAU,OAAO,MAAM,EAAE,MAAM,QAAQ,EAAE;EACzD,MAAM,WAAW,EAAE,aAAa,OAAO,MAAM,EAAE,WAAW,QAAQ;AAClE,UAAQ,OAAO,MACb,IAAI,OAAO,IAAI,EAAE,EAAE,GACjB,IAAI,EAAE,QAAQ,GAAG,GACjB,IAAI,EAAE,SAAS,GAAG,GAClB,IAAI,OAAO,EAAE,GACb,IAAI,EAAE,QAAQ,GAAG,GACjB,IAAI,UAAU,EAAE,GAChB,IAAI,EAAE,WAAW,QAAQ,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,GAAG,IACnD,EAAE,cAAc,MACjB,KACH"}