@tarquinen/opencode-dcp 1.2.3 → 1.2.5

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 (54) hide show
  1. package/README.md +13 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +9 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/commands/context.d.ts +49 -0
  6. package/dist/lib/commands/context.d.ts.map +1 -0
  7. package/dist/lib/commands/context.js +190 -0
  8. package/dist/lib/commands/context.js.map +1 -0
  9. package/dist/lib/commands/help.d.ts +15 -0
  10. package/dist/lib/commands/help.d.ts.map +1 -0
  11. package/dist/lib/commands/help.js +30 -0
  12. package/dist/lib/commands/help.js.map +1 -0
  13. package/dist/lib/commands/stats.d.ts +15 -0
  14. package/dist/lib/commands/stats.d.ts.map +1 -0
  15. package/dist/lib/commands/stats.js +44 -0
  16. package/dist/lib/commands/stats.js.map +1 -0
  17. package/dist/lib/config.d.ts +1 -0
  18. package/dist/lib/config.d.ts.map +1 -1
  19. package/dist/lib/config.js +22 -0
  20. package/dist/lib/config.js.map +1 -1
  21. package/dist/lib/hooks.d.ts +7 -0
  22. package/dist/lib/hooks.d.ts.map +1 -1
  23. package/dist/lib/hooks.js +47 -0
  24. package/dist/lib/hooks.js.map +1 -1
  25. package/dist/lib/logger.d.ts.map +1 -1
  26. package/dist/lib/logger.js +6 -0
  27. package/dist/lib/logger.js.map +1 -1
  28. package/dist/lib/prompts/system/both.d.ts +1 -1
  29. package/dist/lib/prompts/system/both.d.ts.map +1 -1
  30. package/dist/lib/prompts/system/both.js +4 -2
  31. package/dist/lib/prompts/system/both.js.map +1 -1
  32. package/dist/lib/prompts/system/discard.d.ts +1 -1
  33. package/dist/lib/prompts/system/discard.d.ts.map +1 -1
  34. package/dist/lib/prompts/system/discard.js +4 -2
  35. package/dist/lib/prompts/system/discard.js.map +1 -1
  36. package/dist/lib/prompts/system/extract.d.ts +1 -1
  37. package/dist/lib/prompts/system/extract.d.ts.map +1 -1
  38. package/dist/lib/prompts/system/extract.js +4 -2
  39. package/dist/lib/prompts/system/extract.js.map +1 -1
  40. package/dist/lib/state/persistence.d.ts +6 -0
  41. package/dist/lib/state/persistence.d.ts.map +1 -1
  42. package/dist/lib/state/persistence.js +34 -0
  43. package/dist/lib/state/persistence.js.map +1 -1
  44. package/dist/lib/state/tool-cache.d.ts.map +1 -1
  45. package/dist/lib/state/tool-cache.js +3 -1
  46. package/dist/lib/state/tool-cache.js.map +1 -1
  47. package/dist/lib/strategies/tools.d.ts.map +1 -1
  48. package/dist/lib/strategies/tools.js +8 -8
  49. package/dist/lib/strategies/tools.js.map +1 -1
  50. package/dist/lib/strategies/utils.d.ts +1 -3
  51. package/dist/lib/strategies/utils.d.ts.map +1 -1
  52. package/dist/lib/strategies/utils.js +9 -10
  53. package/dist/lib/strategies/utils.js.map +1 -1
  54. package/package.json +2 -2
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Automatically reduces token usage in OpenCode by removing obsolete tool outputs from conversation history.
6
6
 
7
- ![DCP in action](dcp-demo3.png)
7
+ ![DCP in action](dcp-demo5.png)
8
8
 
9
9
  ## Installation
10
10
 
@@ -19,8 +19,6 @@ Add to your OpenCode config:
19
19
 
20
20
  Using `@latest` ensures you always get the newest version automatically when OpenCode starts.
21
21
 
22
- > **Note:** If you use OAuth plugins (e.g., for Google or other services), place this plugin last in your `plugin` array to avoid interfering with their authentication flows.
23
-
24
22
  Restart OpenCode. The plugin will automatically start optimizing your sessions.
25
23
 
26
24
  ## How Pruning Works
@@ -49,6 +47,8 @@ LLM providers like Anthropic and OpenAI cache prompts based on exact prefix matc
49
47
 
50
48
  **Trade-off:** You lose some cache read benefits but gain larger token savings from reduced context size and performance improvements through reduced context poisoning. In most cases, the token savings outweigh the cache miss cost—especially in long sessions where context bloat becomes significant.
51
49
 
50
+ > **Note:** In testing, cache hit rates were approximately 65% with DCP enabled vs 85% without.
51
+
52
52
  **Best use case:** Providers that count usage in requests, such as Github Copilot and Google Antigravity have no negative price impact.
53
53
 
54
54
  ## Configuration
@@ -71,6 +71,8 @@ DCP uses its own config file:
71
71
  "debug": false,
72
72
  // Notification display: "off", "minimal", or "detailed"
73
73
  "pruneNotification": "detailed",
74
+ // Enable or disable slash commands (/dcp)
75
+ "commands": true,
74
76
  // Protect from pruning for <turns> message turns
75
77
  "turnProtection": {
76
78
  "enabled": false,
@@ -126,6 +128,14 @@ DCP uses its own config file:
126
128
 
127
129
  </details>
128
130
 
131
+ ### Commands
132
+
133
+ DCP provides a `/dcp` slash command:
134
+
135
+ - `/dcp` — Shows available DCP commands
136
+ - `/dcp context` — Shows a breakdown of your current session's token usage by category (system, user, assistant, tools, etc.) and how much has been saved through pruning.
137
+ - `/dcp stats` — Shows cumulative pruning statistics across all sessions.
138
+
129
139
  ### Turn Protection
130
140
 
131
141
  When enabled, turn protection prevents tool outputs from being pruned for a configurable number of message turns. This gives the AI time to reference recent tool outputs before they become prunable. Applies to both `discard` and `extract` tools, as well as automatic strategies.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAOjD,QAAA,MAAM,MAAM,EAAE,MA6EK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAWjD,QAAA,MAAM,MAAM,EAAE,MAoFK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { getConfig } from "./lib/config";
2
2
  import { Logger } from "./lib/logger";
3
3
  import { createSessionState } from "./lib/state";
4
4
  import { createDiscardTool, createExtractTool } from "./lib/strategies";
5
- import { createChatMessageTransformHandler, createSystemPromptHandler } from "./lib/hooks";
5
+ import { createChatMessageTransformHandler, createCommandExecuteHandler, createSystemPromptHandler, } from "./lib/hooks";
6
6
  const plugin = (async (ctx) => {
7
7
  const config = getConfig(ctx);
8
8
  if (!config.enabled) {
@@ -43,8 +43,13 @@ const plugin = (async (ctx) => {
43
43
  }),
44
44
  },
45
45
  config: async (opencodeConfig) => {
46
- // Add enabled tools to primary_tools by mutating the opencode config
47
- // This works because config is cached and passed by reference
46
+ if (config.commands) {
47
+ opencodeConfig.command ??= {};
48
+ opencodeConfig.command["dcp"] = {
49
+ template: "",
50
+ description: "Show available DCP commands",
51
+ };
52
+ }
48
53
  const toolsToAdd = [];
49
54
  if (config.tools.discard.enabled)
50
55
  toolsToAdd.push("discard");
@@ -59,6 +64,7 @@ const plugin = (async (ctx) => {
59
64
  logger.info(`Added ${toolsToAdd.map((t) => `'${t}'`).join(" and ")} to experimental.primary_tools via config mutation`);
60
65
  }
61
66
  },
67
+ "command.execute.before": createCommandExecuteHandler(ctx.client, state, logger, config),
62
68
  };
63
69
  });
64
70
  export default plugin;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,iCAAiC,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAE1F,MAAM,MAAM,GAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAClC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACb,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAA;IAElC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;KAChC,CAAC,CAAA;IAEF,OAAO;QACH,oCAAoC,EAAE,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;QAEtF,sCAAsC,EAAE,iCAAiC,CACrE,GAAG,CAAC,MAAM,EACV,KAAK,EACL,MAAM,EACN,MAAM,CACT;QACD,cAAc,EAAE,KAAK,EACjB,KAMC,EACD,OAAY,EACd,EAAE;YACA,wDAAwD;YACxD,oDAAoD;YACpD,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;YAC7B,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,EAAE;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;SACL;QACD,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;YAC7B,qEAAqE;YACrE,8DAA8D;YAC9D,MAAM,UAAU,GAAa,EAAE,CAAA;YAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAE5D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,oBAAoB,GAAG,cAAc,CAAC,YAAY,EAAE,aAAa,IAAI,EAAE,CAAA;gBAC7E,cAAc,CAAC,YAAY,GAAG;oBAC1B,GAAG,cAAc,CAAC,YAAY;oBAC9B,aAAa,EAAE,CAAC,GAAG,oBAAoB,EAAE,GAAG,UAAU,CAAC;iBAC1D,CAAA;gBACD,MAAM,CAAC,IAAI,CACP,SAAS,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,oDAAoD,CAC7G,CAAA;YACL,CAAC;QACL,CAAC;KACJ,CAAA;AACL,CAAC,CAAkB,CAAA;AAEnB,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EACH,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,GAC5B,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,GAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAClC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACb,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAA;IAElC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;KAChC,CAAC,CAAA;IAEF,OAAO;QACH,oCAAoC,EAAE,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;QAEtF,sCAAsC,EAAE,iCAAiC,CACrE,GAAG,CAAC,MAAM,EACV,KAAK,EACL,MAAM,EACN,MAAM,CACT;QACD,cAAc,EAAE,KAAK,EACjB,KAMC,EACD,OAAY,EACd,EAAE;YACA,wDAAwD;YACxD,oDAAoD;YACpD,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;YAC7B,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,EAAE;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;SACL;QACD,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;YAC7B,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAClB,cAAc,CAAC,OAAO,KAAK,EAAE,CAAA;gBAC7B,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG;oBAC5B,QAAQ,EAAE,EAAE;oBACZ,WAAW,EAAE,6BAA6B;iBAC7C,CAAA;YACL,CAAC;YAED,MAAM,UAAU,GAAa,EAAE,CAAA;YAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAE5D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,oBAAoB,GAAG,cAAc,CAAC,YAAY,EAAE,aAAa,IAAI,EAAE,CAAA;gBAC7E,cAAc,CAAC,YAAY,GAAG;oBAC1B,GAAG,cAAc,CAAC,YAAY;oBAC9B,aAAa,EAAE,CAAC,GAAG,oBAAoB,EAAE,GAAG,UAAU,CAAC;iBAC1D,CAAA;gBACD,MAAM,CAAC,IAAI,CACP,SAAS,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,oDAAoD,CAC7G,CAAA;YACL,CAAC;QACL,CAAC;QACD,wBAAwB,EAAE,2BAA2B,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;KAC3F,CAAA;AACL,CAAC,CAAkB,CAAA;AAEnB,eAAe,MAAM,CAAA"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * DCP Context Command
3
+ * Shows a visual breakdown of token usage in the current session.
4
+ *
5
+ * TOKEN CALCULATION STRATEGY
6
+ * ==========================
7
+ * We minimize tokenizer estimation by leveraging API-reported values wherever possible.
8
+ *
9
+ * WHAT WE GET FROM THE API (exact):
10
+ * - tokens.input : Input tokens for each assistant response
11
+ * - tokens.output : Output tokens generated (includes text + tool calls)
12
+ * - tokens.reasoning: Reasoning tokens used
13
+ * - tokens.cache : Cache read/write tokens
14
+ *
15
+ * HOW WE CALCULATE EACH CATEGORY:
16
+ *
17
+ * SYSTEM = firstAssistant.input + cache.read - tokenizer(firstUserMessage)
18
+ * The first response's input contains system + first user message.
19
+ *
20
+ * TOOLS = tokenizer(toolInputs + toolOutputs) - prunedTokens
21
+ * We must tokenize tools anyway for pruning decisions.
22
+ *
23
+ * USER = tokenizer(all user messages)
24
+ * User messages are typically small, so estimation is acceptable.
25
+ *
26
+ * ASSISTANT = total - system - user - tools
27
+ * Calculated as residual. This absorbs:
28
+ * - Assistant text output tokens
29
+ * - Reasoning tokens (if persisted by the model)
30
+ * - Any estimation errors
31
+ *
32
+ * TOTAL = input + output + reasoning + cache.read + cache.write
33
+ * Matches opencode's UI display.
34
+ *
35
+ * WHY ASSISTANT IS THE RESIDUAL:
36
+ * If reasoning tokens persist in context (model-dependent), they semantically
37
+ * belong with "Assistant" since reasoning IS assistant-generated content.
38
+ */
39
+ import type { Logger } from "../logger";
40
+ import type { SessionState, WithParts } from "../state";
41
+ export interface ContextCommandContext {
42
+ client: any;
43
+ state: SessionState;
44
+ logger: Logger;
45
+ sessionId: string;
46
+ messages: WithParts[];
47
+ }
48
+ export declare function handleContextCommand(ctx: ContextCommandContext): Promise<void>;
49
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../lib/commands/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAQvD,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACxB;AAsLD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * DCP Context Command
3
+ * Shows a visual breakdown of token usage in the current session.
4
+ *
5
+ * TOKEN CALCULATION STRATEGY
6
+ * ==========================
7
+ * We minimize tokenizer estimation by leveraging API-reported values wherever possible.
8
+ *
9
+ * WHAT WE GET FROM THE API (exact):
10
+ * - tokens.input : Input tokens for each assistant response
11
+ * - tokens.output : Output tokens generated (includes text + tool calls)
12
+ * - tokens.reasoning: Reasoning tokens used
13
+ * - tokens.cache : Cache read/write tokens
14
+ *
15
+ * HOW WE CALCULATE EACH CATEGORY:
16
+ *
17
+ * SYSTEM = firstAssistant.input + cache.read - tokenizer(firstUserMessage)
18
+ * The first response's input contains system + first user message.
19
+ *
20
+ * TOOLS = tokenizer(toolInputs + toolOutputs) - prunedTokens
21
+ * We must tokenize tools anyway for pruning decisions.
22
+ *
23
+ * USER = tokenizer(all user messages)
24
+ * User messages are typically small, so estimation is acceptable.
25
+ *
26
+ * ASSISTANT = total - system - user - tools
27
+ * Calculated as residual. This absorbs:
28
+ * - Assistant text output tokens
29
+ * - Reasoning tokens (if persisted by the model)
30
+ * - Any estimation errors
31
+ *
32
+ * TOTAL = input + output + reasoning + cache.read + cache.write
33
+ * Matches opencode's UI display.
34
+ *
35
+ * WHY ASSISTANT IS THE RESIDUAL:
36
+ * If reasoning tokens persist in context (model-dependent), they semantically
37
+ * belong with "Assistant" since reasoning IS assistant-generated content.
38
+ */
39
+ import { sendIgnoredMessage } from "../ui/notification";
40
+ import { formatTokenCount } from "../ui/utils";
41
+ import { isMessageCompacted } from "../shared-utils";
42
+ import { isIgnoredUserMessage } from "../messages/utils";
43
+ import { countTokens, getCurrentParams } from "../strategies/utils";
44
+ function analyzeTokens(state, messages) {
45
+ const breakdown = {
46
+ system: 0,
47
+ user: 0,
48
+ assistant: 0,
49
+ tools: 0,
50
+ toolCount: 0,
51
+ prunedTokens: state.stats.totalPruneTokens,
52
+ prunedCount: state.prune.toolIds.length,
53
+ total: 0,
54
+ };
55
+ let firstAssistant;
56
+ for (const msg of messages) {
57
+ if (msg.info.role === "assistant") {
58
+ const assistantInfo = msg.info;
59
+ if (assistantInfo.tokens?.input > 0 || assistantInfo.tokens?.cache?.read > 0) {
60
+ firstAssistant = assistantInfo;
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ let lastAssistant;
66
+ for (let i = messages.length - 1; i >= 0; i--) {
67
+ const msg = messages[i];
68
+ if (msg.info.role === "assistant") {
69
+ const assistantInfo = msg.info;
70
+ if (assistantInfo.tokens?.output > 0) {
71
+ lastAssistant = assistantInfo;
72
+ break;
73
+ }
74
+ }
75
+ }
76
+ const apiInput = lastAssistant?.tokens?.input || 0;
77
+ const apiOutput = lastAssistant?.tokens?.output || 0;
78
+ const apiReasoning = lastAssistant?.tokens?.reasoning || 0;
79
+ const apiCacheRead = lastAssistant?.tokens?.cache?.read || 0;
80
+ const apiCacheWrite = lastAssistant?.tokens?.cache?.write || 0;
81
+ breakdown.total = apiInput + apiOutput + apiReasoning + apiCacheRead + apiCacheWrite;
82
+ const userTextParts = [];
83
+ const toolInputParts = [];
84
+ const toolOutputParts = [];
85
+ let firstUserText = "";
86
+ let foundFirstUser = false;
87
+ for (const msg of messages) {
88
+ if (isMessageCompacted(state, msg))
89
+ continue;
90
+ if (msg.info.role === "user" && isIgnoredUserMessage(msg))
91
+ continue;
92
+ for (const part of msg.parts) {
93
+ if (part.type === "text" && msg.info.role === "user") {
94
+ const textPart = part;
95
+ const text = textPart.text || "";
96
+ userTextParts.push(text);
97
+ if (!foundFirstUser) {
98
+ firstUserText += text;
99
+ }
100
+ }
101
+ else if (part.type === "tool") {
102
+ const toolPart = part;
103
+ breakdown.toolCount++;
104
+ if (toolPart.state?.input) {
105
+ const inputStr = typeof toolPart.state.input === "string"
106
+ ? toolPart.state.input
107
+ : JSON.stringify(toolPart.state.input);
108
+ toolInputParts.push(inputStr);
109
+ }
110
+ if (toolPart.state?.status === "completed" && toolPart.state?.output) {
111
+ const outputStr = typeof toolPart.state.output === "string"
112
+ ? toolPart.state.output
113
+ : JSON.stringify(toolPart.state.output);
114
+ toolOutputParts.push(outputStr);
115
+ }
116
+ }
117
+ }
118
+ if (msg.info.role === "user" && !isIgnoredUserMessage(msg) && !foundFirstUser) {
119
+ foundFirstUser = true;
120
+ }
121
+ }
122
+ const firstUserTokens = countTokens(firstUserText);
123
+ breakdown.user = countTokens(userTextParts.join("\n"));
124
+ const toolInputTokens = countTokens(toolInputParts.join("\n"));
125
+ const toolOutputTokens = countTokens(toolOutputParts.join("\n"));
126
+ if (firstAssistant) {
127
+ const firstInput = (firstAssistant.tokens?.input || 0) + (firstAssistant.tokens?.cache?.read || 0);
128
+ breakdown.system = Math.max(0, firstInput - firstUserTokens);
129
+ }
130
+ breakdown.tools = Math.max(0, toolInputTokens + toolOutputTokens - breakdown.prunedTokens);
131
+ breakdown.assistant = Math.max(0, breakdown.total - breakdown.system - breakdown.user - breakdown.tools);
132
+ return breakdown;
133
+ }
134
+ function createBar(value, maxValue, width, char = "█") {
135
+ if (maxValue === 0)
136
+ return "";
137
+ const filled = Math.round((value / maxValue) * width);
138
+ const bar = char.repeat(Math.max(0, filled));
139
+ return bar;
140
+ }
141
+ function formatContextMessage(breakdown) {
142
+ const lines = [];
143
+ const barWidth = 30;
144
+ const toolsInContext = breakdown.toolCount - breakdown.prunedCount;
145
+ const toolsLabel = `Tools (${toolsInContext})`;
146
+ const categories = [
147
+ { label: "System", value: breakdown.system, char: "█" },
148
+ { label: "User", value: breakdown.user, char: "▓" },
149
+ { label: "Assistant", value: breakdown.assistant, char: "▒" },
150
+ { label: toolsLabel, value: breakdown.tools, char: "░" },
151
+ ];
152
+ const maxLabelLen = Math.max(...categories.map((c) => c.label.length));
153
+ lines.push("╭───────────────────────────────────────────────────────────╮");
154
+ lines.push("│ DCP Context Analysis │");
155
+ lines.push("╰───────────────────────────────────────────────────────────╯");
156
+ lines.push("");
157
+ lines.push("Session Context Breakdown:");
158
+ lines.push("─".repeat(60));
159
+ lines.push("");
160
+ for (const cat of categories) {
161
+ const bar = createBar(cat.value, breakdown.total, barWidth, cat.char);
162
+ const percentage = breakdown.total > 0 ? ((cat.value / breakdown.total) * 100).toFixed(1) : "0.0";
163
+ const labelWithPct = `${cat.label.padEnd(maxLabelLen)} ${percentage.padStart(5)}% `;
164
+ const valueStr = formatTokenCount(cat.value).padStart(13);
165
+ lines.push(`${labelWithPct}│${bar.padEnd(barWidth)}│${valueStr}`);
166
+ }
167
+ lines.push("");
168
+ lines.push("─".repeat(60));
169
+ lines.push("");
170
+ lines.push("Summary:");
171
+ if (breakdown.prunedTokens > 0) {
172
+ const withoutPruning = breakdown.total + breakdown.prunedTokens;
173
+ lines.push(` Pruned: ${breakdown.prunedCount} tools (~${formatTokenCount(breakdown.prunedTokens)})`);
174
+ lines.push(` Current context: ~${formatTokenCount(breakdown.total)}`);
175
+ lines.push(` Without DCP: ~${formatTokenCount(withoutPruning)}`);
176
+ }
177
+ else {
178
+ lines.push(` Current context: ~${formatTokenCount(breakdown.total)}`);
179
+ }
180
+ lines.push("");
181
+ return lines.join("\n");
182
+ }
183
+ export async function handleContextCommand(ctx) {
184
+ const { client, state, logger, sessionId, messages } = ctx;
185
+ const breakdown = analyzeTokens(state, messages);
186
+ const message = formatContextMessage(breakdown);
187
+ const params = getCurrentParams(state, messages, logger);
188
+ await sendIgnoredMessage(client, sessionId, message, params, logger);
189
+ }
190
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../lib/commands/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * DCP Help command handler.
3
+ * Shows available DCP commands and their descriptions.
4
+ */
5
+ import type { Logger } from "../logger";
6
+ import type { SessionState, WithParts } from "../state";
7
+ export interface HelpCommandContext {
8
+ client: any;
9
+ state: SessionState;
10
+ logger: Logger;
11
+ sessionId: string;
12
+ messages: WithParts[];
13
+ }
14
+ export declare function handleHelpCommand(ctx: HelpCommandContext): Promise<void>;
15
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/commands/help.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAIvD,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACxB;AAqBD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9E"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * DCP Help command handler.
3
+ * Shows available DCP commands and their descriptions.
4
+ */
5
+ import { sendIgnoredMessage } from "../ui/notification";
6
+ import { getCurrentParams } from "../strategies/utils";
7
+ function formatHelpMessage() {
8
+ const lines = [];
9
+ lines.push("╭───────────────────────────────────────────────────────────╮");
10
+ lines.push("│ DCP Commands │");
11
+ lines.push("╰───────────────────────────────────────────────────────────╯");
12
+ lines.push("");
13
+ lines.push("Available commands:");
14
+ lines.push(" context - Show token usage breakdown for current session");
15
+ lines.push(" stats - Show DCP pruning statistics");
16
+ lines.push("");
17
+ lines.push("Examples:");
18
+ lines.push(" /dcp context");
19
+ lines.push(" /dcp stats");
20
+ lines.push("");
21
+ return lines.join("\n");
22
+ }
23
+ export async function handleHelpCommand(ctx) {
24
+ const { client, state, logger, sessionId, messages } = ctx;
25
+ const message = formatHelpMessage();
26
+ const params = getCurrentParams(state, messages, logger);
27
+ await sendIgnoredMessage(client, sessionId, message, params, logger);
28
+ logger.info("Help command executed");
29
+ }
30
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../../lib/commands/help.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAUtD,SAAS,iBAAiB;IACtB,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;IACjC,KAAK,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAA;IACzE,KAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;IACtD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACvB,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IAC5B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAuB;IAC3D,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;IAE1D,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAA;IAEnC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IACxD,MAAM,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAEpE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * DCP Stats command handler.
3
+ * Shows pruning statistics for the current session and all-time totals.
4
+ */
5
+ import type { Logger } from "../logger";
6
+ import type { SessionState, WithParts } from "../state";
7
+ export interface StatsCommandContext {
8
+ client: any;
9
+ state: SessionState;
10
+ logger: Logger;
11
+ sessionId: string;
12
+ messages: WithParts[];
13
+ }
14
+ export declare function handleStatsCommand(ctx: StatsCommandContext): Promise<void>;
15
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../lib/commands/stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAMvD,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,GAAG,CAAA;IACX,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACxB;AA2BD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhF"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * DCP Stats command handler.
3
+ * Shows pruning statistics for the current session and all-time totals.
4
+ */
5
+ import { sendIgnoredMessage } from "../ui/notification";
6
+ import { formatTokenCount } from "../ui/utils";
7
+ import { loadAllSessionStats } from "../state/persistence";
8
+ import { getCurrentParams } from "../strategies/utils";
9
+ function formatStatsMessage(sessionTokens, sessionTools, allTime) {
10
+ const lines = [];
11
+ lines.push("╭───────────────────────────────────────────────────────────╮");
12
+ lines.push("│ DCP Statistics │");
13
+ lines.push("╰───────────────────────────────────────────────────────────╯");
14
+ lines.push("");
15
+ lines.push("Session:");
16
+ lines.push("─".repeat(60));
17
+ lines.push(` Tokens pruned: ~${formatTokenCount(sessionTokens)}`);
18
+ lines.push(` Tools pruned: ${sessionTools}`);
19
+ lines.push("");
20
+ lines.push("All-time:");
21
+ lines.push("─".repeat(60));
22
+ lines.push(` Tokens saved: ~${formatTokenCount(allTime.totalTokens)}`);
23
+ lines.push(` Tools pruned: ${allTime.totalTools}`);
24
+ lines.push(` Sessions: ${allTime.sessionCount}`);
25
+ return lines.join("\n");
26
+ }
27
+ export async function handleStatsCommand(ctx) {
28
+ const { client, state, logger, sessionId, messages } = ctx;
29
+ // Session stats from in-memory state
30
+ const sessionTokens = state.stats.totalPruneTokens;
31
+ const sessionTools = state.prune.toolIds.length;
32
+ // All-time stats from storage files
33
+ const allTime = await loadAllSessionStats(logger);
34
+ const message = formatStatsMessage(sessionTokens, sessionTools, allTime);
35
+ const params = getCurrentParams(state, messages, logger);
36
+ await sendIgnoredMessage(client, sessionId, message, params, logger);
37
+ logger.info("Stats command executed", {
38
+ sessionTokens,
39
+ sessionTools,
40
+ allTimeTokens: allTime.totalTokens,
41
+ allTimeTools: allTime.totalTools,
42
+ });
43
+ }
44
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../lib/commands/stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAwB,MAAM,sBAAsB,CAAA;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAUtD,SAAS,kBAAkB,CACvB,aAAqB,EACrB,YAAoB,EACpB,OAAwB;IAExB,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACtB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,KAAK,CAAC,IAAI,CAAC,qBAAqB,gBAAgB,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;IAClE,KAAK,CAAC,IAAI,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAA;IAC/C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACvB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,KAAK,CAAC,IAAI,CAAC,qBAAqB,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IACxE,KAAK,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;IACrD,KAAK,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IAEvD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAwB;IAC7D,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;IAE1D,qCAAqC;IACrC,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAA;IAClD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAA;IAE/C,oCAAoC;IACpC,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAEjD,MAAM,OAAO,GAAG,kBAAkB,CAAC,aAAa,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAExE,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IACxD,MAAM,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAEpE,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE;QAClC,aAAa;QACb,YAAY;QACZ,aAAa,EAAE,OAAO,CAAC,WAAW;QAClC,YAAY,EAAE,OAAO,CAAC,UAAU;KACnC,CAAC,CAAA;AACN,CAAC"}
@@ -36,6 +36,7 @@ export interface PluginConfig {
36
36
  enabled: boolean;
37
37
  debug: boolean;
38
38
  pruneNotification: "off" | "minimal" | "detailed";
39
+ commands: boolean;
39
40
  turnProtection: TurnProtection;
40
41
  protectedFilePatterns: string[];
41
42
  tools: Tools;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,gBAAgB,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,KAAK;IAClB,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;CACvB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,iBAAiB,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAAA;IACjD,cAAc,EAAE,cAAc,CAAA;IAC9B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE;QACR,aAAa,EAAE,aAAa,CAAA;QAC5B,eAAe,EAAE,eAAe,CAAA;QAChC,WAAW,EAAE,WAAW,CAAA;KAC3B,CAAA;CACJ;AAgBD,eAAO,MAAM,iBAAiB,aAkC5B,CAAA;AAgBF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAG9E;AA4hBD,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,YAAY,CA6HxD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,gBAAgB,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,KAAK;IAClB,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;CACvB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,iBAAiB,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAAA;IACjD,QAAQ,EAAE,OAAO,CAAA;IACjB,cAAc,EAAE,cAAc,CAAA;IAC9B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE;QACR,aAAa,EAAE,aAAa,CAAA;QAC5B,eAAe,EAAE,eAAe,CAAA;QAChC,WAAW,EAAE,WAAW,CAAA;KAC3B,CAAA;CACJ;AAgBD,eAAO,MAAM,iBAAiB,aAmC5B,CAAA;AAgBF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAG9E;AAkjBD,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,YAAY,CAgIxD"}
@@ -26,6 +26,7 @@ export const VALID_CONFIG_KEYS = new Set([
26
26
  "turnProtection.enabled",
27
27
  "turnProtection.turns",
28
28
  "protectedFilePatterns",
29
+ "commands",
29
30
  "tools",
30
31
  "tools.settings",
31
32
  "tools.settings.nudgeEnabled",
@@ -121,6 +122,15 @@ function validateConfigTypes(config) {
121
122
  });
122
123
  }
123
124
  }
125
+ // Commands validator
126
+ const commands = config.commands;
127
+ if (commands !== undefined && typeof commands !== "boolean") {
128
+ errors.push({
129
+ key: "commands",
130
+ expected: "boolean",
131
+ actual: typeof commands,
132
+ });
133
+ }
124
134
  // Tools validators
125
135
  const tools = config.tools;
126
136
  if (tools) {
@@ -278,6 +288,7 @@ const defaultConfig = {
278
288
  enabled: true,
279
289
  debug: false,
280
290
  pruneNotification: "detailed",
291
+ commands: true,
281
292
  turnProtection: {
282
293
  enabled: false,
283
294
  turns: 4,
@@ -380,6 +391,8 @@ function createDefaultConfig() {
380
391
  "debug": false,
381
392
  // Notification display: "off", "minimal", or "detailed"
382
393
  "pruneNotification": "detailed",
394
+ // Enable or disable slash commands (/dcp)
395
+ "commands": true,
383
396
  // Protect from pruning for <turns> message turns
384
397
  "turnProtection": {
385
398
  "enabled": false,
@@ -505,9 +518,15 @@ function mergeTools(base, override) {
505
518
  },
506
519
  };
507
520
  }
521
+ function mergeCommands(base, override) {
522
+ if (override === undefined)
523
+ return base;
524
+ return override;
525
+ }
508
526
  function deepCloneConfig(config) {
509
527
  return {
510
528
  ...config,
529
+ commands: config.commands,
511
530
  turnProtection: { ...config.turnProtection },
512
531
  protectedFilePatterns: [...config.protectedFilePatterns],
513
532
  tools: {
@@ -561,6 +580,7 @@ export function getConfig(ctx) {
561
580
  enabled: result.data.enabled ?? config.enabled,
562
581
  debug: result.data.debug ?? config.debug,
563
582
  pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
583
+ commands: mergeCommands(config.commands, result.data.commands),
564
584
  turnProtection: {
565
585
  enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
566
586
  turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,
@@ -605,6 +625,7 @@ export function getConfig(ctx) {
605
625
  enabled: result.data.enabled ?? config.enabled,
606
626
  debug: result.data.debug ?? config.debug,
607
627
  pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
628
+ commands: mergeCommands(config.commands, result.data.commands),
608
629
  turnProtection: {
609
630
  enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
610
631
  turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,
@@ -645,6 +666,7 @@ export function getConfig(ctx) {
645
666
  enabled: result.data.enabled ?? config.enabled,
646
667
  debug: result.data.debug ?? config.debug,
647
668
  pruneNotification: result.data.pruneNotification ?? config.pruneNotification,
669
+ commands: mergeCommands(config.commands, result.data.commands),
648
670
  turnProtection: {
649
671
  enabled: result.data.turnProtection?.enabled ?? config.turnProtection.enabled,
650
672
  turns: result.data.turnProtection?.turns ?? config.turnProtection.turns,