@vyuhlabs/dxkit 2.12.0 → 2.13.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/CHANGELOG.md +42 -0
- package/README.md +192 -279
- package/dist/baseline/check.d.ts +7 -0
- package/dist/baseline/check.d.ts.map +1 -1
- package/dist/baseline/check.js +3 -1
- package/dist/baseline/check.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +81 -1
- package/dist/cli.js.map +1 -1
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +5 -0
- package/dist/generator.js.map +1 -1
- package/dist/loop/demo.d.ts +11 -0
- package/dist/loop/demo.d.ts.map +1 -0
- package/dist/loop/demo.js +156 -0
- package/dist/loop/demo.js.map +1 -0
- package/dist/loop/doctor.d.ts +37 -0
- package/dist/loop/doctor.d.ts.map +1 -0
- package/dist/loop/doctor.js +294 -0
- package/dist/loop/doctor.js.map +1 -0
- package/dist/loop/ledger-cli.d.ts +7 -0
- package/dist/loop/ledger-cli.d.ts.map +1 -0
- package/dist/loop/ledger-cli.js +95 -0
- package/dist/loop/ledger-cli.js.map +1 -0
- package/dist/loop/ledger.d.ts +95 -0
- package/dist/loop/ledger.d.ts.map +1 -0
- package/dist/loop/ledger.js +201 -0
- package/dist/loop/ledger.js.map +1 -0
- package/dist/loop/policy.d.ts +35 -0
- package/dist/loop/policy.d.ts.map +1 -0
- package/dist/loop/policy.js +151 -0
- package/dist/loop/policy.js.map +1 -0
- package/dist/loop/scaffold.d.ts +26 -0
- package/dist/loop/scaffold.d.ts.map +1 -0
- package/dist/loop/scaffold.js +221 -0
- package/dist/loop/scaffold.js.map +1 -0
- package/dist/loop/stop-gate.d.ts +71 -0
- package/dist/loop/stop-gate.d.ts.map +1 -0
- package/dist/loop/stop-gate.js +295 -0
- package/dist/loop/stop-gate.js.map +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +9 -0
- package/dist/update.js.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/skills/dxkit-config/SKILL.md +17 -0
- package/templates/.claude/skills/dxkit-init/SKILL.md +1 -0
- package/templates/.claude/skills/dxkit-learn/SKILL.md +17 -0
- package/templates/.claude/skills/dxkit-loop/SKILL.md +114 -0
- package/templates/.claude/skills/dxkit-onboard/SKILL.md +2 -0
- package/templates/.claude/skills/dxkit-update/SKILL.md +3 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runLoopLedger = runLoopLedger;
|
|
37
|
+
/**
|
|
38
|
+
* CLI for `vyuh-dxkit loop ledger [show | summarize | clear]`.
|
|
39
|
+
*
|
|
40
|
+
* A thin renderer over the pure ledger functions. The ledger is an
|
|
41
|
+
* audit trail ("what did the loop do?"), not a dashboard, so the output
|
|
42
|
+
* is deliberately plain text (or `--json` for tooling).
|
|
43
|
+
*/
|
|
44
|
+
const logger = __importStar(require("../logger"));
|
|
45
|
+
const ledger_1 = require("./ledger");
|
|
46
|
+
function renderEventLine(e) {
|
|
47
|
+
const verdict = e.allowed ? 'PASS ' : 'BLOCK';
|
|
48
|
+
const cont = e.stop_hook_active ? ' (continuation)' : '';
|
|
49
|
+
const nn = e.allowed ? '' : `, ${e.net_new_findings} net-new`;
|
|
50
|
+
return `${e.timestamp} ${verdict} guardrail=${e.guardrail_status}${nn}${cont}`;
|
|
51
|
+
}
|
|
52
|
+
async function runLoopLedger(cwd, action, opts) {
|
|
53
|
+
const act = action ?? 'show';
|
|
54
|
+
if (act === 'clear') {
|
|
55
|
+
const removed = (0, ledger_1.clearLedger)(cwd);
|
|
56
|
+
if (opts.json) {
|
|
57
|
+
process.stdout.write(JSON.stringify({ cleared: removed }) + '\n');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
logger.info(removed ? 'Loop ledger cleared.' : 'No loop ledger to clear.');
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const events = (0, ledger_1.readLedger)(cwd);
|
|
65
|
+
if (act === 'summarize') {
|
|
66
|
+
const summary = (0, ledger_1.summarizeLedger)(events);
|
|
67
|
+
if (opts.json) {
|
|
68
|
+
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
logger.header('Loop ledger summary');
|
|
72
|
+
logger.info(`Total postflights: ${summary.total}`);
|
|
73
|
+
logger.info(`Allowed (clean stop): ${summary.allowed}`);
|
|
74
|
+
logger.info(`Blocked completions: ${summary.blocked}`);
|
|
75
|
+
logger.info(`Net-new findings blocked: ${summary.netNewBlocked}`);
|
|
76
|
+
logger.info(`Repaired after block: ${summary.repairedAfterBlock}`);
|
|
77
|
+
logger.info(`Unrepaired sessions: ${summary.unrepairedSessions}`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Default: show.
|
|
81
|
+
const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;
|
|
82
|
+
const shown = limit && Number.isFinite(limit) ? events.slice(-limit) : events;
|
|
83
|
+
if (opts.json) {
|
|
84
|
+
process.stdout.write(JSON.stringify(shown, null, 2) + '\n');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (shown.length === 0) {
|
|
88
|
+
logger.info('Loop ledger is empty.');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
logger.header(`Loop ledger (${shown.length}${limit ? ` of ${events.length}` : ''} events)`);
|
|
92
|
+
for (const e of shown)
|
|
93
|
+
process.stdout.write(renderEventLine(e) + '\n');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=ledger-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-cli.js","sourceRoot":"","sources":["../../src/loop/ledger-cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,sCAgDC;AAvED;;;;;;GAMG;AACH,kDAAoC;AACpC,qCAAsF;AAQtF,SAAS,eAAe,CAAC,CAAc;IACrC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,UAAU,CAAC;IAC9D,OAAO,GAAG,CAAC,CAAC,SAAS,KAAK,OAAO,eAAe,CAAC,CAAC,gBAAgB,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;AACnF,CAAC;AAEM,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,MAA0B,EAC1B,IAAuB;IAEvB,MAAM,GAAG,GAAG,MAAM,IAAI,MAAM,CAAC;IAE7B,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,IAAA,oBAAW,EAAC,GAAG,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACpE,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,IAAA,wBAAe,EAAC,MAAM,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;QACvE,OAAO;IACT,CAAC;IAED,iBAAiB;IACjB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,MAAM,KAAK,GAAG,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9E,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC5F,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { LoopPreset } from './policy';
|
|
2
|
+
/** Bump only on a breaking change to the event shape. */
|
|
3
|
+
export declare const LEDGER_SCHEMA_VERSION = 1;
|
|
4
|
+
/** Relative location of the ledger inside a repo. */
|
|
5
|
+
export declare const LEDGER_DIR: string;
|
|
6
|
+
export declare const LEDGER_FILE: string;
|
|
7
|
+
/** Status of a deterministic check at the moment the Stop-gate ran. */
|
|
8
|
+
export type CheckStatus = 'pass' | 'fail' | 'error' | 'not_configured' | 'skipped';
|
|
9
|
+
/**
|
|
10
|
+
* One postflight event. Mirrors the schema in the loop pack spec so
|
|
11
|
+
* the ledger is stable across releases. Optional agent fields are
|
|
12
|
+
* populated when the hook payload carries them (agent teams / subagents).
|
|
13
|
+
*/
|
|
14
|
+
export interface LedgerEvent {
|
|
15
|
+
readonly schema_version: number;
|
|
16
|
+
readonly timestamp: string;
|
|
17
|
+
readonly event: 'Stop';
|
|
18
|
+
readonly session_id: string;
|
|
19
|
+
readonly agent_id?: string;
|
|
20
|
+
readonly agent_type?: string;
|
|
21
|
+
readonly cwd: string;
|
|
22
|
+
readonly branch: string;
|
|
23
|
+
readonly commit: string;
|
|
24
|
+
/** Loop posture in force when the gate ran (`security-only` /
|
|
25
|
+
* `full-debt`). Optional for forward/backward compat — absent on
|
|
26
|
+
* events written before presets existed. */
|
|
27
|
+
readonly preset?: LoopPreset;
|
|
28
|
+
/** Outcome of the dxkit guardrail check. */
|
|
29
|
+
readonly guardrail_status: CheckStatus;
|
|
30
|
+
/** Net-new findings that blocked completion (0 when guardrail passed). */
|
|
31
|
+
readonly net_new_findings: number;
|
|
32
|
+
/** Size of the prior baseline the current scan was diffed against. */
|
|
33
|
+
readonly baseline_findings: number;
|
|
34
|
+
/** Files changed relative to the baseline commit, when derivable. */
|
|
35
|
+
readonly files_changed: number;
|
|
36
|
+
/**
|
|
37
|
+
* Whether THIS event blocked the loop from stopping. A blocked event
|
|
38
|
+
* is the durable record of "the loop tried to declare done while
|
|
39
|
+
* unsafe." `allowed: true` events are clean completions (or a
|
|
40
|
+
* non-blocking allow after an un-fixable config error).
|
|
41
|
+
*/
|
|
42
|
+
readonly allowed: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* True when Claude was already continuing because a prior Stop-gate
|
|
45
|
+
* blocked this turn (the Claude Code `stop_hook_active` flag). Lets
|
|
46
|
+
* the summary distinguish "repaired on first try" from "needed N
|
|
47
|
+
* continuations."
|
|
48
|
+
*/
|
|
49
|
+
readonly stop_hook_active: boolean;
|
|
50
|
+
readonly tests_status: CheckStatus;
|
|
51
|
+
readonly lint_status: CheckStatus;
|
|
52
|
+
readonly typecheck_status: CheckStatus;
|
|
53
|
+
readonly duration_ms: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fill in the repo-derived fields (branch, commit) and stamp the
|
|
57
|
+
* schema version + timestamp, so callers only supply the outcome.
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildLedgerEvent(cwd: string, fields: Omit<LedgerEvent, 'schema_version' | 'timestamp' | 'event' | 'branch' | 'commit'> & Partial<Pick<LedgerEvent, 'branch' | 'commit'>>): LedgerEvent;
|
|
60
|
+
/**
|
|
61
|
+
* Append one event to the ledger. Creates `.dxkit/loop/` on demand.
|
|
62
|
+
* Best-effort: a ledger write must never abort the Stop-gate (the
|
|
63
|
+
* gate's verdict matters more than its audit line), so failures are
|
|
64
|
+
* swallowed and reported via the return value.
|
|
65
|
+
*/
|
|
66
|
+
export declare function appendLedgerEvent(cwd: string, event: LedgerEvent): boolean;
|
|
67
|
+
/** Read every ledger event. Returns [] when the ledger is absent. */
|
|
68
|
+
export declare function readLedger(cwd: string): LedgerEvent[];
|
|
69
|
+
/** Remove the ledger file. Returns true when a file was deleted. */
|
|
70
|
+
export declare function clearLedger(cwd: string): boolean;
|
|
71
|
+
export interface LedgerSummary {
|
|
72
|
+
readonly total: number;
|
|
73
|
+
readonly allowed: number;
|
|
74
|
+
readonly blocked: number;
|
|
75
|
+
/** Total net-new findings across all blocked events. */
|
|
76
|
+
readonly netNewBlocked: number;
|
|
77
|
+
/**
|
|
78
|
+
* Sessions where a blocked Stop was later followed by a clean
|
|
79
|
+
* (allowed, guardrail-pass) Stop — i.e. the agent repaired the
|
|
80
|
+
* net-new findings after being blocked. The headline "repair-after-
|
|
81
|
+
* block" metric for the Loop-Safety study.
|
|
82
|
+
*/
|
|
83
|
+
readonly repairedAfterBlock: number;
|
|
84
|
+
/** Sessions that were blocked at least once and never repaired. */
|
|
85
|
+
readonly unrepairedSessions: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Reduce a list of events to the audit-trail summary. Repair detection
|
|
89
|
+
* is per-session: a session counts as "repaired" if it has at least one
|
|
90
|
+
* blocked event AND a strictly-later allowed event with a passing
|
|
91
|
+
* guardrail. Order is taken from event position (the ledger is
|
|
92
|
+
* append-only, so file order is chronological).
|
|
93
|
+
*/
|
|
94
|
+
export declare function summarizeLedger(events: ReadonlyArray<LedgerEvent>): LedgerSummary;
|
|
95
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/loop/ledger.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,yDAAyD;AACzD,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,qDAAqD;AACrD,eAAO,MAAM,UAAU,QAA8B,CAAC;AACtD,eAAO,MAAM,WAAW,QAAwC,CAAC;AAEjE,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAAC;AAEnF;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;iDAE6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AA4BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,GACvF,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC,GAChD,WAAW,CASb;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAS1E;AAED,qEAAqE;AACrE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAqBrD;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOhD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,mEAAmE;IACnE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,aAAa,CAuCjF"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LEDGER_FILE = exports.LEDGER_DIR = exports.LEDGER_SCHEMA_VERSION = void 0;
|
|
37
|
+
exports.buildLedgerEvent = buildLedgerEvent;
|
|
38
|
+
exports.appendLedgerEvent = appendLedgerEvent;
|
|
39
|
+
exports.readLedger = readLedger;
|
|
40
|
+
exports.clearLedger = clearLedger;
|
|
41
|
+
exports.summarizeLedger = summarizeLedger;
|
|
42
|
+
/**
|
|
43
|
+
* Loop ledger — an append-only audit trail of postflight (Stop-gate)
|
|
44
|
+
* events for autonomous coding loops.
|
|
45
|
+
*
|
|
46
|
+
* Every time the Stop-gate runs (whether it allows the loop to stop or
|
|
47
|
+
* blocks it on net-new findings), it appends one line to
|
|
48
|
+
* `.dxkit/loop/ledger.jsonl`. The ledger answers "what did the loop
|
|
49
|
+
* actually do?" — how many completions were blocked, how many net-new
|
|
50
|
+
* findings, and whether the agent repaired after a block.
|
|
51
|
+
*
|
|
52
|
+
* This is deliberately NOT a dashboard. It is a flat JSONL file so a
|
|
53
|
+
* loop can write to it from any process without coordination, and a
|
|
54
|
+
* human (or a benchmark harness) can `cat` / `jq` it directly.
|
|
55
|
+
*/
|
|
56
|
+
const child_process_1 = require("child_process");
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const path = __importStar(require("path"));
|
|
59
|
+
/** Bump only on a breaking change to the event shape. */
|
|
60
|
+
exports.LEDGER_SCHEMA_VERSION = 1;
|
|
61
|
+
/** Relative location of the ledger inside a repo. */
|
|
62
|
+
exports.LEDGER_DIR = path.join('.dxkit', 'loop');
|
|
63
|
+
exports.LEDGER_FILE = path.join(exports.LEDGER_DIR, 'ledger.jsonl');
|
|
64
|
+
/** Best-effort current branch; empty string when not derivable. */
|
|
65
|
+
function gitBranch(cwd) {
|
|
66
|
+
try {
|
|
67
|
+
return (0, child_process_1.execFileSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
68
|
+
cwd,
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
71
|
+
}).trim();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Best-effort current commit SHA; empty string when not derivable. */
|
|
78
|
+
function gitCommit(cwd) {
|
|
79
|
+
try {
|
|
80
|
+
return (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], {
|
|
81
|
+
cwd,
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
84
|
+
}).trim();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Fill in the repo-derived fields (branch, commit) and stamp the
|
|
92
|
+
* schema version + timestamp, so callers only supply the outcome.
|
|
93
|
+
*/
|
|
94
|
+
function buildLedgerEvent(cwd, fields) {
|
|
95
|
+
return {
|
|
96
|
+
schema_version: exports.LEDGER_SCHEMA_VERSION,
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
event: 'Stop',
|
|
99
|
+
branch: fields.branch ?? gitBranch(cwd),
|
|
100
|
+
commit: fields.commit ?? gitCommit(cwd),
|
|
101
|
+
...fields,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Append one event to the ledger. Creates `.dxkit/loop/` on demand.
|
|
106
|
+
* Best-effort: a ledger write must never abort the Stop-gate (the
|
|
107
|
+
* gate's verdict matters more than its audit line), so failures are
|
|
108
|
+
* swallowed and reported via the return value.
|
|
109
|
+
*/
|
|
110
|
+
function appendLedgerEvent(cwd, event) {
|
|
111
|
+
try {
|
|
112
|
+
const dir = path.join(cwd, exports.LEDGER_DIR);
|
|
113
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
114
|
+
fs.appendFileSync(path.join(cwd, exports.LEDGER_FILE), JSON.stringify(event) + '\n', 'utf8');
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Read every ledger event. Returns [] when the ledger is absent. */
|
|
122
|
+
function readLedger(cwd) {
|
|
123
|
+
const file = path.join(cwd, exports.LEDGER_FILE);
|
|
124
|
+
let raw;
|
|
125
|
+
try {
|
|
126
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
const out = [];
|
|
132
|
+
for (const line of raw.split('\n')) {
|
|
133
|
+
const trimmed = line.trim();
|
|
134
|
+
if (!trimmed)
|
|
135
|
+
continue;
|
|
136
|
+
try {
|
|
137
|
+
out.push(JSON.parse(trimmed));
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Skip a corrupt line rather than failing the whole read — the
|
|
141
|
+
// ledger is append-only and a partial write shouldn't blind the
|
|
142
|
+
// summary to every other event.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
/** Remove the ledger file. Returns true when a file was deleted. */
|
|
148
|
+
function clearLedger(cwd) {
|
|
149
|
+
try {
|
|
150
|
+
fs.rmSync(path.join(cwd, exports.LEDGER_FILE));
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Reduce a list of events to the audit-trail summary. Repair detection
|
|
159
|
+
* is per-session: a session counts as "repaired" if it has at least one
|
|
160
|
+
* blocked event AND a strictly-later allowed event with a passing
|
|
161
|
+
* guardrail. Order is taken from event position (the ledger is
|
|
162
|
+
* append-only, so file order is chronological).
|
|
163
|
+
*/
|
|
164
|
+
function summarizeLedger(events) {
|
|
165
|
+
let allowed = 0;
|
|
166
|
+
let blocked = 0;
|
|
167
|
+
let netNewBlocked = 0;
|
|
168
|
+
// Per-session timeline of (blocked?, repaired?) — repaired means a
|
|
169
|
+
// clean allowed+pass event appeared after the session's first block.
|
|
170
|
+
const blockedAt = new Map(); // session → index of first block
|
|
171
|
+
const repairedSessions = new Set();
|
|
172
|
+
const blockedSessions = new Set();
|
|
173
|
+
events.forEach((e, idx) => {
|
|
174
|
+
if (e.allowed)
|
|
175
|
+
allowed++;
|
|
176
|
+
else {
|
|
177
|
+
blocked++;
|
|
178
|
+
netNewBlocked += e.net_new_findings;
|
|
179
|
+
}
|
|
180
|
+
const sid = e.session_id || '(unknown)';
|
|
181
|
+
if (!e.allowed) {
|
|
182
|
+
blockedSessions.add(sid);
|
|
183
|
+
if (!blockedAt.has(sid))
|
|
184
|
+
blockedAt.set(sid, idx);
|
|
185
|
+
}
|
|
186
|
+
else if (e.guardrail_status === 'pass' &&
|
|
187
|
+
blockedAt.has(sid) &&
|
|
188
|
+
idx > blockedAt.get(sid)) {
|
|
189
|
+
repairedSessions.add(sid);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
total: events.length,
|
|
194
|
+
allowed,
|
|
195
|
+
blocked,
|
|
196
|
+
netNewBlocked,
|
|
197
|
+
repairedAfterBlock: repairedSessions.size,
|
|
198
|
+
unrepairedSessions: [...blockedSessions].filter((s) => !repairedSessions.has(s)).length,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/loop/ledger.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0GA,4CAaC;AAQD,8CASC;AAGD,gCAqBC;AAGD,kCAOC;AA0BD,0CAuCC;AA3OD;;;;;;;;;;;;;GAaG;AACH,iDAA6C;AAC7C,uCAAyB;AACzB,2CAA6B;AAG7B,yDAAyD;AAC5C,QAAA,qBAAqB,GAAG,CAAC,CAAC;AAEvC,qDAAqD;AACxC,QAAA,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACzC,QAAA,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAU,EAAE,cAAc,CAAC,CAAC;AAoDjE,mEAAmE;AACnE,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE;YAChE,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE;YAChD,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAC9B,GAAW,EACX,MACiD;IAEjD,OAAO;QACL,cAAc,EAAE,6BAAqB;QACrC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,CAAC;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,CAAC;QACvC,GAAG,MAAM;KACV,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,GAAW,EAAE,KAAkB;IAC/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAU,CAAC,CAAC;QACvC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,SAAgB,UAAU,CAAC,GAAW;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAW,CAAC,CAAC;IACzC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,gEAAgE;YAChE,gCAAgC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oEAAoE;AACpE,SAAgB,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAW,CAAC,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAmBD;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,MAAkC;IAChE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,mEAAmE;IACnE,qEAAqE;IACrE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAC,iCAAiC;IAC9E,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QACxB,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;aACpB,CAAC;YACJ,OAAO,EAAE,CAAC;YACV,aAAa,IAAI,CAAC,CAAC,gBAAgB,CAAC;QACtC,CAAC;QAED,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,IAAI,WAAW,CAAC;QACxC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACf,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;aAAM,IACL,CAAC,CAAC,gBAAgB,KAAK,MAAM;YAC7B,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;YAClB,GAAG,GAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAY,EACpC,CAAC;YACD,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,OAAO;QACP,OAAO;QACP,aAAa;QACb,kBAAkB,EAAE,gBAAgB,CAAC,IAAI;QACzC,kBAAkB,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;KACxF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type BrownfieldPolicy } from '../baseline/policy';
|
|
2
|
+
/**
|
|
3
|
+
* The two shipped loop postures.
|
|
4
|
+
* - `security-only` (default): block only on net-new secrets + crit/high
|
|
5
|
+
* security + crit/high reachable dependency vulns. test-gap + quality
|
|
6
|
+
* are NOT blocked — they warn. Cost-bounded; safe to run unattended.
|
|
7
|
+
* - `full-debt`: block on every net-new finding (adds test-gap +
|
|
8
|
+
* quality). Exhaustive but can drive an open-ended repair; opt-in.
|
|
9
|
+
*/
|
|
10
|
+
export type LoopPreset = 'security-only' | 'full-debt';
|
|
11
|
+
/** The cost-bounded default — the posture an unattended loop gets unless
|
|
12
|
+
* the repo explicitly opts into `full-debt`. */
|
|
13
|
+
export declare const DEFAULT_LOOP_PRESET: LoopPreset;
|
|
14
|
+
/** Resolved loop posture: the policy the Stop-gate hands to the guardrail,
|
|
15
|
+
* plus the preset name that produced it (recorded in the ledger). */
|
|
16
|
+
export interface ResolvedLoopPolicy {
|
|
17
|
+
readonly policy: BrownfieldPolicy;
|
|
18
|
+
readonly preset: LoopPreset;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the active loop preset. Precedence (mirrors the other
|
|
22
|
+
* `DXKIT_LOOP_*` knobs the Stop-gate already honours):
|
|
23
|
+
* 1. `DXKIT_LOOP_PRESET` env var (benchmark / CI override).
|
|
24
|
+
* 2. `.dxkit/policy.json` → `loop.preset`.
|
|
25
|
+
* 3. `DEFAULT_LOOP_PRESET` (`security-only`).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveLoopPreset(cwd: string): LoopPreset;
|
|
28
|
+
/**
|
|
29
|
+
* Build the loop-scoped policy: the repo's base `BrownfieldPolicy`
|
|
30
|
+
* (confidence thresholds, baseline mode, drift handling preserved) with
|
|
31
|
+
* its `block` list + `blockRules` REPLACED by the active preset's. Only
|
|
32
|
+
* the Stop-gate calls this — see the scope note at the top of the file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveLoopPolicy(cwd: string): ResolvedLoopPolicy;
|
|
35
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/loop/policy.ts"],"names":[],"mappings":"AA0BA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,WAAW,CAAC;AAEvD;iDACiD;AACjD,eAAO,MAAM,mBAAmB,EAAE,UAA4B,CAAC;AA8C/D;sEACsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAuBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAIzD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAYjE"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DEFAULT_LOOP_PRESET = void 0;
|
|
37
|
+
exports.resolveLoopPreset = resolveLoopPreset;
|
|
38
|
+
exports.resolveLoopPolicy = resolveLoopPolicy;
|
|
39
|
+
/**
|
|
40
|
+
* Loop policy presets — a curated blocking posture scoped to autonomous
|
|
41
|
+
* coding loops ONLY.
|
|
42
|
+
*
|
|
43
|
+
* ──────────────────────────────────────────────────────────────────────
|
|
44
|
+
* SCOPE: this layer is read by exactly one consumer — the Stop-gate
|
|
45
|
+
* (`src/loop/stop-gate.ts`). The CI / PR guardrail (`vyuh-dxkit baseline
|
|
46
|
+
* check`) and `createBaseline` resolve the shared `BrownfieldPolicy`
|
|
47
|
+
* directly via `resolvePolicy` and NEVER read `loop.preset`. So setting a
|
|
48
|
+
* preset changes how an unattended loop blocks WITHOUT silently
|
|
49
|
+
* downgrading a repo's CI posture. The `loop.*` namespace in
|
|
50
|
+
* `.dxkit/policy.json` and the `Loop`-prefixed names here both signal
|
|
51
|
+
* that boundary.
|
|
52
|
+
* ──────────────────────────────────────────────────────────────────────
|
|
53
|
+
*
|
|
54
|
+
* Why a loop-only posture exists: in CI a guardrail block just fails a
|
|
55
|
+
* check a human then reads — blocking on every debt class (test-gap,
|
|
56
|
+
* quality) is fine. In a loop a block instead FEEDS THE MODEL a repair
|
|
57
|
+
* instruction, so blocking on open-ended debt makes the agent grind on it
|
|
58
|
+
* unattended (writing tests / refactoring until the gap closes), which is
|
|
59
|
+
* expensive and unbounded. The default loop posture therefore blocks only
|
|
60
|
+
* on the unambiguous, must-fix security class; the open-ended debt classes
|
|
61
|
+
* are an explicit opt-in.
|
|
62
|
+
*/
|
|
63
|
+
const fs = __importStar(require("fs"));
|
|
64
|
+
const path = __importStar(require("path"));
|
|
65
|
+
const policy_1 = require("../baseline/policy");
|
|
66
|
+
/** The cost-bounded default — the posture an unattended loop gets unless
|
|
67
|
+
* the repo explicitly opts into `full-debt`. */
|
|
68
|
+
exports.DEFAULT_LOOP_PRESET = 'security-only';
|
|
69
|
+
/** The security class: secrets, crit/high SAST, crit/high reachable dep
|
|
70
|
+
* vulns. Shared by both presets — full-debt is this plus the debt rules. */
|
|
71
|
+
const SECURITY_BLOCK_RULES = {
|
|
72
|
+
newSecret: true,
|
|
73
|
+
newCriticalSecurity: true,
|
|
74
|
+
newHighSecurity: true,
|
|
75
|
+
newCriticalDependencyVulnerability: true,
|
|
76
|
+
newHighReachableDependencyVulnerability: true,
|
|
77
|
+
// Open-ended debt — OFF in security-only (warn, never block in a loop).
|
|
78
|
+
newUntestedChangedSource: false,
|
|
79
|
+
newSevereQualityIssueInChangedFiles: false,
|
|
80
|
+
};
|
|
81
|
+
const PRESETS = Object.freeze({
|
|
82
|
+
'security-only': {
|
|
83
|
+
// Empty generic block list: nothing auto-blocks by status alone, so
|
|
84
|
+
// test-gap + quality net-new findings warn but never block the loop.
|
|
85
|
+
// Blocking comes solely from SECURITY_BLOCK_RULES.
|
|
86
|
+
block: [],
|
|
87
|
+
blockRules: SECURITY_BLOCK_RULES,
|
|
88
|
+
},
|
|
89
|
+
'full-debt': {
|
|
90
|
+
// Any net-new finding blocks (generic `added`), plus every escalation.
|
|
91
|
+
block: ['added'],
|
|
92
|
+
blockRules: {
|
|
93
|
+
...SECURITY_BLOCK_RULES,
|
|
94
|
+
newUntestedChangedSource: true,
|
|
95
|
+
newSevereQualityIssueInChangedFiles: true,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
function isLoopPreset(v) {
|
|
100
|
+
return v === 'security-only' || v === 'full-debt';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Read `loop.preset` from `.dxkit/policy.json`. Best-effort: a missing /
|
|
104
|
+
* malformed file or absent `loop` block yields `undefined` so the caller
|
|
105
|
+
* falls back to the default. Read here (not via `resolvePolicy`) so the
|
|
106
|
+
* loop concept stays out of the shared `BrownfieldPolicy` schema.
|
|
107
|
+
*/
|
|
108
|
+
function readPresetFromPolicyFile(cwd) {
|
|
109
|
+
try {
|
|
110
|
+
const raw = fs.readFileSync(path.join(cwd, policy_1.DEFAULT_POLICY_FILENAME), 'utf8');
|
|
111
|
+
const parsed = JSON.parse(raw);
|
|
112
|
+
const preset = parsed.loop?.preset;
|
|
113
|
+
return isLoopPreset(preset) ? preset : undefined;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolve the active loop preset. Precedence (mirrors the other
|
|
121
|
+
* `DXKIT_LOOP_*` knobs the Stop-gate already honours):
|
|
122
|
+
* 1. `DXKIT_LOOP_PRESET` env var (benchmark / CI override).
|
|
123
|
+
* 2. `.dxkit/policy.json` → `loop.preset`.
|
|
124
|
+
* 3. `DEFAULT_LOOP_PRESET` (`security-only`).
|
|
125
|
+
*/
|
|
126
|
+
function resolveLoopPreset(cwd) {
|
|
127
|
+
const env = process.env.DXKIT_LOOP_PRESET;
|
|
128
|
+
if (isLoopPreset(env))
|
|
129
|
+
return env;
|
|
130
|
+
return readPresetFromPolicyFile(cwd) ?? exports.DEFAULT_LOOP_PRESET;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Build the loop-scoped policy: the repo's base `BrownfieldPolicy`
|
|
134
|
+
* (confidence thresholds, baseline mode, drift handling preserved) with
|
|
135
|
+
* its `block` list + `blockRules` REPLACED by the active preset's. Only
|
|
136
|
+
* the Stop-gate calls this — see the scope note at the top of the file.
|
|
137
|
+
*/
|
|
138
|
+
function resolveLoopPolicy(cwd) {
|
|
139
|
+
const base = (0, policy_1.resolvePolicy)(undefined, cwd);
|
|
140
|
+
const preset = resolveLoopPreset(cwd);
|
|
141
|
+
const def = PRESETS[preset];
|
|
142
|
+
return {
|
|
143
|
+
preset,
|
|
144
|
+
policy: {
|
|
145
|
+
...base,
|
|
146
|
+
block: def.block,
|
|
147
|
+
blockRules: def.blockRules,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/loop/policy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+HA,8CAIC;AAQD,8CAYC;AAvJD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,uCAAyB;AACzB,2CAA6B;AAC7B,+CAK4B;AAa5B;iDACiD;AACpC,QAAA,mBAAmB,GAAe,eAAe,CAAC;AAc/D;6EAC6E;AAC7E,MAAM,oBAAoB,GAAyB;IACjD,SAAS,EAAE,IAAI;IACf,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,IAAI;IACrB,kCAAkC,EAAE,IAAI;IACxC,uCAAuC,EAAE,IAAI;IAC7C,wEAAwE;IACxE,wBAAwB,EAAE,KAAK;IAC/B,mCAAmC,EAAE,KAAK;CAC3C,CAAC;AAEF,MAAM,OAAO,GAA4C,MAAM,CAAC,MAAM,CAAC;IACrE,eAAe,EAAE;QACf,oEAAoE;QACpE,qEAAqE;QACrE,mDAAmD;QACnD,KAAK,EAAE,EAAE;QACT,UAAU,EAAE,oBAAoB;KACjC;IACD,WAAW,EAAE;QACX,uEAAuE;QACvE,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,UAAU,EAAE;YACV,GAAG,oBAAoB;YACvB,wBAAwB,EAAE,IAAI;YAC9B,mCAAmC,EAAE,IAAI;SAC1C;KACF;CACF,CAAC,CAAC;AASH,SAAS,YAAY,CAAC,CAAU;IAC9B,OAAO,CAAC,KAAK,eAAe,IAAI,CAAC,KAAK,WAAW,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,SAAS,wBAAwB,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gCAAuB,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoC,CAAC;QAClE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;QACnC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,GAAW;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC1C,IAAI,YAAY,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAClC,OAAO,wBAAwB,CAAC,GAAG,CAAC,IAAI,2BAAmB,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,IAAA,sBAAa,EAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO;QACL,MAAM;QACN,MAAM,EAAE;YACN,GAAG,IAAI;YACP,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,UAAU,EAAE,GAAG,CAAC,UAAU;SAC3B;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ShipInstallResult } from '../ship-installers';
|
|
2
|
+
import { type LoopPreset } from './policy';
|
|
3
|
+
/** The command Claude Code runs on Stop. Kept in one place so the
|
|
4
|
+
* installer, doctor, and any future tooling agree on the exact string. */
|
|
5
|
+
export declare const STOP_HOOK_COMMAND = "npx vyuh-dxkit hook stop-gate";
|
|
6
|
+
interface LoopScaffoldOpts {
|
|
7
|
+
/**
|
|
8
|
+
* Explicit loop posture to write into `.dxkit/policy.json`. When set
|
|
9
|
+
* (init with `--loop-preset`), it OVERRIDES any existing preset. When
|
|
10
|
+
* omitted (bare init re-run, or update), an existing preset is PRESERVED
|
|
11
|
+
* and `security-only` is seeded only if none exists — so an upgrade
|
|
12
|
+
* never silently resets a user's chosen posture.
|
|
13
|
+
*/
|
|
14
|
+
readonly preset?: LoopPreset;
|
|
15
|
+
}
|
|
16
|
+
/** True when `.claude/settings.json` already registers the Stop-gate. Used
|
|
17
|
+
* by `update`'s install-flag detection so an upgrade refreshes the loop
|
|
18
|
+
* surface only on repos that opted into it. */
|
|
19
|
+
export declare function isClaudeLoopInstalled(cwd: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Scaffold the loop pack into `cwd`. Additive + idempotent: safe to run on
|
|
22
|
+
* a fresh repo or re-run on one that already has settings/CLAUDE.md/policy.
|
|
23
|
+
*/
|
|
24
|
+
export declare function installClaudeLoop(cwd: string, opts?: LoopScaffoldOpts): ShipInstallResult;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/loop/scaffold.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAEhE;2EAC2E;AAC3E,eAAO,MAAM,iBAAiB,kCAAkC,CAAC;AA0BjE,UAAU,gBAAgB;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC9B;AAWD;;gDAEgD;AAChD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAY1D;AA2ID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,iBAAiB,CAM7F"}
|