@kaitranntt/ccs 4.4.0 → 5.0.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 (262) hide show
  1. package/README.md +14 -7
  2. package/VERSION +1 -1
  3. package/config/base-agy.settings.json +10 -0
  4. package/config/base-codex.settings.json +10 -0
  5. package/config/base-gemini.settings.json +10 -0
  6. package/dist/auth/auth-commands.d.ts +52 -0
  7. package/dist/auth/auth-commands.d.ts.map +1 -0
  8. package/dist/auth/auth-commands.js +479 -0
  9. package/dist/auth/auth-commands.js.map +1 -0
  10. package/dist/auth/profile-detector.d.ts +68 -0
  11. package/dist/auth/profile-detector.d.ts.map +1 -0
  12. package/dist/auth/profile-detector.js +209 -0
  13. package/dist/auth/profile-detector.js.map +1 -0
  14. package/dist/auth/profile-registry.d.ts +60 -0
  15. package/dist/auth/profile-registry.d.ts.map +1 -0
  16. package/dist/auth/profile-registry.js +188 -0
  17. package/dist/auth/profile-registry.js.map +1 -0
  18. package/dist/ccs.d.ts +10 -0
  19. package/dist/ccs.d.ts.map +1 -0
  20. package/dist/ccs.js +320 -0
  21. package/dist/ccs.js.map +1 -0
  22. package/dist/cliproxy/auth-handler.d.ts +93 -0
  23. package/dist/cliproxy/auth-handler.d.ts.map +1 -0
  24. package/dist/cliproxy/auth-handler.js +402 -0
  25. package/dist/cliproxy/auth-handler.js.map +1 -0
  26. package/dist/cliproxy/base-config-loader.d.ts +42 -0
  27. package/dist/cliproxy/base-config-loader.d.ts.map +1 -0
  28. package/dist/cliproxy/base-config-loader.js +123 -0
  29. package/dist/cliproxy/base-config-loader.js.map +1 -0
  30. package/dist/cliproxy/binary-manager.d.ts +104 -0
  31. package/dist/cliproxy/binary-manager.d.ts.map +1 -0
  32. package/dist/cliproxy/binary-manager.js +567 -0
  33. package/dist/cliproxy/binary-manager.js.map +1 -0
  34. package/dist/cliproxy/cliproxy-executor.d.ts +33 -0
  35. package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -0
  36. package/dist/cliproxy/cliproxy-executor.js +297 -0
  37. package/dist/cliproxy/cliproxy-executor.js.map +1 -0
  38. package/dist/cliproxy/config-generator.d.ts +89 -0
  39. package/dist/cliproxy/config-generator.d.ts.map +1 -0
  40. package/dist/cliproxy/config-generator.js +263 -0
  41. package/dist/cliproxy/config-generator.js.map +1 -0
  42. package/dist/cliproxy/index.d.ts +13 -0
  43. package/dist/cliproxy/index.d.ts.map +1 -0
  44. package/dist/cliproxy/index.js +62 -0
  45. package/dist/cliproxy/index.js.map +1 -0
  46. package/dist/cliproxy/platform-detector.d.ts +48 -0
  47. package/dist/cliproxy/platform-detector.d.ts.map +1 -0
  48. package/dist/cliproxy/platform-detector.js +118 -0
  49. package/dist/cliproxy/platform-detector.js.map +1 -0
  50. package/dist/cliproxy/types.d.ts +169 -0
  51. package/dist/cliproxy/types.d.ts.map +1 -0
  52. package/dist/cliproxy/types.js +7 -0
  53. package/dist/cliproxy/types.js.map +1 -0
  54. package/dist/commands/doctor-command.d.ts +10 -0
  55. package/dist/commands/doctor-command.d.ts.map +1 -0
  56. package/dist/commands/doctor-command.js +44 -0
  57. package/dist/commands/doctor-command.js.map +1 -0
  58. package/dist/commands/help-command.d.ts +5 -0
  59. package/dist/commands/help-command.d.ts.map +1 -0
  60. package/dist/commands/help-command.js +104 -0
  61. package/dist/commands/help-command.js.map +1 -0
  62. package/dist/commands/install-command.d.ts +14 -0
  63. package/dist/commands/install-command.d.ts.map +1 -0
  64. package/dist/commands/install-command.js +39 -0
  65. package/dist/commands/install-command.js.map +1 -0
  66. package/dist/commands/shell-completion-command.d.ts +10 -0
  67. package/dist/commands/shell-completion-command.d.ts.map +1 -0
  68. package/dist/commands/shell-completion-command.js +85 -0
  69. package/dist/commands/shell-completion-command.js.map +1 -0
  70. package/dist/commands/sync-command.d.ts +10 -0
  71. package/dist/commands/sync-command.d.ts.map +1 -0
  72. package/dist/commands/sync-command.js +59 -0
  73. package/dist/commands/sync-command.js.map +1 -0
  74. package/dist/commands/update-command.d.ts +12 -0
  75. package/dist/commands/update-command.d.ts.map +1 -0
  76. package/dist/commands/update-command.js +295 -0
  77. package/dist/commands/update-command.js.map +1 -0
  78. package/dist/commands/version-command.d.ts +10 -0
  79. package/dist/commands/version-command.d.ts.map +1 -0
  80. package/dist/commands/version-command.js +100 -0
  81. package/dist/commands/version-command.js.map +1 -0
  82. package/dist/delegation/delegation-handler.d.ts +60 -0
  83. package/dist/delegation/delegation-handler.d.ts.map +1 -0
  84. package/dist/delegation/delegation-handler.js +174 -0
  85. package/dist/delegation/delegation-handler.js.map +1 -0
  86. package/dist/delegation/headless-executor.d.ts +114 -0
  87. package/dist/delegation/headless-executor.d.ts.map +1 -0
  88. package/dist/delegation/headless-executor.js +562 -0
  89. package/dist/delegation/headless-executor.js.map +1 -0
  90. package/dist/delegation/result-formatter.d.ts +108 -0
  91. package/dist/delegation/result-formatter.d.ts.map +1 -0
  92. package/dist/delegation/result-formatter.js +391 -0
  93. package/dist/delegation/result-formatter.js.map +1 -0
  94. package/dist/delegation/session-manager.d.ts +58 -0
  95. package/dist/delegation/session-manager.d.ts.map +1 -0
  96. package/dist/delegation/session-manager.js +153 -0
  97. package/dist/delegation/session-manager.js.map +1 -0
  98. package/dist/delegation/settings-parser.d.ts +31 -0
  99. package/dist/delegation/settings-parser.d.ts.map +1 -0
  100. package/dist/delegation/settings-parser.js +107 -0
  101. package/dist/delegation/settings-parser.js.map +1 -0
  102. package/dist/glmt/delta-accumulator.d.ts +210 -0
  103. package/dist/glmt/delta-accumulator.d.ts.map +1 -0
  104. package/dist/glmt/delta-accumulator.js +351 -0
  105. package/dist/glmt/delta-accumulator.js.map +1 -0
  106. package/dist/glmt/glmt-proxy.d.ts +72 -0
  107. package/dist/glmt/glmt-proxy.d.ts.map +1 -0
  108. package/dist/glmt/glmt-proxy.js +427 -0
  109. package/dist/glmt/glmt-proxy.js.map +1 -0
  110. package/dist/glmt/glmt-transformer.d.ts +265 -0
  111. package/dist/glmt/glmt-transformer.d.ts.map +1 -0
  112. package/dist/glmt/glmt-transformer.js +832 -0
  113. package/dist/glmt/glmt-transformer.js.map +1 -0
  114. package/dist/glmt/locale-enforcer.d.ts +38 -0
  115. package/dist/glmt/locale-enforcer.d.ts.map +1 -0
  116. package/dist/glmt/locale-enforcer.js +69 -0
  117. package/dist/glmt/locale-enforcer.js.map +1 -0
  118. package/dist/glmt/reasoning-enforcer.d.ts +52 -0
  119. package/dist/glmt/reasoning-enforcer.d.ts.map +1 -0
  120. package/dist/glmt/reasoning-enforcer.js +151 -0
  121. package/dist/glmt/reasoning-enforcer.js.map +1 -0
  122. package/dist/glmt/sse-parser.d.ts +47 -0
  123. package/dist/glmt/sse-parser.d.ts.map +1 -0
  124. package/dist/glmt/sse-parser.js +93 -0
  125. package/dist/glmt/sse-parser.js.map +1 -0
  126. package/dist/management/doctor.d.ts +104 -0
  127. package/dist/management/doctor.d.ts.map +1 -0
  128. package/dist/management/doctor.js +673 -0
  129. package/dist/management/doctor.js.map +1 -0
  130. package/dist/management/instance-manager.d.ts +57 -0
  131. package/dist/management/instance-manager.d.ts.map +1 -0
  132. package/dist/management/instance-manager.js +195 -0
  133. package/dist/management/instance-manager.js.map +1 -0
  134. package/dist/management/recovery-manager.d.ts +39 -0
  135. package/dist/management/recovery-manager.d.ts.map +1 -0
  136. package/dist/management/recovery-manager.js +141 -0
  137. package/dist/management/recovery-manager.js.map +1 -0
  138. package/dist/management/shared-manager.d.ts +47 -0
  139. package/dist/management/shared-manager.d.ts.map +1 -0
  140. package/dist/management/shared-manager.js +388 -0
  141. package/dist/management/shared-manager.js.map +1 -0
  142. package/dist/types/cli.d.ts +50 -0
  143. package/dist/types/cli.d.ts.map +1 -0
  144. package/dist/types/cli.js +16 -0
  145. package/dist/types/cli.js.map +1 -0
  146. package/dist/types/config.d.ts +51 -0
  147. package/dist/types/config.d.ts.map +1 -0
  148. package/dist/types/config.js +26 -0
  149. package/dist/types/config.js.map +1 -0
  150. package/dist/types/delegation.d.ts +61 -0
  151. package/dist/types/delegation.d.ts.map +1 -0
  152. package/dist/types/delegation.js +6 -0
  153. package/dist/types/delegation.js.map +1 -0
  154. package/dist/types/glmt.d.ts +95 -0
  155. package/dist/types/glmt.d.ts.map +1 -0
  156. package/dist/types/glmt.js +7 -0
  157. package/dist/types/glmt.js.map +1 -0
  158. package/dist/types/index.d.ts +13 -0
  159. package/dist/types/index.d.ts.map +1 -0
  160. package/dist/types/index.js +16 -0
  161. package/dist/types/index.js.map +1 -0
  162. package/dist/types/utils.d.ts +36 -0
  163. package/dist/types/utils.d.ts.map +1 -0
  164. package/dist/types/utils.js +22 -0
  165. package/dist/types/utils.js.map +1 -0
  166. package/dist/utils/claude-detector.d.ts +14 -0
  167. package/dist/utils/claude-detector.d.ts.map +1 -0
  168. package/dist/utils/claude-detector.js +112 -0
  169. package/dist/utils/claude-detector.js.map +1 -0
  170. package/dist/utils/claude-dir-installer.d.ts +46 -0
  171. package/dist/utils/claude-dir-installer.d.ts.map +1 -0
  172. package/dist/utils/claude-dir-installer.js +289 -0
  173. package/dist/utils/claude-dir-installer.js.map +1 -0
  174. package/dist/utils/claude-symlink-manager.d.ts +61 -0
  175. package/dist/utils/claude-symlink-manager.d.ts.map +1 -0
  176. package/dist/utils/claude-symlink-manager.js +291 -0
  177. package/dist/utils/claude-symlink-manager.js.map +1 -0
  178. package/dist/utils/config-manager.d.ts +32 -0
  179. package/dist/utils/config-manager.d.ts.map +1 -0
  180. package/dist/utils/config-manager.js +143 -0
  181. package/dist/utils/config-manager.js.map +1 -0
  182. package/dist/utils/delegation-validator.d.ts +39 -0
  183. package/dist/utils/delegation-validator.d.ts.map +1 -0
  184. package/dist/utils/delegation-validator.js +161 -0
  185. package/dist/utils/delegation-validator.js.map +1 -0
  186. package/dist/utils/error-codes.d.ts +36 -0
  187. package/dist/utils/error-codes.d.ts.map +1 -0
  188. package/dist/utils/error-codes.js +63 -0
  189. package/dist/utils/error-codes.js.map +1 -0
  190. package/dist/utils/error-manager.d.ts +59 -0
  191. package/dist/utils/error-manager.d.ts.map +1 -0
  192. package/dist/utils/error-manager.js +228 -0
  193. package/dist/utils/error-manager.js.map +1 -0
  194. package/dist/utils/helpers.d.ts +27 -0
  195. package/dist/utils/helpers.d.ts.map +1 -0
  196. package/dist/utils/helpers.js +150 -0
  197. package/dist/utils/helpers.js.map +1 -0
  198. package/dist/utils/package-manager-detector.d.ts +14 -0
  199. package/dist/utils/package-manager-detector.d.ts.map +1 -0
  200. package/dist/utils/package-manager-detector.js +162 -0
  201. package/dist/utils/package-manager-detector.js.map +1 -0
  202. package/dist/utils/progress-indicator.d.ts +52 -0
  203. package/dist/utils/progress-indicator.d.ts.map +1 -0
  204. package/dist/utils/progress-indicator.js +102 -0
  205. package/dist/utils/progress-indicator.js.map +1 -0
  206. package/dist/utils/prompt.d.ts +29 -0
  207. package/dist/utils/prompt.d.ts.map +1 -0
  208. package/dist/utils/prompt.js +116 -0
  209. package/dist/utils/prompt.js.map +1 -0
  210. package/dist/utils/shell-completion.d.ts +52 -0
  211. package/dist/utils/shell-completion.d.ts.map +1 -0
  212. package/dist/utils/shell-completion.js +231 -0
  213. package/dist/utils/shell-completion.js.map +1 -0
  214. package/dist/utils/shell-executor.d.ts +15 -0
  215. package/dist/utils/shell-executor.d.ts.map +1 -0
  216. package/dist/utils/shell-executor.js +57 -0
  217. package/dist/utils/shell-executor.js.map +1 -0
  218. package/dist/utils/update-checker.d.ts +48 -0
  219. package/dist/utils/update-checker.d.ts.map +1 -0
  220. package/dist/utils/update-checker.js +241 -0
  221. package/dist/utils/update-checker.js.map +1 -0
  222. package/lib/ccs +21 -1907
  223. package/lib/ccs.ps1 +26 -1800
  224. package/lib/error-codes.ps1 +2 -1
  225. package/lib/prompt.ps1 +2 -2
  226. package/package.json +31 -11
  227. package/scripts/add-shebang.js +39 -0
  228. package/scripts/bump-version.sh +25 -37
  229. package/scripts/dev-install.sh +32 -11
  230. package/scripts/postinstall.js +29 -29
  231. package/bin/auth/auth-commands.js +0 -499
  232. package/bin/auth/profile-detector.js +0 -204
  233. package/bin/auth/profile-registry.js +0 -225
  234. package/bin/ccs.js +0 -1034
  235. package/bin/delegation/README.md +0 -191
  236. package/bin/delegation/delegation-handler.js +0 -212
  237. package/bin/delegation/headless-executor.js +0 -618
  238. package/bin/delegation/result-formatter.js +0 -485
  239. package/bin/delegation/session-manager.js +0 -157
  240. package/bin/delegation/settings-parser.js +0 -109
  241. package/bin/glmt/delta-accumulator.js +0 -276
  242. package/bin/glmt/glmt-proxy.js +0 -495
  243. package/bin/glmt/glmt-transformer.js +0 -999
  244. package/bin/glmt/locale-enforcer.js +0 -72
  245. package/bin/glmt/reasoning-enforcer.js +0 -173
  246. package/bin/glmt/sse-parser.js +0 -96
  247. package/bin/management/doctor.js +0 -721
  248. package/bin/management/instance-manager.js +0 -202
  249. package/bin/management/recovery-manager.js +0 -135
  250. package/bin/management/shared-manager.js +0 -402
  251. package/bin/utils/claude-detector.js +0 -73
  252. package/bin/utils/claude-dir-installer.js +0 -283
  253. package/bin/utils/claude-symlink-manager.js +0 -289
  254. package/bin/utils/config-manager.js +0 -103
  255. package/bin/utils/delegation-validator.js +0 -154
  256. package/bin/utils/error-codes.js +0 -59
  257. package/bin/utils/error-manager.js +0 -165
  258. package/bin/utils/helpers.js +0 -136
  259. package/bin/utils/progress-indicator.js +0 -111
  260. package/bin/utils/prompt.js +0 -134
  261. package/bin/utils/shell-completion.js +0 -256
  262. package/bin/utils/update-checker.js +0 -243
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- /**
8
- * Parses Claude Code settings for tool restrictions
9
- */
10
- class SettingsParser {
11
- /**
12
- * Parse default permission mode from project settings
13
- * @param {string} projectDir - Project directory (usually cwd)
14
- * @returns {string} Default permission mode (e.g., 'acceptEdits', 'bypassPermissions', 'plan', 'default')
15
- */
16
- static parseDefaultPermissionMode(projectDir) {
17
- const settings = this._loadSettings(projectDir);
18
- const permissions = settings.permissions || {};
19
-
20
- // Priority: local > shared > fallback to 'acceptEdits'
21
- const defaultMode = permissions.defaultMode || 'acceptEdits';
22
-
23
- if (process.env.CCS_DEBUG) {
24
- console.error(`[i] Permission mode from settings: ${defaultMode}`);
25
- }
26
-
27
- return defaultMode;
28
- }
29
-
30
- /**
31
- * Parse project settings for tool restrictions
32
- * @param {string} projectDir - Project directory (usually cwd)
33
- * @returns {Object} { allowedTools: string[], disallowedTools: string[] }
34
- */
35
- static parseToolRestrictions(projectDir) {
36
- const settings = this._loadSettings(projectDir);
37
- const permissions = settings.permissions || {};
38
-
39
- const allowed = permissions.allow || [];
40
- const denied = permissions.deny || [];
41
-
42
- if (process.env.CCS_DEBUG) {
43
- console.error(`[i] Tool restrictions: ${allowed.length} allowed, ${denied.length} denied`);
44
- }
45
-
46
- return {
47
- allowedTools: allowed,
48
- disallowedTools: denied
49
- };
50
- }
51
-
52
- /**
53
- * Load and merge settings files (local overrides shared)
54
- * @param {string} projectDir - Project directory
55
- * @returns {Object} Merged settings
56
- * @private
57
- */
58
- static _loadSettings(projectDir) {
59
- const claudeDir = path.join(projectDir, '.claude');
60
- const sharedPath = path.join(claudeDir, 'settings.json');
61
- const localPath = path.join(claudeDir, 'settings.local.json');
62
-
63
- // Load shared settings
64
- const shared = this._readJsonSafe(sharedPath) || {};
65
-
66
- // Load local settings (overrides shared)
67
- const local = this._readJsonSafe(localPath) || {};
68
-
69
- // Merge permissions (local overrides shared)
70
- return {
71
- permissions: {
72
- allow: [
73
- ...(shared.permissions?.allow || []),
74
- ...(local.permissions?.allow || [])
75
- ],
76
- deny: [
77
- ...(shared.permissions?.deny || []),
78
- ...(local.permissions?.deny || [])
79
- ],
80
- // Local defaultMode takes priority over shared
81
- defaultMode: local.permissions?.defaultMode || shared.permissions?.defaultMode || null
82
- }
83
- };
84
- }
85
-
86
- /**
87
- * Read JSON file safely (no throw)
88
- * @param {string} filePath - Path to JSON file
89
- * @returns {Object|null} Parsed JSON or null
90
- * @private
91
- */
92
- static _readJsonSafe(filePath) {
93
- try {
94
- if (!fs.existsSync(filePath)) {
95
- return null;
96
- }
97
-
98
- const content = fs.readFileSync(filePath, 'utf8');
99
- return JSON.parse(content);
100
- } catch (error) {
101
- if (process.env.CCS_DEBUG) {
102
- console.warn(`[!] Failed to read settings: ${filePath}: ${error.message}`);
103
- }
104
- return null;
105
- }
106
- }
107
- }
108
-
109
- module.exports = { SettingsParser };
@@ -1,276 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * DeltaAccumulator - Maintain state across streaming deltas
6
- *
7
- * Tracks:
8
- * - Message metadata (id, model, role)
9
- * - Content blocks (thinking, text)
10
- * - Current block index
11
- * - Accumulated content
12
- *
13
- * Usage:
14
- * const acc = new DeltaAccumulator(thinkingConfig);
15
- * const events = transformer.transformDelta(openaiEvent, acc);
16
- */
17
- class DeltaAccumulator {
18
- constructor(thinkingConfig = {}, options = {}) {
19
- this.thinkingConfig = thinkingConfig;
20
- this.messageId = 'msg_' + Date.now() + '_' + Math.random().toString(36).substring(7);
21
- this.model = null;
22
- this.role = 'assistant';
23
-
24
- // Content blocks
25
- this.contentBlocks = [];
26
- this.currentBlockIndex = -1;
27
-
28
- // Tool calls tracking
29
- this.toolCalls = [];
30
- this.toolCallsIndex = {};
31
-
32
- // Buffers
33
- this.thinkingBuffer = '';
34
- this.textBuffer = '';
35
-
36
- // C-02 Fix: Limits to prevent unbounded accumulation
37
- this.maxBlocks = options.maxBlocks || 100;
38
- this.maxBufferSize = options.maxBufferSize || 10 * 1024 * 1024; // 10MB
39
-
40
- // Loop detection configuration
41
- this.loopDetectionThreshold = options.loopDetectionThreshold || 3;
42
- this.loopDetected = false;
43
-
44
- // State flags
45
- this.messageStarted = false;
46
- this.finalized = false;
47
- this.usageReceived = false; // Track if usage data has arrived
48
-
49
- // Statistics
50
- this.inputTokens = 0;
51
- this.outputTokens = 0;
52
- this.finishReason = null;
53
- }
54
-
55
- /**
56
- * Get current content block
57
- * @returns {Object|null} Current block or null
58
- */
59
- getCurrentBlock() {
60
- if (this.currentBlockIndex >= 0 && this.currentBlockIndex < this.contentBlocks.length) {
61
- return this.contentBlocks[this.currentBlockIndex];
62
- }
63
- return null;
64
- }
65
-
66
- /**
67
- * Start new content block
68
- * @param {string} type - Block type ('thinking', 'text', or 'tool_use')
69
- * @returns {Object} New block
70
- */
71
- startBlock(type) {
72
- // C-02 Fix: Enforce max blocks limit
73
- if (this.contentBlocks.length >= this.maxBlocks) {
74
- throw new Error(`Maximum ${this.maxBlocks} content blocks exceeded (DoS protection)`);
75
- }
76
-
77
- this.currentBlockIndex++;
78
- const block = {
79
- index: this.currentBlockIndex,
80
- type: type,
81
- content: '',
82
- started: true,
83
- stopped: false
84
- };
85
- this.contentBlocks.push(block);
86
-
87
- // Reset buffer for new block (tool_use doesn't use buffers)
88
- if (type === 'thinking') {
89
- this.thinkingBuffer = '';
90
- } else if (type === 'text') {
91
- this.textBuffer = '';
92
- }
93
-
94
- return block;
95
- }
96
-
97
- /**
98
- * Add delta to current block
99
- * @param {string} delta - Content delta
100
- */
101
- addDelta(delta) {
102
- const block = this.getCurrentBlock();
103
- if (!block) {
104
- // FIX: Guard against null block (should never happen, but defensive)
105
- console.error('[DeltaAccumulator] ERROR: addDelta called with no current block');
106
- return;
107
- }
108
-
109
- if (block.type === 'thinking') {
110
- // C-02 Fix: Enforce buffer size limit
111
- if (this.thinkingBuffer.length + delta.length > this.maxBufferSize) {
112
- throw new Error(`Thinking buffer exceeded ${this.maxBufferSize} bytes (DoS protection)`);
113
- }
114
- this.thinkingBuffer += delta;
115
- block.content = this.thinkingBuffer;
116
-
117
- // FIX: Verify assignment succeeded (paranoid check for race conditions)
118
- if (block.content.length !== this.thinkingBuffer.length) {
119
- console.error('[DeltaAccumulator] ERROR: Block content assignment failed');
120
- console.error(`Expected: ${this.thinkingBuffer.length}, Got: ${block.content.length}`);
121
- }
122
- } else if (block.type === 'text') {
123
- // C-02 Fix: Enforce buffer size limit
124
- if (this.textBuffer.length + delta.length > this.maxBufferSize) {
125
- throw new Error(`Text buffer exceeded ${this.maxBufferSize} bytes (DoS protection)`);
126
- }
127
- this.textBuffer += delta;
128
- block.content = this.textBuffer;
129
- }
130
- }
131
-
132
- /**
133
- * Mark current block as stopped
134
- */
135
- stopCurrentBlock() {
136
- const block = this.getCurrentBlock();
137
- if (block) {
138
- block.stopped = true;
139
-
140
- // FIX: Log block closure for debugging (helps diagnose timing issues)
141
- if (block.type === 'thinking' && process.env.CCS_DEBUG === '1') {
142
- console.error(`[DeltaAccumulator] Stopped thinking block ${block.index}: ${block.content?.length || 0} chars`);
143
- }
144
- }
145
- }
146
-
147
- /**
148
- * Update usage statistics
149
- * @param {Object} usage - Usage object from OpenAI
150
- */
151
- updateUsage(usage) {
152
- if (usage) {
153
- this.inputTokens = usage.prompt_tokens || usage.input_tokens || 0;
154
- this.outputTokens = usage.completion_tokens || usage.output_tokens || 0;
155
- this.usageReceived = true; // Mark that we've received usage data
156
- }
157
- }
158
-
159
- /**
160
- * Add or update tool call delta
161
- * @param {Object} toolCallDelta - Tool call delta from OpenAI
162
- */
163
- addToolCallDelta(toolCallDelta) {
164
- const index = toolCallDelta.index;
165
-
166
- // Initialize tool call if not exists
167
- if (!this.toolCallsIndex[index]) {
168
- const toolCall = {
169
- index: index,
170
- id: '',
171
- type: 'function',
172
- function: {
173
- name: '',
174
- arguments: ''
175
- }
176
- };
177
- this.toolCalls.push(toolCall);
178
- this.toolCallsIndex[index] = toolCall;
179
- }
180
-
181
- const toolCall = this.toolCallsIndex[index];
182
-
183
- // Update id if present
184
- if (toolCallDelta.id) {
185
- toolCall.id = toolCallDelta.id;
186
- }
187
-
188
- // Update type if present
189
- if (toolCallDelta.type) {
190
- toolCall.type = toolCallDelta.type;
191
- }
192
-
193
- // Update function name if present
194
- if (toolCallDelta.function?.name) {
195
- toolCall.function.name += toolCallDelta.function.name;
196
- }
197
-
198
- // Update function arguments if present
199
- if (toolCallDelta.function?.arguments) {
200
- toolCall.function.arguments += toolCallDelta.function.arguments;
201
- }
202
- }
203
-
204
- /**
205
- * Get all tool calls
206
- * @returns {Array} Tool calls array
207
- */
208
- getToolCalls() {
209
- return this.toolCalls;
210
- }
211
-
212
- /**
213
- * Check for planning loop pattern
214
- * Loop = N consecutive thinking blocks with no tool calls
215
- * @returns {boolean} True if loop detected
216
- */
217
- checkForLoop() {
218
- // Already detected loop
219
- if (this.loopDetected) {
220
- return true;
221
- }
222
-
223
- // Need minimum blocks to detect pattern
224
- if (this.contentBlocks.length < this.loopDetectionThreshold) {
225
- return false;
226
- }
227
-
228
- // Get last N blocks
229
- const recentBlocks = this.contentBlocks.slice(-this.loopDetectionThreshold);
230
-
231
- // Check if all recent blocks are thinking blocks
232
- const allThinking = recentBlocks.every(b => b.type === 'thinking');
233
-
234
- // Check if no tool calls have been made at all
235
- const noToolCalls = this.toolCalls.length === 0;
236
-
237
- // Loop detected if: all recent blocks are thinking AND no tool calls yet
238
- if (allThinking && noToolCalls) {
239
- this.loopDetected = true;
240
- return true;
241
- }
242
-
243
- return false;
244
- }
245
-
246
- /**
247
- * Reset loop detection state (for testing)
248
- */
249
- resetLoopDetection() {
250
- this.loopDetected = false;
251
- }
252
-
253
- /**
254
- * Get summary of accumulated state
255
- * @returns {Object} Summary
256
- */
257
- getSummary() {
258
- return {
259
- messageId: this.messageId,
260
- model: this.model,
261
- role: this.role,
262
- blockCount: this.contentBlocks.length,
263
- currentIndex: this.currentBlockIndex,
264
- toolCallCount: this.toolCalls.length,
265
- messageStarted: this.messageStarted,
266
- finalized: this.finalized,
267
- loopDetected: this.loopDetected,
268
- usage: {
269
- input_tokens: this.inputTokens,
270
- output_tokens: this.outputTokens
271
- }
272
- };
273
- }
274
- }
275
-
276
- module.exports = DeltaAccumulator;