mewkit 1.11.0 → 1.11.2
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 +7 -14
- package/dist/commands/budget.d.ts.map +1 -1
- package/dist/commands/budget.js +10 -3
- package/dist/commands/budget.js.map +1 -1
- package/dist/commands/build-plugin.d.ts +8 -0
- package/dist/commands/build-plugin.d.ts.map +1 -0
- package/dist/commands/build-plugin.js +48 -0
- package/dist/commands/build-plugin.js.map +1 -0
- package/dist/commands/doctor-checks.d.ts +9 -0
- package/dist/commands/doctor-checks.d.ts.map +1 -1
- package/dist/commands/doctor-checks.js +42 -0
- package/dist/commands/doctor-checks.js.map +1 -1
- package/dist/commands/doctor-hard-gates.d.ts.map +1 -1
- package/dist/commands/doctor-hard-gates.js +46 -14
- package/dist/commands/doctor-hard-gates.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/index-command.d.ts +7 -0
- package/dist/commands/index-command.d.ts.map +1 -0
- package/dist/commands/index-command.js +67 -0
- package/dist/commands/index-command.js.map +1 -0
- package/dist/commands/init.js +1 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/inventory.d.ts +4 -4
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +35 -26
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/memory.d.ts +0 -3
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +0 -67
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/pack.d.ts +0 -2
- package/dist/commands/pack.d.ts.map +1 -1
- package/dist/commands/pack.js +0 -32
- package/dist/commands/pack.js.map +1 -1
- package/dist/commands/providers.d.ts +6 -0
- package/dist/commands/providers.d.ts.map +1 -0
- package/dist/commands/providers.js +94 -0
- package/dist/commands/providers.js.map +1 -0
- package/dist/commands/trace.d.ts +11 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +146 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/validate.d.ts +17 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +198 -0
- package/dist/commands/validate.js.map +1 -1
- package/dist/core/build-inventory.d.ts +4 -0
- package/dist/core/build-inventory.d.ts.map +1 -1
- package/dist/core/build-inventory.js +4 -0
- package/dist/core/build-inventory.js.map +1 -1
- package/dist/core/check-plugin-manifests.d.ts +10 -0
- package/dist/core/check-plugin-manifests.d.ts.map +1 -0
- package/dist/core/check-plugin-manifests.js +150 -0
- package/dist/core/check-plugin-manifests.js.map +1 -0
- package/dist/core/context-budget.d.ts +19 -1
- package/dist/core/context-budget.d.ts.map +1 -1
- package/dist/core/context-budget.js +53 -21
- package/dist/core/context-budget.js.map +1 -1
- package/dist/core/derived-index.d.ts +34 -0
- package/dist/core/derived-index.d.ts.map +1 -0
- package/dist/core/derived-index.js +137 -0
- package/dist/core/derived-index.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/plugin-agent-refs.d.ts +22 -0
- package/dist/core/plugin-agent-refs.d.ts.map +1 -0
- package/dist/core/plugin-agent-refs.js +87 -0
- package/dist/core/plugin-agent-refs.js.map +1 -0
- package/dist/core/plugin-hooks.d.ts +15 -0
- package/dist/core/plugin-hooks.d.ts.map +1 -0
- package/dist/core/plugin-hooks.js +58 -0
- package/dist/core/plugin-hooks.js.map +1 -0
- package/dist/core/plugin-manifest.d.ts +289 -0
- package/dist/core/plugin-manifest.d.ts.map +1 -0
- package/dist/core/plugin-manifest.js +125 -0
- package/dist/core/plugin-manifest.js.map +1 -0
- package/dist/core/plugin-payload.d.ts +26 -0
- package/dist/core/plugin-payload.d.ts.map +1 -0
- package/dist/core/plugin-payload.js +138 -0
- package/dist/core/plugin-payload.js.map +1 -0
- package/dist/core/substrate.d.ts +47 -0
- package/dist/core/substrate.d.ts.map +1 -0
- package/dist/core/substrate.js +183 -0
- package/dist/core/substrate.js.map +1 -0
- package/dist/core/trace-analysis.d.ts +60 -0
- package/dist/core/trace-analysis.d.ts.map +1 -0
- package/dist/core/trace-analysis.js +167 -0
- package/dist/core/trace-analysis.js.map +1 -0
- package/dist/index.js +58 -94
- package/dist/index.js.map +1 -1
- package/dist/migrate/converters/md-to-codex-rules.d.ts.map +1 -1
- package/dist/migrate/converters/md-to-codex-rules.js +30 -0
- package/dist/migrate/converters/md-to-codex-rules.js.map +1 -1
- package/dist/migrate/portability-policy.d.ts.map +1 -1
- package/dist/migrate/portability-policy.js +45 -24
- package/dist/migrate/portability-policy.js.map +1 -1
- package/dist/migrate/provider-support-summary.d.ts +49 -0
- package/dist/migrate/provider-support-summary.d.ts.map +1 -0
- package/dist/migrate/provider-support-summary.js +98 -0
- package/dist/migrate/provider-support-summary.js.map +1 -0
- package/dist/migrate/skill-directory-audit.d.ts +4 -1
- package/dist/migrate/skill-directory-audit.d.ts.map +1 -1
- package/dist/migrate/skill-directory-audit.js +7 -1
- package/dist/migrate/skill-directory-audit.js.map +1 -1
- package/dist/orchviz/plan/plan-lifecycle.d.ts +17 -0
- package/dist/orchviz/plan/plan-lifecycle.d.ts.map +1 -0
- package/dist/orchviz/plan/plan-lifecycle.js +97 -0
- package/dist/orchviz/plan/plan-lifecycle.js.map +1 -0
- package/dist/orchviz/server/write-handlers.d.ts.map +1 -1
- package/dist/orchviz/server/write-handlers.js +5 -2
- package/dist/orchviz/server/write-handlers.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Generate the plugin payload from the canonical `.claude` source tree.
|
|
2
|
+
//
|
|
3
|
+
// The shipped source keeps bare agent names + bare references so the flat-copy
|
|
4
|
+
// install (`mewkit init`) keeps working unchanged. This builder produces the
|
|
5
|
+
// plugin variant: a transformed copy of `.claude` at the plugin root, with kit
|
|
6
|
+
// agent references namespaced to `<plugin>:<agent>` and the one skill dir whose
|
|
7
|
+
// name diverges from its slug (`mk-loop`) renamed so the plugin's
|
|
8
|
+
// directory-derived slash command resolves to `/mk:loop`.
|
|
9
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
10
|
+
import { extname, join, relative } from "node:path";
|
|
11
|
+
import { buildClaudePluginJson, buildCodexPluginJson, PLUGIN_NAME, } from "./plugin-manifest.js";
|
|
12
|
+
import { collectAgentNames, rewriteAgentRefs } from "./plugin-agent-refs.js";
|
|
13
|
+
import { buildPluginHooks, readSettingsHooks } from "./plugin-hooks.js";
|
|
14
|
+
/** File extensions whose contents are scanned for agent references. */
|
|
15
|
+
const TEXT_EXTENSIONS = new Set([
|
|
16
|
+
".md",
|
|
17
|
+
".json",
|
|
18
|
+
".sh",
|
|
19
|
+
".cjs",
|
|
20
|
+
".mjs",
|
|
21
|
+
".js",
|
|
22
|
+
".ts",
|
|
23
|
+
".py",
|
|
24
|
+
".txt",
|
|
25
|
+
".yaml",
|
|
26
|
+
".yml",
|
|
27
|
+
]);
|
|
28
|
+
/** Top-level `.claude` entries excluded from the plugin payload (runtime state). */
|
|
29
|
+
const EXCLUDED_DIRS = new Set(["session-state", "memory", "logs"]);
|
|
30
|
+
const EXCLUDED_FILES = new Set(["metadata.json", ".env"]);
|
|
31
|
+
/**
|
|
32
|
+
* Build the plugin payload at `outDir`. Idempotent: clears and regenerates.
|
|
33
|
+
* Returns counts for verification.
|
|
34
|
+
*/
|
|
35
|
+
export function generatePluginPayload(opts) {
|
|
36
|
+
const pluginName = opts.name ?? PLUGIN_NAME;
|
|
37
|
+
const agentNames = opts.agentNames ?? collectAgentNames(join(opts.sourceDir, "agents"));
|
|
38
|
+
if (existsSync(opts.outDir))
|
|
39
|
+
rmSync(opts.outDir, { recursive: true, force: true });
|
|
40
|
+
mkdirSync(opts.outDir, { recursive: true });
|
|
41
|
+
// Copy every non-excluded top-level entry of the source tree.
|
|
42
|
+
for (const entry of readdirSync(opts.sourceDir)) {
|
|
43
|
+
if (EXCLUDED_DIRS.has(entry) || EXCLUDED_FILES.has(entry))
|
|
44
|
+
continue;
|
|
45
|
+
const src = join(opts.sourceDir, entry);
|
|
46
|
+
const dest = join(opts.outDir, entry);
|
|
47
|
+
if (statSync(src).isDirectory() && entry === "skills") {
|
|
48
|
+
copySkills(src, dest);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
cpSync(src, dest, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Rename the one skill dir whose name diverges from its slug.
|
|
55
|
+
let loopDirRenamed = false;
|
|
56
|
+
const mkLoop = join(opts.outDir, "skills", "mk-loop");
|
|
57
|
+
if (existsSync(mkLoop)) {
|
|
58
|
+
renameSync(mkLoop, join(opts.outDir, "skills", "loop"));
|
|
59
|
+
loopDirRenamed = true;
|
|
60
|
+
}
|
|
61
|
+
// Drop non-agent `.md` files from `agents/` (index files have no `name:`),
|
|
62
|
+
// so the plugin registry does not register them as agents.
|
|
63
|
+
const nonAgentsPruned = pruneNonAgents(join(opts.outDir, "agents"));
|
|
64
|
+
// Translate flat-copy hook wiring (settings.json) into plugin hooks.json.
|
|
65
|
+
const settingsHooks = readSettingsHooks(join(opts.sourceDir, "settings.json"));
|
|
66
|
+
const hooksGenerated = settingsHooks !== null;
|
|
67
|
+
if (settingsHooks) {
|
|
68
|
+
writeManifest(join(opts.outDir, "hooks", "hooks.json"), buildPluginHooks(settingsHooks));
|
|
69
|
+
}
|
|
70
|
+
// Rewrite kit agent references across every text file in the payload.
|
|
71
|
+
let filesScanned = 0;
|
|
72
|
+
let refsRewritten = 0;
|
|
73
|
+
for (const file of walkFiles(opts.outDir)) {
|
|
74
|
+
if (!TEXT_EXTENSIONS.has(extname(file).toLowerCase()))
|
|
75
|
+
continue;
|
|
76
|
+
filesScanned += 1;
|
|
77
|
+
const original = readFileSync(file, "utf-8");
|
|
78
|
+
const { content, count } = rewriteAgentRefs(original, agentNames, pluginName);
|
|
79
|
+
if (count > 0) {
|
|
80
|
+
writeFileSync(file, content);
|
|
81
|
+
refsRewritten += count;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Write both runtime plugin manifests into the plugin root.
|
|
85
|
+
writeManifest(join(opts.outDir, ".claude-plugin", "plugin.json"), buildClaudePluginJson(opts));
|
|
86
|
+
writeManifest(join(opts.outDir, ".codex-plugin", "plugin.json"), buildCodexPluginJson(opts));
|
|
87
|
+
return { filesScanned, refsRewritten, loopDirRenamed, nonAgentsPruned, hooksGenerated };
|
|
88
|
+
}
|
|
89
|
+
/** Remove `.md` files in `agents/` that lack a `name:` frontmatter (not agents). */
|
|
90
|
+
function pruneNonAgents(agentsDir) {
|
|
91
|
+
if (!existsSync(agentsDir))
|
|
92
|
+
return 0;
|
|
93
|
+
let pruned = 0;
|
|
94
|
+
for (const entry of readdirSync(agentsDir)) {
|
|
95
|
+
if (!entry.endsWith(".md"))
|
|
96
|
+
continue;
|
|
97
|
+
const file = join(agentsDir, entry);
|
|
98
|
+
if (!/^name:/m.test(readFileSync(file, "utf-8"))) {
|
|
99
|
+
unlinkSync(file);
|
|
100
|
+
pruned += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return pruned;
|
|
104
|
+
}
|
|
105
|
+
/** Copy the skills tree but drop the bundled Python virtualenv. */
|
|
106
|
+
function copySkills(srcSkills, destSkills) {
|
|
107
|
+
mkdirSync(destSkills, { recursive: true });
|
|
108
|
+
for (const entry of readdirSync(srcSkills)) {
|
|
109
|
+
if (entry === ".venv")
|
|
110
|
+
continue;
|
|
111
|
+
cpSync(join(srcSkills, entry), join(destSkills, entry), { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Yield every file path under a directory, recursively. */
|
|
115
|
+
function* walkFiles(dir) {
|
|
116
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
117
|
+
const full = join(dir, entry.name);
|
|
118
|
+
if (entry.isDirectory()) {
|
|
119
|
+
yield* walkFiles(full);
|
|
120
|
+
}
|
|
121
|
+
else if (entry.isFile()) {
|
|
122
|
+
yield full;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Deterministic, pretty-printed JSON write with a trailing newline. */
|
|
127
|
+
function writeManifest(path, value) {
|
|
128
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
129
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
130
|
+
}
|
|
131
|
+
/** Relative payload paths of the two generated plugin manifests (for callers). */
|
|
132
|
+
export function pluginManifestPaths(outDir) {
|
|
133
|
+
return [
|
|
134
|
+
relative(process.cwd(), join(outDir, ".claude-plugin", "plugin.json")),
|
|
135
|
+
relative(process.cwd(), join(outDir, ".codex-plugin", "plugin.json")),
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=plugin-payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-payload.js","sourceRoot":"","sources":["../../src/core/plugin-payload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CheckResult } from "../commands/validate.js";
|
|
2
|
+
import type { Status } from "../commands/doctor-checks.js";
|
|
3
|
+
/** Canonical taxonomy: 11 vendor-neutral responsibilities + 1 MeowKit-specific. Order is the
|
|
4
|
+
* display order; `core` marks the 11 Runtime-Substrate values vs the kit-specific addition. */
|
|
5
|
+
export declare const TAXONOMY: {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
core: boolean;
|
|
9
|
+
}[];
|
|
10
|
+
export type Coverage = "covered" | "partial" | "missing";
|
|
11
|
+
export interface ResponsibilityRow {
|
|
12
|
+
value: string;
|
|
13
|
+
label: string;
|
|
14
|
+
core: boolean;
|
|
15
|
+
coverage: Coverage;
|
|
16
|
+
count: number;
|
|
17
|
+
active: number;
|
|
18
|
+
examples: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface SubstrateAggregate {
|
|
21
|
+
rows: ResponsibilityRow[];
|
|
22
|
+
/** Artifacts whose responsibility value is not in the taxonomy enum (always a problem). */
|
|
23
|
+
invalid: {
|
|
24
|
+
path: string;
|
|
25
|
+
value: string;
|
|
26
|
+
}[];
|
|
27
|
+
/** Registry-sourced artifacts with no responsibility (a hard gap — registry is the seeded set). */
|
|
28
|
+
untaggedRegistry: string[];
|
|
29
|
+
/** Frontmatter-sourced artifacts (skills/agents) with no responsibility (allowed; tag-on-touch). */
|
|
30
|
+
untaggedFrontmatter: string[];
|
|
31
|
+
totalArtifacts: number;
|
|
32
|
+
}
|
|
33
|
+
/** Load the allowed responsibility values from the schema; fall back to the taxonomy. */
|
|
34
|
+
export declare function loadResponsibilityEnum(claudeDir: string): Set<string>;
|
|
35
|
+
/** Build the responsibility×coverage aggregate from the live inventory. */
|
|
36
|
+
export declare function aggregateSubstrate(claudeDir: string): SubstrateAggregate;
|
|
37
|
+
/** Deterministic markdown view — generated, never hand-edited. Stable ordering keeps the
|
|
38
|
+
* regenerate-and-diff drift check clean. */
|
|
39
|
+
export declare function renderSubstrateView(agg: SubstrateAggregate): string;
|
|
40
|
+
/** Validate substrate tagging + the committed view's freshness. Registry untagged / out-of-enum
|
|
41
|
+
* / stale-view are FAIL; frontmatter untagged is WARN (tag-on-touch, reported not hidden). */
|
|
42
|
+
export declare function checkSubstrate(claudeDir: string, opts?: {
|
|
43
|
+
missingViewSeverity?: Status;
|
|
44
|
+
}): CheckResult[];
|
|
45
|
+
/** Write/refresh the committed view from the live registry. Returns the absolute path. */
|
|
46
|
+
export declare function emitSubstrateView(claudeDir: string): string;
|
|
47
|
+
//# sourceMappingURL=substrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrate.d.ts","sourceRoot":"","sources":["../../src/core/substrate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAQ3D;gGACgG;AAChG,eAAO,MAAM,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EAarE,CAAC;AAIF,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,2FAA2F;IAC3F,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,mGAAmG;IACnG,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oGAAoG;IACpG,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,yFAAyF;AACzF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAYrE;AAQD,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CA8CxE;AAED;6CAC6C;AAC7C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAgCnE;AAED;+FAC+F;AAC/F,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,WAAW,EAAE,CAwD5G;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAI3D"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildInventory } from "./build-inventory.js";
|
|
4
|
+
// The responsibility substrate. Aggregates every harness artifact by the vendor-neutral
|
|
5
|
+
// `responsibility` it serves, so coverage is auditable by responsibility rather than by file.
|
|
6
|
+
// The matrix is GENERATED from the registry/frontmatter on every call — a hand-maintained map
|
|
7
|
+
// would lie about state. A committed view (.claude/harness-substrate.md) is regenerated via
|
|
8
|
+
// `inventory --substrate --emit` and drift-checked by `validate`.
|
|
9
|
+
/** Canonical taxonomy: 11 vendor-neutral responsibilities + 1 MeowKit-specific. Order is the
|
|
10
|
+
* display order; `core` marks the 11 Runtime-Substrate values vs the kit-specific addition. */
|
|
11
|
+
export const TAXONOMY = [
|
|
12
|
+
{ value: "task-specification", label: "Task specification", core: true },
|
|
13
|
+
{ value: "context-selection", label: "Context selection", core: true },
|
|
14
|
+
{ value: "tool-access", label: "Tool access", core: true },
|
|
15
|
+
{ value: "project-memory", label: "Project memory", core: true },
|
|
16
|
+
{ value: "task-state", label: "Task state", core: true },
|
|
17
|
+
{ value: "observability", label: "Observability", core: true },
|
|
18
|
+
{ value: "failure-attribution", label: "Failure attribution", core: true },
|
|
19
|
+
{ value: "verification", label: "Verification", core: true },
|
|
20
|
+
{ value: "permissions", label: "Permissions", core: true },
|
|
21
|
+
{ value: "entropy-auditing", label: "Entropy auditing", core: true },
|
|
22
|
+
{ value: "intervention-recording", label: "Intervention recording", core: true },
|
|
23
|
+
{ value: "gate-enforcement", label: "Gate enforcement", core: false },
|
|
24
|
+
];
|
|
25
|
+
const VIEW_PATH = "harness-substrate.md";
|
|
26
|
+
/** Load the allowed responsibility values from the schema; fall back to the taxonomy. */
|
|
27
|
+
export function loadResponsibilityEnum(claudeDir) {
|
|
28
|
+
const schemaPath = path.join(claudeDir, "schemas", "harness-metadata-schema.json");
|
|
29
|
+
try {
|
|
30
|
+
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
|
|
31
|
+
const en = schema.properties?.responsibility?.enum;
|
|
32
|
+
if (Array.isArray(en) && en.length > 0)
|
|
33
|
+
return new Set(en);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* fall through */
|
|
37
|
+
}
|
|
38
|
+
return new Set(TAXONOMY.map((t) => t.value));
|
|
39
|
+
}
|
|
40
|
+
function coverageOf(count, active) {
|
|
41
|
+
if (count === 0)
|
|
42
|
+
return "missing";
|
|
43
|
+
if (active === 0)
|
|
44
|
+
return "partial"; // served only by deprecated/experimental artifacts
|
|
45
|
+
return "covered";
|
|
46
|
+
}
|
|
47
|
+
/** Build the responsibility×coverage aggregate from the live inventory. */
|
|
48
|
+
export function aggregateSubstrate(claudeDir) {
|
|
49
|
+
const { entries } = buildInventory(claudeDir);
|
|
50
|
+
const allowed = loadResponsibilityEnum(claudeDir);
|
|
51
|
+
const byResp = new Map();
|
|
52
|
+
const invalid = [];
|
|
53
|
+
const untaggedRegistry = [];
|
|
54
|
+
const untaggedFrontmatter = [];
|
|
55
|
+
for (const e of entries) {
|
|
56
|
+
const r = e.responsibility;
|
|
57
|
+
if (!r) {
|
|
58
|
+
if (e.source === "registry")
|
|
59
|
+
untaggedRegistry.push(e.path);
|
|
60
|
+
else
|
|
61
|
+
untaggedFrontmatter.push(e.path);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!allowed.has(r)) {
|
|
65
|
+
invalid.push({ path: e.path, value: r });
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const list = byResp.get(r) ?? [];
|
|
69
|
+
list.push(e);
|
|
70
|
+
byResp.set(r, list);
|
|
71
|
+
}
|
|
72
|
+
const rows = TAXONOMY.map((t) => {
|
|
73
|
+
const list = byResp.get(t.value) ?? [];
|
|
74
|
+
const active = list.filter((e) => e.status === "active").length;
|
|
75
|
+
return {
|
|
76
|
+
value: t.value,
|
|
77
|
+
label: t.label,
|
|
78
|
+
core: t.core,
|
|
79
|
+
coverage: coverageOf(list.length, active),
|
|
80
|
+
count: list.length,
|
|
81
|
+
active,
|
|
82
|
+
examples: list.slice(0, 3).map((e) => e.id),
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
rows,
|
|
87
|
+
invalid,
|
|
88
|
+
untaggedRegistry,
|
|
89
|
+
untaggedFrontmatter,
|
|
90
|
+
totalArtifacts: entries.length,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Deterministic markdown view — generated, never hand-edited. Stable ordering keeps the
|
|
94
|
+
* regenerate-and-diff drift check clean. */
|
|
95
|
+
export function renderSubstrateView(agg) {
|
|
96
|
+
const icon = { covered: "✅ covered", partial: "🟡 partial", missing: "⬜ missing" };
|
|
97
|
+
const lines = [];
|
|
98
|
+
lines.push("<!-- GENERATED by `mewkit inventory --substrate --emit` — DO NOT EDIT BY HAND. -->");
|
|
99
|
+
lines.push("<!-- Regenerate after tagging; `mewkit validate` fails if this drifts from the registry. -->");
|
|
100
|
+
lines.push("");
|
|
101
|
+
lines.push("# Harness Responsibility Substrate");
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push("Coverage of each vendor-neutral substrate responsibility, generated from the harness registry " +
|
|
104
|
+
"+ artifact frontmatter. Eleven core values are the Runtime-Substrate taxonomy (repo-harness " +
|
|
105
|
+
"synthesis, Runtime-Substrate-rooted); `Gate enforcement` is the MeowKit-specific addition.");
|
|
106
|
+
lines.push("");
|
|
107
|
+
lines.push("| Responsibility | Coverage | Tagged | Active | Examples |");
|
|
108
|
+
lines.push("| -------------- | -------- | -----: | -----: | -------- |");
|
|
109
|
+
for (const r of agg.rows) {
|
|
110
|
+
const label = r.core ? r.label : `${r.label} *(kit)*`;
|
|
111
|
+
lines.push(`| ${label} | ${icon[r.coverage]} | ${r.count} | ${r.active} | ${r.examples.join(", ") || "—"} |`);
|
|
112
|
+
}
|
|
113
|
+
lines.push("");
|
|
114
|
+
const missing = agg.rows.filter((r) => r.coverage === "missing").map((r) => r.label);
|
|
115
|
+
lines.push(`**Coverage:** ${agg.rows.filter((r) => r.coverage === "covered").length}/${agg.rows.length} responsibilities have active artifacts.` +
|
|
116
|
+
(missing.length ? ` Missing: ${missing.join(", ")}.` : ""));
|
|
117
|
+
lines.push(`**Untagged:** ${agg.untaggedRegistry.length} registry + ${agg.untaggedFrontmatter.length} frontmatter ` +
|
|
118
|
+
`artifacts carry no responsibility (frontmatter is tag-on-touch; registry should be 100%).`);
|
|
119
|
+
lines.push("");
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
}
|
|
122
|
+
/** Validate substrate tagging + the committed view's freshness. Registry untagged / out-of-enum
|
|
123
|
+
* / stale-view are FAIL; frontmatter untagged is WARN (tag-on-touch, reported not hidden). */
|
|
124
|
+
export function checkSubstrate(claudeDir, opts = {}) {
|
|
125
|
+
const section = "Substrate";
|
|
126
|
+
const results = [];
|
|
127
|
+
const agg = aggregateSubstrate(claudeDir);
|
|
128
|
+
for (const inv of agg.invalid) {
|
|
129
|
+
results.push({ name: `Substrate: ${inv.path}`, status: "fail", detail: `responsibility="${inv.value}" not in taxonomy enum`, section });
|
|
130
|
+
}
|
|
131
|
+
for (const p of agg.untaggedRegistry) {
|
|
132
|
+
results.push({ name: `Substrate: ${p}`, status: "fail", detail: "registry artifact has no responsibility (seed it)", section });
|
|
133
|
+
}
|
|
134
|
+
if (agg.untaggedFrontmatter.length > 0) {
|
|
135
|
+
results.push({
|
|
136
|
+
name: "Substrate: untagged frontmatter artifacts",
|
|
137
|
+
status: "warn",
|
|
138
|
+
detail: `${agg.untaggedFrontmatter.length} skill/agent artifact(s) untagged — tag-on-touch (allowed, reported).`,
|
|
139
|
+
section,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// View freshness: regenerate and diff against the committed file.
|
|
143
|
+
const viewPath = path.join(claudeDir, VIEW_PATH);
|
|
144
|
+
const fresh = renderSubstrateView(agg);
|
|
145
|
+
if (!fs.existsSync(viewPath)) {
|
|
146
|
+
const status = opts.missingViewSeverity ?? "fail";
|
|
147
|
+
results.push({
|
|
148
|
+
name: "Substrate view present",
|
|
149
|
+
status,
|
|
150
|
+
detail: status === "warn"
|
|
151
|
+
? "No .claude/harness-substrate.md — run `mewkit inventory --substrate --emit`"
|
|
152
|
+
: "Missing .claude/harness-substrate.md (run `mewkit inventory --substrate --emit`)",
|
|
153
|
+
section,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const committed = fs.readFileSync(viewPath, "utf-8");
|
|
158
|
+
const inSync = committed.trim() === fresh.trim();
|
|
159
|
+
results.push({
|
|
160
|
+
name: "Substrate view in sync",
|
|
161
|
+
status: inSync ? "pass" : "fail",
|
|
162
|
+
detail: inSync ? viewPath : "harness-substrate.md is stale — run `mewkit inventory --substrate --emit`",
|
|
163
|
+
section,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const fails = results.filter((r) => r.status === "fail").length;
|
|
167
|
+
results.push({
|
|
168
|
+
name: "Substrate coverage",
|
|
169
|
+
status: fails === 0 ? "pass" : "fail",
|
|
170
|
+
detail: fails === 0
|
|
171
|
+
? `${agg.totalArtifacts} artifacts; ${agg.rows.filter((r) => r.coverage === "covered").length}/${agg.rows.length} responsibilities covered`
|
|
172
|
+
: `${fails} substrate issue(s)`,
|
|
173
|
+
section,
|
|
174
|
+
});
|
|
175
|
+
return results;
|
|
176
|
+
}
|
|
177
|
+
/** Write/refresh the committed view from the live registry. Returns the absolute path. */
|
|
178
|
+
export function emitSubstrateView(claudeDir) {
|
|
179
|
+
const viewPath = path.join(claudeDir, VIEW_PATH);
|
|
180
|
+
fs.writeFileSync(viewPath, renderSubstrateView(aggregateSubstrate(claudeDir)) + "\n");
|
|
181
|
+
return viewPath;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=substrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrate.js","sourceRoot":"","sources":["../../src/core/substrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** One JSONL trace record (shape written by hooks/append-trace.sh; fields are best-effort). */
|
|
2
|
+
export interface TraceRecord {
|
|
3
|
+
schema_version?: string;
|
|
4
|
+
ts?: string;
|
|
5
|
+
event?: string;
|
|
6
|
+
run_id?: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
density?: string;
|
|
9
|
+
data?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export type TraceTier = "minimal" | "standard" | "detailed";
|
|
12
|
+
/** Parse JSONL; skip blank/malformed lines rather than throwing (logs are append-only and
|
|
13
|
+
* may contain a partially-written trailing line). */
|
|
14
|
+
export declare function parseTraceLog(content: string): TraceRecord[];
|
|
15
|
+
export interface ScoreResult {
|
|
16
|
+
tier: TraceTier;
|
|
17
|
+
events: number;
|
|
18
|
+
types: number;
|
|
19
|
+
hasVerification: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Trace-quality tier for a set of records: richer + more diverse + verified ⇒ higher tier. */
|
|
22
|
+
export declare function scoreTier(records: TraceRecord[]): ScoreResult;
|
|
23
|
+
/** Group records by run_id (a "lane") and score each. Records with no run_id share the
|
|
24
|
+
* synthetic "(unattributed)" lane. */
|
|
25
|
+
export declare function scoreByRun(records: TraceRecord[]): Map<string, ScoreResult>;
|
|
26
|
+
/** Shannon entropy (bits) over the event-type distribution — a disorder measure. */
|
|
27
|
+
export declare function shannonEntropy(records: TraceRecord[]): number;
|
|
28
|
+
/** Normalize a friction message for grouping: lowercase, collapse whitespace, strip wrapping
|
|
29
|
+
* quotes and trailing punctuation. Identical-in-meaning lines collapse to one key. */
|
|
30
|
+
export declare function normalizeFriction(msg: string): string;
|
|
31
|
+
export interface FrictionGroup {
|
|
32
|
+
message: string;
|
|
33
|
+
count: number;
|
|
34
|
+
responsibility?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Group friction records by normalized message, descending by count then message. */
|
|
37
|
+
export declare function groupFriction(records: TraceRecord[]): FrictionGroup[];
|
|
38
|
+
export interface AuditResult {
|
|
39
|
+
total: number;
|
|
40
|
+
orphaned: number;
|
|
41
|
+
stale: number;
|
|
42
|
+
unverifiedRuns: number;
|
|
43
|
+
entropy: number;
|
|
44
|
+
repeatedFriction: FrictionGroup[];
|
|
45
|
+
frictionByResponsibility: Record<string, number>;
|
|
46
|
+
}
|
|
47
|
+
/** Entropy / drift audit. `now` + `staleDays` are injected for determinism. */
|
|
48
|
+
export declare function auditTraces(records: TraceRecord[], opts: {
|
|
49
|
+
now: Date;
|
|
50
|
+
staleDays?: number;
|
|
51
|
+
}): AuditResult;
|
|
52
|
+
export interface ProposalItem {
|
|
53
|
+
kind: "friction" | "drift";
|
|
54
|
+
title: string;
|
|
55
|
+
evidenceCount: number;
|
|
56
|
+
responsibility?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Advisory backlog proposals: repeated friction (≥2) + audit drift findings. Never gates. */
|
|
59
|
+
export declare function proposeImprovements(audit: AuditResult): ProposalItem[];
|
|
60
|
+
//# sourceMappingURL=trace-analysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-analysis.d.ts","sourceRoot":"","sources":["../../src/core/trace-analysis.ts"],"names":[],"mappings":"AAIA,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAK5D;sDACsD;AACtD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAa5D;AAED,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,OAAO,CAAC;CACzB;AAED,+FAA+F;AAC/F,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,CAQ7D;AAED;uCACuC;AACvC,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAW3E;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAc7D;AAED;uFACuF;AACvF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOrD;AAgBD,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,aAAa,EAAE,CAYrE;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,aAAa,EAAE,CAAC;IAClC,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CA2CxG;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE,CAWtE"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Pure, deterministic analysis over the append trace log. No filesystem, no clock — the CLI
|
|
2
|
+
// supplies records and `now`. On-demand only: nothing here runs in a hook hot-path. Everything
|
|
3
|
+
// is advisory — these functions report; they never gate.
|
|
4
|
+
const VERIFY_RE = /verif|test|review|evaluat|pass|lint|typecheck/i;
|
|
5
|
+
const WORK_RE = /edit|build|implement|write|generat|fix|refactor/i;
|
|
6
|
+
/** Parse JSONL; skip blank/malformed lines rather than throwing (logs are append-only and
|
|
7
|
+
* may contain a partially-written trailing line). */
|
|
8
|
+
export function parseTraceLog(content) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const line of content.split("\n")) {
|
|
11
|
+
const t = line.trim();
|
|
12
|
+
if (!t)
|
|
13
|
+
continue;
|
|
14
|
+
try {
|
|
15
|
+
const obj = JSON.parse(t);
|
|
16
|
+
if (obj && typeof obj === "object")
|
|
17
|
+
out.push(obj);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
/* skip malformed line */
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
/** Trace-quality tier for a set of records: richer + more diverse + verified ⇒ higher tier. */
|
|
26
|
+
export function scoreTier(records) {
|
|
27
|
+
const events = records.length;
|
|
28
|
+
const types = new Set(records.map((r) => r.event ?? "unknown")).size;
|
|
29
|
+
const hasVerification = records.some((r) => VERIFY_RE.test(r.event ?? ""));
|
|
30
|
+
let tier = "minimal";
|
|
31
|
+
if (events >= 10 && types >= 4)
|
|
32
|
+
tier = "detailed";
|
|
33
|
+
else if (events >= 3 && types >= 2)
|
|
34
|
+
tier = "standard";
|
|
35
|
+
return { tier, events, types, hasVerification };
|
|
36
|
+
}
|
|
37
|
+
/** Group records by run_id (a "lane") and score each. Records with no run_id share the
|
|
38
|
+
* synthetic "(unattributed)" lane. */
|
|
39
|
+
export function scoreByRun(records) {
|
|
40
|
+
const byRun = new Map();
|
|
41
|
+
for (const r of records) {
|
|
42
|
+
const id = r.run_id && r.run_id.length > 0 ? r.run_id : "(unattributed)";
|
|
43
|
+
const list = byRun.get(id) ?? [];
|
|
44
|
+
list.push(r);
|
|
45
|
+
byRun.set(id, list);
|
|
46
|
+
}
|
|
47
|
+
const out = new Map();
|
|
48
|
+
for (const [id, list] of byRun)
|
|
49
|
+
out.set(id, scoreTier(list));
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Shannon entropy (bits) over the event-type distribution — a disorder measure. */
|
|
53
|
+
export function shannonEntropy(records) {
|
|
54
|
+
if (records.length === 0)
|
|
55
|
+
return 0;
|
|
56
|
+
const counts = new Map();
|
|
57
|
+
for (const r of records) {
|
|
58
|
+
const e = r.event ?? "unknown";
|
|
59
|
+
counts.set(e, (counts.get(e) ?? 0) + 1);
|
|
60
|
+
}
|
|
61
|
+
const n = records.length;
|
|
62
|
+
let h = 0;
|
|
63
|
+
for (const c of counts.values()) {
|
|
64
|
+
const p = c / n;
|
|
65
|
+
h -= p * Math.log2(p);
|
|
66
|
+
}
|
|
67
|
+
return Math.round(h * 1000) / 1000;
|
|
68
|
+
}
|
|
69
|
+
/** Normalize a friction message for grouping: lowercase, collapse whitespace, strip wrapping
|
|
70
|
+
* quotes and trailing punctuation. Identical-in-meaning lines collapse to one key. */
|
|
71
|
+
export function normalizeFriction(msg) {
|
|
72
|
+
return msg
|
|
73
|
+
.toLowerCase()
|
|
74
|
+
.replace(/\s+/g, " ")
|
|
75
|
+
.replace(/^["'`]+|["'`]+$/g, "")
|
|
76
|
+
.replace(/[.!?,;:]+$/g, "")
|
|
77
|
+
.trim();
|
|
78
|
+
}
|
|
79
|
+
function isFriction(r) {
|
|
80
|
+
return r.event === "friction";
|
|
81
|
+
}
|
|
82
|
+
function frictionMessage(r) {
|
|
83
|
+
const m = r.data?.["message"];
|
|
84
|
+
return typeof m === "string" ? m : "";
|
|
85
|
+
}
|
|
86
|
+
function frictionResponsibility(r) {
|
|
87
|
+
const v = r.data?.["responsibility"];
|
|
88
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
89
|
+
}
|
|
90
|
+
/** Group friction records by normalized message, descending by count then message. */
|
|
91
|
+
export function groupFriction(records) {
|
|
92
|
+
const groups = new Map();
|
|
93
|
+
for (const r of records) {
|
|
94
|
+
if (!isFriction(r))
|
|
95
|
+
continue;
|
|
96
|
+
const raw = frictionMessage(r);
|
|
97
|
+
if (!raw)
|
|
98
|
+
continue;
|
|
99
|
+
const key = normalizeFriction(raw);
|
|
100
|
+
const existing = groups.get(key);
|
|
101
|
+
if (existing)
|
|
102
|
+
existing.count += 1;
|
|
103
|
+
else
|
|
104
|
+
groups.set(key, { message: raw, count: 1, responsibility: frictionResponsibility(r) });
|
|
105
|
+
}
|
|
106
|
+
return [...groups.values()].sort((a, b) => b.count - a.count || a.message.localeCompare(b.message));
|
|
107
|
+
}
|
|
108
|
+
/** Entropy / drift audit. `now` + `staleDays` are injected for determinism. */
|
|
109
|
+
export function auditTraces(records, opts) {
|
|
110
|
+
const staleDays = opts.staleDays ?? 30;
|
|
111
|
+
const cutoff = opts.now.getTime() - staleDays * 24 * 60 * 60 * 1000;
|
|
112
|
+
let orphaned = 0;
|
|
113
|
+
let stale = 0;
|
|
114
|
+
const byRun = new Map();
|
|
115
|
+
const frictionByResponsibility = {};
|
|
116
|
+
for (const r of records) {
|
|
117
|
+
if (!r.run_id)
|
|
118
|
+
orphaned += 1;
|
|
119
|
+
if (r.ts) {
|
|
120
|
+
const t = Date.parse(r.ts);
|
|
121
|
+
if (!Number.isNaN(t) && t < cutoff)
|
|
122
|
+
stale += 1;
|
|
123
|
+
}
|
|
124
|
+
const id = r.run_id ?? "";
|
|
125
|
+
if (id) {
|
|
126
|
+
const list = byRun.get(id) ?? [];
|
|
127
|
+
list.push(r);
|
|
128
|
+
byRun.set(id, list);
|
|
129
|
+
}
|
|
130
|
+
if (isFriction(r)) {
|
|
131
|
+
const resp = frictionResponsibility(r);
|
|
132
|
+
if (resp)
|
|
133
|
+
frictionByResponsibility[resp] = (frictionByResponsibility[resp] ?? 0) + 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
let unverifiedRuns = 0;
|
|
137
|
+
for (const list of byRun.values()) {
|
|
138
|
+
const hasWork = list.some((r) => WORK_RE.test(r.event ?? ""));
|
|
139
|
+
const hasVerify = list.some((r) => VERIFY_RE.test(r.event ?? ""));
|
|
140
|
+
if (hasWork && !hasVerify)
|
|
141
|
+
unverifiedRuns += 1;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
total: records.length,
|
|
145
|
+
orphaned,
|
|
146
|
+
stale,
|
|
147
|
+
unverifiedRuns,
|
|
148
|
+
entropy: shannonEntropy(records),
|
|
149
|
+
repeatedFriction: groupFriction(records).filter((g) => g.count >= 2),
|
|
150
|
+
frictionByResponsibility,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Advisory backlog proposals: repeated friction (≥2) + audit drift findings. Never gates. */
|
|
154
|
+
export function proposeImprovements(audit) {
|
|
155
|
+
const items = [];
|
|
156
|
+
for (const g of audit.repeatedFriction) {
|
|
157
|
+
items.push({ kind: "friction", title: g.message, evidenceCount: g.count, responsibility: g.responsibility });
|
|
158
|
+
}
|
|
159
|
+
if (audit.unverifiedRuns > 0)
|
|
160
|
+
items.push({ kind: "drift", title: "Runs with work but no verification event", evidenceCount: audit.unverifiedRuns });
|
|
161
|
+
if (audit.orphaned > 0)
|
|
162
|
+
items.push({ kind: "drift", title: "Unattributed trace records (no run_id)", evidenceCount: audit.orphaned });
|
|
163
|
+
if (audit.stale > 0)
|
|
164
|
+
items.push({ kind: "drift", title: "Stale trace records", evidenceCount: audit.stale });
|
|
165
|
+
return items;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=trace-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-analysis.js","sourceRoot":"","sources":["../../src/core/trace-analysis.ts"],"names":[],"mappings":"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"}
|