@osovv/vv-opencode 0.11.0 → 0.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/README.md +13 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/secrets-redaction/engine.js +20 -60
- package/dist/plugins/secrets-redaction/engine.js.map +1 -1
- package/dist/plugins/system-context-injection/index.d.ts +2 -0
- package/dist/plugins/system-context-injection/index.js +89 -0
- package/dist/plugins/system-context-injection/index.js.map +1 -0
- package/package.json +6 -2
- package/templates/agents/enhancer.md +1 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Portable OpenCode workflow package with plugins and a Bun CLI for setup, sync, d
|
|
|
7
7
|
- `vvoc` CLI for bootstrap, sync, inspection, and model overrides
|
|
8
8
|
- `GuardianPlugin` for permission review
|
|
9
9
|
- `MemoryPlugin` for explicit persistent memory
|
|
10
|
+
- `SystemContextInjectionPlugin` for reusable primary-session system guidance
|
|
10
11
|
- `SecretsRedactionPlugin` for redacting secrets before LLM requests
|
|
11
12
|
- report-only `memory-reviewer` subagent
|
|
12
13
|
- vvoc-managed prompt files and OpenCode agent registrations
|
|
@@ -49,7 +50,7 @@ vvoc install --scope project
|
|
|
49
50
|
- keeps vvoc-managed config separate from native OpenCode config
|
|
50
51
|
- leaves unmanaged files alone unless `--force` is passed
|
|
51
52
|
|
|
52
|
-
For conversational meta-prompting, use the managed `enhancer` primary agent. It can ask follow-up questions and then return a clean XML prompt with semantically unique repeated tags such as `<constraint-1>...</constraint-1>` and `<verification-check-2>...</verification-check-2>`.
|
|
53
|
+
For conversational meta-prompting, use the managed `enhancer` primary agent. It can ask follow-up questions and then return a clean XML prompt in English with semantically unique repeated tags such as `<constraint-1>...</constraint-1>` and `<verification-check-2>...</verification-check-2>`.
|
|
53
54
|
|
|
54
55
|
Typical workflow:
|
|
55
56
|
|
|
@@ -69,7 +70,7 @@ The OpenCode config entry written by `install` looks like this:
|
|
|
69
70
|
}
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
That package entry points at the package root, which exports `GuardianPlugin`, `MemoryPlugin`, and `SecretsRedactionPlugin`.
|
|
73
|
+
That package entry points at the package root, which exports `GuardianPlugin`, `MemoryPlugin`, `SystemContextInjectionPlugin`, and `SecretsRedactionPlugin`.
|
|
73
74
|
|
|
74
75
|
## Common Workflows
|
|
75
76
|
|
|
@@ -313,6 +314,14 @@ Example:
|
|
|
313
314
|
|
|
314
315
|
The reviewer can read memory but cannot modify it.
|
|
315
316
|
|
|
317
|
+
### SystemContextInjectionPlugin
|
|
318
|
+
|
|
319
|
+
`SystemContextInjectionPlugin` injects reusable system guidance into primary chat sessions without polluting known subagent prompts.
|
|
320
|
+
|
|
321
|
+
The default injected guidance tells the main session to proactively use the `explore` subagent when the task depends on unfamiliar code, unclear scope, or multiple candidate implementation areas.
|
|
322
|
+
|
|
323
|
+
The plugin currently injects guidance through the `chat.message` hook so it can inspect the resolved agent name and skip known subagents such as `general`, `explore`, `implementer`, and `memory-reviewer`.
|
|
324
|
+
|
|
316
325
|
### SecretsRedactionPlugin
|
|
317
326
|
|
|
318
327
|
`SecretsRedactionPlugin` redacts secrets from chat content before LLM requests and restores placeholders after the request lifecycle where needed.
|
|
@@ -372,6 +381,7 @@ Root exports:
|
|
|
372
381
|
import {
|
|
373
382
|
GuardianPlugin,
|
|
374
383
|
MemoryPlugin,
|
|
384
|
+
SystemContextInjectionPlugin,
|
|
375
385
|
SecretsRedactionPlugin,
|
|
376
386
|
} from "@osovv/vv-opencode";
|
|
377
387
|
```
|
|
@@ -381,6 +391,7 @@ Subpath exports:
|
|
|
381
391
|
```ts
|
|
382
392
|
import { GuardianPlugin } from "@osovv/vv-opencode/plugins/guardian";
|
|
383
393
|
import { MemoryPlugin } from "@osovv/vv-opencode/plugins/memory";
|
|
394
|
+
import { SystemContextInjectionPlugin } from "@osovv/vv-opencode/plugins/system-context-injection";
|
|
384
395
|
import { SecretsRedactionPlugin } from "@osovv/vv-opencode/plugins/secrets-redaction";
|
|
385
396
|
```
|
|
386
397
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { GuardianPlugin } from "./plugins/guardian/index.js";
|
|
2
2
|
export { MemoryPlugin } from "./plugins/memory/index.js";
|
|
3
|
+
export { SystemContextInjectionPlugin } from "./plugins/system-context-injection/index.js";
|
|
3
4
|
export { SecretsRedactionPlugin } from "./plugins/secrets-redaction.js";
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
// FILE: src/index.ts
|
|
2
|
-
// VERSION: 0.
|
|
2
|
+
// VERSION: 0.5.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Re-export the public vv-opencode plugin entrypoints from the package root.
|
|
5
|
-
// SCOPE: Package-root exports for GuardianPlugin, MemoryPlugin, and SecretsRedactionPlugin.
|
|
6
|
-
// DEPENDS: [src/plugins/guardian/index.ts, src/plugins/memory/index.ts, src/plugins/secrets-redaction.ts]
|
|
7
|
-
// LINKS: [M-PLUGIN-GUARDIAN, M-PLUGIN-MEMORY, M-PLUGIN-SECRETS-REDACTION]
|
|
5
|
+
// SCOPE: Package-root exports for GuardianPlugin, MemoryPlugin, SystemContextInjectionPlugin, and SecretsRedactionPlugin.
|
|
6
|
+
// DEPENDS: [src/plugins/guardian/index.ts, src/plugins/memory/index.ts, src/plugins/system-context-injection/index.ts, src/plugins/secrets-redaction.ts]
|
|
7
|
+
// LINKS: [M-PLUGIN-GUARDIAN, M-PLUGIN-MEMORY, M-PLUGIN-SYSTEM-CONTEXT-INJECTION, M-PLUGIN-SECRETS-REDACTION]
|
|
8
8
|
// ROLE: BARREL
|
|
9
9
|
// MAP_MODE: SUMMARY
|
|
10
10
|
// END_MODULE_CONTRACT
|
|
11
11
|
//
|
|
12
12
|
// START_MODULE_MAP
|
|
13
|
-
// GuardianPlugin, MemoryPlugin, SecretsRedactionPlugin - Public plugin exports available from @osovv/vv-opencode.
|
|
13
|
+
// GuardianPlugin, MemoryPlugin, SystemContextInjectionPlugin, SecretsRedactionPlugin - Public plugin exports available from @osovv/vv-opencode.
|
|
14
14
|
// END_MODULE_MAP
|
|
15
15
|
//
|
|
16
16
|
// START_CHANGE_SUMMARY
|
|
17
|
-
// LAST_CHANGE: [v0.
|
|
17
|
+
// LAST_CHANGE: [v0.5.0 - Added SystemContextInjectionPlugin to the package-root plugin exports.]
|
|
18
18
|
// END_CHANGE_SUMMARY
|
|
19
19
|
export { GuardianPlugin } from "./plugins/guardian/index.js";
|
|
20
20
|
export { MemoryPlugin } from "./plugins/memory/index.js";
|
|
21
|
+
export { SystemContextInjectionPlugin } from "./plugins/system-context-injection/index.js";
|
|
21
22
|
export { SecretsRedactionPlugin } from "./plugins/secrets-redaction.js";
|
|
22
23
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,iBAAiB;AACjB,wBAAwB;AACxB,wFAAwF;AACxF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,iBAAiB;AACjB,wBAAwB;AACxB,wFAAwF;AACxF,4HAA4H;AAC5H,2JAA2J;AAC3J,+GAA+G;AAC/G,iBAAiB;AACjB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,kJAAkJ;AAClJ,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,mGAAmG;AACnG,qBAAqB;AAErB,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,6CAA6C,CAAC;AAC3F,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// FILE: src/plugins/secrets-redaction/engine.ts
|
|
2
|
-
// VERSION: 1.
|
|
2
|
+
// VERSION: 1.1.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Core redaction engine — performs find/replace of secrets with placeholders in text.
|
|
5
|
-
// SCOPE: text scanning, match sorting,
|
|
5
|
+
// SCOPE: text scanning, overlap resolution, match sorting, and replacement
|
|
6
6
|
// DEPENDS: session, patterns
|
|
7
7
|
// LINKS: knowledge-graph://plugins/secrets-redaction
|
|
8
8
|
// ROLE: RUNTIME
|
|
@@ -12,37 +12,11 @@
|
|
|
12
12
|
// START_MODULE_MAP
|
|
13
13
|
// redactText - replaces secrets in text with placeholders, returns changed text + match list
|
|
14
14
|
// END_MODULE_MAP
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
let currentEnd = intervals[0][0];
|
|
21
|
-
for (const [start, end] of intervals) {
|
|
22
|
-
if (start > currentEnd) {
|
|
23
|
-
result.push([currentEnd, start]);
|
|
24
|
-
}
|
|
25
|
-
if (end > currentEnd) {
|
|
26
|
-
currentEnd = end;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return result;
|
|
30
|
-
}
|
|
31
|
-
function insertCovered(intervals, newInterval) {
|
|
32
|
-
const merged = [...intervals, newInterval];
|
|
33
|
-
merged.sort((a, b) => a[0] - b[0]);
|
|
34
|
-
const result = [];
|
|
35
|
-
for (const interval of merged) {
|
|
36
|
-
if (result.length > 0 && interval[0] <= result[result.length - 1][1]) {
|
|
37
|
-
result[result.length - 1][1] = Math.max(result[result.length - 1][1], interval[1]);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
result.push([...interval]);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return result;
|
|
44
|
-
}
|
|
45
|
-
function sortByPositionDesc(rules, text) {
|
|
15
|
+
//
|
|
16
|
+
// START_CHANGE_SUMMARY
|
|
17
|
+
// LAST_CHANGE: [v1.1.0 - Fixed overlap handling so first and wider earlier matches redact correctly instead of being skipped entirely.]
|
|
18
|
+
// END_CHANGE_SUMMARY
|
|
19
|
+
function sortByPositionAsc(rules, text) {
|
|
46
20
|
const allMatches = [];
|
|
47
21
|
for (const rule of rules) {
|
|
48
22
|
const re = new RegExp(rule.pattern.source, rule.pattern.flags.includes("g") ? rule.pattern.flags : `${rule.pattern.flags}g`);
|
|
@@ -55,17 +29,23 @@ function sortByPositionDesc(rules, text) {
|
|
|
55
29
|
const aStart = a.match.index;
|
|
56
30
|
const bStart = b.match.index;
|
|
57
31
|
if (aStart !== bStart)
|
|
58
|
-
return
|
|
32
|
+
return aStart - bStart;
|
|
59
33
|
return b.match[0].length - a.match[0].length;
|
|
60
34
|
});
|
|
61
35
|
return allMatches.map((x) => ({ rule: x.rule, matches: x.match }));
|
|
62
36
|
}
|
|
37
|
+
function overlapsSelected(start, selected) {
|
|
38
|
+
const lastSelected = selected[selected.length - 1];
|
|
39
|
+
if (!lastSelected) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return start < lastSelected.end;
|
|
43
|
+
}
|
|
63
44
|
export function redactText(input, patternSet, session) {
|
|
64
45
|
if (!input || patternSet.rules.length === 0) {
|
|
65
46
|
return { text: input, matches: [] };
|
|
66
47
|
}
|
|
67
|
-
const sorted =
|
|
68
|
-
const covered = [];
|
|
48
|
+
const sorted = sortByPositionAsc(patternSet.rules, input);
|
|
69
49
|
const matches = [];
|
|
70
50
|
for (const { rule, matches: match } of sorted) {
|
|
71
51
|
const start = match.index;
|
|
@@ -74,40 +54,20 @@ export function redactText(input, patternSet, session) {
|
|
|
74
54
|
if (patternSet.exclude.has(value.toLowerCase())) {
|
|
75
55
|
continue;
|
|
76
56
|
}
|
|
77
|
-
|
|
78
|
-
const isInside = gaps.every(([gStart, gEnd]) => start >= gStart && end <= gEnd);
|
|
79
|
-
if (isInside)
|
|
57
|
+
if (overlapsSelected(start, matches)) {
|
|
80
58
|
continue;
|
|
59
|
+
}
|
|
81
60
|
const placeholder = session.getOrCreatePlaceholder(value, rule.category);
|
|
82
61
|
matches.push({ start, end, original: value, placeholder, category: rule.category });
|
|
83
|
-
const remainingGaps = [];
|
|
84
|
-
for (const [gStart, gEnd] of gaps) {
|
|
85
|
-
if (start >= gEnd || end <= gStart) {
|
|
86
|
-
remainingGaps.push([gStart, gEnd]);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
if (start > gStart) {
|
|
90
|
-
remainingGaps.push([gStart, start]);
|
|
91
|
-
}
|
|
92
|
-
if (end < gEnd) {
|
|
93
|
-
remainingGaps.push([end, gEnd]);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
covered.length = 0;
|
|
98
|
-
for (const g of remainingGaps) {
|
|
99
|
-
insertCovered(covered, g);
|
|
100
|
-
}
|
|
101
62
|
}
|
|
102
|
-
const sortedMatches = [...matches].sort((a, b) => a.start - b.start);
|
|
103
63
|
let result = "";
|
|
104
64
|
let lastIndex = 0;
|
|
105
|
-
for (const m of
|
|
65
|
+
for (const m of matches) {
|
|
106
66
|
result += input.slice(lastIndex, m.start);
|
|
107
67
|
result += m.placeholder;
|
|
108
68
|
lastIndex = m.end;
|
|
109
69
|
}
|
|
110
70
|
result += input.slice(lastIndex);
|
|
111
|
-
return { text: result, matches
|
|
71
|
+
return { text: result, matches };
|
|
112
72
|
}
|
|
113
73
|
//# sourceMappingURL=engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/engine.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,iBAAiB;AACjB,wBAAwB;AACxB,iGAAiG;AACjG,
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// FILE: src/plugins/system-context-injection/index.ts
|
|
2
|
+
// VERSION: 0.1.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Inject reusable vvoc system context into primary chat sessions without polluting known subagent prompts.
|
|
5
|
+
// SCOPE: Main-session system instruction definitions, known subagent filtering, config-aware custom subagent tracking, and chat.message system prompt injection.
|
|
6
|
+
// DEPENDS: [@opencode-ai/plugin, src/lib/managed-agents.ts]
|
|
7
|
+
// LINKS: [M-PLUGIN-SYSTEM-CONTEXT-INJECTION, M-CLI-MANAGED-AGENTS]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// SystemContextInjectionPlugin - Injects reusable system guidance into primary sessions while skipping known subagents.
|
|
14
|
+
// END_MODULE_MAP
|
|
15
|
+
//
|
|
16
|
+
// START_CHANGE_SUMMARY
|
|
17
|
+
// LAST_CHANGE: [v0.1.0 - Added a reusable main-session system context injector with default proactive explore guidance.]
|
|
18
|
+
// END_CHANGE_SUMMARY
|
|
19
|
+
import { MANAGED_SUBAGENT_NAMES } from "../../lib/managed-agents.js";
|
|
20
|
+
const BUILT_IN_SUBAGENTS = ["general", "explore"];
|
|
21
|
+
const PLUGIN_MANAGED_SUBAGENTS = ["guardian", "memory-reviewer"];
|
|
22
|
+
const INTERNAL_PRIMARY_AGENTS = ["compaction", "title", "summary"];
|
|
23
|
+
const MAIN_SESSION_SYSTEM_CONTEXTS = [
|
|
24
|
+
[
|
|
25
|
+
"<proactive_context_gathering>",
|
|
26
|
+
"Before answering questions about the codebase or making changes, proactively use the explore subagent to gather the context you need whenever the task depends on unfamiliar code, unclear scope, or multiple candidate implementation areas.",
|
|
27
|
+
"Do not guess about code you have not inspected.",
|
|
28
|
+
"If the task is already localized and the required context is already in view, work directly instead of delegating.",
|
|
29
|
+
"</proactive_context_gathering>",
|
|
30
|
+
].join("\n"),
|
|
31
|
+
];
|
|
32
|
+
// START_BLOCK_AGENT_FILTERS
|
|
33
|
+
function createKnownSubagentSet() {
|
|
34
|
+
return new Set([...BUILT_IN_SUBAGENTS, ...PLUGIN_MANAGED_SUBAGENTS, ...MANAGED_SUBAGENT_NAMES]);
|
|
35
|
+
}
|
|
36
|
+
function syncConfiguredSubagents(config, knownSubagents) {
|
|
37
|
+
for (const [name, definition] of Object.entries(config.agent ?? {})) {
|
|
38
|
+
if (definition?.mode === "subagent") {
|
|
39
|
+
knownSubagents.add(name);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function shouldInjectForAgent(agentName, knownSubagents) {
|
|
44
|
+
if (!agentName) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (knownSubagents.has(agentName)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (INTERNAL_PRIMARY_AGENTS.includes(agentName)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// END_BLOCK_AGENT_FILTERS
|
|
56
|
+
// START_BLOCK_SYSTEM_CONTEXT_FORMATTING
|
|
57
|
+
function hasInjectedContext(existingSystem, context) {
|
|
58
|
+
return typeof existingSystem === "string" && existingSystem.includes(context);
|
|
59
|
+
}
|
|
60
|
+
function appendSystemContexts(existingSystem, contexts) {
|
|
61
|
+
const parts = [];
|
|
62
|
+
if (typeof existingSystem === "string" && existingSystem.trim()) {
|
|
63
|
+
parts.push(existingSystem.trim());
|
|
64
|
+
}
|
|
65
|
+
for (const context of contexts) {
|
|
66
|
+
if (!hasInjectedContext(existingSystem, context)) {
|
|
67
|
+
parts.push(context);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return parts.join("\n\n");
|
|
71
|
+
}
|
|
72
|
+
// END_BLOCK_SYSTEM_CONTEXT_FORMATTING
|
|
73
|
+
// START_BLOCK_PLUGIN_ENTRY
|
|
74
|
+
export const SystemContextInjectionPlugin = async () => {
|
|
75
|
+
const knownSubagents = createKnownSubagentSet();
|
|
76
|
+
return {
|
|
77
|
+
config: async (config) => {
|
|
78
|
+
syncConfiguredSubagents(config, knownSubagents);
|
|
79
|
+
},
|
|
80
|
+
"chat.message": async (_input, output) => {
|
|
81
|
+
if (!shouldInjectForAgent(output.message.agent, knownSubagents)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
output.message.system = appendSystemContexts(output.message.system, MAIN_SESSION_SYSTEM_CONTEXTS);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
// END_BLOCK_PLUGIN_ENTRY
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/system-context-injection/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osovv/vv-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Portable OpenCode workflow plugins, explicit memory, and CLI tooling.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
"types": "./dist/plugins/memory/index.d.ts",
|
|
42
42
|
"import": "./dist/plugins/memory/index.js"
|
|
43
43
|
},
|
|
44
|
+
"./plugins/system-context-injection": {
|
|
45
|
+
"types": "./dist/plugins/system-context-injection/index.d.ts",
|
|
46
|
+
"import": "./dist/plugins/system-context-injection/index.js"
|
|
47
|
+
},
|
|
44
48
|
"./plugins/secrets-redaction": {
|
|
45
49
|
"types": "./dist/plugins/secrets-redaction/index.d.ts",
|
|
46
50
|
"import": "./dist/plugins/secrets-redaction/index.js"
|
|
@@ -54,7 +58,7 @@
|
|
|
54
58
|
"fmt:check": "oxfmt --check src",
|
|
55
59
|
"test": "bun test",
|
|
56
60
|
"check": "bun run typecheck && bun run lint && bun run fmt:check && bun test",
|
|
57
|
-
"pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('MemoryPlugin' in root)) throw new Error('dist root export missing MemoryPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/memory/index.js')\" && npm pack --dry-run",
|
|
61
|
+
"pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('MemoryPlugin' in root)) throw new Error('dist root export missing MemoryPlugin'); if (!('SystemContextInjectionPlugin' in root)) throw new Error('dist root export missing SystemContextInjectionPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/memory/index.js'); await import('./dist/plugins/system-context-injection/index.js')\" && npm pack --dry-run",
|
|
58
62
|
"prepare": "lefthook install --force"
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
@@ -20,6 +20,7 @@ Operating rules:
|
|
|
20
20
|
- If the user says not to keep clarifying, finish with explicit assumptions instead of blocking.
|
|
21
21
|
- Do not add requirements, scope, or constraints that the user did not ask for.
|
|
22
22
|
- Do not include the raw request verbatim in the final XML unless the user explicitly asks for it.
|
|
23
|
+
- The final XML prompt must always be written in English.
|
|
23
24
|
- Omit empty sections instead of emitting placeholders.
|
|
24
25
|
|
|
25
26
|
XML rules:
|