wave-agent-sdk 0.19.3 → 0.19.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.
- package/dist/managers/aiManager.d.ts +1 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +57 -0
- package/dist/managers/backgroundTaskManager.d.ts +6 -1
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +5 -0
- package/dist/managers/workflowManager.d.ts.map +1 -1
- package/dist/managers/workflowManager.js +8 -4
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +6 -0
- package/dist/tools/grepTool.d.ts.map +1 -1
- package/dist/tools/grepTool.js +23 -1
- package/dist/tools/lspTool.js +3 -3
- package/dist/types/hooks.d.ts +19 -0
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/utils/path.d.ts +8 -2
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +10 -4
- package/dist/utils/pathEncoder.d.ts.map +1 -1
- package/dist/utils/pathEncoder.js +7 -2
- package/dist/workflow/workflowApis.d.ts +1 -3
- package/dist/workflow/workflowApis.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/install_ripgrep.js +1 -1
- package/src/managers/aiManager.ts +69 -0
- package/src/managers/backgroundTaskManager.ts +6 -1
- package/src/managers/workflowManager.ts +8 -6
- package/src/services/hook.ts +7 -0
- package/src/tools/grepTool.ts +25 -1
- package/src/tools/lspTool.ts +3 -3
- package/src/types/hooks.ts +29 -0
- package/src/utils/path.ts +10 -4
- package/src/utils/pathEncoder.ts +8 -2
- package/src/workflow/workflowApis.ts +1 -3
|
@@ -96,6 +96,7 @@ export declare class AIManager {
|
|
|
96
96
|
getIsCompacting(): boolean;
|
|
97
97
|
setIsCompacting(isCompacting: boolean): void;
|
|
98
98
|
private get subagentManager();
|
|
99
|
+
private get cronManager();
|
|
99
100
|
private get skillManager();
|
|
100
101
|
sendAIMessage(options?: {
|
|
101
102
|
recursionDepth?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,KAAK,EAGN,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,42 @@ import { recoverTruncatedJson } from "../utils/stringUtils.js";
|
|
|
12
12
|
import { logger } from "../utils/globalLogger.js";
|
|
13
13
|
import { startInteractionSpan, endInteractionSpan, startLLMRequestSpan, endLLMRequestSpan, resetTracingState, } from "../telemetry/sessionTracing.js";
|
|
14
14
|
import { logOTelEvent } from "../telemetry/events.js";
|
|
15
|
+
// Truncate text to `max` chars and append a "… [+N chars]" marker when exceeded.
|
|
16
|
+
// Used for background_tasks description/command fields (≤1000 chars per spec FR-063).
|
|
17
|
+
function truncateWithMarker(text, max) {
|
|
18
|
+
if (text.length <= max)
|
|
19
|
+
return text;
|
|
20
|
+
return text.slice(0, max) + `… [+${text.length - max} chars]`;
|
|
21
|
+
}
|
|
22
|
+
// Map a BackgroundTask (from BackgroundTaskManager) to the Stop hook's
|
|
23
|
+
// background_tasks array element shape (aligned with Claude Code v2.1.145+).
|
|
24
|
+
// Conditional fields are populated based on task type:
|
|
25
|
+
// - shell: `command`
|
|
26
|
+
// - subagent: `agent_type` (looked up via SubagentManager by subagentId)
|
|
27
|
+
// - workflow: `name` (extracted from "Workflow: <name>" description)
|
|
28
|
+
function mapBackgroundTask(task, subagentManager) {
|
|
29
|
+
const base = {
|
|
30
|
+
id: task.id,
|
|
31
|
+
type: task.type,
|
|
32
|
+
status: task.status,
|
|
33
|
+
description: truncateWithMarker(task.description ?? "", 1000),
|
|
34
|
+
};
|
|
35
|
+
if (task.type === "shell") {
|
|
36
|
+
return { ...base, command: truncateWithMarker(task.command ?? "", 1000) };
|
|
37
|
+
}
|
|
38
|
+
if (task.type === "subagent") {
|
|
39
|
+
const instance = subagentManager
|
|
40
|
+
?.getActiveInstances()
|
|
41
|
+
.find((i) => i.subagentId === task.subagentId);
|
|
42
|
+
return { ...base, agent_type: instance?.subagentType ?? "" };
|
|
43
|
+
}
|
|
44
|
+
// workflow
|
|
45
|
+
const prefix = "Workflow: ";
|
|
46
|
+
const name = task.description?.startsWith(prefix)
|
|
47
|
+
? task.description.slice(prefix.length)
|
|
48
|
+
: (task.description ?? "");
|
|
49
|
+
return { ...base, name };
|
|
50
|
+
}
|
|
15
51
|
export class AIManager {
|
|
16
52
|
// Service overrides
|
|
17
53
|
constructor(container, options) {
|
|
@@ -499,6 +535,9 @@ export class AIManager {
|
|
|
499
535
|
get subagentManager() {
|
|
500
536
|
return this.container.get("SubagentManager");
|
|
501
537
|
}
|
|
538
|
+
get cronManager() {
|
|
539
|
+
return this.container.get("CronManager");
|
|
540
|
+
}
|
|
502
541
|
get skillManager() {
|
|
503
542
|
return this.container.get("SkillManager");
|
|
504
543
|
}
|
|
@@ -1033,6 +1072,22 @@ export class AIManager {
|
|
|
1033
1072
|
try {
|
|
1034
1073
|
// Use "SubagentStop" hook name when triggered by a subagent, otherwise use "Stop"
|
|
1035
1074
|
const hookName = this.subagentType ? "SubagentStop" : "Stop";
|
|
1075
|
+
// For main-agent Stop events, snapshot running background tasks and
|
|
1076
|
+
// session cron jobs so the hook can decide whether to block stopping.
|
|
1077
|
+
// SubagentStop does not include these fields (per spec FR-065).
|
|
1078
|
+
const backgroundTasks = hookName === "Stop"
|
|
1079
|
+
? (this.backgroundTaskManager?.getAllTasks() ?? [])
|
|
1080
|
+
.filter((t) => t.status === "running")
|
|
1081
|
+
.map((t) => mapBackgroundTask(t, this.subagentManager))
|
|
1082
|
+
: undefined;
|
|
1083
|
+
const sessionCrons = hookName === "Stop"
|
|
1084
|
+
? (this.cronManager?.listJobs() ?? []).map((j) => ({
|
|
1085
|
+
id: j.id,
|
|
1086
|
+
schedule: j.cron,
|
|
1087
|
+
recurring: j.recurring,
|
|
1088
|
+
prompt: j.prompt,
|
|
1089
|
+
}))
|
|
1090
|
+
: undefined;
|
|
1036
1091
|
const context = {
|
|
1037
1092
|
event: hookName,
|
|
1038
1093
|
projectDir: this.getWorkdir(),
|
|
@@ -1041,6 +1096,8 @@ export class AIManager {
|
|
|
1041
1096
|
transcriptPath: this.messageManager.getTranscriptPath(),
|
|
1042
1097
|
cwd: this.getWorkdir(),
|
|
1043
1098
|
subagentType: this.subagentType, // Include subagent type in hook context
|
|
1099
|
+
backgroundTasks, // Stop-only: running background tasks snapshot
|
|
1100
|
+
sessionCrons, // Stop-only: session cron jobs snapshot
|
|
1044
1101
|
// Stop hooks don't need toolName, toolInput, toolResponse, or userPrompt
|
|
1045
1102
|
env: Object.fromEntries(Object.entries(process.env).filter((e) => e[1] !== undefined)), // Include environment variables
|
|
1046
1103
|
};
|
|
@@ -16,7 +16,12 @@ export declare class BackgroundTaskManager {
|
|
|
16
16
|
private workdir;
|
|
17
17
|
constructor(container: Container, options: BackgroundTaskManagerOptions);
|
|
18
18
|
private get notificationQueue();
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Fire the onBackgroundTasksChange callback so UI consumers refresh.
|
|
21
|
+
* Public so other managers (e.g. WorkflowManager) can trigger a refresh
|
|
22
|
+
* when their state changes without mutating a background task.
|
|
23
|
+
*/
|
|
24
|
+
notifyTasksChange(): void;
|
|
20
25
|
generateId(): string;
|
|
21
26
|
addTask(task: BackgroundTask): void;
|
|
22
27
|
getTask(id: string): BackgroundTask | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/managers/backgroundTaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAmB,MAAM,uBAAuB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,OAAO,CAAS;gBAGd,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,4BAA4B;IAMvC,OAAO,KAAK,iBAAiB,GAE5B;IAED,
|
|
1
|
+
{"version":3,"file":"backgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/managers/backgroundTaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAmB,MAAM,uBAAuB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,OAAO,CAAS;gBAGd,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,4BAA4B;IAMvC,OAAO,KAAK,iBAAiB,GAE5B;IAED;;;;OAIG;IACI,iBAAiB,IAAI,IAAI;IAIzB,UAAU,IAAI,MAAM;IAIpB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAKnC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI/C,WAAW,IAAI,cAAc,EAAE;IAI/B,UAAU,CACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE;IA8KnD,YAAY,CACjB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,MAAW,EAC1B,aAAa,GAAE,MAAW,GACzB,MAAM;IAqIF,SAAS,CACd,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd;QACD,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;IAoCD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAgC7B,OAAO,IAAI,IAAI;CAUvB"}
|
|
@@ -15,6 +15,11 @@ export class BackgroundTaskManager {
|
|
|
15
15
|
get notificationQueue() {
|
|
16
16
|
return this.container.get("NotificationQueue");
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Fire the onBackgroundTasksChange callback so UI consumers refresh.
|
|
20
|
+
* Public so other managers (e.g. WorkflowManager) can trigger a refresh
|
|
21
|
+
* when their state changes without mutating a background task.
|
|
22
|
+
*/
|
|
18
23
|
notifyTasksChange() {
|
|
19
24
|
this.callbacks.onBackgroundTasksChange?.(Array.from(this.tasks.values()));
|
|
20
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflowManager.d.ts","sourceRoot":"","sources":["../../src/managers/workflowManager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAelD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAOxD,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,aAAa,CAA8B;gBAEvC,SAAS,EAAE,SAAS;IAKhC,OAAO,KAAK,UAAU,GAOrB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,UAAU,GASrB;IAED;;;OAGG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,WAAW,CAAC;IAoDvB;;;OAGG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"workflowManager.d.ts","sourceRoot":"","sources":["../../src/managers/workflowManager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAelD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAOxD,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,aAAa,CAA8B;gBAEvC,SAAS,EAAE,SAAS;IAKhC,OAAO,KAAK,UAAU,GAOrB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,UAAU,GASrB;IAED;;;OAGG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,WAAW,CAAC;IAoDvB;;;OAGG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,IAAI,CAAC;IA6NhB;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7C;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY5B;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAUlD;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlE;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAsB5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAcxC;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI9C;;OAEG;IACH,OAAO,IAAI,IAAI;CAkBhB"}
|
|
@@ -112,9 +112,16 @@ export class WorkflowManager {
|
|
|
112
112
|
? run.args.budget
|
|
113
113
|
: null);
|
|
114
114
|
const progressReporter = new ProgressReporter(run.meta, runId);
|
|
115
|
-
// Forward progress events
|
|
115
|
+
// Forward progress events: mirror live counts onto the WorkflowRun and
|
|
116
|
+
// trigger a UI refresh so /workflows updates mid-execution (not just at
|
|
117
|
+
// completion). The UI reads getWorkflowRuns() -> listRuns(), which returns
|
|
118
|
+
// these same in-memory run objects.
|
|
116
119
|
const onProgress = (event) => {
|
|
117
120
|
logger.debug(`[Workflow:${runId}] progress: ${event.type} phase=${event.phaseIndex} agent=${event.agentIndex}`);
|
|
121
|
+
run.phases = progressReporter.getPhaseStates();
|
|
122
|
+
run.totalAgents = progressReporter.totalAgents;
|
|
123
|
+
run.totalTokens = progressReporter.totalTokens;
|
|
124
|
+
this.backgroundTaskManager.notifyTasksChange();
|
|
118
125
|
};
|
|
119
126
|
progressReporter.onEvent(onProgress);
|
|
120
127
|
// Journal — load previous journal if resuming
|
|
@@ -175,9 +182,6 @@ export class WorkflowManager {
|
|
|
175
182
|
sessionDir: this.sessionDir,
|
|
176
183
|
runDir: path.join(this.sessionDir, "workflows", runId),
|
|
177
184
|
agentControllers: runAgentControllers,
|
|
178
|
-
onProgress: (event) => {
|
|
179
|
-
logger.debug(`[Workflow:${runId}] progress: ${event.type} phase=${event.phaseIndex} agent=${event.agentIndex}`);
|
|
180
|
-
},
|
|
181
185
|
onLog: (message) => {
|
|
182
186
|
logger.info(`[Workflow:${runId}] ${message}`);
|
|
183
187
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/services/hook.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAElC,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/services/hook.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAElC,MAAM,mBAAmB,CAAC;AA8G3B;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA6I9B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAchC;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAMhC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAsBtD"}
|
package/dist/services/hook.js
CHANGED
|
@@ -83,6 +83,12 @@ async function buildHookJsonInput(context) {
|
|
|
83
83
|
jsonInput.end_source = context.endSource;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
// Add background_tasks and session_crons for Stop events only (not SubagentStop).
|
|
87
|
+
// Fields are always present for Stop (empty arrays when nothing in flight).
|
|
88
|
+
if (context.event === "Stop") {
|
|
89
|
+
jsonInput.background_tasks = context.backgroundTasks ?? [];
|
|
90
|
+
jsonInput.session_crons = context.sessionCrons ?? [];
|
|
91
|
+
}
|
|
86
92
|
return jsonInput;
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAsBtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA0TtB,CAAC"}
|
package/dist/tools/grepTool.js
CHANGED
|
@@ -2,6 +2,17 @@ import { spawn } from "child_process";
|
|
|
2
2
|
import { rgPath } from "../utils/ripgrep.js";
|
|
3
3
|
import { getDisplayPath } from "../utils/path.js";
|
|
4
4
|
import { GREP_TOOL_NAME, BASH_TOOL_NAME, AGENT_TOOL_NAME, } from "../constants/tools.js";
|
|
5
|
+
// Version control system directories to exclude from searches.
|
|
6
|
+
// These are excluded automatically because they create noise in search results.
|
|
7
|
+
// Mirrors Claude Code's VCS_DIRECTORIES_TO_EXCLUDE.
|
|
8
|
+
const VCS_DIRECTORIES_TO_EXCLUDE = [
|
|
9
|
+
".git",
|
|
10
|
+
".svn",
|
|
11
|
+
".hg",
|
|
12
|
+
".bzr",
|
|
13
|
+
".jj",
|
|
14
|
+
".sl",
|
|
15
|
+
];
|
|
5
16
|
/**
|
|
6
17
|
* Grep tool plugin - powerful search tool based on ripgrep
|
|
7
18
|
*/
|
|
@@ -119,7 +130,18 @@ export const grepTool = {
|
|
|
119
130
|
}
|
|
120
131
|
try {
|
|
121
132
|
const workdir = context.workdir;
|
|
122
|
-
const rgArgs = [
|
|
133
|
+
const rgArgs = [
|
|
134
|
+
"--color=never",
|
|
135
|
+
"--max-columns=500",
|
|
136
|
+
// Search hidden files/directories by default (aligns with Claude Code).
|
|
137
|
+
// --hidden does NOT disable .gitignore; only --no-ignore would.
|
|
138
|
+
"--hidden",
|
|
139
|
+
];
|
|
140
|
+
// Exclude VCS directories to avoid noise from version control metadata.
|
|
141
|
+
// --hidden above would otherwise traverse .git/.svn/etc.
|
|
142
|
+
for (const dir of VCS_DIRECTORIES_TO_EXCLUDE) {
|
|
143
|
+
rgArgs.push("--glob", `!${dir}`);
|
|
144
|
+
}
|
|
123
145
|
// Set output mode
|
|
124
146
|
if (outputMode === "files_with_matches") {
|
|
125
147
|
rgArgs.push("-l");
|
package/dist/tools/lspTool.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { relative, join, isAbsolute } from "path";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import { logger } from "../utils/globalLogger.js";
|
|
4
|
-
import { getDisplayPath } from "../utils/path.js";
|
|
4
|
+
import { getDisplayPath, toPosixPath } from "../utils/path.js";
|
|
5
5
|
import { LSP_TOOL_NAME } from "../constants/tools.js";
|
|
6
6
|
export const MAX_RESULTS = 1000;
|
|
7
7
|
export const MAX_FILES = 100;
|
|
@@ -25,10 +25,10 @@ function formatUri(uri, workdir) {
|
|
|
25
25
|
const relativePath = relative(workdir, path);
|
|
26
26
|
if (relativePath.length < path.length &&
|
|
27
27
|
!relativePath.startsWith("../../")) {
|
|
28
|
-
return relativePath;
|
|
28
|
+
return toPosixPath(relativePath);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
return path;
|
|
31
|
+
return toPosixPath(path);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Formats an error message when no results are found, including context from the file
|
package/dist/types/hooks.d.ts
CHANGED
|
@@ -79,6 +79,23 @@ export interface HookJsonInput {
|
|
|
79
79
|
end_source?: SessionEndSource;
|
|
80
80
|
compact_instructions?: string;
|
|
81
81
|
compact_summary?: string;
|
|
82
|
+
background_tasks?: BackgroundTaskInfo[];
|
|
83
|
+
session_crons?: SessionCronInfo[];
|
|
84
|
+
}
|
|
85
|
+
export interface BackgroundTaskInfo {
|
|
86
|
+
id: string;
|
|
87
|
+
type: "shell" | "subagent" | "workflow";
|
|
88
|
+
status: string;
|
|
89
|
+
description: string;
|
|
90
|
+
command?: string;
|
|
91
|
+
agent_type?: string;
|
|
92
|
+
name?: string;
|
|
93
|
+
}
|
|
94
|
+
export interface SessionCronInfo {
|
|
95
|
+
id: string;
|
|
96
|
+
schedule: string;
|
|
97
|
+
recurring: boolean;
|
|
98
|
+
prompt: string;
|
|
82
99
|
}
|
|
83
100
|
export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
84
101
|
sessionId?: string;
|
|
@@ -97,6 +114,8 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
97
114
|
endSource?: SessionEndSource;
|
|
98
115
|
compactInstructions?: string;
|
|
99
116
|
compactSummary?: string;
|
|
117
|
+
backgroundTasks?: BackgroundTaskInfo[];
|
|
118
|
+
sessionCrons?: SessionCronInfo[];
|
|
100
119
|
}
|
|
101
120
|
export interface HookEnvironment {
|
|
102
121
|
WAVE_PROJECT_DIR: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/types/hooks.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/types/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/path.d.ts
CHANGED
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function resolvePath(filePath: string, workdir: string): string;
|
|
8
8
|
/**
|
|
9
|
-
* Get relative path for display, use relative path if shorter and not in parent directory
|
|
9
|
+
* Get relative path for display, use relative path if shorter and not in parent directory.
|
|
10
|
+
*
|
|
11
|
+
* The returned path is always normalized to forward slashes (posix) regardless of
|
|
12
|
+
* platform. This keeps display output consistent across Windows/Unix so that logs,
|
|
13
|
+
* LLM context, and tests don't need platform-specific branches — `path.relative`
|
|
14
|
+
* and `path.join` produce backslashes on Windows, which we collapse here.
|
|
15
|
+
*
|
|
10
16
|
* @param filePath Absolute path
|
|
11
17
|
* @param workdir Working directory
|
|
12
|
-
* @returns Path for display (relative or absolute)
|
|
18
|
+
* @returns Path for display (relative or absolute), always forward-slash
|
|
13
19
|
*/
|
|
14
20
|
export declare function getDisplayPath(filePath: string, workdir: string): string;
|
|
15
21
|
/**
|
package/dist/utils/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAarE;AAED
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAarE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAwBxE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C"}
|
package/dist/utils/path.js
CHANGED
|
@@ -20,10 +20,16 @@ export function resolvePath(filePath, workdir) {
|
|
|
20
20
|
return resolve(workdir, filePath);
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Get relative path for display, use relative path if shorter and not in parent directory
|
|
23
|
+
* Get relative path for display, use relative path if shorter and not in parent directory.
|
|
24
|
+
*
|
|
25
|
+
* The returned path is always normalized to forward slashes (posix) regardless of
|
|
26
|
+
* platform. This keeps display output consistent across Windows/Unix so that logs,
|
|
27
|
+
* LLM context, and tests don't need platform-specific branches — `path.relative`
|
|
28
|
+
* and `path.join` produce backslashes on Windows, which we collapse here.
|
|
29
|
+
*
|
|
24
30
|
* @param filePath Absolute path
|
|
25
31
|
* @param workdir Working directory
|
|
26
|
-
* @returns Path for display (relative or absolute)
|
|
32
|
+
* @returns Path for display (relative or absolute), always forward-slash
|
|
27
33
|
*/
|
|
28
34
|
export function getDisplayPath(filePath, workdir) {
|
|
29
35
|
if (!filePath) {
|
|
@@ -38,13 +44,13 @@ export function getDisplayPath(filePath, workdir) {
|
|
|
38
44
|
// If the relative path is shorter than the absolute path and does not start with .. (not in parent directory), use the relative path
|
|
39
45
|
if (relativePath.length < filePath.length &&
|
|
40
46
|
!relativePath.startsWith("..")) {
|
|
41
|
-
return relativePath;
|
|
47
|
+
return toPosixPath(relativePath);
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
catch {
|
|
45
51
|
// If calculating the relative path fails, keep the original path
|
|
46
52
|
}
|
|
47
|
-
return filePath;
|
|
53
|
+
return toPosixPath(filePath);
|
|
48
54
|
}
|
|
49
55
|
/**
|
|
50
56
|
* Convert backslashes to forward slashes for shell compatibility on Windows.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathEncoder.d.ts","sourceRoot":"","sources":["../../src/utils/pathEncoder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;gBAExC,OAAO,GAAE,mBAAwB;IAW7C;;OAEG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnD;;;OAGG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"pathEncoder.d.ts","sourceRoot":"","sources":["../../src/utils/pathEncoder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;gBAExC,OAAO,GAAE,mBAAwB;IAW7C;;OAEG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnD;;;OAGG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA4CxC;;;OAGG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIzD;;;OAGG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgC9C;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBhD;;OAEG;IACG,mBAAmB,CACvB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,gBAAgB,CAAC;IAmC5B;;OAEG;IACG,sBAAsB,CAC1B,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,gBAAgB,CAAC;IAgB5B;;OAEG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IA+BjD;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM;IAqBtE;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsDhC;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,WAAW;CAMpB;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
|
@@ -35,8 +35,13 @@ export class PathEncoder {
|
|
|
35
35
|
encodeSync(pathToEncode) {
|
|
36
36
|
// Convert to safe directory name
|
|
37
37
|
let encoded = pathToEncode;
|
|
38
|
-
// Remove
|
|
39
|
-
|
|
38
|
+
// Remove Windows drive letter prefix (e.g. "D:") so encoded names are
|
|
39
|
+
// stable across platforms — path.resolve("/home/user/project") yields
|
|
40
|
+
// "D:\home\user\project" on Windows and we want the same encoded name
|
|
41
|
+
// as on Linux ("home-user-project").
|
|
42
|
+
encoded = encoded.replace(/^[a-zA-Z]:/, "");
|
|
43
|
+
// Remove leading slash/backslash to avoid empty directory names
|
|
44
|
+
if (encoded.startsWith("/") || encoded.startsWith("\\")) {
|
|
40
45
|
encoded = encoded.substring(1);
|
|
41
46
|
}
|
|
42
47
|
// Replace path separators with hyphens
|
|
@@ -3,7 +3,7 @@ import { ConcurrencyLimiter } from "./concurrencyLimiter.js";
|
|
|
3
3
|
import { BudgetTracker } from "./budgetTracker.js";
|
|
4
4
|
import { ProgressReporter } from "./progressReporter.js";
|
|
5
5
|
import { Journal } from "./journal.js";
|
|
6
|
-
import type { BudgetInfo
|
|
6
|
+
import type { BudgetInfo } from "./types.js";
|
|
7
7
|
interface WorkflowApiContext {
|
|
8
8
|
subagentManager: SubagentManager;
|
|
9
9
|
concurrencyLimiter: ConcurrencyLimiter;
|
|
@@ -21,8 +21,6 @@ interface WorkflowApiContext {
|
|
|
21
21
|
runDir: string;
|
|
22
22
|
/** Per-agent abort controllers for kill/skip support */
|
|
23
23
|
agentControllers: Map<number, AbortController>;
|
|
24
|
-
/** Optional callback for progress events */
|
|
25
|
-
onProgress?: (event: WorkflowProgressEvent) => void;
|
|
26
24
|
}
|
|
27
25
|
interface AgentOpts {
|
|
28
26
|
label?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflowApis.d.ts","sourceRoot":"","sources":["../../src/workflow/workflowApis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAGtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAa,
|
|
1
|
+
{"version":3,"file":"workflowApis.d.ts","sourceRoot":"","sources":["../../src/workflow/workflowApis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAGtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AAgCxD,UAAU,kBAAkB;IAC1B,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAChD;AAED,UAAU,SAAS;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,QAAQ,EAAE,CACR,KAAK,EAAE,OAAO,EAAE,EAChB,GAAG,MAAM,EAAE,KAAK,CACd,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAClE,KACE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,CAuUxE"}
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ async function main() {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const manifestContent = fs.readFileSync(MANIFEST_PATH, "utf-8");
|
|
19
|
-
const jsonContent = manifestContent.replace(/^#!.*\n/, "");
|
|
19
|
+
const jsonContent = manifestContent.replace(/^#!.*\r?\n/, "");
|
|
20
20
|
const manifest = JSON.parse(jsonContent);
|
|
21
21
|
const platforms = manifest.platforms;
|
|
22
22
|
|
|
@@ -26,8 +26,10 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
|
26
26
|
|
|
27
27
|
import type { HookManager } from "./hookManager.js";
|
|
28
28
|
import type { ExtendedHookExecutionContext } from "../types/hooks.js";
|
|
29
|
+
import type { BackgroundTaskInfo, SessionCronInfo } from "../types/hooks.js";
|
|
29
30
|
import type { PermissionManager } from "./permissionManager.js";
|
|
30
31
|
import type { SubagentManager } from "./subagentManager.js";
|
|
32
|
+
import type { CronManager } from "./cronManager.js";
|
|
31
33
|
import type { SkillManager } from "./skillManager.js";
|
|
32
34
|
import { buildSystemPrompt } from "../prompts/index.js";
|
|
33
35
|
import {
|
|
@@ -49,6 +51,47 @@ import {
|
|
|
49
51
|
resetTracingState,
|
|
50
52
|
} from "../telemetry/sessionTracing.js";
|
|
51
53
|
import { logOTelEvent } from "../telemetry/events.js";
|
|
54
|
+
import type { BackgroundTask } from "../types/processes.js";
|
|
55
|
+
|
|
56
|
+
// Truncate text to `max` chars and append a "… [+N chars]" marker when exceeded.
|
|
57
|
+
// Used for background_tasks description/command fields (≤1000 chars per spec FR-063).
|
|
58
|
+
function truncateWithMarker(text: string, max: number): string {
|
|
59
|
+
if (text.length <= max) return text;
|
|
60
|
+
return text.slice(0, max) + `… [+${text.length - max} chars]`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Map a BackgroundTask (from BackgroundTaskManager) to the Stop hook's
|
|
64
|
+
// background_tasks array element shape (aligned with Claude Code v2.1.145+).
|
|
65
|
+
// Conditional fields are populated based on task type:
|
|
66
|
+
// - shell: `command`
|
|
67
|
+
// - subagent: `agent_type` (looked up via SubagentManager by subagentId)
|
|
68
|
+
// - workflow: `name` (extracted from "Workflow: <name>" description)
|
|
69
|
+
function mapBackgroundTask(
|
|
70
|
+
task: BackgroundTask,
|
|
71
|
+
subagentManager: SubagentManager | undefined,
|
|
72
|
+
): BackgroundTaskInfo {
|
|
73
|
+
const base: BackgroundTaskInfo = {
|
|
74
|
+
id: task.id,
|
|
75
|
+
type: task.type,
|
|
76
|
+
status: task.status,
|
|
77
|
+
description: truncateWithMarker(task.description ?? "", 1000),
|
|
78
|
+
};
|
|
79
|
+
if (task.type === "shell") {
|
|
80
|
+
return { ...base, command: truncateWithMarker(task.command ?? "", 1000) };
|
|
81
|
+
}
|
|
82
|
+
if (task.type === "subagent") {
|
|
83
|
+
const instance = subagentManager
|
|
84
|
+
?.getActiveInstances()
|
|
85
|
+
.find((i) => i.subagentId === task.subagentId);
|
|
86
|
+
return { ...base, agent_type: instance?.subagentType ?? "" };
|
|
87
|
+
}
|
|
88
|
+
// workflow
|
|
89
|
+
const prefix = "Workflow: ";
|
|
90
|
+
const name = task.description?.startsWith(prefix)
|
|
91
|
+
? task.description.slice(prefix.length)
|
|
92
|
+
: (task.description ?? "");
|
|
93
|
+
return { ...base, name };
|
|
94
|
+
}
|
|
52
95
|
|
|
53
96
|
export interface AIManagerCallbacks {
|
|
54
97
|
onCompactionStateChange?: (isCompacting: boolean) => void;
|
|
@@ -734,6 +777,10 @@ export class AIManager {
|
|
|
734
777
|
return this.container.get<SubagentManager>("SubagentManager");
|
|
735
778
|
}
|
|
736
779
|
|
|
780
|
+
private get cronManager(): CronManager | undefined {
|
|
781
|
+
return this.container.get<CronManager>("CronManager");
|
|
782
|
+
}
|
|
783
|
+
|
|
737
784
|
private get skillManager(): SkillManager | undefined {
|
|
738
785
|
return this.container.get<SkillManager>("SkillManager");
|
|
739
786
|
}
|
|
@@ -1435,6 +1482,26 @@ export class AIManager {
|
|
|
1435
1482
|
// Use "SubagentStop" hook name when triggered by a subagent, otherwise use "Stop"
|
|
1436
1483
|
const hookName = this.subagentType ? "SubagentStop" : "Stop";
|
|
1437
1484
|
|
|
1485
|
+
// For main-agent Stop events, snapshot running background tasks and
|
|
1486
|
+
// session cron jobs so the hook can decide whether to block stopping.
|
|
1487
|
+
// SubagentStop does not include these fields (per spec FR-065).
|
|
1488
|
+
const backgroundTasks: BackgroundTaskInfo[] | undefined =
|
|
1489
|
+
hookName === "Stop"
|
|
1490
|
+
? (this.backgroundTaskManager?.getAllTasks() ?? [])
|
|
1491
|
+
.filter((t) => t.status === "running")
|
|
1492
|
+
.map((t) => mapBackgroundTask(t, this.subagentManager))
|
|
1493
|
+
: undefined;
|
|
1494
|
+
|
|
1495
|
+
const sessionCrons: SessionCronInfo[] | undefined =
|
|
1496
|
+
hookName === "Stop"
|
|
1497
|
+
? (this.cronManager?.listJobs() ?? []).map((j) => ({
|
|
1498
|
+
id: j.id,
|
|
1499
|
+
schedule: j.cron,
|
|
1500
|
+
recurring: j.recurring,
|
|
1501
|
+
prompt: j.prompt,
|
|
1502
|
+
}))
|
|
1503
|
+
: undefined;
|
|
1504
|
+
|
|
1438
1505
|
const context: ExtendedHookExecutionContext = {
|
|
1439
1506
|
event: hookName,
|
|
1440
1507
|
projectDir: this.getWorkdir(),
|
|
@@ -1443,6 +1510,8 @@ export class AIManager {
|
|
|
1443
1510
|
transcriptPath: this.messageManager.getTranscriptPath(),
|
|
1444
1511
|
cwd: this.getWorkdir(),
|
|
1445
1512
|
subagentType: this.subagentType, // Include subagent type in hook context
|
|
1513
|
+
backgroundTasks, // Stop-only: running background tasks snapshot
|
|
1514
|
+
sessionCrons, // Stop-only: session cron jobs snapshot
|
|
1446
1515
|
// Stop hooks don't need toolName, toolInput, toolResponse, or userPrompt
|
|
1447
1516
|
env: Object.fromEntries(
|
|
1448
1517
|
Object.entries(process.env).filter((e) => e[1] !== undefined),
|
|
@@ -35,7 +35,12 @@ export class BackgroundTaskManager {
|
|
|
35
35
|
return this.container.get<NotificationQueue>("NotificationQueue")!;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Fire the onBackgroundTasksChange callback so UI consumers refresh.
|
|
40
|
+
* Public so other managers (e.g. WorkflowManager) can trigger a refresh
|
|
41
|
+
* when their state changes without mutating a background task.
|
|
42
|
+
*/
|
|
43
|
+
public notifyTasksChange(): void {
|
|
39
44
|
this.callbacks.onBackgroundTasksChange?.(Array.from(this.tasks.values()));
|
|
40
45
|
}
|
|
41
46
|
|
|
@@ -164,13 +164,20 @@ export class WorkflowManager {
|
|
|
164
164
|
);
|
|
165
165
|
const progressReporter = new ProgressReporter(run.meta, runId);
|
|
166
166
|
|
|
167
|
-
// Forward progress events
|
|
167
|
+
// Forward progress events: mirror live counts onto the WorkflowRun and
|
|
168
|
+
// trigger a UI refresh so /workflows updates mid-execution (not just at
|
|
169
|
+
// completion). The UI reads getWorkflowRuns() -> listRuns(), which returns
|
|
170
|
+
// these same in-memory run objects.
|
|
168
171
|
const onProgress = (
|
|
169
172
|
event: import("../workflow/types.js").WorkflowProgressEvent,
|
|
170
173
|
) => {
|
|
171
174
|
logger.debug(
|
|
172
175
|
`[Workflow:${runId}] progress: ${event.type} phase=${event.phaseIndex} agent=${event.agentIndex}`,
|
|
173
176
|
);
|
|
177
|
+
run.phases = progressReporter.getPhaseStates();
|
|
178
|
+
run.totalAgents = progressReporter.totalAgents;
|
|
179
|
+
run.totalTokens = progressReporter.totalTokens;
|
|
180
|
+
this.backgroundTaskManager.notifyTasksChange();
|
|
174
181
|
};
|
|
175
182
|
progressReporter.onEvent(onProgress);
|
|
176
183
|
|
|
@@ -251,11 +258,6 @@ export class WorkflowManager {
|
|
|
251
258
|
sessionDir: this.sessionDir,
|
|
252
259
|
runDir: path.join(this.sessionDir, "workflows", runId),
|
|
253
260
|
agentControllers: runAgentControllers,
|
|
254
|
-
onProgress: (event) => {
|
|
255
|
-
logger.debug(
|
|
256
|
-
`[Workflow:${runId}] progress: ${event.type} phase=${event.phaseIndex} agent=${event.agentIndex}`,
|
|
257
|
-
);
|
|
258
|
-
},
|
|
259
261
|
onLog: (message: string) => {
|
|
260
262
|
logger.info(`[Workflow:${runId}] ${message}`);
|
|
261
263
|
},
|
package/src/services/hook.ts
CHANGED
|
@@ -113,6 +113,13 @@ async function buildHookJsonInput(
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
// Add background_tasks and session_crons for Stop events only (not SubagentStop).
|
|
117
|
+
// Fields are always present for Stop (empty arrays when nothing in flight).
|
|
118
|
+
if (context.event === "Stop") {
|
|
119
|
+
jsonInput.background_tasks = context.backgroundTasks ?? [];
|
|
120
|
+
jsonInput.session_crons = context.sessionCrons ?? [];
|
|
121
|
+
}
|
|
122
|
+
|
|
116
123
|
return jsonInput;
|
|
117
124
|
}
|
|
118
125
|
|
package/src/tools/grepTool.ts
CHANGED
|
@@ -8,6 +8,18 @@ import {
|
|
|
8
8
|
AGENT_TOOL_NAME,
|
|
9
9
|
} from "../constants/tools.js";
|
|
10
10
|
|
|
11
|
+
// Version control system directories to exclude from searches.
|
|
12
|
+
// These are excluded automatically because they create noise in search results.
|
|
13
|
+
// Mirrors Claude Code's VCS_DIRECTORIES_TO_EXCLUDE.
|
|
14
|
+
const VCS_DIRECTORIES_TO_EXCLUDE = [
|
|
15
|
+
".git",
|
|
16
|
+
".svn",
|
|
17
|
+
".hg",
|
|
18
|
+
".bzr",
|
|
19
|
+
".jj",
|
|
20
|
+
".sl",
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
11
23
|
/**
|
|
12
24
|
* Grep tool plugin - powerful search tool based on ripgrep
|
|
13
25
|
*/
|
|
@@ -144,7 +156,19 @@ export const grepTool: ToolPlugin = {
|
|
|
144
156
|
|
|
145
157
|
try {
|
|
146
158
|
const workdir = context.workdir;
|
|
147
|
-
const rgArgs: string[] = [
|
|
159
|
+
const rgArgs: string[] = [
|
|
160
|
+
"--color=never",
|
|
161
|
+
"--max-columns=500",
|
|
162
|
+
// Search hidden files/directories by default (aligns with Claude Code).
|
|
163
|
+
// --hidden does NOT disable .gitignore; only --no-ignore would.
|
|
164
|
+
"--hidden",
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// Exclude VCS directories to avoid noise from version control metadata.
|
|
168
|
+
// --hidden above would otherwise traverse .git/.svn/etc.
|
|
169
|
+
for (const dir of VCS_DIRECTORIES_TO_EXCLUDE) {
|
|
170
|
+
rgArgs.push("--glob", `!${dir}`);
|
|
171
|
+
}
|
|
148
172
|
|
|
149
173
|
// Set output mode
|
|
150
174
|
if (outputMode === "files_with_matches") {
|
package/src/tools/lspTool.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
|
2
2
|
import { relative, join, isAbsolute } from "path";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import { logger } from "../utils/globalLogger.js";
|
|
5
|
-
import { getDisplayPath } from "../utils/path.js";
|
|
5
|
+
import { getDisplayPath, toPosixPath } from "../utils/path.js";
|
|
6
6
|
import { LSP_TOOL_NAME } from "../constants/tools.js";
|
|
7
7
|
import type {
|
|
8
8
|
LspLocation as Location,
|
|
@@ -45,10 +45,10 @@ function formatUri(uri: string, workdir?: string): string {
|
|
|
45
45
|
relativePath.length < path.length &&
|
|
46
46
|
!relativePath.startsWith("../../")
|
|
47
47
|
) {
|
|
48
|
-
return relativePath;
|
|
48
|
+
return toPosixPath(relativePath);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
return path;
|
|
51
|
+
return toPosixPath(path);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
package/src/types/hooks.ts
CHANGED
|
@@ -196,6 +196,33 @@ export interface HookJsonInput {
|
|
|
196
196
|
end_source?: SessionEndSource; // Present for SessionEnd events
|
|
197
197
|
compact_instructions?: string; // Present for PreCompact events
|
|
198
198
|
compact_summary?: string; // Present for PostCompact events
|
|
199
|
+
background_tasks?: BackgroundTaskInfo[]; // Present for Stop events: running background tasks snapshot
|
|
200
|
+
session_crons?: SessionCronInfo[]; // Present for Stop events: session-scoped cron jobs snapshot
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Describes one in-flight background task in the Stop hook input.
|
|
204
|
+
// Aligned with Claude Code (v2.1.145+) background_tasks array element schema.
|
|
205
|
+
// Conditional fields are populated based on `type`:
|
|
206
|
+
// - "shell": `command` is set
|
|
207
|
+
// - "subagent": `agent_type` is set
|
|
208
|
+
// - "workflow": `name` is set
|
|
209
|
+
export interface BackgroundTaskInfo {
|
|
210
|
+
id: string;
|
|
211
|
+
type: "shell" | "subagent" | "workflow";
|
|
212
|
+
status: string;
|
|
213
|
+
description: string; // Capped at 1000 chars with "… [+N chars]" marker
|
|
214
|
+
command?: string; // Present only for shell tasks (≤1000 chars)
|
|
215
|
+
agent_type?: string; // Present only for subagent tasks
|
|
216
|
+
name?: string; // Present only for workflow tasks
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Describes one session-scoped cron job in the Stop hook input.
|
|
220
|
+
// Aligned with Claude Code (v2.1.145+) session_crons array element schema.
|
|
221
|
+
export interface SessionCronInfo {
|
|
222
|
+
id: string;
|
|
223
|
+
schedule: string; // Cron expression
|
|
224
|
+
recurring: boolean;
|
|
225
|
+
prompt: string;
|
|
199
226
|
}
|
|
200
227
|
|
|
201
228
|
// Extended context interface for passing additional data to hook executor
|
|
@@ -216,6 +243,8 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
216
243
|
endSource?: SessionEndSource; // Session end source (SessionEnd only)
|
|
217
244
|
compactInstructions?: string; // Custom instructions for PreCompact
|
|
218
245
|
compactSummary?: string; // Summary text for PostCompact
|
|
246
|
+
backgroundTasks?: BackgroundTaskInfo[]; // Running background tasks snapshot (Stop only)
|
|
247
|
+
sessionCrons?: SessionCronInfo[]; // Session-scoped cron jobs snapshot (Stop only)
|
|
219
248
|
}
|
|
220
249
|
|
|
221
250
|
// Environment variables injected into hook processes
|
package/src/utils/path.ts
CHANGED
|
@@ -24,10 +24,16 @@ export function resolvePath(filePath: string, workdir: string): string {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Get relative path for display, use relative path if shorter and not in parent directory
|
|
27
|
+
* Get relative path for display, use relative path if shorter and not in parent directory.
|
|
28
|
+
*
|
|
29
|
+
* The returned path is always normalized to forward slashes (posix) regardless of
|
|
30
|
+
* platform. This keeps display output consistent across Windows/Unix so that logs,
|
|
31
|
+
* LLM context, and tests don't need platform-specific branches — `path.relative`
|
|
32
|
+
* and `path.join` produce backslashes on Windows, which we collapse here.
|
|
33
|
+
*
|
|
28
34
|
* @param filePath Absolute path
|
|
29
35
|
* @param workdir Working directory
|
|
30
|
-
* @returns Path for display (relative or absolute)
|
|
36
|
+
* @returns Path for display (relative or absolute), always forward-slash
|
|
31
37
|
*/
|
|
32
38
|
export function getDisplayPath(filePath: string, workdir: string): string {
|
|
33
39
|
if (!filePath) {
|
|
@@ -47,12 +53,12 @@ export function getDisplayPath(filePath: string, workdir: string): string {
|
|
|
47
53
|
relativePath.length < filePath.length &&
|
|
48
54
|
!relativePath.startsWith("..")
|
|
49
55
|
) {
|
|
50
|
-
return relativePath;
|
|
56
|
+
return toPosixPath(relativePath);
|
|
51
57
|
}
|
|
52
58
|
} catch {
|
|
53
59
|
// If calculating the relative path fails, keep the original path
|
|
54
60
|
}
|
|
55
|
-
return filePath;
|
|
61
|
+
return toPosixPath(filePath);
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/**
|
package/src/utils/pathEncoder.ts
CHANGED
|
@@ -86,8 +86,14 @@ export class PathEncoder {
|
|
|
86
86
|
// Convert to safe directory name
|
|
87
87
|
let encoded = pathToEncode;
|
|
88
88
|
|
|
89
|
-
// Remove
|
|
90
|
-
|
|
89
|
+
// Remove Windows drive letter prefix (e.g. "D:") so encoded names are
|
|
90
|
+
// stable across platforms — path.resolve("/home/user/project") yields
|
|
91
|
+
// "D:\home\user\project" on Windows and we want the same encoded name
|
|
92
|
+
// as on Linux ("home-user-project").
|
|
93
|
+
encoded = encoded.replace(/^[a-zA-Z]:/, "");
|
|
94
|
+
|
|
95
|
+
// Remove leading slash/backslash to avoid empty directory names
|
|
96
|
+
if (encoded.startsWith("/") || encoded.startsWith("\\")) {
|
|
91
97
|
encoded = encoded.substring(1);
|
|
92
98
|
}
|
|
93
99
|
|
|
@@ -5,7 +5,7 @@ import { ConcurrencyLimiter } from "./concurrencyLimiter.js";
|
|
|
5
5
|
import { BudgetTracker } from "./budgetTracker.js";
|
|
6
6
|
import { ProgressReporter } from "./progressReporter.js";
|
|
7
7
|
import { Journal } from "./journal.js";
|
|
8
|
-
import type { BudgetInfo, AgentMeta
|
|
8
|
+
import type { BudgetInfo, AgentMeta } from "./types.js";
|
|
9
9
|
import {
|
|
10
10
|
createStructuredOutputPrompt,
|
|
11
11
|
createStructuredOutputTool,
|
|
@@ -54,8 +54,6 @@ interface WorkflowApiContext {
|
|
|
54
54
|
runDir: string;
|
|
55
55
|
/** Per-agent abort controllers for kill/skip support */
|
|
56
56
|
agentControllers: Map<number, AbortController>;
|
|
57
|
-
/** Optional callback for progress events */
|
|
58
|
-
onProgress?: (event: WorkflowProgressEvent) => void;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
interface AgentOpts {
|