{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../../src/extensions/core/prompt-reactive/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,uEAAuE;AACvE,MAAM,WAAW,UAAU;IAC1B,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;CAChB;AAiDD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAErD;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,IAAI,UAAU,EAAE,CAElD;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,EAAE,CAG9E;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOpE","sourcesContent":["/**\n * Prompt-reactive reuse policy — the single source of truth for the runtime\n * \"plugin reuse nudge\".\n *\n * The plugin-productivity guidance in `core/tools/plugins.ts` and\n * `core/tools/propose-plugin.ts` ships as static `promptGuidelines` folded into\n * the system prompt once at session build. That text is never re-surfaced when\n * the work actually shows an actionable cue, so the model tends to repeat the\n * same advice by hand instead of reaching for the plugin layer.\n *\n * This module holds the reactive policy that fixes that:\n *   - {@link REUSE_NUDGES}       the curated cue → nudge table\n *   - {@link matchReuseNudges}   scan runtime text (tool output, turn text) for cues\n *   - the armed registry         nudges that fired this process, so the plugin\n *                                layer can surface them even when no tool asked\n *   - {@link isAutonomousPluginSystemEnabled}\n *                                the one enablement gate shared with the\n *                                tool-attach path in main.ts (settings.json\n *                                `enablePluginTools`)\n *\n * The extension in `./nudges.ts` wires this policy to tool/turn events; the\n * policy itself stays pure and independently testable.\n *\n * Conservative by construction: the patterns are specific (a false positive\n * becoming a nag is the real risk), each nudge fires at most once per category\n * per session, and every nudge points back at the plugin layer rather than\n * re-stating advice.\n */\n\nimport { getAgentDir } from \"../../../config.js\";\nimport { SettingsManager } from \"../../../core/settings-manager.js\";\n\n/** A single reactive reuse cue and the plugin-facing nudge it arms. */\nexport interface ReuseNudge {\n\t/** Stable id, also used as the de-dupe key so a nudge fires once per session. */\n\tid: string;\n\t/** Human-facing category label (grouping for the one-per-category cap). */\n\tcategory: string;\n\t/** Specific cue matched against runtime text. Kept tight to avoid false positives. */\n\tpattern: RegExp;\n\t/** The reusable-facing note injected into the turn; always points at the plugin layer. */\n\tsnippet: string;\n}\n\n/**\n * Curated cue → nudge table. Seeded from the static plugin-reuse guidance, but\n * keyed on concrete cues that show up in real work (style/policy directives,\n * format standardization, explicit capability gaps). Patterns are deliberately\n * specific — first-hit arming (see nudges.ts) only stays safe if the cue is\n * unambiguous.\n */\nconst REUSE_NUDGES: readonly ReuseNudge[] = [\n\t{\n\t\tid: \"style-active-voice\",\n\t\tcategory: \"writing-style\",\n\t\tpattern: /\\b(?:in\\s+)?active voice\\b|\\bavoid(?:ing)?\\s+passive voice\\b/i,\n\t\tsnippet:\n\t\t\t'A writing-style rule is in play (\"active voice\"). If this is a recurring convention, it can live as a reusable skill/command instead of being re-applied by hand — SearchPlugins for one, or author it with ProposePlugin.',\n\t},\n\t{\n\t\tid: \"style-avoid-repetition\",\n\t\tcategory: \"writing-style\",\n\t\tpattern: /\\bavoid(?:ing)?\\s+repetition\\b|\\bdon['’]?t\\s+repeat\\b|\\bavoid\\s+repeat(?:ing|s)?\\b/i,\n\t\tsnippet:\n\t\t\t'A writing-style rule is in play (\"avoid repetition\"). A reusable skill/command can encode this convention rather than restating it each time — SearchPlugins for one, or author it with ProposePlugin.',\n\t},\n\t{\n\t\tid: \"format-prefer-json\",\n\t\tcategory: \"output-format\",\n\t\tpattern: /\\bprefer\\s+JSON\\b|\\buse\\s+JSON\\b|\\boutput\\s+(?:as\\s+)?JSON\\b|\\breturn\\s+(?:as\\s+)?JSON\\b/i,\n\t\tsnippet:\n\t\t\t\"An output-format convention is in play (JSON). Standardizing a format is exactly the kind of thing a reusable skill/plugin captures — SearchPlugins for one, or author it with ProposePlugin.\",\n\t},\n\t{\n\t\tid: \"capability-gap\",\n\t\tcategory: \"capability-gap\",\n\t\tpattern: /\\bcapability gap\\b|\\bno tool for\\b|\\blacks? a tool\\b|\\bwish (?:I|we) had a tool\\b/i,\n\t\tsnippet:\n\t\t\t\"This reads like a capability gap. Before hand-rolling it, SearchPlugins for a plugin that fills it (installable and usable this same turn), or author one with ProposePlugin.\",\n\t},\n];\n\n// ── Armed registry (process-scoped) ──────────────────────────────────────────\n//\n// When a nudge fires, its id is recorded here so the plugin layer (SearchPlugins)\n// can surface \"there is already a reuse candidate for this work\" even if the\n// model never explicitly asked. The CLI is single-process per session, so a\n// module-level set is the natural home; nudges.ts clears it on session start.\n\nconst armed = new Map<string, ReuseNudge>();\n\n/** Record that a nudge fired this session so the plugin layer can surface it. */\nexport function armReuseNudge(nudge: ReuseNudge): void {\n\tarmed.set(nudge.id, nudge);\n}\n\n/** Reuse nudges that have fired this session, in insertion order. */\nexport function getArmedReuseNudges(): ReuseNudge[] {\n\treturn [...armed.values()];\n}\n\n/** Reset the armed registry (called on session start). */\nexport function clearArmedReuseNudges(): void {\n\tarmed.clear();\n}\n\n/**\n * Scan a blob of runtime text (tool output, turn text, user prompt) and return\n * every reuse nudge whose cue matches. Pure — arming/de-duping is the caller's\n * job.\n */\nexport function matchReuseNudges(text: string | undefined | null): ReuseNudge[] {\n\tif (!text) return [];\n\treturn REUSE_NUDGES.filter((n) => n.pattern.test(text));\n}\n\n/**\n * The one enablement gate for the whole autonomous plugin system.\n *\n * Reads settings.json `enablePluginTools` (default false) — the same setting\n * that gates whether the plugin lifecycle tools are attached to the top-level\n * agent in main.ts. Keeping both the tool surface and the reactive nudge behind\n * a single flag is the \"whole autonomous plugin system, off by default\" switch.\n */\nexport function isAutonomousPluginSystemEnabled(cwd: string): boolean {\n\ttry {\n\t\treturn SettingsManager.create(cwd, getAgentDir()).getEnablePluginTools();\n\t} catch {\n\t\t// Fail closed: if settings can't be read, treat the autonomous system as off.\n\t\treturn false;\n\t}\n}\n"]}