@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.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +36 -0
- package/README.zh.md +38 -0
- package/lib/advise.d.ts +46 -0
- package/lib/advise.d.ts.map +1 -0
- package/lib/advise.js +71 -0
- package/lib/advise.js.map +1 -0
- package/lib/delta.d.ts +80 -0
- package/lib/delta.d.ts.map +1 -0
- package/lib/delta.js +140 -0
- package/lib/delta.js.map +1 -0
- package/lib/guard.d.ts +66 -0
- package/lib/guard.d.ts.map +1 -0
- package/lib/guard.js +113 -0
- package/lib/guard.js.map +1 -0
- package/lib/index.d.ts +40 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +45 -0
- package/lib/index.js.map +1 -0
- package/lib/journal.d.ts +41 -0
- package/lib/journal.d.ts.map +1 -0
- package/lib/journal.js +32 -0
- package/lib/journal.js.map +1 -0
- package/lib/quarantine.d.ts +16 -0
- package/lib/quarantine.d.ts.map +1 -0
- package/lib/quarantine.js +23 -0
- package/lib/quarantine.js.map +1 -0
- package/lib/settings.d.ts +62 -0
- package/lib/settings.d.ts.map +1 -0
- package/lib/settings.js +164 -0
- package/lib/settings.js.map +1 -0
- package/lib/wiring.d.ts +35 -0
- package/lib/wiring.d.ts.map +1 -0
- package/lib/wiring.js +283 -0
- package/lib/wiring.js.map +1 -0
- package/package.json +58 -0
package/lib/delta.js.map
ADDED
|
@@ -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
|
package/lib/guard.js.map
ADDED
|
@@ -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
|
package/lib/index.js.map
ADDED
|
@@ -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"}
|
package/lib/journal.d.ts
ADDED
|
@@ -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"}
|