karajan-code 3.1.0 → 3.3.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.
- package/README.md +12 -4
- package/package.json +6 -1
- package/packages/hu-board/package.json +3 -1
- package/packages/hu-board/public/index.html +1 -0
- package/packages/hu-board/public/styles.css +32 -0
- package/packages/hu-board/public/utils/board-view.js +21 -1
- package/packages/hu-board/public/utils/formatters.js +68 -0
- package/packages/hu-board/public/wiki.html +32 -0
- package/packages/hu-board/public/wiki.js +53 -0
- package/packages/hu-board/src/db.js +137 -0
- package/packages/hu-board/src/format.js +124 -0
- package/packages/hu-board/src/plan-mutations.js +4 -4
- package/packages/hu-board/src/routes/api.js +16 -1
- package/packages/hu-board/src/routes/rag.js +1 -1
- package/packages/hu-board/src/routes/wiki.js +43 -0
- package/packages/hu-board/src/run-tracker.js +1 -1
- package/packages/hu-board/src/server.js +4 -2
- package/packages/hu-board/src/sync.js +1 -1
- package/scripts/git-hooks/post-merge +13 -2
- package/src/agents/aider-agent.js +42 -1
- package/src/agents/claude-agent.js +14 -3
- package/src/agents/codex-agent.js +44 -7
- package/src/agents/gemini-agent.js +37 -1
- package/src/agents/opencode-agent.js +34 -1
- package/src/audit/ai-slop-findings.js +102 -0
- package/src/audit/deterministic-summary.js +18 -0
- package/src/brain/standby-scheduler.js +10 -92
- package/src/brain/standby-store.js +12 -168
- package/src/checks/ai-trash.js +34 -0
- package/src/checks/qmd.js +41 -0
- package/src/checks/squeezr.js +36 -0
- package/src/cli/register-meta.js +21 -0
- package/src/cli/register-pipeline.js +3 -0
- package/src/commands/audit.js +6 -4
- package/src/commands/board.js +34 -0
- package/src/commands/doctor.js +6 -0
- package/src/commands/init.js +73 -8
- package/src/commands/qmd.js +86 -0
- package/src/commands/resume.js +6 -45
- package/src/commands/run.js +6 -50
- package/src/git/hu-snapshot.js +10 -105
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +27 -0
- package/src/orchestrator/drivers/run-hu-batch.js +5 -1
- package/src/orchestrator/flow-runner.js +10 -2
- package/src/orchestrator/hu-sub-pipeline.js +82 -8
- package/src/plan/plan-hu-ops.js +16 -338
- package/src/plan/plan-id.js +4 -45
- package/src/plan/plan-validation.js +4 -82
- package/src/rag/vec-store.js +17 -253
- package/src/roles/audit-role.js +11 -1
- package/src/session/journal/summary-writer.js +55 -1
- package/src/utils/ai-trash.js +48 -0
- package/src/utils/atomic-write.js +6 -43
- package/src/utils/budget.js +38 -9
- package/src/utils/cli-ask-question.js +76 -0
- package/src/utils/doc-links.js +2 -0
- package/src/utils/os-detect.js +10 -0
- package/src/utils/paths.js +14 -123
- package/src/utils/port-check.js +6 -45
- package/src/utils/process.js +4 -188
- package/src/utils/qmd-collection.js +72 -0
- package/src/utils/qmd-detect.js +18 -0
- package/src/utils/qmd-install.js +37 -0
- package/src/utils/run-registry.js +9 -116
- package/src/utils/shared-paths.js +12 -41
- package/src/utils/squeezr-detect.js +18 -0
- package/src/utils/squeezr-install.js +37 -0
- package/src/utils/telemetry.js +43 -0
|
@@ -1,41 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* (`packages/hu-board/src/sync.js`) — diverging the constant breaks the
|
|
14
|
-
* watcher silently. One source of truth lives here.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
|
|
19
|
-
export const SHARED_DIR_NAME = ".karajan-shared";
|
|
20
|
-
|
|
21
|
-
export function getSharedRoot(projectDir) {
|
|
22
|
-
return path.join(projectDir, SHARED_DIR_NAME);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getSharedPlansDir(projectDir) {
|
|
26
|
-
return path.join(getSharedRoot(projectDir), "plans");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getSharedHuStoriesDir(projectDir) {
|
|
30
|
-
return path.join(getSharedRoot(projectDir), "hu-stories");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Quick check used by callers that decide whether a plan came from local
|
|
35
|
-
* (`~/.karajan/plans/`) or from the shared dir. The HU Board uses this to
|
|
36
|
-
* stamp a `source` column on each record so the UI can render a 🌐 badge.
|
|
37
|
-
*/
|
|
38
|
-
export function isSharedPath(p) {
|
|
39
|
-
if (!p) return false;
|
|
40
|
-
return p.split(path.sep).includes(SHARED_DIR_NAME);
|
|
41
|
-
}
|
|
1
|
+
// Shim — the real implementation now lives in @karajan/core/shared-paths.
|
|
2
|
+
// Kept here so CLI callers (src/**/*.js) keep importing
|
|
3
|
+
// "../utils/shared-paths.js" without churn during KJC-TSK-0511 (decouple
|
|
4
|
+
// @karajan/hu-board). Will be retired once every consumer migrates to
|
|
5
|
+
// the @karajan/core import.
|
|
6
|
+
export {
|
|
7
|
+
SHARED_DIR_NAME,
|
|
8
|
+
getSharedRoot,
|
|
9
|
+
getSharedPlansDir,
|
|
10
|
+
getSharedHuStoriesDir,
|
|
11
|
+
isSharedPath,
|
|
12
|
+
} from "@karajan/core/shared-paths";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { runCommand } from "./process.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detect whether Squeezr is installed and available.
|
|
5
|
+
* @returns {Promise<{ available: boolean, version: string|null }>}
|
|
6
|
+
*/
|
|
7
|
+
export async function detectSqueezr() {
|
|
8
|
+
try {
|
|
9
|
+
const result = await runCommand("squeezr", ["--version"]);
|
|
10
|
+
if (result.exitCode === 0) {
|
|
11
|
+
const version = (result.stdout || "").trim() || null;
|
|
12
|
+
return { available: true, version };
|
|
13
|
+
}
|
|
14
|
+
return { available: false, version: null };
|
|
15
|
+
} catch { /* squeezr binary not found */
|
|
16
|
+
return { available: false, version: null };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { runCommand } from "./process.js";
|
|
2
|
+
import { getInstallCommand } from "./os-detect.js";
|
|
3
|
+
import { detectSqueezr } from "./squeezr-detect.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Install Squeezr using the OS-appropriate command.
|
|
7
|
+
* @param {object} logger - Logger with info/warn methods
|
|
8
|
+
* @returns {Promise<{ ok: boolean, version: string|null, error: string|null }>}
|
|
9
|
+
*/
|
|
10
|
+
export async function installSqueezr(logger) {
|
|
11
|
+
const command = getInstallCommand("squeezr");
|
|
12
|
+
|
|
13
|
+
logger.info("Installing Squeezr...");
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const result = await runCommand("sh", ["-c", command], { timeout: 120_000 });
|
|
17
|
+
|
|
18
|
+
if (result.exitCode !== 0) {
|
|
19
|
+
const error = (result.stderr || "").trim() || `exit code ${result.exitCode}`;
|
|
20
|
+
logger.warn(`Squeezr install failed: ${error}`);
|
|
21
|
+
return { ok: false, version: null, error };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const check = await detectSqueezr();
|
|
25
|
+
if (check.available) {
|
|
26
|
+
logger.info(`Squeezr ${check.version || ""} installed successfully.`);
|
|
27
|
+
return { ok: true, version: check.version, error: null };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
logger.warn("Squeezr install command succeeded but squeezr binary not found in PATH.");
|
|
31
|
+
return { ok: false, version: null, error: "Binary not found after install" };
|
|
32
|
+
} catch (err) {
|
|
33
|
+
const error = err.message || String(err);
|
|
34
|
+
logger.warn(`Squeezr install failed: ${error}`);
|
|
35
|
+
return { ok: false, version: null, error };
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/utils/telemetry.js
CHANGED
|
@@ -26,6 +26,49 @@ export function buildTelemetryPayload(eventName, data = {}) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Φ0-H (KJC-TSK-0526): aggregate cache-hit ratio per role from the budget
|
|
31
|
+
* summary the orchestrator already builds. Returns `{ cached_pct_coder,
|
|
32
|
+
* cached_pct_reviewer, cached_pct_total }` with values rounded to one
|
|
33
|
+
* decimal, or `null` per slot when there is no measurable input (rather
|
|
34
|
+
* than `0`, so the backend can distinguish "no cache" from "no signal").
|
|
35
|
+
*
|
|
36
|
+
* Provider-agnostic by design: the BudgetTracker entries already
|
|
37
|
+
* normalise `cached_tokens` for Anthropic (`cache_read_input_tokens`),
|
|
38
|
+
* OpenAI / Codex (`prompt_tokens_details.cached_tokens`), Gemini
|
|
39
|
+
* (`cachedContentTokenCount`) and the LiteLLM-routed providers
|
|
40
|
+
* (aider, opencode), so this helper does not need to know which
|
|
41
|
+
* provider produced the run.
|
|
42
|
+
*
|
|
43
|
+
* @param {{ breakdown_by_role?: object, total_cached_tokens?: number } | null | undefined} summary
|
|
44
|
+
* @returns {{ cached_pct_coder: number|null, cached_pct_reviewer: number|null, cached_pct_total: number|null }}
|
|
45
|
+
*/
|
|
46
|
+
export function computeCachedPct(summary) {
|
|
47
|
+
const empty = { cached_pct_coder: null, cached_pct_reviewer: null, cached_pct_total: null };
|
|
48
|
+
if (!summary || typeof summary !== "object") return empty;
|
|
49
|
+
const ratio = (cached, tokensIn) => {
|
|
50
|
+
const c = Number(cached);
|
|
51
|
+
const t = Number(tokensIn);
|
|
52
|
+
if (!Number.isFinite(c) || !Number.isFinite(t) || t <= 0 || c < 0) return null;
|
|
53
|
+
return Math.round((c / t) * 1000) / 10;
|
|
54
|
+
};
|
|
55
|
+
const byRole = summary.breakdown_by_role || {};
|
|
56
|
+
const coder = byRole.coder || null;
|
|
57
|
+
const reviewer = byRole.reviewer || null;
|
|
58
|
+
let totalCached = 0;
|
|
59
|
+
let totalIn = 0;
|
|
60
|
+
for (const role of Object.keys(byRole)) {
|
|
61
|
+
const r = byRole[role];
|
|
62
|
+
totalCached += Number(r?.cached_tokens || 0);
|
|
63
|
+
totalIn += Number(r?.tokens_in || 0);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
cached_pct_coder: coder ? ratio(coder.cached_tokens, coder.tokens_in) : null,
|
|
67
|
+
cached_pct_reviewer: reviewer ? ratio(reviewer.cached_tokens, reviewer.tokens_in) : null,
|
|
68
|
+
cached_pct_total: ratio(totalCached, totalIn)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
29
72
|
/**
|
|
30
73
|
* Send an anonymous telemetry event. Non-blocking, fire-and-forget.
|
|
31
74
|
* Never throws, never blocks the pipeline.
|