@dsh-cc/advisor-watchdog 0.8.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.js","sourceRoot":"","sources":["../src/delta.ts"],"names":[],"mappings":"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"}
package/lib/guard.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Emission guard (plan docs/plans/2026-09-23-advisor-watchdog.md §4.4),
3
+ * ported from oh-my-pi's advisor emission-guard (Appendix A). Applied in the
4
+ * FIXED order — severity, normalized denylist, quarantine, dedupe, immune
5
+ * window, per-run budget — every drop incrementing its named journal
6
+ * counter. Pure: state is passed in, mutated in place.
7
+ *
8
+ * @module
9
+ */
10
+ import type { Severity } from './settings.ts';
11
+ /**
12
+ * The verbatim omp suppressed-phrase set (omp emission-guard.ts:52-89),
13
+ * pre-normalized. EXACT-SET semantics: substring matching is NOT the design —
14
+ * "Stop." normalizes to `stop` and matches; a genuine blocker like
15
+ * "Stop: 'await' missing on writeStream.end()" must NOT match.
16
+ * 37 entries, copied verbatim.
17
+ */
18
+ export declare const SUPPRESSED_NORMALIZED_PHRASES: Record<string, true>;
19
+ /** omp's exact normalize shape (emission-guard.ts:33-39): lowercase → NFKC → fold non-alphanumeric runs to one space → trim. Unicode-aware (\p{L}/\p{N}): an ASCII-only class would collapse every non-Latin note to one shared fingerprint and make dedupe eat distinct notes. */
20
+ export declare function normalizeAdvisorNote(text: string): string;
21
+ /** The dedupe LRU capacity (omp `DEFAULT_HISTORY_CAPACITY`, 309→92 rationale). */
22
+ export declare const DEDUPE_CAPACITY = 4096;
23
+ /** The named drop counters of the journal (§4.6), verbatim field list. */
24
+ export interface DropCounters {
25
+ denylist: number;
26
+ duplicate: number;
27
+ budget: number;
28
+ immune: number;
29
+ quarantined: number;
30
+ stale: number;
31
+ malformed: number;
32
+ severity: number;
33
+ cursorReset: number;
34
+ sessionCap: number;
35
+ }
36
+ export declare function emptyDrops(): DropCounters;
37
+ /** A note as parsed from the advisor's output. */
38
+ export interface AdvisorNote {
39
+ severity: Severity;
40
+ text: string;
41
+ }
42
+ /** The mutable per-session guard state (§4.4). */
43
+ export interface GuardState {
44
+ /** Flat fingerprint LRU: normalized text → true, `4096` entries. */
45
+ dedupe: Map<string, true>;
46
+ /** Delivered notes this session (the §4.4 session cap). */
47
+ deliveredNotes: number;
48
+ /** Immune-window arm: fresh `concern` notes are dropped while `turnCounter < immuneUntil`. */
49
+ immuneUntil: number;
50
+ }
51
+ export declare function emptyGuardState(): GuardState;
52
+ /** One fingerprint insertion with flat-LRU eviction (oldest insertion order). */
53
+ export declare function rememberFingerprint(state: GuardState, fingerprint: string): void;
54
+ /**
55
+ * Apply the emission guard in its FIXED order (§4.4 steps 1-6; step 7
56
+ * staleness is resolve-time in wiring.ts), mutating `drops` per drop and
57
+ * returning the surviving notes in order.
58
+ * @param turnCounter - the RESOLVE-time turn counter (immune arithmetic).
59
+ * @param delivered - true when this run will actually deliver (guards the
60
+ * immune re-arm decision made by the caller, §4.4 step 5).
61
+ */
62
+ export declare function applyEmissionGuard(state: GuardState, notes: readonly AdvisorNote[], drops: DropCounters, settings: {
63
+ severities: readonly Severity[];
64
+ budget: number;
65
+ }, turnCounter: number): AdvisorNote[];
66
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAUtB,CAAA;AAEzC,mRAAmR;AACnR,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,kFAAkF;AAClF,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,IAAI,YAAY,CAEzC;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACzB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAA;IACtB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAQhF;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE;IAAE,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC7D,WAAW,EAAE,MAAM,GAClB,WAAW,EAAE,CAmDf"}
package/lib/guard.js ADDED
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Emission guard (plan docs/plans/2026-09-23-advisor-watchdog.md §4.4),
3
+ * ported from oh-my-pi's advisor emission-guard (Appendix A). Applied in the
4
+ * FIXED order — severity, normalized denylist, quarantine, dedupe, immune
5
+ * window, per-run budget — every drop incrementing its named journal
6
+ * counter. Pure: state is passed in, mutated in place.
7
+ *
8
+ * @module
9
+ */
10
+ import { quarantineHit } from "./quarantine.js";
11
+ /**
12
+ * The verbatim omp suppressed-phrase set (omp emission-guard.ts:52-89),
13
+ * pre-normalized. EXACT-SET semantics: substring matching is NOT the design —
14
+ * "Stop." normalizes to `stop` and matches; a genuine blocker like
15
+ * "Stop: 'await' missing on writeStream.end()" must NOT match.
16
+ * 37 entries, copied verbatim.
17
+ */
18
+ export const SUPPRESSED_NORMALIZED_PHRASES = Object.fromEntries([
19
+ 'stop', 'stop here', 'stop now', 'halt', 'abort', 'done', 'task done',
20
+ 'task complete', 'complete', 'finished', 'ok', 'okay', 'ok done',
21
+ 'no issue', 'no issues', 'no issue continue', 'no concerns', 'no concern',
22
+ 'nothing to add', 'nothing to flag', 'nothing to report', 'no notes',
23
+ 'no further input', 'no further input needed', 'no further input required',
24
+ 'no further watcher input', 'no further watcher input needed',
25
+ 'no further advice', 'no further advice needed', 'lgtm', 'looks good',
26
+ 'all good', 'agent is on track', 'agent on track', 'on track', 'continue',
27
+ 'carry on',
28
+ ].map(phrase => [phrase, true]));
29
+ /** omp's exact normalize shape (emission-guard.ts:33-39): lowercase → NFKC → fold non-alphanumeric runs to one space → trim. Unicode-aware (\p{L}/\p{N}): an ASCII-only class would collapse every non-Latin note to one shared fingerprint and make dedupe eat distinct notes. */
30
+ export function normalizeAdvisorNote(text) {
31
+ return text.toLowerCase().normalize('NFKC').replace(/[^\p{L}\p{N}]+/gu, ' ').trim();
32
+ }
33
+ /** The dedupe LRU capacity (omp `DEFAULT_HISTORY_CAPACITY`, 309→92 rationale). */
34
+ export const DEDUPE_CAPACITY = 4096;
35
+ export function emptyDrops() {
36
+ return { denylist: 0, duplicate: 0, budget: 0, immune: 0, quarantined: 0, stale: 0, malformed: 0, severity: 0, cursorReset: 0, sessionCap: 0 };
37
+ }
38
+ export function emptyGuardState() {
39
+ return { dedupe: new Map(), deliveredNotes: 0, immuneUntil: 0 };
40
+ }
41
+ /** One fingerprint insertion with flat-LRU eviction (oldest insertion order). */
42
+ export function rememberFingerprint(state, fingerprint) {
43
+ if (state.dedupe.has(fingerprint))
44
+ state.dedupe.delete(fingerprint);
45
+ state.dedupe.set(fingerprint, true);
46
+ while (state.dedupe.size > DEDUPE_CAPACITY) {
47
+ const oldest = state.dedupe.keys().next().value;
48
+ if (oldest === undefined)
49
+ break;
50
+ state.dedupe.delete(oldest);
51
+ }
52
+ }
53
+ /**
54
+ * Apply the emission guard in its FIXED order (§4.4 steps 1-6; step 7
55
+ * staleness is resolve-time in wiring.ts), mutating `drops` per drop and
56
+ * returning the surviving notes in order.
57
+ * @param turnCounter - the RESOLVE-time turn counter (immune arithmetic).
58
+ * @param delivered - true when this run will actually deliver (guards the
59
+ * immune re-arm decision made by the caller, §4.4 step 5).
60
+ */
61
+ export function applyEmissionGuard(state, notes, drops, settings, turnCounter) {
62
+ const survivors = [];
63
+ for (const note of notes) {
64
+ // 1. severity filter.
65
+ if (!settings.severities.includes(note.severity)) {
66
+ drops.severity += 1;
67
+ continue;
68
+ }
69
+ // 2. normalized denylist: exact membership only.
70
+ if (SUPPRESSED_NORMALIZED_PHRASES[normalizeAdvisorNote(note.text)] === true) {
71
+ drops.denylist += 1;
72
+ continue;
73
+ }
74
+ // 3. quarantine (§4.5).
75
+ if (quarantineHit(note.text) !== undefined) {
76
+ drops.quarantined += 1;
77
+ continue;
78
+ }
79
+ // 4. flat dedupe (deliberate deviation from omp: shown at most once
80
+ // regardless of severity — errs toward silence, §4.4).
81
+ const fingerprint = normalizeAdvisorNote(note.text);
82
+ if (state.dedupe.has(fingerprint)) {
83
+ drops.duplicate += 1;
84
+ continue;
85
+ }
86
+ // 5. immune window: only fresh `concern` notes are suppressed; `nit` and
87
+ // `blocker` are unaffected.
88
+ if (note.severity === 'concern' && turnCounter < state.immuneUntil) {
89
+ drops.immune += 1;
90
+ continue;
91
+ }
92
+ survivors.push(note);
93
+ }
94
+ // 6. per-run budget: blockers exempt; excess non-blockers drop.
95
+ let nonBlockers = 0;
96
+ const budgeted = [];
97
+ for (const note of survivors) {
98
+ if (note.severity === 'blocker') {
99
+ budgeted.push(note);
100
+ continue;
101
+ }
102
+ if (nonBlockers >= settings.budget) {
103
+ drops.budget += 1;
104
+ continue;
105
+ }
106
+ nonBlockers += 1;
107
+ budgeted.push(note);
108
+ }
109
+ // Fingerprints are remembered for DELIVERED notes only (the caller moves
110
+ // them into the LRU on delivery success — see wiring.ts).
111
+ return budgeted;
112
+ }
113
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Advisor watchdog (plan docs/plans/2026-09-23-advisor-watchdog.md): an
3
+ * opt-in second model, on its own cheap lane, that reviews the snapshot
4
+ * window of every completed turn (passive `llm/stream` snapshots, captured
5
+ * at `agent/turn-stopping`) and emits severity-tiered notes
6
+ * (`nit | concern | blocker`) the primary agent consumes via a resolve-time
7
+ * `agent.inject()` with source kind `advisor`.
8
+ *
9
+ * Plain plugin (not a Service): `apply(ctx)`, no isolate key. Settings are
10
+ * registered for /config UX only; the listener reads the raw user file per
11
+ * use. Ship-dark: `cc-advisor.enabled` defaults to false.
12
+ *
13
+ * @module @dsh-cc/advisor-watchdog
14
+ */
15
+ import type { Context } from '@deepseek-ai/cordis';
16
+ export { SETTINGS_NAMESPACE, SettingsSchema, DEFAULT_ADVISOR_SETTINGS, registerSettings, readUserSettings, readUserSettingsSync, type AdvisorSettings, type Severity, } from './settings.ts';
17
+ export { INJECTED_SOURCE_DENYLIST, ADVISOR_SOURCE_KIND, MAX_DELTA_BYTES, fullCursor, isGenuineUser, renderDelta, reviewWindow, type Cursor, type DeltaMessage, type ReviewWindow, } from './delta.ts';
18
+ export { DEDUPE_CAPACITY, SUPPRESSED_NORMALIZED_PHRASES, applyEmissionGuard, emptyDrops, emptyGuardState, normalizeAdvisorNote, rememberFingerprint, type AdvisorNote, type DropCounters, type GuardState, } from './guard.ts';
19
+ export { ADVISOR_SYSTEM_PROMPT, parseAdvisorNotes, runAdvisor } from './advise.ts';
20
+ export { quarantineHit } from './quarantine.ts';
21
+ export { appendJournal, journalFileFor, type AdvisorJournalEntry } from './journal.ts';
22
+ export { registerListeners } from './wiring.ts';
23
+ /** Cordis plugin id. */
24
+ export declare const name = "cc-advisor-watchdog";
25
+ /**
26
+ * Cordis lazy-injection declaration: the resolve-time side query reaches
27
+ * `ctx.llm` (runSideQuery → `ctx.llm.stream`) from THIS plugin's context —
28
+ * without `inject: ['llm']`, cordis throws "cannot get property 'llm' without
29
+ * inject" at call time (tool-web-fetch / session-title-provider precedent;
30
+ * verified live in the 2026-09-24 dogfood: every run journaled
31
+ * `reason: 'error'` in 1-2ms until this declaration landed).
32
+ */
33
+ export declare const inject: string[];
34
+ /**
35
+ * Mount the plugin: register the settings namespace and the two listeners.
36
+ * Plain plugin — no Service, no isolate key.
37
+ * @param ctx - the plug context.
38
+ */
39
+ export declare function apply(ctx: Context): void;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,QAAQ,GACd,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,eAAe,EACf,6BAA6B,EAC7B,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,wBAAwB;AACxB,eAAO,MAAM,IAAI,wBAAwB,CAAA;AAEzC;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,UAAU,CAAA;AAE7B;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAIxC"}
package/lib/index.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Advisor watchdog (plan docs/plans/2026-09-23-advisor-watchdog.md): an
3
+ * opt-in second model, on its own cheap lane, that reviews the snapshot
4
+ * window of every completed turn (passive `llm/stream` snapshots, captured
5
+ * at `agent/turn-stopping`) and emits severity-tiered notes
6
+ * (`nit | concern | blocker`) the primary agent consumes via a resolve-time
7
+ * `agent.inject()` with source kind `advisor`.
8
+ *
9
+ * Plain plugin (not a Service): `apply(ctx)`, no isolate key. Settings are
10
+ * registered for /config UX only; the listener reads the raw user file per
11
+ * use. Ship-dark: `cc-advisor.enabled` defaults to false.
12
+ *
13
+ * @module @dsh-cc/advisor-watchdog
14
+ */
15
+ import { registerSettings } from "./settings.js";
16
+ import { registerListeners } from "./wiring.js";
17
+ export { SETTINGS_NAMESPACE, SettingsSchema, DEFAULT_ADVISOR_SETTINGS, registerSettings, readUserSettings, readUserSettingsSync, } from "./settings.js";
18
+ export { INJECTED_SOURCE_DENYLIST, ADVISOR_SOURCE_KIND, MAX_DELTA_BYTES, fullCursor, isGenuineUser, renderDelta, reviewWindow, } from "./delta.js";
19
+ export { DEDUPE_CAPACITY, SUPPRESSED_NORMALIZED_PHRASES, applyEmissionGuard, emptyDrops, emptyGuardState, normalizeAdvisorNote, rememberFingerprint, } from "./guard.js";
20
+ export { ADVISOR_SYSTEM_PROMPT, parseAdvisorNotes, runAdvisor } from "./advise.js";
21
+ export { quarantineHit } from "./quarantine.js";
22
+ export { appendJournal, journalFileFor } from "./journal.js";
23
+ export { registerListeners } from "./wiring.js";
24
+ /** Cordis plugin id. */
25
+ export const name = 'cc-advisor-watchdog';
26
+ /**
27
+ * Cordis lazy-injection declaration: the resolve-time side query reaches
28
+ * `ctx.llm` (runSideQuery → `ctx.llm.stream`) from THIS plugin's context —
29
+ * without `inject: ['llm']`, cordis throws "cannot get property 'llm' without
30
+ * inject" at call time (tool-web-fetch / session-title-provider precedent;
31
+ * verified live in the 2026-09-24 dogfood: every run journaled
32
+ * `reason: 'error'` in 1-2ms until this declaration landed).
33
+ */
34
+ export const inject = ['llm'];
35
+ /**
36
+ * Mount the plugin: register the settings namespace and the two listeners.
37
+ * Plain plugin — no Service, no isolate key.
38
+ * @param ctx - the plug context.
39
+ */
40
+ export function apply(ctx) {
41
+ // /config UX + validation only; the listener reads the raw user file per use.
42
+ registerSettings(ctx);
43
+ registerListeners(ctx);
44
+ }
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GAGrB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,GAIb,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,eAAe,EACf,6BAA6B,EAC7B,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,GAIpB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,cAAc,EAA4B,MAAM,cAAc,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,wBAAwB;AACxB,MAAM,CAAC,MAAM,IAAI,GAAG,qBAAqB,CAAA;AAEzC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAA;AAE7B;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY;IAChC,8EAA8E;IAC9E,gBAAgB,CAAC,GAAG,CAAC,CAAA;IACrB,iBAAiB,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Per-session run journal (plan docs/plans/2026-09-23-advisor-watchdog.md
3
+ * §4.6): one JSON line per actually-attempted run, appended to
4
+ * `$DSH_HOME/advisor/<sessionId>.jsonl` — flat per-session file under
5
+ * `$DSH_HOME` (turn-rules ledger posture: no projectKey segment, fail-soft
6
+ * IO). The journal is dogfood telemetry only; nothing reads it at runtime.
7
+ *
8
+ * Line fields (§4.6, verbatim): ts, turn, alias, model, inheritedRoute, ok,
9
+ * reason, durationMs, deltaMessages, deltaBytes, notesIn, notesOut, drops,
10
+ * usage (reserved, always null in v0 — `SideQueryResult` surfaces no token
11
+ * usage; see §7 open thread).
12
+ *
13
+ * @module
14
+ */
15
+ import type { DropCounters } from './guard.ts';
16
+ /** One journal line, exactly the §4.6 field list. */
17
+ export interface AdvisorJournalEntry {
18
+ ts: number;
19
+ /** capturedTurn at capture time. */
20
+ turn: number;
21
+ alias: string;
22
+ /** The resolveAlias route's model id; null when unrouted, unset, or inherited. */
23
+ model: string | null;
24
+ inheritedRoute: boolean;
25
+ ok: boolean;
26
+ /** On failure only; absent on success (exactOptionalPropertyTypes-safe at the call site via a union). */
27
+ reason: 'unrouted' | 'timeout' | 'error' | 'empty' | undefined;
28
+ durationMs: number;
29
+ deltaMessages: number;
30
+ deltaBytes: number;
31
+ notesIn: number;
32
+ notesOut: number;
33
+ drops: DropCounters;
34
+ /** Reserved: N/A in v0 (§4.6). */
35
+ usage: null;
36
+ }
37
+ /** The journal file for one session. */
38
+ export declare function journalFileFor(dshHome: string, sessionId: string): string;
39
+ /** Append one journal line. Never throws: observability must not poison a listener. */
40
+ export declare function appendJournal(dshHome: string, sessionId: string, entry: AdvisorJournalEntry): Promise<void>;
41
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,kFAAkF;IAClF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,cAAc,EAAE,OAAO,CAAA;IACvB,EAAE,EAAE,OAAO,CAAA;IACb,yGAAyG;IACvG,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,YAAY,CAAA;IACnB,kCAAkC;IAClC,KAAK,EAAE,IAAI,CAAA;CACZ;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,uFAAuF;AACvF,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjH"}
package/lib/journal.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Per-session run journal (plan docs/plans/2026-09-23-advisor-watchdog.md
3
+ * §4.6): one JSON line per actually-attempted run, appended to
4
+ * `$DSH_HOME/advisor/<sessionId>.jsonl` — flat per-session file under
5
+ * `$DSH_HOME` (turn-rules ledger posture: no projectKey segment, fail-soft
6
+ * IO). The journal is dogfood telemetry only; nothing reads it at runtime.
7
+ *
8
+ * Line fields (§4.6, verbatim): ts, turn, alias, model, inheritedRoute, ok,
9
+ * reason, durationMs, deltaMessages, deltaBytes, notesIn, notesOut, drops,
10
+ * usage (reserved, always null in v0 — `SideQueryResult` surfaces no token
11
+ * usage; see §7 open thread).
12
+ *
13
+ * @module
14
+ */
15
+ import { mkdir, appendFile } from 'node:fs/promises';
16
+ import { dirname, join } from 'node:path';
17
+ /** The journal file for one session. */
18
+ export function journalFileFor(dshHome, sessionId) {
19
+ return join(dshHome, 'advisor', `${sessionId}.jsonl`);
20
+ }
21
+ /** Append one journal line. Never throws: observability must not poison a listener. */
22
+ export async function appendJournal(dshHome, sessionId, entry) {
23
+ try {
24
+ const file = journalFileFor(dshHome, sessionId);
25
+ await mkdir(dirname(file), { recursive: true });
26
+ await appendFile(file, `${JSON.stringify(entry)}\n`, 'utf8');
27
+ }
28
+ catch {
29
+ // Dogfood data only; never surface into a hot path.
30
+ }
31
+ }
32
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAyBzC,wCAAwC;AACxC,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,SAAiB;IAC/D,OAAO,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAA;AACvD,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,SAAiB,EAAE,KAA0B;IAChG,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAC/C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/C,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,oDAAoD;IACtD,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Quarantine scan (plan docs/plans/2026-09-23-advisor-watchdog.md §4.5):
3
+ * each surviving note's text is scanned against
4
+ * `DEFAULT_DANGEROUS_PATTERNS` (packages/interaction/permission-rules) before
5
+ * delivery. CAVEAT: those patterns are tuned for shell-command strings, so
6
+ * matching advisory prose is a heuristic — false positives (a note discussing
7
+ * `sudo`) drop safely, which is the correct failure direction.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * The quarantine verdict for one note text: the matched `reason`, or
13
+ * `undefined` when the note passes.
14
+ */
15
+ export declare function quarantineHit(text: string): string | undefined;
16
+ //# sourceMappingURL=quarantine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quarantine.d.ts","sourceRoot":"","sources":["../src/quarantine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK9D"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Quarantine scan (plan docs/plans/2026-09-23-advisor-watchdog.md §4.5):
3
+ * each surviving note's text is scanned against
4
+ * `DEFAULT_DANGEROUS_PATTERNS` (packages/interaction/permission-rules) before
5
+ * delivery. CAVEAT: those patterns are tuned for shell-command strings, so
6
+ * matching advisory prose is a heuristic — false positives (a note discussing
7
+ * `sudo`) drop safely, which is the correct failure direction.
8
+ *
9
+ * @module
10
+ */
11
+ import { DEFAULT_DANGEROUS_PATTERNS } from '@dsh-cc/permission-rules';
12
+ /**
13
+ * The quarantine verdict for one note text: the matched `reason`, or
14
+ * `undefined` when the note passes.
15
+ */
16
+ export function quarantineHit(text) {
17
+ for (const pattern of DEFAULT_DANGEROUS_PATTERNS) {
18
+ if (pattern.regex.test(text))
19
+ return pattern.reason;
20
+ }
21
+ return undefined;
22
+ }
23
+ //# sourceMappingURL=quarantine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quarantine.js","sourceRoot":"","sources":["../src/quarantine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAErE;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,KAAK,MAAM,OAAO,IAAI,0BAA0B,EAAE,CAAC;QACjD,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC,MAAM,CAAA;IACrD,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Settings for the advisor watchdog (plan
3
+ * docs/plans/2026-09-23-advisor-watchdog.md §4.9), two halves — the turn-rules
4
+ * dual-half pattern (packages/interaction/turn-rules/src/settings.ts):
5
+ *
6
+ * 1. namespace registration via `@dsh-cc/settings-ns` (kebab keys, for /config
7
+ * UX and validation only);
8
+ * 2. a RAW user-layer read of `<dshHome>/settings.json` re-read per use, so a
9
+ * turn never depends on cascade timing.
10
+ *
11
+ * Schemastery has no `z.enum`; enum members are expressed as
12
+ * `z.union([z.const(...), ...])`.
13
+ *
14
+ * @module
15
+ */
16
+ import type { Context } from '@deepseek-ai/cordis';
17
+ import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
18
+ import z from '@deepseek-ai/schemastery';
19
+ /** The settings namespace carrying the advisor flags. */
20
+ export declare const SETTINGS_NAMESPACE: SettingsNamespace;
21
+ /** The severity taxonomy (omp advise-tool.ts:20,62-63, kept verbatim). */
22
+ export type Severity = 'nit' | 'concern' | 'blocker';
23
+ /** Resolved settings shape. */
24
+ export interface AdvisorSettings {
25
+ enabled: boolean;
26
+ alias: string;
27
+ budget: number;
28
+ immuneTurns: number;
29
+ sessionCap: number;
30
+ severities: readonly Severity[];
31
+ subagents: 'off' | 'on' | string;
32
+ }
33
+ /**
34
+ * Namespace schema. Wrapped in the z.const(undefined) union (turn-rules
35
+ * convention) so a genuinely absent namespace value stays absent instead of
36
+ * materializing defaults into the cascade.
37
+ */
38
+ export declare const SettingsSchema: z<Record<string, unknown>>;
39
+ /** Ship-dark defaults (§4.8): enabled false. */
40
+ export declare const DEFAULT_ADVISOR_SETTINGS: AdvisorSettings;
41
+ /**
42
+ * Register the settings namespace (for /config UX and validation only —
43
+ * the listener reads the raw user file). Returns the live reader, or
44
+ * `undefined` when the host has no settings provider.
45
+ */
46
+ export declare function registerSettings(ctx: Context): (() => AdvisorSettings) | undefined;
47
+ /**
48
+ * Read the settings DIRECTLY from `<dshHome>/settings.json`, bypassing the
49
+ * merged cascade. Fail-soft: absent file, parse error, or a malformed section
50
+ * yields the ship defaults. Project scope is never read — invisible, not refused.
51
+ */
52
+ export declare function readUserSettings(dshHome: string): Promise<AdvisorSettings>;
53
+ /**
54
+ * SYNCHRONOUS raw read of `<dshHome>/settings.json` — the trigger-side half
55
+ * of the dual-half pattern (§4.9): the `agent/turn-stopping` handler must run
56
+ * synchronously up to capture (a step can begin during the handler's
57
+ * microtasks, and an async read would let the next request's snapshot
58
+ * overwrite the one being reviewed). Same fail-soft semantics as
59
+ * {@link readUserSettings}.
60
+ */
61
+ export declare function readUserSettingsSync(dshHome: string): AdvisorSettings;
62
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAGxC,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,EAAmB,iBAAiB,CAAA;AAEnE,0EAA0E;AAC1E,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAA;AAEpD,+BAA+B;AAC/B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC/B,SAAS,EAAE,KAAK,GAAG,IAAI,GAAG,MAAM,CAAA;CACjC;AAuBD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACQ,CAAA;AAE9D,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,EAAE,eAQtC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,MAAM,eAAe,CAAC,GAAG,SAAS,CAkBlF;AAoBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAqBhF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAqBrE"}