karajan-code 2.34.0 → 3.1.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 (69) hide show
  1. package/README.md +120 -38
  2. package/bin/kj-rag-mcp.js +75 -0
  3. package/docs/README.es.md +5 -5
  4. package/package.json +22 -17
  5. package/packages/hu-board/package.json +5 -2
  6. package/packages/hu-board/public/app.js +81 -4025
  7. package/packages/hu-board/public/index.html +20 -0
  8. package/packages/hu-board/public/utils/api.js +139 -0
  9. package/packages/hu-board/public/utils/board-view.js +453 -0
  10. package/packages/hu-board/public/utils/command-launcher.js +213 -0
  11. package/packages/hu-board/public/utils/config-editor.js +181 -0
  12. package/packages/hu-board/public/utils/dashboard-view.js +103 -0
  13. package/packages/hu-board/public/utils/formatters.js +232 -0
  14. package/packages/hu-board/public/utils/graph-view.js +216 -0
  15. package/packages/hu-board/public/utils/hu-actions.js +224 -0
  16. package/packages/hu-board/public/utils/init-listeners.js +180 -0
  17. package/packages/hu-board/public/utils/log-panel.js +222 -0
  18. package/packages/hu-board/public/utils/modals.js +290 -0
  19. package/packages/hu-board/public/utils/plan-rollup-view.js +53 -0
  20. package/packages/hu-board/public/utils/preflight-view.js +89 -0
  21. package/packages/hu-board/public/utils/project-actions.js +143 -0
  22. package/packages/hu-board/public/utils/project-picker-view.js +139 -0
  23. package/packages/hu-board/public/utils/run-launcher.js +169 -0
  24. package/packages/hu-board/public/utils/server-push.js +252 -0
  25. package/packages/hu-board/public/utils/sessions-view.js +199 -0
  26. package/packages/hu-board/public/utils/story-detail-view.js +324 -0
  27. package/packages/hu-board/public/utils/story-edit-form.js +271 -0
  28. package/packages/hu-board/src/config-yaml.js +14 -0
  29. package/packages/hu-board/src/db.js +15 -2
  30. package/packages/hu-board/src/routes/api.js +27 -9
  31. package/scripts/audit-test-diet.mjs +151 -0
  32. package/src/audit/deterministic-summary.js +20 -0
  33. package/src/audit/harness-scorecard.js +52 -3
  34. package/src/audit/harness-section.js +6 -2
  35. package/src/audit/injection-findings.js +105 -0
  36. package/src/checks/hardware.js +150 -0
  37. package/src/checks/node.js +9 -10
  38. package/src/checks/runner.js +10 -0
  39. package/src/cli/register-meta.js +48 -2
  40. package/src/cli/register-plan.js +10 -1
  41. package/src/commands/clean.js +62 -0
  42. package/src/commands/doctor.js +2 -0
  43. package/src/commands/init.js +41 -1
  44. package/src/commands/plan/generate.js +9 -3
  45. package/src/commands/rag-mcp.js +18 -0
  46. package/src/commands/sync.js +30 -2
  47. package/src/commands/telemetry.js +70 -0
  48. package/src/config/defaults.js +9 -1
  49. package/src/config/schema.js +2 -0
  50. package/src/orchestrator/config-init.js +1 -0
  51. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +23 -0
  52. package/src/orchestrator/stages/coder-stage.js +11 -2
  53. package/src/orchestrator/stages/reviewer-stage.js +11 -0
  54. package/src/orchestrator/stages/tdd-discipline-stage.js +56 -0
  55. package/src/orchestrator/stages/tool-judge-stage.js +53 -0
  56. package/src/prompts/tool-correctness-judge.js +31 -0
  57. package/src/review/git-stash-helper.js +104 -0
  58. package/src/review/tdd-discipline.js +90 -0
  59. package/src/roles/audit-role.js +9 -1
  60. package/src/roles/tool-correctness-judge-role.js +78 -0
  61. package/src/session/mutators.js +4 -0
  62. package/src/sonar/scanner.js +51 -16
  63. package/src/sync/apply-canvas-patch.js +55 -0
  64. package/src/utils/paths.js +12 -0
  65. package/src/utils/quota-simulator.js +56 -0
  66. package/src/utils/repo-cleaner.js +79 -0
  67. package/src/utils/telemetry.js +34 -12
  68. package/src/utils/tool-call-extractor.js +56 -0
  69. package/src/utils/vector-store-orphans.js +89 -0
@@ -1,4 +1,30 @@
1
- const TELEMETRY_ENDPOINT = "https://karajan-code.web.app/api/telemetry";
1
+ export const TELEMETRY_ENDPOINT = "https://karajan-code.web.app/api/telemetry";
2
+
3
+ /**
4
+ * Build the exact JSON payload that would be POSTed for an event.
5
+ * Pure function: deterministic given (eventName, data) — exposed so
6
+ * `kj telemetry preview` can render the literal bytes the backend
7
+ * receives without performing any network call.
8
+ *
9
+ * The `data.version` field is folded into `v`; the rest of the
10
+ * event-specific keys ride through `...data` after the common ones,
11
+ * matching the order sent over the wire.
12
+ *
13
+ * @param {string} eventName
14
+ * @param {object} [data]
15
+ * @returns {object}
16
+ */
17
+ export function buildTelemetryPayload(eventName, data = {}) {
18
+ const { version, ...rest } = data;
19
+ return {
20
+ event: eventName,
21
+ v: version || "unknown",
22
+ os: process.platform,
23
+ node: process.version,
24
+ ts: Date.now(),
25
+ ...rest
26
+ };
27
+ }
2
28
 
3
29
  /**
4
30
  * Send an anonymous telemetry event. Non-blocking, fire-and-forget.
@@ -12,14 +38,7 @@ export async function sendTelemetryEvent(eventName, data, config) {
12
38
  if (!isTelemetryEnabled(config)) return;
13
39
 
14
40
  try {
15
- const payload = {
16
- event: eventName,
17
- v: data.version || "unknown",
18
- os: process.platform,
19
- node: process.version,
20
- ts: Date.now(),
21
- ...data
22
- };
41
+ const payload = buildTelemetryPayload(eventName, data);
23
42
  const controller = new AbortController();
24
43
  const timeout = setTimeout(() => controller.abort(), 3000);
25
44
  try {
@@ -48,12 +67,15 @@ export async function sendTelemetryEvent(eventName, data, config) {
48
67
  }
49
68
 
50
69
  /**
51
- * Check if telemetry is enabled (opt-out model).
52
- * Returns false only when the user explicitly sets telemetry: false.
70
+ * Check if telemetry is enabled (opt-in model).
71
+ *
72
+ * Returns true ONLY when the user explicitly answered "yes" in the
73
+ * `kj init` wizard and we persisted `telemetry: true` to their config.
74
+ * Anything else — undefined, null, missing key, false — disables sending.
53
75
  *
54
76
  * @param {object} [config] - Karajan config
55
77
  * @returns {boolean}
56
78
  */
57
79
  export function isTelemetryEnabled(config) {
58
- return config?.telemetry !== false;
80
+ return config?.telemetry === true;
59
81
  }
@@ -0,0 +1,56 @@
1
+ // KJC-TSK-0375 PR2 — Extract structured tool calls from an agent transcript.
2
+ //
3
+ // The ToolCorrectnessJudgeRole (PR1) consumes a list of `{tool, args}`
4
+ // objects. The coder writes a raw transcript (provider-dependent format) to
5
+ // disk per iteration. This module bridges the two: parse the transcript,
6
+ // return the ordered list of tool invocations.
7
+ //
8
+ // Provider-agnostic interface; Claude stream-json is the only format
9
+ // implemented today. New providers add a branch below — keep parsers
10
+ // pure (no I/O), so the role tests can mock transcripts trivially.
11
+
12
+ const PROVIDER_PARSERS = {
13
+ claude: parseClaudeStreamJson,
14
+ };
15
+
16
+ /**
17
+ * Extract tool calls from a transcript string.
18
+ *
19
+ * @param {object} args
20
+ * @param {string} args.transcript - raw agent output (stdout/stderr buffer).
21
+ * @param {string} [args.provider] - "claude" (default). Unknown returns [].
22
+ * @returns {Array<{tool:string, args:object}>}
23
+ */
24
+ export function extractToolCalls({ transcript, provider = "claude" } = {}) {
25
+ if (typeof transcript !== "string" || transcript.length === 0) return [];
26
+ const parser = PROVIDER_PARSERS[provider];
27
+ if (!parser) return [];
28
+ return parser(transcript);
29
+ }
30
+
31
+ // Claude emits one JSON event per line. We care about `assistant` events
32
+ // whose `message.content` is an array containing `tool_use` blocks with
33
+ // `{type:"tool_use", name, input}`. Lines that fail to parse, that are
34
+ // not `assistant`, or whose content is not an array are silently skipped:
35
+ // the transcript also carries `system`, `result`, `rate_limit_event`, etc.
36
+ function parseClaudeStreamJson(transcript) {
37
+ const out = [];
38
+ for (const raw of transcript.split("\n")) {
39
+ const line = raw.trim();
40
+ if (!line || line[0] !== "{") continue;
41
+ let obj;
42
+ try { obj = JSON.parse(line); } catch { continue; }
43
+ if (obj?.type !== "assistant") continue;
44
+ const content = obj?.message?.content;
45
+ if (!Array.isArray(content)) continue;
46
+ for (const block of content) {
47
+ if (block?.type === "tool_use" && typeof block.name === "string") {
48
+ out.push({
49
+ tool: block.name,
50
+ args: block.input && typeof block.input === "object" ? block.input : {},
51
+ });
52
+ }
53
+ }
54
+ }
55
+ return out;
56
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * RAG vector-store orphan collector — KJC-TSK-0499 PR2.
3
+ *
4
+ * Enumerates distinct `project_slug` rows in `~/.karajan/rag.db`,
5
+ * augments each with chunk count + last_indexed_{at,commit}, and
6
+ * marks as orphan the slugs whose basename does not resolve to a
7
+ * directory in any of the configured `projectRoots`.
8
+ *
9
+ * Read-only. Returns rows + a copy-paste sqlite3 command per orphan.
10
+ * Deliberate inverse of the RAG indexer: never opens the DB for write.
11
+ */
12
+ import fs from "node:fs/promises";
13
+ import path from "node:path";
14
+ import os from "node:os";
15
+ import { dbPath, openVecStore, projectSlug } from "../rag/vec-store.js";
16
+
17
+ const DEFAULT_ROOTS = [
18
+ path.join(os.homedir(), "ws_npm-packages"),
19
+ path.join(os.homedir(), "ws_firebase"),
20
+ path.join(os.homedir(), "projects"),
21
+ path.join(os.homedir(), "code"),
22
+ ];
23
+
24
+ async function listDirs(root) {
25
+ try {
26
+ const entries = await fs.readdir(root, { withFileTypes: true });
27
+ return entries.filter((e) => e.isDirectory()).map((e) => path.join(root, e.name));
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+
33
+ async function buildSlugIndex(roots) {
34
+ const index = new Map();
35
+ for (const root of roots) {
36
+ for (const dir of await listDirs(root)) {
37
+ const slug = projectSlug(dir);
38
+ if (slug && !index.has(slug)) index.set(slug, dir);
39
+ }
40
+ }
41
+ return index;
42
+ }
43
+
44
+ function purgeCommand(slug) {
45
+ const slugSafe = slug.replace(/'/g, "''");
46
+ return `sqlite3 ${dbPath()} "DELETE FROM chunks WHERE project_slug='${slugSafe}'; DELETE FROM vec_store_meta WHERE project_slug='${slugSafe}';"`;
47
+ }
48
+
49
+ /**
50
+ * Collect RAG vector-store orphans.
51
+ * @param {object} [opts]
52
+ * @param {string[]} [opts.projectRoots] — directories to look for live
53
+ * projects whose basename matches each slug. Defaults to the usual
54
+ * `~/ws_*`, `~/projects`, `~/code` set.
55
+ * @returns {Promise<{rows: Array, orphans: Array, errors: Array}>}
56
+ */
57
+ export async function collectVectorStoreOrphans({ projectRoots = DEFAULT_ROOTS } = {}) {
58
+ const rows = [];
59
+ const errors = [];
60
+ let db;
61
+ try { db = openVecStore(); } catch (e) {
62
+ return { rows, orphans: [], errors: [{ stage: "open", error: String(e?.message ?? e) }] };
63
+ }
64
+ try {
65
+ const stats = db.prepare(`
66
+ SELECT COALESCE(c.project_slug, '<null>') AS slug,
67
+ COUNT(c.id) AS chunkCount,
68
+ COALESCE(m.last_indexed_commit, '') AS lastCommit,
69
+ COALESCE(m.last_indexed_at, '') AS lastAt
70
+ FROM chunks c
71
+ LEFT JOIN vec_store_meta m ON m.project_slug = c.project_slug
72
+ GROUP BY c.project_slug
73
+ ORDER BY chunkCount DESC
74
+ `).all();
75
+ const slugIndex = await buildSlugIndex(projectRoots);
76
+ for (const r of stats) {
77
+ const resolved = slugIndex.get(r.slug) || null;
78
+ rows.push({ ...r, resolvedDir: resolved, orphan: !resolved && r.slug !== "<null>" });
79
+ }
80
+ } catch (e) {
81
+ errors.push({ stage: "query", error: String(e?.message ?? e) });
82
+ } finally {
83
+ try { db.close(); } catch { /* close errors are non-fatal */ }
84
+ }
85
+ const orphans = rows
86
+ .filter((r) => r.orphan)
87
+ .map((r) => ({ ...r, command: purgeCommand(r.slug) }));
88
+ return { rows, orphans, errors };
89
+ }