@dev4s/opencode-dcp 0.1.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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +87 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/config.d.ts +58 -0
  8. package/dist/lib/config.d.ts.map +1 -0
  9. package/dist/lib/config.js +696 -0
  10. package/dist/lib/config.js.map +1 -0
  11. package/dist/lib/hooks.d.ts +10 -0
  12. package/dist/lib/hooks.d.ts.map +1 -0
  13. package/dist/lib/hooks.js +45 -0
  14. package/dist/lib/hooks.js.map +1 -0
  15. package/dist/lib/logger.d.ts +31 -0
  16. package/dist/lib/logger.d.ts.map +1 -0
  17. package/dist/lib/logger.js +183 -0
  18. package/dist/lib/logger.js.map +1 -0
  19. package/dist/lib/messages/index.d.ts +2 -0
  20. package/dist/lib/messages/index.d.ts.map +1 -0
  21. package/dist/lib/messages/index.js +2 -0
  22. package/dist/lib/messages/index.js.map +1 -0
  23. package/dist/lib/messages/prune.d.ts +6 -0
  24. package/dist/lib/messages/prune.d.ts.map +1 -0
  25. package/dist/lib/messages/prune.js +187 -0
  26. package/dist/lib/messages/prune.js.map +1 -0
  27. package/dist/lib/messages/utils.d.ts +9 -0
  28. package/dist/lib/messages/utils.d.ts.map +1 -0
  29. package/dist/lib/messages/utils.js +124 -0
  30. package/dist/lib/messages/utils.js.map +1 -0
  31. package/dist/lib/model-selector.d.ts +17 -0
  32. package/dist/lib/model-selector.d.ts.map +1 -0
  33. package/dist/lib/model-selector.js +141 -0
  34. package/dist/lib/model-selector.js.map +1 -0
  35. package/dist/lib/prompt.d.ts +3 -0
  36. package/dist/lib/prompt.d.ts.map +1 -0
  37. package/dist/lib/prompt.js +128 -0
  38. package/dist/lib/prompt.js.map +1 -0
  39. package/dist/lib/prompts/discard-tool-spec.txt +41 -0
  40. package/dist/lib/prompts/extract-tool-spec.txt +47 -0
  41. package/dist/lib/prompts/on-idle-analysis.txt +30 -0
  42. package/dist/lib/prompts/user/nudge/nudge-both.txt +10 -0
  43. package/dist/lib/prompts/user/nudge/nudge-discard.txt +9 -0
  44. package/dist/lib/prompts/user/nudge/nudge-extract.txt +9 -0
  45. package/dist/lib/prompts/user/system/system-prompt-both.txt +58 -0
  46. package/dist/lib/prompts/user/system/system-prompt-discard.txt +49 -0
  47. package/dist/lib/prompts/user/system/system-prompt-extract.txt +49 -0
  48. package/dist/lib/shared-utils.d.ts +4 -0
  49. package/dist/lib/shared-utils.d.ts.map +1 -0
  50. package/dist/lib/shared-utils.js +13 -0
  51. package/dist/lib/shared-utils.js.map +1 -0
  52. package/dist/lib/state/index.d.ts +4 -0
  53. package/dist/lib/state/index.d.ts.map +1 -0
  54. package/dist/lib/state/index.js +4 -0
  55. package/dist/lib/state/index.js.map +1 -0
  56. package/dist/lib/state/persistence.d.ts +16 -0
  57. package/dist/lib/state/persistence.d.ts.map +1 -0
  58. package/dist/lib/state/persistence.js +73 -0
  59. package/dist/lib/state/persistence.js.map +1 -0
  60. package/dist/lib/state/state.d.ts +8 -0
  61. package/dist/lib/state/state.d.ts.map +1 -0
  62. package/dist/lib/state/state.js +112 -0
  63. package/dist/lib/state/state.js.map +1 -0
  64. package/dist/lib/state/tool-cache.d.ts +13 -0
  65. package/dist/lib/state/tool-cache.d.ts.map +1 -0
  66. package/dist/lib/state/tool-cache.js +74 -0
  67. package/dist/lib/state/tool-cache.js.map +1 -0
  68. package/dist/lib/state/types.d.ts +32 -0
  69. package/dist/lib/state/types.d.ts.map +1 -0
  70. package/dist/lib/state/types.js +2 -0
  71. package/dist/lib/state/types.js.map +1 -0
  72. package/dist/lib/state/utils.d.ts +2 -0
  73. package/dist/lib/state/utils.d.ts.map +1 -0
  74. package/dist/lib/state/utils.js +10 -0
  75. package/dist/lib/state/utils.js.map +1 -0
  76. package/dist/lib/strategies/deduplication.d.ts +10 -0
  77. package/dist/lib/strategies/deduplication.d.ts.map +1 -0
  78. package/dist/lib/strategies/deduplication.js +89 -0
  79. package/dist/lib/strategies/deduplication.js.map +1 -0
  80. package/dist/lib/strategies/index.d.ts +6 -0
  81. package/dist/lib/strategies/index.d.ts.map +1 -0
  82. package/dist/lib/strategies/index.js +6 -0
  83. package/dist/lib/strategies/index.js.map +1 -0
  84. package/dist/lib/strategies/on-idle.d.ts +14 -0
  85. package/dist/lib/strategies/on-idle.d.ts.map +1 -0
  86. package/dist/lib/strategies/on-idle.js +220 -0
  87. package/dist/lib/strategies/on-idle.js.map +1 -0
  88. package/dist/lib/strategies/purge-errors.d.ts +13 -0
  89. package/dist/lib/strategies/purge-errors.d.ts.map +1 -0
  90. package/dist/lib/strategies/purge-errors.js +54 -0
  91. package/dist/lib/strategies/purge-errors.js.map +1 -0
  92. package/dist/lib/strategies/supersede-writes.d.ts +13 -0
  93. package/dist/lib/strategies/supersede-writes.d.ts.map +1 -0
  94. package/dist/lib/strategies/supersede-writes.js +80 -0
  95. package/dist/lib/strategies/supersede-writes.js.map +1 -0
  96. package/dist/lib/strategies/tools.d.ts +14 -0
  97. package/dist/lib/strategies/tools.d.ts.map +1 -0
  98. package/dist/lib/strategies/tools.js +137 -0
  99. package/dist/lib/strategies/tools.js.map +1 -0
  100. package/dist/lib/strategies/utils.d.ts +12 -0
  101. package/dist/lib/strategies/utils.d.ts.map +1 -0
  102. package/dist/lib/strategies/utils.js +82 -0
  103. package/dist/lib/strategies/utils.js.map +1 -0
  104. package/dist/lib/tokenizer.d.ts +24 -0
  105. package/dist/lib/tokenizer.d.ts.map +1 -0
  106. package/dist/lib/tokenizer.js +45 -0
  107. package/dist/lib/tokenizer.js.map +1 -0
  108. package/dist/lib/ui/notification.d.ts +9 -0
  109. package/dist/lib/ui/notification.d.ts.map +1 -0
  110. package/dist/lib/ui/notification.js +70 -0
  111. package/dist/lib/ui/notification.js.map +1 -0
  112. package/dist/lib/ui/utils.d.ts +15 -0
  113. package/dist/lib/ui/utils.d.ts.map +1 -0
  114. package/dist/lib/ui/utils.js +87 -0
  115. package/dist/lib/ui/utils.js.map +1 -0
  116. package/package.json +57 -0
@@ -0,0 +1,137 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+ import { buildToolIdList } from "../messages/utils";
3
+ import { sendUnifiedNotification } from "../ui/notification";
4
+ import { formatPruningResultForTool } from "../ui/utils";
5
+ import { ensureSessionInitialized } from "../state";
6
+ import { saveSessionState } from "../state/persistence";
7
+ import { loadPrompt } from "../prompt";
8
+ import { calculateTokensSaved, getCurrentParams } from "./utils";
9
+ // Lazy-loaded tool descriptions (deferred to first tool creation)
10
+ let discardToolDescription = null;
11
+ let extractToolDescription = null;
12
+ function getDiscardToolDescription() {
13
+ if (!discardToolDescription) {
14
+ discardToolDescription = loadPrompt("discard-tool-spec");
15
+ }
16
+ return discardToolDescription;
17
+ }
18
+ function getExtractToolDescription() {
19
+ if (!extractToolDescription) {
20
+ extractToolDescription = loadPrompt("extract-tool-spec");
21
+ }
22
+ return extractToolDescription;
23
+ }
24
+ // Shared logic for executing prune operations.
25
+ async function executePruneOperation(ctx, toolCtx, ids, reason, toolName, distillation) {
26
+ const { client, state, logger, config, workingDirectory } = ctx;
27
+ const sessionId = toolCtx.sessionID;
28
+ logger.info(`${toolName} tool invoked`);
29
+ logger.info(JSON.stringify(reason ? { ids, reason } : { ids }));
30
+ if (!ids || ids.length === 0) {
31
+ logger.debug(`${toolName} tool called but ids is empty or undefined`);
32
+ return `No IDs provided. Check the <prunable-tools> list for available IDs to ${toolName.toLowerCase()}.`;
33
+ }
34
+ const numericToolIds = ids
35
+ .map((id) => parseInt(id, 10))
36
+ .filter((n) => !isNaN(n));
37
+ if (numericToolIds.length === 0) {
38
+ logger.debug(`No numeric tool IDs provided for ${toolName}: ` + JSON.stringify(ids));
39
+ return "No numeric IDs provided. Format: ids: [id1, id2, ...]";
40
+ }
41
+ // Fetch messages to calculate tokens and find current agent
42
+ const messagesResponse = await client.session.messages({
43
+ path: { id: sessionId },
44
+ });
45
+ const messages = messagesResponse.data || messagesResponse;
46
+ await ensureSessionInitialized(ctx.client, state, sessionId, logger, messages);
47
+ const currentParams = getCurrentParams(messages, logger);
48
+ const toolIdList = buildToolIdList(state, messages, logger);
49
+ // Validate that all numeric IDs are within bounds
50
+ if (numericToolIds.some((id) => id < 0 || id >= toolIdList.length)) {
51
+ logger.debug("Invalid tool IDs provided: " + numericToolIds.join(", "));
52
+ return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list.";
53
+ }
54
+ // Validate that all IDs exist in cache and aren't protected
55
+ // (rejects hallucinated IDs and turn-protected tools not shown in <prunable-tools>)
56
+ for (const index of numericToolIds) {
57
+ const id = toolIdList[index];
58
+ const metadata = state.toolParameters.get(id);
59
+ if (!metadata) {
60
+ logger.debug("Rejecting prune request - ID not in cache (turn-protected or hallucinated)", { index, id });
61
+ return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list.";
62
+ }
63
+ const allProtectedTools = config.tools.settings.protectedTools;
64
+ if (allProtectedTools.includes(metadata.tool)) {
65
+ logger.debug("Rejecting prune request - protected tool", {
66
+ index,
67
+ id,
68
+ tool: metadata.tool,
69
+ });
70
+ return "Invalid IDs provided. Only use numeric IDs from the <prunable-tools> list.";
71
+ }
72
+ }
73
+ const pruneToolIds = numericToolIds.map((index) => toolIdList[index]);
74
+ state.prune.toolIds.push(...pruneToolIds);
75
+ const toolMetadata = new Map();
76
+ for (const id of pruneToolIds) {
77
+ const toolParameters = state.toolParameters.get(id);
78
+ if (toolParameters) {
79
+ toolMetadata.set(id, toolParameters);
80
+ }
81
+ else {
82
+ logger.debug("No metadata found for ID", { id });
83
+ }
84
+ }
85
+ state.stats.pruneTokenCounter += calculateTokensSaved(state, messages, pruneToolIds);
86
+ await sendUnifiedNotification(client, logger, config, state, sessionId, pruneToolIds, toolMetadata, reason, currentParams, workingDirectory, distillation);
87
+ state.stats.totalPruneTokens += state.stats.pruneTokenCounter;
88
+ state.stats.pruneTokenCounter = 0;
89
+ state.nudgeCounter = 0;
90
+ saveSessionState(state, logger).catch((err) => logger.error("Failed to persist state", { error: err.message }));
91
+ return formatPruningResultForTool(pruneToolIds, toolMetadata, workingDirectory);
92
+ }
93
+ export function createDiscardTool(ctx) {
94
+ return tool({
95
+ description: getDiscardToolDescription(),
96
+ args: {
97
+ ids: tool.schema
98
+ .array(tool.schema.string())
99
+ .describe("First element is the reason ('completion' or 'noise'), followed by numeric IDs as strings to discard"),
100
+ },
101
+ async execute(args, toolCtx) {
102
+ // Parse reason from first element, numeric IDs from the rest
103
+ const reason = args.ids?.[0];
104
+ const validReasons = ["completion", "noise"];
105
+ if (typeof reason !== "string" || !validReasons.includes(reason)) {
106
+ ctx.logger.debug("Invalid discard reason provided: " + reason);
107
+ return "No valid reason found. Use 'completion' or 'noise' as the first element.";
108
+ }
109
+ const numericIds = args.ids.slice(1);
110
+ return executePruneOperation(ctx, toolCtx, numericIds, reason, "Discard");
111
+ },
112
+ });
113
+ }
114
+ export function createExtractTool(ctx) {
115
+ return tool({
116
+ description: getExtractToolDescription(),
117
+ args: {
118
+ ids: tool.schema
119
+ .array(tool.schema.string())
120
+ .describe("Numeric IDs as strings to extract from the <prunable-tools> list"),
121
+ distillation: tool.schema
122
+ .array(tool.schema.string())
123
+ .describe("REQUIRED. Array of strings, one per ID (positional: distillation[0] is for ids[0], etc.)"),
124
+ },
125
+ async execute(args, toolCtx) {
126
+ if (!args.distillation || args.distillation.length === 0) {
127
+ ctx.logger.debug("Extract tool called without distillation: " + JSON.stringify(args));
128
+ return "Missing distillation. You must provide a distillation string for each ID.";
129
+ }
130
+ // Log the distillation for debugging/analysis
131
+ ctx.logger.info("Distillation data received:");
132
+ ctx.logger.info(JSON.stringify(args.distillation, null, 2));
133
+ return executePruneOperation(ctx, toolCtx, args.ids, "extraction", "Extract", args.distillation);
134
+ },
135
+ });
136
+ }
137
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../lib/strategies/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { SessionState, WithParts } from "../state";
2
+ import { Logger } from "../logger";
3
+ export declare function getCurrentParams(messages: WithParts[], logger: Logger): {
4
+ providerId: string | undefined;
5
+ modelId: string | undefined;
6
+ agent: string | undefined;
7
+ };
8
+ /**
9
+ * Calculates approximate tokens saved by pruning the given tool call IDs.
10
+ */
11
+ export declare const calculateTokensSaved: (state: SessionState, messages: WithParts[], pruneToolIds: string[]) => number;
12
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../lib/strategies/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAIlC,wBAAgB,gBAAgB,CAC5B,QAAQ,EAAE,SAAS,EAAE,EACrB,MAAM,EAAE,MAAM,GACf;IACC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B,CAWA;AAaD;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC7B,OAAO,YAAY,EACnB,UAAU,SAAS,EAAE,EACrB,cAAc,MAAM,EAAE,KACvB,MAsDF,CAAA"}
@@ -0,0 +1,82 @@
1
+ import { encodeText } from "../tokenizer";
2
+ import { getLastUserMessage, isMessageCompacted } from "../shared-utils";
3
+ export function getCurrentParams(messages, logger) {
4
+ const userMsg = getLastUserMessage(messages);
5
+ if (!userMsg) {
6
+ logger.debug("No user message found when determining current params");
7
+ return { providerId: undefined, modelId: undefined, agent: undefined };
8
+ }
9
+ const agent = userMsg.info.agent;
10
+ const providerId = userMsg.info.model.providerID;
11
+ const modelId = userMsg.info.model.modelID;
12
+ return { providerId, modelId, agent };
13
+ }
14
+ /**
15
+ * Estimates token counts for a batch of texts using the lazy tokenizer.
16
+ */
17
+ function estimateTokensBatch(texts) {
18
+ try {
19
+ return texts.map((text) => encodeText(text).length);
20
+ }
21
+ catch {
22
+ return texts.map((text) => Math.round(text.length / 4));
23
+ }
24
+ }
25
+ /**
26
+ * Calculates approximate tokens saved by pruning the given tool call IDs.
27
+ */
28
+ export const calculateTokensSaved = (state, messages, pruneToolIds) => {
29
+ try {
30
+ const contents = [];
31
+ for (const msg of messages) {
32
+ if (isMessageCompacted(state, msg)) {
33
+ continue;
34
+ }
35
+ for (const part of msg.parts) {
36
+ if (part.type !== "tool" || !pruneToolIds.includes(part.callID)) {
37
+ continue;
38
+ }
39
+ // For write and edit tools, count input content as that is all we prune for these tools
40
+ // (input is present in both completed and error states)
41
+ if (part.tool === "write") {
42
+ const inputContent = part.state.input?.content;
43
+ const content = typeof inputContent === "string"
44
+ ? inputContent
45
+ : JSON.stringify(inputContent ?? "");
46
+ contents.push(content);
47
+ continue;
48
+ }
49
+ if (part.tool === "edit") {
50
+ const oldString = part.state.input?.oldString;
51
+ const newString = part.state.input?.newString;
52
+ if (typeof oldString === "string") {
53
+ contents.push(oldString);
54
+ }
55
+ if (typeof newString === "string") {
56
+ contents.push(newString);
57
+ }
58
+ continue;
59
+ }
60
+ // For other tools, count output or error based on status
61
+ if (part.state.status === "completed") {
62
+ const content = typeof part.state.output === "string"
63
+ ? part.state.output
64
+ : JSON.stringify(part.state.output);
65
+ contents.push(content);
66
+ }
67
+ else if (part.state.status === "error") {
68
+ const content = typeof part.state.error === "string"
69
+ ? part.state.error
70
+ : JSON.stringify(part.state.error);
71
+ contents.push(content);
72
+ }
73
+ }
74
+ }
75
+ const tokenCounts = estimateTokensBatch(contents);
76
+ return tokenCounts.reduce((sum, count) => sum + count, 0);
77
+ }
78
+ catch (error) {
79
+ return 0;
80
+ }
81
+ };
82
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../lib/strategies/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Lazy tokenizer module - loads gpt-tokenizer in background to avoid blocking startup.
3
+ *
4
+ * The gpt-tokenizer package takes 5-15 seconds to initialize due to loading
5
+ * large vocabulary files. This module defers that load to happen asynchronously
6
+ * after plugin initialization, keeping startup instant.
7
+ */
8
+ /**
9
+ * Starts loading the tokenizer in the background.
10
+ * Call this at plugin startup - it returns immediately and loads async.
11
+ */
12
+ export declare function preloadTokenizer(): void;
13
+ /**
14
+ * Encodes text to tokens. Returns immediately with either:
15
+ * - Accurate token array (if tokenizer loaded)
16
+ * - Estimated token array based on char/4 heuristic (if still loading)
17
+ */
18
+ export declare function encodeText(text: string): number[];
19
+ /**
20
+ * Returns whether the tokenizer has finished loading.
21
+ * Useful for logging/debugging.
22
+ */
23
+ export declare function isTokenizerReady(): boolean;
24
+ //# sourceMappingURL=tokenizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../../lib/tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAUvC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Lazy tokenizer module - loads gpt-tokenizer in background to avoid blocking startup.
3
+ *
4
+ * The gpt-tokenizer package takes 5-15 seconds to initialize due to loading
5
+ * large vocabulary files. This module defers that load to happen asynchronously
6
+ * after plugin initialization, keeping startup instant.
7
+ */
8
+ let encodeFn = null;
9
+ let loadPromise = null;
10
+ /**
11
+ * Starts loading the tokenizer in the background.
12
+ * Call this at plugin startup - it returns immediately and loads async.
13
+ */
14
+ export function preloadTokenizer() {
15
+ if (loadPromise)
16
+ return;
17
+ loadPromise = import("gpt-tokenizer")
18
+ .then(({ encode }) => {
19
+ encodeFn = encode;
20
+ })
21
+ .catch(() => {
22
+ // Silently fail - fallback estimation will be used
23
+ });
24
+ }
25
+ /**
26
+ * Encodes text to tokens. Returns immediately with either:
27
+ * - Accurate token array (if tokenizer loaded)
28
+ * - Estimated token array based on char/4 heuristic (if still loading)
29
+ */
30
+ export function encodeText(text) {
31
+ if (encodeFn) {
32
+ return encodeFn(text);
33
+ }
34
+ // Fallback: ~4 chars per token (reasonable estimate for English text)
35
+ const estimatedLength = Math.ceil(text.length / 4);
36
+ return new Array(estimatedLength);
37
+ }
38
+ /**
39
+ * Returns whether the tokenizer has finished loading.
40
+ * Useful for logging/debugging.
41
+ */
42
+ export function isTokenizerReady() {
43
+ return encodeFn !== null;
44
+ }
45
+ //# sourceMappingURL=tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../lib/tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,IAAI,QAAQ,GAAoB,IAAI,CAAA;AACpC,IAAI,WAAW,GAAyB,IAAI,CAAA;AAE5C;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC5B,IAAI,WAAW;QAAE,OAAM;IAEvB,WAAW,GAAG,MAAM,CAAC,eAAe,CAAC;SAChC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;QACjB,QAAQ,GAAG,MAAM,CAAA;IACrB,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE;QACR,mDAAmD;IACvD,CAAC,CAAC,CAAA;AACV,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,IAAI,QAAQ,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IACD,sEAAsE;IACtE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAClD,OAAO,IAAI,KAAK,CAAC,eAAe,CAAC,CAAA;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC5B,OAAO,QAAQ,KAAK,IAAI,CAAA;AAC5B,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Logger } from "../logger";
2
+ import type { SessionState } from "../state";
3
+ import { ToolParameterEntry } from "../state";
4
+ import { PluginConfig } from "../config";
5
+ export type PruneReason = "completion" | "noise" | "extraction";
6
+ export declare const PRUNE_REASON_LABELS: Record<PruneReason, string>;
7
+ export declare function sendUnifiedNotification(client: any, logger: Logger, config: PluginConfig, state: SessionState, sessionId: string, pruneToolIds: string[], toolMetadata: Map<string, ToolParameterEntry>, reason: PruneReason | undefined, params: any, workingDirectory: string, distillation?: string[]): Promise<boolean>;
8
+ export declare function sendIgnoredMessage(client: any, sessionID: string, text: string, params: any, logger: Logger): Promise<void>;
9
+ //# sourceMappingURL=notification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../../../lib/ui/notification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAO5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,YAAY,CAAA;AAC/D,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAI3D,CAAA;AAqCD,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,GAAG,EACX,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,MAAM,EAAE,GAAG,EACX,gBAAgB,EAAE,MAAM,EACxB,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CA0BlB;AAED,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,GAAG,EACX,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,GAAG,EACX,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -0,0 +1,70 @@
1
+ import { formatExtracted, formatPrunedItemsList, formatStatsHeader, formatTokenCount, } from "./utils";
2
+ export const PRUNE_REASON_LABELS = {
3
+ completion: "Task Complete",
4
+ noise: "Noise Removal",
5
+ extraction: "Extraction",
6
+ };
7
+ function buildMinimalMessage(state, reason, distillation) {
8
+ const reasonSuffix = reason ? ` — ${PRUNE_REASON_LABELS[reason]}` : "";
9
+ let message = formatStatsHeader(state.stats.totalPruneTokens, state.stats.pruneTokenCounter) +
10
+ reasonSuffix;
11
+ return message + formatExtracted(distillation);
12
+ }
13
+ function buildDetailedMessage(state, reason, pruneToolIds, toolMetadata, workingDirectory, distillation) {
14
+ let message = formatStatsHeader(state.stats.totalPruneTokens, state.stats.pruneTokenCounter);
15
+ if (pruneToolIds.length > 0) {
16
+ const pruneTokenCounterStr = `~${formatTokenCount(state.stats.pruneTokenCounter)}`;
17
+ const reasonLabel = reason ? ` — ${PRUNE_REASON_LABELS[reason]}` : "";
18
+ message += `\n\n▣ Pruning (${pruneTokenCounterStr})${reasonLabel}`;
19
+ const itemLines = formatPrunedItemsList(pruneToolIds, toolMetadata, workingDirectory);
20
+ message += "\n" + itemLines.join("\n");
21
+ }
22
+ return (message + formatExtracted(distillation)).trim();
23
+ }
24
+ export async function sendUnifiedNotification(client, logger, config, state, sessionId, pruneToolIds, toolMetadata, reason, params, workingDirectory, distillation) {
25
+ const hasPruned = pruneToolIds.length > 0;
26
+ if (!hasPruned) {
27
+ return false;
28
+ }
29
+ if (config.pruneNotification === "off") {
30
+ return false;
31
+ }
32
+ const showExtraction = config.tools.extract.showDistillation ? distillation : undefined;
33
+ const message = config.pruneNotification === "minimal"
34
+ ? buildMinimalMessage(state, reason, showExtraction)
35
+ : buildDetailedMessage(state, reason, pruneToolIds, toolMetadata, workingDirectory, showExtraction);
36
+ await sendIgnoredMessage(client, sessionId, message, params, logger);
37
+ return true;
38
+ }
39
+ export async function sendIgnoredMessage(client, sessionID, text, params, logger) {
40
+ const agent = params.agent || undefined;
41
+ const model = params.providerId && params.modelId
42
+ ? {
43
+ providerID: params.providerId,
44
+ modelID: params.modelId,
45
+ }
46
+ : undefined;
47
+ try {
48
+ await client.session.prompt({
49
+ path: {
50
+ id: sessionID,
51
+ },
52
+ body: {
53
+ noReply: true,
54
+ agent: agent,
55
+ model: model,
56
+ parts: [
57
+ {
58
+ type: "text",
59
+ text: text,
60
+ ignored: true,
61
+ },
62
+ ],
63
+ },
64
+ });
65
+ }
66
+ catch (error) {
67
+ logger.error("Failed to send notification", { error: error.message });
68
+ }
69
+ }
70
+ //# sourceMappingURL=notification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.js","sourceRoot":"","sources":["../../../lib/ui/notification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { ToolParameterEntry } from "../state";
2
+ export declare function formatExtracted(distillation?: string[]): string;
3
+ export declare function formatStatsHeader(totalTokensSaved: number, pruneTokenCounter: number): string;
4
+ export declare function formatTokenCount(tokens: number): string;
5
+ export declare function truncate(str: string, maxLen?: number): string;
6
+ export declare function shortenPath(input: string, workingDirectory?: string): string;
7
+ /**
8
+ * Formats a list of pruned items in the style: "→ tool: parameter"
9
+ */
10
+ export declare function formatPrunedItemsList(pruneToolIds: string[], toolMetadata: Map<string, ToolParameterEntry>, workingDirectory?: string): string[];
11
+ /**
12
+ * Formats a PruningResult into a human-readable string for the prune tool output.
13
+ */
14
+ export declare function formatPruningResultForTool(prunedIds: string[], toolMetadata: Map<string, ToolParameterEntry>, workingDirectory?: string): string;
15
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../lib/ui/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAG7C,wBAAgB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAS/D;AAED,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAG7F;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAGjE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAU5E;AAeD;;GAEG;AACH,wBAAgB,qBAAqB,CACjC,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,gBAAgB,CAAC,EAAE,MAAM,GAC1B,MAAM,EAAE,CA0BV;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACtC,SAAS,EAAE,MAAM,EAAE,EACnB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,gBAAgB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAWR"}
@@ -0,0 +1,87 @@
1
+ import { extractParameterKey } from "../messages/utils";
2
+ export function formatExtracted(distillation) {
3
+ if (!distillation || distillation.length === 0) {
4
+ return "";
5
+ }
6
+ let result = `\n\n▣ Extracted`;
7
+ for (const finding of distillation) {
8
+ result += `\n───\n${finding}`;
9
+ }
10
+ return result;
11
+ }
12
+ export function formatStatsHeader(totalTokensSaved, pruneTokenCounter) {
13
+ const totalTokensSavedStr = `~${formatTokenCount(totalTokensSaved + pruneTokenCounter)}`;
14
+ return [`▣ DCP | ${totalTokensSavedStr} saved total`].join("\n");
15
+ }
16
+ export function formatTokenCount(tokens) {
17
+ if (tokens >= 1000) {
18
+ return `${(tokens / 1000).toFixed(1)}K`.replace(".0K", "K") + " tokens";
19
+ }
20
+ return tokens.toString() + " tokens";
21
+ }
22
+ export function truncate(str, maxLen = 60) {
23
+ if (str.length <= maxLen)
24
+ return str;
25
+ return str.slice(0, maxLen - 3) + "...";
26
+ }
27
+ export function shortenPath(input, workingDirectory) {
28
+ const inPathMatch = input.match(/^(.+) in (.+)$/);
29
+ if (inPathMatch) {
30
+ const prefix = inPathMatch[1];
31
+ const pathPart = inPathMatch[2];
32
+ const shortenedPath = shortenSinglePath(pathPart, workingDirectory);
33
+ return `${prefix} in ${shortenedPath}`;
34
+ }
35
+ return shortenSinglePath(input, workingDirectory);
36
+ }
37
+ function shortenSinglePath(path, workingDirectory) {
38
+ if (workingDirectory) {
39
+ if (path.startsWith(workingDirectory + "/")) {
40
+ return path.slice(workingDirectory.length + 1);
41
+ }
42
+ if (path === workingDirectory) {
43
+ return ".";
44
+ }
45
+ }
46
+ return path;
47
+ }
48
+ /**
49
+ * Formats a list of pruned items in the style: "→ tool: parameter"
50
+ */
51
+ export function formatPrunedItemsList(pruneToolIds, toolMetadata, workingDirectory) {
52
+ const lines = [];
53
+ for (const id of pruneToolIds) {
54
+ const metadata = toolMetadata.get(id);
55
+ if (metadata) {
56
+ const paramKey = extractParameterKey(metadata.tool, metadata.parameters);
57
+ if (paramKey) {
58
+ // Use 60 char limit to match notification style
59
+ const displayKey = truncate(shortenPath(paramKey, workingDirectory), 60);
60
+ lines.push(`→ ${metadata.tool}: ${displayKey}`);
61
+ }
62
+ else {
63
+ lines.push(`→ ${metadata.tool}`);
64
+ }
65
+ }
66
+ }
67
+ const knownCount = pruneToolIds.filter((id) => toolMetadata.has(id)).length;
68
+ const unknownCount = pruneToolIds.length - knownCount;
69
+ if (unknownCount > 0) {
70
+ lines.push(`→ (${unknownCount} tool${unknownCount > 1 ? "s" : ""} with unknown metadata)`);
71
+ }
72
+ return lines;
73
+ }
74
+ /**
75
+ * Formats a PruningResult into a human-readable string for the prune tool output.
76
+ */
77
+ export function formatPruningResultForTool(prunedIds, toolMetadata, workingDirectory) {
78
+ const lines = [];
79
+ lines.push(`Context pruning complete. Pruned ${prunedIds.length} tool outputs.`);
80
+ lines.push("");
81
+ if (prunedIds.length > 0) {
82
+ lines.push(`Semantically pruned (${prunedIds.length}):`);
83
+ lines.push(...formatPrunedItemsList(prunedIds, toolMetadata, workingDirectory));
84
+ }
85
+ return lines.join("\n").trim();
86
+ }
87
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../lib/ui/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package.json",
3
+ "name": "@dev4s/opencode-dcp",
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "description": "OpenCode plugin that optimizes token usage by pruning obsolete tool outputs from conversation context",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "scripts": {
10
+ "clean": "rimraf dist",
11
+ "build": "npm run clean && tsc && cpy \"lib/prompts/**/*\" dist/lib/prompts",
12
+ "postbuild": "rimraf dist/logs",
13
+ "prepublishOnly": "npm run build",
14
+ "dev": "opencode plugin dev",
15
+ "typecheck": "tsc --noEmit",
16
+ "test": "node --import tsx --test tests/*.test.ts",
17
+ "format": "prettier --write .",
18
+ "format:check": "prettier --check ."
19
+ },
20
+ "keywords": [
21
+ "opencode",
22
+ "opencode-plugin",
23
+ "plugin",
24
+ "context",
25
+ "pruning",
26
+ "optimization",
27
+ "tokens"
28
+ ],
29
+ "author": "dev4s",
30
+ "license": "MIT",
31
+ "peerDependencies": {
32
+ "@opencode-ai/plugin": ">=0.13.7"
33
+ },
34
+ "dependencies": {
35
+ "@ai-sdk/openai-compatible": "^1.0.28",
36
+ "@opencode-ai/sdk": "latest",
37
+ "@tarquinen/opencode-auth-provider": "^0.1.7",
38
+ "ai": "^5.0.106",
39
+ "gpt-tokenizer": "^3.4.0",
40
+ "jsonc-parser": "^3.3.1",
41
+ "zod": "^4.1.13"
42
+ },
43
+ "devDependencies": {
44
+ "@opencode-ai/plugin": "^1.0.143",
45
+ "@types/node": "^24.10.1",
46
+ "cpy-cli": "^5.0.0",
47
+ "prettier": "^3.4.2",
48
+ "rimraf": "^6.0.0",
49
+ "tsx": "^4.21.0",
50
+ "typescript": "^5.9.3"
51
+ },
52
+ "files": [
53
+ "dist/",
54
+ "README.md",
55
+ "LICENSE"
56
+ ]
57
+ }