claude-ide-bridge 2.25.11 → 2.25.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automation.d.ts +23 -0
- package/dist/automation.js +83 -4
- package/dist/automation.js.map +1 -1
- package/dist/claudeDriver.d.ts +2 -0
- package/dist/claudeDriver.js +3 -1
- package/dist/claudeDriver.js.map +1 -1
- package/dist/claudeOrchestrator.d.ts +4 -0
- package/dist/claudeOrchestrator.js +9 -0
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/extensionClient.d.ts +7 -0
- package/dist/extensionClient.js.map +1 -1
- package/dist/tools/contextBundle.js +12 -5
- package/dist/tools/contextBundle.js.map +1 -1
- package/dist/tools/getDiagnostics.js +25 -5
- package/dist/tools/getDiagnostics.js.map +1 -1
- package/dist/tools/getFileTree.d.ts +6 -0
- package/dist/tools/getFileTree.js +14 -6
- package/dist/tools/getFileTree.js.map +1 -1
- package/dist/tools/getGitStatus.js +16 -4
- package/dist/tools/getGitStatus.js.map +1 -1
- package/dist/tools/runClaudeTask.d.ts +5 -0
- package/dist/tools/runClaudeTask.js +17 -0
- package/dist/tools/runClaudeTask.js.map +1 -1
- package/dist/tools/runTests.js +11 -1
- package/dist/tools/runTests.js.map +1 -1
- package/package.json +1 -1
package/dist/automation.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export interface PromptSource {
|
|
|
18
18
|
promptName?: string;
|
|
19
19
|
promptArgs?: Record<string, string>;
|
|
20
20
|
condition?: string;
|
|
21
|
+
/** Per-hook model override. Falls back to policy.defaultModel (Haiku). */
|
|
22
|
+
model?: string;
|
|
23
|
+
/** Per-hook effort override. Falls back to policy.defaultEffort ("low"). */
|
|
24
|
+
effort?: "low" | "medium" | "high" | "max";
|
|
21
25
|
}
|
|
22
26
|
export interface OnDiagnosticsErrorPolicy extends PromptSource {
|
|
23
27
|
enabled: boolean;
|
|
@@ -249,6 +253,19 @@ export interface AutomationPolicy {
|
|
|
249
253
|
* Defaults to 20. Set to 0 to disable.
|
|
250
254
|
*/
|
|
251
255
|
maxTasksPerHour?: number;
|
|
256
|
+
/**
|
|
257
|
+
* Custom system prompt passed via --system-prompt to every automation subprocess.
|
|
258
|
+
* Replaces the default Claude Code system prompt, preventing CLAUDE.md from being
|
|
259
|
+
* loaded as workspace instructions. Keep it short — this is the biggest token lever.
|
|
260
|
+
* Default: a lean "be brief" prompt. Max 4096 chars.
|
|
261
|
+
*/
|
|
262
|
+
automationSystemPrompt?: string;
|
|
263
|
+
/**
|
|
264
|
+
* Default effort level for all automation tasks (low/medium/high/max).
|
|
265
|
+
* Defaults to "low" — automation tasks rarely need deep reasoning.
|
|
266
|
+
* Override per-hook via the hook's own effort field.
|
|
267
|
+
*/
|
|
268
|
+
defaultEffort?: "low" | "medium" | "high" | "max";
|
|
252
269
|
onDiagnosticsError?: OnDiagnosticsErrorPolicy;
|
|
253
270
|
onFileSave?: OnFileSavePolicy;
|
|
254
271
|
/** Fired by Claude Code 2.1.83+ FileChanged hook — reacts to any file edit, not just explicit saves. */
|
|
@@ -341,6 +358,10 @@ export declare class AutomationHooks {
|
|
|
341
358
|
private prevDiagnosticErrors;
|
|
342
359
|
/** Active task ID for the task-success handler (workspace-global). */
|
|
343
360
|
private activeTaskSuccessTaskId;
|
|
361
|
+
/** Active task ID for the post-compact handler (workspace-global). */
|
|
362
|
+
private activePostCompactTaskId;
|
|
363
|
+
/** Active task ID for the instructions-loaded handler (workspace-global). */
|
|
364
|
+
private activeInstructionsLoadedTaskId;
|
|
344
365
|
/**
|
|
345
366
|
* Rolling window of task enqueue timestamps for maxTasksPerHour enforcement.
|
|
346
367
|
* Entries older than 60 minutes are pruned on each enqueue.
|
|
@@ -498,5 +519,7 @@ export declare class AutomationHooks {
|
|
|
498
519
|
defaultModel: string;
|
|
499
520
|
maxTasksPerHour: number;
|
|
500
521
|
tasksThisHour: number;
|
|
522
|
+
defaultEffort: string;
|
|
523
|
+
automationSystemPrompt: string;
|
|
501
524
|
};
|
|
502
525
|
}
|
package/dist/automation.js
CHANGED
|
@@ -5,6 +5,7 @@ import { minimatch } from "minimatch";
|
|
|
5
5
|
import { getPrompt } from "./prompts.js";
|
|
6
6
|
/** Maximum length (chars) of a single diagnostic message before truncation */
|
|
7
7
|
const MAX_DIAGNOSTIC_MSG_CHARS = 500;
|
|
8
|
+
const MAX_DIAGNOSTICS_IN_PROMPT = 20;
|
|
8
9
|
/**
|
|
9
10
|
* Wrap an untrusted user-controlled value in delimiters that include a
|
|
10
11
|
* per-trigger nonce so a crafted value cannot forge a closing delimiter.
|
|
@@ -50,6 +51,10 @@ function truncatePrompt(prompt) {
|
|
|
50
51
|
}
|
|
51
52
|
/** Prune lastTrigger entries older than this to prevent unbounded Map growth */
|
|
52
53
|
const LAST_TRIGGER_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
|
|
54
|
+
/** Default system prompt for automation subprocesses when none is set in policy. */
|
|
55
|
+
const DEFAULT_AUTOMATION_SYSTEM_PROMPT = "You are a concise automation assistant. " +
|
|
56
|
+
"Respond in \u22645 lines. No preamble. No markdown headers. " +
|
|
57
|
+
"Call the tools listed in the task prompt, then report results only.";
|
|
53
58
|
/**
|
|
54
59
|
* Deterministic signature over a diagnostic list — used for content-aware
|
|
55
60
|
* dedupe in onDiagnosticsError. Sorting by a stable key makes the signature
|
|
@@ -104,6 +109,16 @@ function validatePromptSource(hookName, cfg) {
|
|
|
104
109
|
throw new Error(`"${hookName}.condition" must be a string ≤ 1024 characters`);
|
|
105
110
|
}
|
|
106
111
|
}
|
|
112
|
+
if (cfg.model !== undefined) {
|
|
113
|
+
if (typeof cfg.model !== "string" || cfg.model.trim() === "") {
|
|
114
|
+
throw new Error(`"${hookName}.model" must be a non-empty string`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (cfg.effort !== undefined) {
|
|
118
|
+
if (!["low", "medium", "high", "max"].includes(cfg.effort)) {
|
|
119
|
+
throw new Error(`"${hookName}.effort" must be one of "low", "medium", "high", "max"`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
107
122
|
}
|
|
108
123
|
/** Load and validate a JSON automation policy file. Throws on any failure. */
|
|
109
124
|
export function loadPolicy(filePath) {
|
|
@@ -137,6 +152,19 @@ export function loadPolicy(filePath) {
|
|
|
137
152
|
throw new Error(`"maxTasksPerHour" must be a non-negative integer`);
|
|
138
153
|
}
|
|
139
154
|
}
|
|
155
|
+
if (policy.automationSystemPrompt !== undefined) {
|
|
156
|
+
if (typeof policy.automationSystemPrompt !== "string") {
|
|
157
|
+
throw new Error(`"automationSystemPrompt" must be a string`);
|
|
158
|
+
}
|
|
159
|
+
if (policy.automationSystemPrompt.length > 4096) {
|
|
160
|
+
throw new Error(`"automationSystemPrompt" must be ≤ 4096 characters`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (policy.defaultEffort !== undefined) {
|
|
164
|
+
if (!["low", "medium", "high", "max"].includes(policy.defaultEffort)) {
|
|
165
|
+
throw new Error(`"defaultEffort" must be one of "low", "medium", "high", "max"`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
140
168
|
// Validate onDiagnosticsError
|
|
141
169
|
if (policy.onDiagnosticsError !== undefined) {
|
|
142
170
|
const d = policy.onDiagnosticsError;
|
|
@@ -550,6 +578,10 @@ export class AutomationHooks {
|
|
|
550
578
|
prevDiagnosticErrors = new Map();
|
|
551
579
|
/** Active task ID for the task-success handler (workspace-global). */
|
|
552
580
|
activeTaskSuccessTaskId = null;
|
|
581
|
+
/** Active task ID for the post-compact handler (workspace-global). */
|
|
582
|
+
activePostCompactTaskId = null;
|
|
583
|
+
/** Active task ID for the instructions-loaded handler (workspace-global). */
|
|
584
|
+
activeInstructionsLoadedTaskId = null;
|
|
553
585
|
/**
|
|
554
586
|
* Rolling window of task enqueue timestamps for maxTasksPerHour enforcement.
|
|
555
587
|
* Entries older than 60 minutes are pruned on each enqueue.
|
|
@@ -584,13 +616,19 @@ export class AutomationHooks {
|
|
|
584
616
|
}
|
|
585
617
|
this.taskTimestamps.push(now);
|
|
586
618
|
}
|
|
587
|
-
const model =
|
|
619
|
+
const model = opts.hookCfg?.model ??
|
|
620
|
+
this.policy.defaultModel ??
|
|
621
|
+
"claude-haiku-4-5-20251001";
|
|
622
|
+
const effort = opts.hookCfg?.effort ?? this.policy.defaultEffort ?? "low";
|
|
623
|
+
const systemPrompt = this.policy.automationSystemPrompt ?? DEFAULT_AUTOMATION_SYSTEM_PROMPT;
|
|
588
624
|
return this.orchestrator.enqueue({
|
|
589
625
|
prompt: opts.prompt,
|
|
590
626
|
sessionId: "",
|
|
591
627
|
isAutomationTask: true,
|
|
592
628
|
triggerSource: opts.triggerSource,
|
|
593
629
|
model,
|
|
630
|
+
effort,
|
|
631
|
+
systemPrompt,
|
|
594
632
|
});
|
|
595
633
|
}
|
|
596
634
|
/**
|
|
@@ -731,9 +769,12 @@ export class AutomationHooks {
|
|
|
731
769
|
prompt = resolved;
|
|
732
770
|
}
|
|
733
771
|
else {
|
|
734
|
-
const
|
|
772
|
+
const displayMatching = matching.slice(0, MAX_DIAGNOSTICS_IN_PROMPT);
|
|
773
|
+
const omittedCount = matching.length - displayMatching.length;
|
|
774
|
+
const diagnosticsText = displayMatching
|
|
735
775
|
.map((d) => `[${d.severity}] ${d.message.slice(0, MAX_DIAGNOSTIC_MSG_CHARS)}`)
|
|
736
|
-
.join("\n")
|
|
776
|
+
.join("\n") +
|
|
777
|
+
(omittedCount > 0 ? `\n… and ${omittedCount} more` : "");
|
|
737
778
|
const nonce = crypto.randomBytes(6).toString("hex");
|
|
738
779
|
prompt =
|
|
739
780
|
(cfg.prompt ?? "")
|
|
@@ -745,6 +786,7 @@ export class AutomationHooks {
|
|
|
745
786
|
const taskId = this._enqueueAutomationTask({
|
|
746
787
|
prompt,
|
|
747
788
|
triggerSource: "onDiagnosticsError",
|
|
789
|
+
hookCfg: cfg,
|
|
748
790
|
});
|
|
749
791
|
this.lastTrigger.set(key, now);
|
|
750
792
|
this.activeDiagnosticsTasks.set(normalizedFile, taskId);
|
|
@@ -802,6 +844,7 @@ export class AutomationHooks {
|
|
|
802
844
|
const taskId = this._enqueueAutomationTask({
|
|
803
845
|
prompt,
|
|
804
846
|
triggerSource: "onCwdChanged",
|
|
847
|
+
hookCfg: cfg,
|
|
805
848
|
});
|
|
806
849
|
this.lastTrigger.set(key, now);
|
|
807
850
|
this.log(`[automation] triggered cwd-changed task ${taskId.slice(0, 8)} for ${newCwd}`);
|
|
@@ -818,6 +861,15 @@ export class AutomationHooks {
|
|
|
818
861
|
const cfg = this.policy.onPostCompact;
|
|
819
862
|
if (!cfg?.enabled)
|
|
820
863
|
return;
|
|
864
|
+
if (this.activePostCompactTaskId) {
|
|
865
|
+
const existing = this.orchestrator.getTask(this.activePostCompactTaskId);
|
|
866
|
+
if (existing &&
|
|
867
|
+
(existing.status === "pending" || existing.status === "running")) {
|
|
868
|
+
this.log(`[automation] skipping post-compact trigger — task ${this.activePostCompactTaskId.slice(0, 8)} still active`);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
this.activePostCompactTaskId = null;
|
|
872
|
+
}
|
|
821
873
|
const key = "post-compact";
|
|
822
874
|
const now = Date.now();
|
|
823
875
|
const last = this.lastTrigger.get(key) ?? 0;
|
|
@@ -841,10 +893,12 @@ export class AutomationHooks {
|
|
|
841
893
|
const taskId = this._enqueueAutomationTask({
|
|
842
894
|
prompt: postCompactPrompt,
|
|
843
895
|
triggerSource: "onPostCompact",
|
|
896
|
+
hookCfg: cfg,
|
|
844
897
|
});
|
|
845
898
|
// Set lastTrigger AFTER successful enqueue so a failed enqueue does not
|
|
846
899
|
// impose a spurious cooldown on the next trigger attempt.
|
|
847
900
|
this.lastTrigger.set(key, now);
|
|
901
|
+
this.activePostCompactTaskId = taskId;
|
|
848
902
|
this.log(`[automation] triggered PostCompact task ${taskId.slice(0, 8)}`);
|
|
849
903
|
}
|
|
850
904
|
catch (err) {
|
|
@@ -859,6 +913,15 @@ export class AutomationHooks {
|
|
|
859
913
|
const cfg = this.policy.onInstructionsLoaded;
|
|
860
914
|
if (!cfg?.enabled)
|
|
861
915
|
return;
|
|
916
|
+
if (this.activeInstructionsLoadedTaskId) {
|
|
917
|
+
const existing = this.orchestrator.getTask(this.activeInstructionsLoadedTaskId);
|
|
918
|
+
if (existing &&
|
|
919
|
+
(existing.status === "pending" || existing.status === "running")) {
|
|
920
|
+
this.log(`[automation] skipping instructions-loaded trigger — task ${this.activeInstructionsLoadedTaskId.slice(0, 8)} still active`);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
this.activeInstructionsLoadedTaskId = null;
|
|
924
|
+
}
|
|
862
925
|
const cooldownMs = cfg.cooldownMs ?? 60_000;
|
|
863
926
|
const key = "instructions-loaded";
|
|
864
927
|
const now = Date.now();
|
|
@@ -883,8 +946,10 @@ export class AutomationHooks {
|
|
|
883
946
|
const taskId = this._enqueueAutomationTask({
|
|
884
947
|
prompt: instrPrompt,
|
|
885
948
|
triggerSource: "onInstructionsLoaded",
|
|
949
|
+
hookCfg: cfg,
|
|
886
950
|
});
|
|
887
951
|
this.lastTrigger.set(key, now);
|
|
952
|
+
this.activeInstructionsLoadedTaskId = taskId;
|
|
888
953
|
this.log(`[automation] triggered InstructionsLoaded task ${taskId.slice(0, 8)}`);
|
|
889
954
|
}
|
|
890
955
|
catch (err) {
|
|
@@ -951,6 +1016,7 @@ export class AutomationHooks {
|
|
|
951
1016
|
const taskId = this._enqueueAutomationTask({
|
|
952
1017
|
prompt,
|
|
953
1018
|
triggerSource: "onFileSave",
|
|
1019
|
+
hookCfg: cfg,
|
|
954
1020
|
});
|
|
955
1021
|
this.lastTrigger.set(key, now);
|
|
956
1022
|
this.activeSaveTasks.set(normalizedFile, taskId);
|
|
@@ -1023,6 +1089,7 @@ export class AutomationHooks {
|
|
|
1023
1089
|
const taskId = this._enqueueAutomationTask({
|
|
1024
1090
|
prompt,
|
|
1025
1091
|
triggerSource: "onFileChanged",
|
|
1092
|
+
hookCfg: cfg,
|
|
1026
1093
|
});
|
|
1027
1094
|
this.lastTrigger.set(key, now);
|
|
1028
1095
|
this.activeFileChangedTasks.set(normalizedFile, taskId);
|
|
@@ -1114,6 +1181,7 @@ export class AutomationHooks {
|
|
|
1114
1181
|
const taskId = this._enqueueAutomationTask({
|
|
1115
1182
|
prompt,
|
|
1116
1183
|
triggerSource: "onTestRun",
|
|
1184
|
+
hookCfg: cfg,
|
|
1117
1185
|
});
|
|
1118
1186
|
this.lastTrigger.set(key, now);
|
|
1119
1187
|
this.activeTestRunTaskId = taskId;
|
|
@@ -1201,7 +1269,7 @@ export class AutomationHooks {
|
|
|
1201
1269
|
.replace(/\{\{hash\}\}/g, untrustedBlock("COMMIT HASH", safeHash, nonce))
|
|
1202
1270
|
.replace(/\{\{branch\}\}/g, untrustedBlock("BRANCH", safeBranchCommit, nonce))
|
|
1203
1271
|
.replace(/\{\{message\}\}/g, untrustedBlock("COMMIT MESSAGE", safeMessage, nonce))
|
|
1204
|
-
.replace(/\{\{count\}\}/g, String(result.count))
|
|
1272
|
+
.replace(/\{\{count\}\}/g, untrustedBlock("COMMIT COUNT", String(result.count), nonce))
|
|
1205
1273
|
.replace(/\{\{files\}\}/g, untrustedBlock("COMMITTED FILES", filesText, nonce))
|
|
1206
1274
|
.replace(/\{\{changeImpact\}\}/g, changeImpact
|
|
1207
1275
|
? untrustedBlock("CHANGE IMPACT", changeImpact, nonce)
|
|
@@ -1212,6 +1280,7 @@ export class AutomationHooks {
|
|
|
1212
1280
|
const taskId = this._enqueueAutomationTask({
|
|
1213
1281
|
prompt,
|
|
1214
1282
|
triggerSource: "onGitCommit",
|
|
1283
|
+
hookCfg: cfg,
|
|
1215
1284
|
});
|
|
1216
1285
|
this.lastTrigger.set(key, now);
|
|
1217
1286
|
this.activeGitCommitTaskId = taskId;
|
|
@@ -1273,6 +1342,7 @@ export class AutomationHooks {
|
|
|
1273
1342
|
const taskId = this._enqueueAutomationTask({
|
|
1274
1343
|
prompt,
|
|
1275
1344
|
triggerSource: "onGitPush",
|
|
1345
|
+
hookCfg: cfg,
|
|
1276
1346
|
});
|
|
1277
1347
|
this.lastTrigger.set(key, now);
|
|
1278
1348
|
this.activeGitPushTaskId = taskId;
|
|
@@ -1331,6 +1401,7 @@ export class AutomationHooks {
|
|
|
1331
1401
|
const taskId = this._enqueueAutomationTask({
|
|
1332
1402
|
prompt,
|
|
1333
1403
|
triggerSource: "onGitPull",
|
|
1404
|
+
hookCfg: cfg,
|
|
1334
1405
|
});
|
|
1335
1406
|
this.lastTrigger.set(key, now);
|
|
1336
1407
|
this.activeGitPullTaskId = taskId;
|
|
@@ -1395,6 +1466,7 @@ export class AutomationHooks {
|
|
|
1395
1466
|
const taskId = this._enqueueAutomationTask({
|
|
1396
1467
|
prompt,
|
|
1397
1468
|
triggerSource: "onBranchCheckout",
|
|
1469
|
+
hookCfg: cfg,
|
|
1398
1470
|
});
|
|
1399
1471
|
this.lastTrigger.set(key, now);
|
|
1400
1472
|
this.activeBranchCheckoutTaskId = taskId;
|
|
@@ -1461,6 +1533,7 @@ export class AutomationHooks {
|
|
|
1461
1533
|
const taskId = this._enqueueAutomationTask({
|
|
1462
1534
|
prompt,
|
|
1463
1535
|
triggerSource: "onPullRequest",
|
|
1536
|
+
hookCfg: cfg,
|
|
1464
1537
|
});
|
|
1465
1538
|
this.lastTrigger.set(key, now);
|
|
1466
1539
|
this.activePullRequestTaskId = taskId;
|
|
@@ -1513,6 +1586,7 @@ export class AutomationHooks {
|
|
|
1513
1586
|
const taskId = this._enqueueAutomationTask({
|
|
1514
1587
|
prompt,
|
|
1515
1588
|
triggerSource: "onTaskCreated",
|
|
1589
|
+
hookCfg: cfg,
|
|
1516
1590
|
});
|
|
1517
1591
|
this.lastTrigger.set(key, now);
|
|
1518
1592
|
this.activeTaskCreatedTaskId = taskId;
|
|
@@ -1566,6 +1640,7 @@ export class AutomationHooks {
|
|
|
1566
1640
|
const taskId = this._enqueueAutomationTask({
|
|
1567
1641
|
prompt,
|
|
1568
1642
|
triggerSource: "onPermissionDenied",
|
|
1643
|
+
hookCfg: cfg,
|
|
1569
1644
|
});
|
|
1570
1645
|
this.lastTrigger.set(key, now);
|
|
1571
1646
|
this.activePermissionDeniedTaskId = taskId;
|
|
@@ -1622,6 +1697,7 @@ export class AutomationHooks {
|
|
|
1622
1697
|
const taskId = this._enqueueAutomationTask({
|
|
1623
1698
|
prompt,
|
|
1624
1699
|
triggerSource: "onDiagnosticsCleared",
|
|
1700
|
+
hookCfg: cfg,
|
|
1625
1701
|
});
|
|
1626
1702
|
this.lastTrigger.set(key, now);
|
|
1627
1703
|
this.activeDiagnosticsClearedTasks.set(normalizedFile, taskId);
|
|
@@ -1679,6 +1755,7 @@ export class AutomationHooks {
|
|
|
1679
1755
|
const taskId = this._enqueueAutomationTask({
|
|
1680
1756
|
prompt,
|
|
1681
1757
|
triggerSource: "onTaskSuccess",
|
|
1758
|
+
hookCfg: cfg,
|
|
1682
1759
|
});
|
|
1683
1760
|
this.lastTrigger.set(key, now);
|
|
1684
1761
|
this.activeTaskSuccessTaskId = taskId;
|
|
@@ -1797,6 +1874,8 @@ export class AutomationHooks {
|
|
|
1797
1874
|
defaultModel: p.defaultModel ?? "claude-haiku-4-5-20251001",
|
|
1798
1875
|
maxTasksPerHour: p.maxTasksPerHour ?? 20,
|
|
1799
1876
|
tasksThisHour: this.taskTimestamps.filter((t) => t >= Date.now() - 60 * 60 * 1_000).length,
|
|
1877
|
+
defaultEffort: p.defaultEffort ?? "low",
|
|
1878
|
+
automationSystemPrompt: (p.automationSystemPrompt ?? DEFAULT_AUTOMATION_SYSTEM_PROMPT).slice(0, 80),
|
|
1800
1879
|
};
|
|
1801
1880
|
}
|
|
1802
1881
|
}
|