wave-agent-sdk 0.18.5 → 0.18.7
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.map +1 -1
- package/dist/managers/aiManager.js +92 -87
- package/dist/managers/cronManager.d.ts.map +1 -1
- package/dist/managers/cronManager.js +2 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -1
- package/dist/managers/liveConfigManager.js +0 -9
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +6 -1
- package/dist/managers/messageManager.d.ts +1 -1
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +10 -4
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +2 -0
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +2 -0
- package/dist/telemetry/sessionTracing.d.ts +17 -16
- package/dist/telemetry/sessionTracing.d.ts.map +1 -1
- package/dist/telemetry/sessionTracing.js +62 -58
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +6 -7
- package/dist/types/telemetry.d.ts +2 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/utils/fileUtils.d.ts +0 -6
- package/dist/utils/fileUtils.d.ts.map +1 -1
- package/dist/utils/fileUtils.js +0 -43
- package/dist/utils/gitUtils.d.ts +11 -0
- package/dist/utils/gitUtils.d.ts.map +1 -1
- package/dist/utils/gitUtils.js +51 -0
- package/dist/utils/groupMessagesByApiRound.d.ts.map +1 -1
- package/dist/utils/groupMessagesByApiRound.js +7 -6
- package/dist/utils/openaiClient.d.ts.map +1 -1
- package/dist/utils/openaiClient.js +2 -0
- package/dist/utils/tokenEstimate.d.ts +24 -0
- package/dist/utils/tokenEstimate.d.ts.map +1 -0
- package/dist/utils/tokenEstimate.js +30 -0
- package/dist/utils/worktreeUtils.d.ts.map +1 -1
- package/dist/utils/worktreeUtils.js +3 -1
- package/package.json +1 -1
- package/scripts/install_ripgrep.js +1 -21
- package/src/managers/aiManager.ts +111 -102
- package/src/managers/cronManager.ts +2 -0
- package/src/managers/liveConfigManager.ts +0 -12
- package/src/managers/mcpManager.ts +8 -1
- package/src/managers/messageManager.ts +10 -5
- package/src/managers/toolManager.ts +2 -0
- package/src/services/configurationService.ts +2 -0
- package/src/telemetry/sessionTracing.ts +64 -67
- package/src/tools/readTool.ts +6 -12
- package/src/types/telemetry.ts +2 -0
- package/src/utils/fileUtils.ts +0 -46
- package/src/utils/gitUtils.ts +54 -0
- package/src/utils/groupMessagesByApiRound.ts +7 -6
- package/src/utils/openaiClient.ts +2 -0
- package/src/utils/tokenEstimate.ts +34 -0
- package/src/utils/worktreeUtils.ts +8 -1
- package/vendor/ripgrep/linux-aarch64/rg +0 -0
- package/vendor/ripgrep/macos-aarch64/rg +0 -0
- package/vendor/ripgrep/macos-x86_64/rg +0 -0
- package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
- package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* Session Tracing -- OpenTelemetry Span Management
|
|
3
3
|
*
|
|
4
4
|
* Provides span creation/ending APIs for interactions, LLM requests, and tool
|
|
5
|
-
* executions
|
|
5
|
+
* executions. Uses two independent AsyncLocalStorage contexts:
|
|
6
|
+
* - interactionContext: holds the interaction span for the entire turn
|
|
7
|
+
* - toolContext: holds the current tool span (cleared on end)
|
|
8
|
+
*
|
|
9
|
+
* LLM request spans do not enter any ALS; they are passed explicitly to
|
|
10
|
+
* endLLMRequestSpan, aligning with Claude Code's approach.
|
|
6
11
|
*/
|
|
7
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
13
|
import { getOTELApi, isInitialized, getCurrentConfig, } from "./instrumentation.js";
|
|
9
14
|
// -- AsyncLocalStorage for context propagation --
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const llmSpans = [];
|
|
13
|
-
const toolSpans = [];
|
|
15
|
+
const interactionContext = new AsyncLocalStorage();
|
|
16
|
+
const toolContext = new AsyncLocalStorage();
|
|
14
17
|
// -- Tracer accessor --
|
|
15
18
|
function getTracer() {
|
|
16
19
|
if (!isInitialized())
|
|
@@ -20,29 +23,15 @@ function getTracer() {
|
|
|
20
23
|
return undefined;
|
|
21
24
|
return otelApi.trace.getTracer("wave");
|
|
22
25
|
}
|
|
23
|
-
// -- Helper: create child span with parent context --
|
|
24
|
-
function startChildSpan(name, attributes) {
|
|
25
|
-
const tracer = getTracer();
|
|
26
|
-
if (!tracer)
|
|
27
|
-
return undefined;
|
|
28
|
-
const parent = spanContext.getStore();
|
|
29
|
-
let span;
|
|
30
|
-
if (parent) {
|
|
31
|
-
const otelApi = getOTELApi();
|
|
32
|
-
const ctx = otelApi.trace.setSpan(otelApi.context.active(), parent);
|
|
33
|
-
span = tracer.startSpan(name, { attributes }, ctx);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
span = tracer.startSpan(name, { attributes });
|
|
37
|
-
}
|
|
38
|
-
spanContext.enterWith(span);
|
|
39
|
-
return span;
|
|
40
|
-
}
|
|
41
26
|
// -- Public API --
|
|
42
27
|
/**
|
|
43
28
|
* Creates an interaction span for a user turn.
|
|
29
|
+
* The span is stored in interactionContext for the duration of the turn.
|
|
44
30
|
*/
|
|
45
31
|
export function startInteractionSpan(userPrompt, sequence) {
|
|
32
|
+
const tracer = getTracer();
|
|
33
|
+
if (!tracer)
|
|
34
|
+
return undefined;
|
|
46
35
|
const config = getCurrentConfig();
|
|
47
36
|
const attributes = {
|
|
48
37
|
"span.type": "interaction",
|
|
@@ -52,21 +41,28 @@ export function startInteractionSpan(userPrompt, sequence) {
|
|
|
52
41
|
if (config?.logUserPrompts) {
|
|
53
42
|
attributes.user_prompt = userPrompt;
|
|
54
43
|
}
|
|
55
|
-
|
|
44
|
+
const span = tracer.startSpan("interaction", { attributes });
|
|
45
|
+
interactionContext.enterWith(span);
|
|
46
|
+
return span;
|
|
56
47
|
}
|
|
57
48
|
/**
|
|
58
|
-
* Ends the current
|
|
49
|
+
* Ends the current interaction span and clears the context.
|
|
59
50
|
*/
|
|
60
51
|
export function endInteractionSpan() {
|
|
61
|
-
const span =
|
|
52
|
+
const span = interactionContext.getStore();
|
|
62
53
|
if (!span)
|
|
63
54
|
return;
|
|
64
55
|
span.end();
|
|
56
|
+
interactionContext.enterWith(undefined);
|
|
65
57
|
}
|
|
66
58
|
/**
|
|
67
|
-
* Creates an LLM request span as a child of the
|
|
59
|
+
* Creates an LLM request span as a child of the interaction span.
|
|
60
|
+
* Does NOT enter any ALS — the span must be passed explicitly to endLLMRequestSpan.
|
|
68
61
|
*/
|
|
69
62
|
export function startLLMRequestSpan(model, options) {
|
|
63
|
+
const tracer = getTracer();
|
|
64
|
+
if (!tracer)
|
|
65
|
+
return undefined;
|
|
70
66
|
const attributes = {
|
|
71
67
|
"span.type": "llm_request",
|
|
72
68
|
model,
|
|
@@ -74,17 +70,23 @@ export function startLLMRequestSpan(model, options) {
|
|
|
74
70
|
if (options?.context) {
|
|
75
71
|
attributes["llm_request.context"] = options.context;
|
|
76
72
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
const parent = interactionContext.getStore();
|
|
74
|
+
let span;
|
|
75
|
+
if (parent) {
|
|
76
|
+
const otelApi = getOTELApi();
|
|
77
|
+
const ctx = otelApi.trace.setSpan(otelApi.context.active(), parent);
|
|
78
|
+
span = tracer.startSpan("llm.request", { attributes }, ctx);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
span = tracer.startSpan("llm.request", { attributes });
|
|
80
82
|
}
|
|
81
83
|
return span;
|
|
82
84
|
}
|
|
83
85
|
/**
|
|
84
|
-
* Ends
|
|
86
|
+
* Ends an LLM request span with response metadata.
|
|
87
|
+
* The span is passed explicitly — no ALS is read or modified.
|
|
85
88
|
*/
|
|
86
|
-
export function endLLMRequestSpan(metadata) {
|
|
87
|
-
const span = llmSpans.pop();
|
|
89
|
+
export function endLLMRequestSpan(span, metadata) {
|
|
88
90
|
if (!span)
|
|
89
91
|
return;
|
|
90
92
|
if (metadata.inputTokens != null)
|
|
@@ -105,14 +107,15 @@ export function endLLMRequestSpan(metadata) {
|
|
|
105
107
|
if (metadata.hasToolCall != null)
|
|
106
108
|
span.setAttribute("has_tool_call", metadata.hasToolCall);
|
|
107
109
|
span.end();
|
|
108
|
-
if (llmSpans.length > 0) {
|
|
109
|
-
spanContext.enterWith(llmSpans[llmSpans.length - 1]);
|
|
110
|
-
}
|
|
111
110
|
}
|
|
112
111
|
/**
|
|
113
|
-
* Creates a tool execution span as a child of the
|
|
112
|
+
* Creates a tool execution span as a child of the interaction span.
|
|
113
|
+
* Enters toolContext with the new span.
|
|
114
114
|
*/
|
|
115
115
|
export function startToolSpan(toolName, input) {
|
|
116
|
+
const tracer = getTracer();
|
|
117
|
+
if (!tracer)
|
|
118
|
+
return undefined;
|
|
116
119
|
const config = getCurrentConfig();
|
|
117
120
|
const attributes = {
|
|
118
121
|
"span.type": "tool",
|
|
@@ -125,38 +128,39 @@ export function startToolSpan(toolName, input) {
|
|
|
125
128
|
}
|
|
126
129
|
attributes.tool_input = inputStr;
|
|
127
130
|
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
const parent = interactionContext.getStore();
|
|
132
|
+
let span;
|
|
133
|
+
if (parent) {
|
|
134
|
+
const otelApi = getOTELApi();
|
|
135
|
+
const ctx = otelApi.trace.setSpan(otelApi.context.active(), parent);
|
|
136
|
+
span = tracer.startSpan(`tool.${toolName}`, { attributes }, ctx);
|
|
131
137
|
}
|
|
138
|
+
else {
|
|
139
|
+
span = tracer.startSpan(`tool.${toolName}`, { attributes });
|
|
140
|
+
}
|
|
141
|
+
toolContext.enterWith(span);
|
|
132
142
|
return span;
|
|
133
143
|
}
|
|
134
144
|
/**
|
|
135
|
-
* Ends
|
|
145
|
+
* Ends the current tool span with execution metadata.
|
|
146
|
+
* Reads the span from toolContext, then clears it.
|
|
136
147
|
*/
|
|
137
148
|
export function endToolSpan(metadata) {
|
|
138
|
-
const span =
|
|
149
|
+
const span = toolContext.getStore();
|
|
139
150
|
if (!span)
|
|
140
151
|
return;
|
|
141
152
|
span.setAttribute("success", metadata.success);
|
|
142
153
|
if (metadata.error)
|
|
143
154
|
span.setAttribute("error", metadata.error);
|
|
144
155
|
span.setAttribute("duration_ms", metadata.durationMs);
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
156
|
+
const config = getCurrentConfig();
|
|
157
|
+
if (config?.logToolContent && metadata.output) {
|
|
158
|
+
let outputStr = metadata.output;
|
|
159
|
+
if (outputStr.length > 1000) {
|
|
160
|
+
outputStr = outputStr.substring(0, 1000);
|
|
161
|
+
}
|
|
162
|
+
span.setAttribute("tool_output", outputStr);
|
|
148
163
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
* Returns the current active span from ALS context.
|
|
152
|
-
*/
|
|
153
|
-
export function getActiveInteractionSpan() {
|
|
154
|
-
return spanContext.getStore();
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Executes `fn` with `span` as the active context via ALS.
|
|
158
|
-
* Useful for parallel tool calls that each need their own span context.
|
|
159
|
-
*/
|
|
160
|
-
export function withSpanContext(span, fn) {
|
|
161
|
-
return spanContext.run(span, fn);
|
|
164
|
+
span.end();
|
|
165
|
+
toolContext.enterWith(undefined);
|
|
162
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAmItE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA+RtB,CAAC"}
|
package/dist/tools/readTool.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createHash } from "crypto";
|
|
|
4
4
|
import { logger } from "../utils/globalLogger.js";
|
|
5
5
|
import { resolvePath, getDisplayPath } from "../utils/path.js";
|
|
6
6
|
import { formatLineNumberPrefix } from "../utils/stringUtils.js";
|
|
7
|
+
import { estimateTokens } from "../utils/tokenEstimate.js";
|
|
7
8
|
import { isBinaryDocument, getBinaryDocumentError, } from "../utils/fileFormat.js";
|
|
8
9
|
import { convertImageToBase64 } from "../utils/messageOperations.js";
|
|
9
10
|
import { READ_TOOL_NAME } from "../constants/tools.js";
|
|
@@ -226,11 +227,10 @@ Usage:
|
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
|
-
// Resource Limits
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
typeof limit !== "number") {
|
|
230
|
+
// Resource Limits — align with Claude Code: 256KB default, bypassed only
|
|
231
|
+
// when the caller provides an explicit line limit (not offset alone).
|
|
232
|
+
const maxSizeBytes = context.fileReadingLimits?.maxSizeBytes ?? 0.25 * 1024 * 1024; // Default 256KB
|
|
233
|
+
if (stats.size > maxSizeBytes && typeof limit !== "number") {
|
|
234
234
|
return {
|
|
235
235
|
success: false,
|
|
236
236
|
content: "",
|
|
@@ -299,8 +299,7 @@ Usage:
|
|
|
299
299
|
// Token-level validation: estimate tokens and reject if over limit
|
|
300
300
|
const maxTokens = context.fileReadingLimits?.maxTokens ?? 25000; // Default 25000 tokens
|
|
301
301
|
const ext = extname(actualFilePath).toLowerCase().slice(1);
|
|
302
|
-
const
|
|
303
|
-
const estimatedTokens = Math.ceil(formattedContent.length / bytesPerToken);
|
|
302
|
+
const estimatedTokens = estimateTokens(formattedContent, ext);
|
|
304
303
|
if (estimatedTokens > maxTokens) {
|
|
305
304
|
return {
|
|
306
305
|
success: false,
|
|
@@ -63,6 +63,8 @@ export interface ToolMetadata {
|
|
|
63
63
|
error?: string;
|
|
64
64
|
/** Execution time (ms) */
|
|
65
65
|
durationMs: number;
|
|
66
|
+
/** Tool output content (recorded when logToolContent is true) */
|
|
67
|
+
output?: string;
|
|
66
68
|
}
|
|
67
69
|
/** Event names for OTel structured logging */
|
|
68
70
|
export type OTelEventName = "session_start" | "session_end" | "user_prompt" | "tool_decision" | "compaction" | "error";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/types/telemetry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,8BAA8B;AAC9B,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,WAAW,GAAG,MAAM,CAAC;AAElE,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,wBAAwB;IACxB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oCAAoC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,iCAAiC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACvC,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/types/telemetry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,8BAA8B;AAC9B,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,WAAW,GAAG,MAAM,CAAC;AAElE,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,wBAAwB;IACxB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oCAAoC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,iCAAiC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACvC,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,aAAa,GACb,aAAa,GACb,eAAe,GACf,YAAY,GACZ,OAAO,CAAC"}
|
|
@@ -26,12 +26,6 @@ export declare function readFirstNLines(filePath: string, maxLines: number): Pro
|
|
|
26
26
|
* @return {Promise<string>} - The last non-empty line of the file, or an empty string if no non-empty lines found.
|
|
27
27
|
*/
|
|
28
28
|
export declare function getLastLine(filePath: string, minLength?: number): Promise<string>;
|
|
29
|
-
/**
|
|
30
|
-
* Ensures that a pattern is present in the global git ignore file.
|
|
31
|
-
*
|
|
32
|
-
* @param {string} pattern - The pattern to add to global git ignore.
|
|
33
|
-
*/
|
|
34
|
-
export declare function ensureGlobalGitIgnore(pattern: string): Promise<void>;
|
|
35
29
|
/**
|
|
36
30
|
* Suggests similar paths if a file is not found.
|
|
37
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUtils.d.ts","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fileUtils.d.ts","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBrE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAI,GACZ,OAAO,CAAC,MAAM,CAAC,CA8DjB;AA2BD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBnB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB"}
|
package/dist/utils/fileUtils.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { createReadStream } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { execSync } from "node:child_process";
|
|
5
|
-
import { homedir } from "node:os";
|
|
6
4
|
import { glob } from "glob";
|
|
7
5
|
/**
|
|
8
6
|
* Reads the first line of a file efficiently using Node.js readline.
|
|
@@ -138,47 +136,6 @@ export async function getLastLine(filePath, minLength = 1) {
|
|
|
138
136
|
}
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
|
-
/**
|
|
142
|
-
* Ensures that a pattern is present in the global git ignore file.
|
|
143
|
-
*
|
|
144
|
-
* @param {string} pattern - The pattern to add to global git ignore.
|
|
145
|
-
*/
|
|
146
|
-
export async function ensureGlobalGitIgnore(pattern) {
|
|
147
|
-
try {
|
|
148
|
-
let globalIgnorePath;
|
|
149
|
-
try {
|
|
150
|
-
globalIgnorePath = execSync("git config --get core.excludesfile", {
|
|
151
|
-
encoding: "utf8",
|
|
152
|
-
}).trim();
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
// If not set, use default paths
|
|
156
|
-
const xdgConfigHome = process.env.XDG_CONFIG_HOME || path.join(homedir(), ".config");
|
|
157
|
-
globalIgnorePath = path.join(xdgConfigHome, "git", "ignore");
|
|
158
|
-
}
|
|
159
|
-
if (!globalIgnorePath)
|
|
160
|
-
return;
|
|
161
|
-
// Ensure directory exists
|
|
162
|
-
await fs.mkdir(path.dirname(globalIgnorePath), { recursive: true });
|
|
163
|
-
let content = "";
|
|
164
|
-
try {
|
|
165
|
-
content = await fs.readFile(globalIgnorePath, "utf8");
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
// File doesn't exist
|
|
169
|
-
}
|
|
170
|
-
const lines = content.split("\n").map((line) => line.trim());
|
|
171
|
-
if (!lines.includes(pattern)) {
|
|
172
|
-
const newContent = content.endsWith("\n") || content === ""
|
|
173
|
-
? `${content}${pattern}\n`
|
|
174
|
-
: `${content}\n${pattern}\n`;
|
|
175
|
-
await fs.writeFile(globalIgnorePath, newContent, "utf8");
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch {
|
|
179
|
-
// Ignore errors
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
139
|
/**
|
|
183
140
|
* Simple Levenshtein distance implementation
|
|
184
141
|
*/
|
package/dist/utils/gitUtils.d.ts
CHANGED
|
@@ -45,6 +45,17 @@ export declare function resolveGitDir(cwd: string): string | null;
|
|
|
45
45
|
* @returns Default remote branch name
|
|
46
46
|
*/
|
|
47
47
|
export declare function getDefaultRemoteBranch(cwd: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Ensure that Wave runtime files are excluded from git status by writing
|
|
50
|
+
* patterns to `.git/info/exclude` (per-repo, not global).
|
|
51
|
+
*
|
|
52
|
+
* Idempotent: if the marker `# wave-runtime` is already present in the
|
|
53
|
+
* exclude file, it skips writing. A module-level Set provides additional
|
|
54
|
+
* per-process dedup to avoid redundant file reads.
|
|
55
|
+
*
|
|
56
|
+
* @param cwd Working directory to start searching from
|
|
57
|
+
*/
|
|
58
|
+
export declare function ensureWaveRuntimeFilesExcluded(cwd: string): void;
|
|
48
59
|
/**
|
|
49
60
|
* Check if there are uncommitted changes in the working directory
|
|
50
61
|
* @param cwd Working directory
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAetD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCxD;AAwDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B1D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAYvE"}
|
|
1
|
+
{"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAetD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCxD;AAwDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B1D;AAQD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAoChE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAYvE"}
|
package/dist/utils/gitUtils.js
CHANGED
|
@@ -216,6 +216,57 @@ export function getDefaultRemoteBranch(cwd) {
|
|
|
216
216
|
// 4. Hardcoded fallback
|
|
217
217
|
return "main";
|
|
218
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Module-level set tracking git dirs already processed in this process,
|
|
221
|
+
* to avoid redundant I/O.
|
|
222
|
+
*/
|
|
223
|
+
const excludedGitDirs = new Set();
|
|
224
|
+
/**
|
|
225
|
+
* Ensure that Wave runtime files are excluded from git status by writing
|
|
226
|
+
* patterns to `.git/info/exclude` (per-repo, not global).
|
|
227
|
+
*
|
|
228
|
+
* Idempotent: if the marker `# wave-runtime` is already present in the
|
|
229
|
+
* exclude file, it skips writing. A module-level Set provides additional
|
|
230
|
+
* per-process dedup to avoid redundant file reads.
|
|
231
|
+
*
|
|
232
|
+
* @param cwd Working directory to start searching from
|
|
233
|
+
*/
|
|
234
|
+
export function ensureWaveRuntimeFilesExcluded(cwd) {
|
|
235
|
+
try {
|
|
236
|
+
const gitDir = resolveGitDir(cwd);
|
|
237
|
+
if (!gitDir)
|
|
238
|
+
return;
|
|
239
|
+
if (excludedGitDirs.has(gitDir))
|
|
240
|
+
return;
|
|
241
|
+
const excludePath = path.join(gitDir, "info", "exclude");
|
|
242
|
+
let content = "";
|
|
243
|
+
try {
|
|
244
|
+
content = fsSync.readFileSync(excludePath, "utf8");
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// File doesn't exist yet
|
|
248
|
+
}
|
|
249
|
+
const marker = "# wave-runtime";
|
|
250
|
+
if (content.includes(marker)) {
|
|
251
|
+
excludedGitDirs.add(gitDir);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const block = [
|
|
255
|
+
marker,
|
|
256
|
+
"**/.wave/scheduled_tasks.lock",
|
|
257
|
+
"**/.wave/scheduled_tasks.json",
|
|
258
|
+
"**/.wave/worktrees/",
|
|
259
|
+
"**/.wave/settings.local.json",
|
|
260
|
+
"",
|
|
261
|
+
].join("\n");
|
|
262
|
+
fsSync.mkdirSync(path.join(gitDir, "info"), { recursive: true });
|
|
263
|
+
fsSync.appendFileSync(excludePath, block);
|
|
264
|
+
excludedGitDirs.add(gitDir);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Best-effort: ignore all errors
|
|
268
|
+
}
|
|
269
|
+
}
|
|
219
270
|
/**
|
|
220
271
|
* Check if there are uncommitted changes in the working directory
|
|
221
272
|
* @param cwd Working directory
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groupMessagesByApiRound.d.ts","sourceRoot":"","sources":["../../src/utils/groupMessagesByApiRound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"groupMessagesByApiRound.d.ts","sourceRoot":"","sources":["../../src/utils/groupMessagesByApiRound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CA8DvE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,EAAE,CAIX"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { estimateTokens as estimateStrTokens } from "./tokenEstimate.js";
|
|
1
2
|
/**
|
|
2
3
|
* Groups messages into "API rounds" — each round corresponds to one API
|
|
3
4
|
* call-response cycle. This is critical because in agentic sessions with a
|
|
@@ -74,24 +75,24 @@ export function getLastApiRounds(messages, roundCount) {
|
|
|
74
75
|
return lastRounds.flatMap((r) => r.messages);
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
|
-
*
|
|
78
|
+
* Estimate token count from message blocks using CJK-aware estimation.
|
|
78
79
|
*/
|
|
79
80
|
function estimateTokens(messages) {
|
|
80
|
-
let
|
|
81
|
+
let combined = "";
|
|
81
82
|
for (const msg of messages) {
|
|
82
83
|
for (const block of msg.blocks) {
|
|
83
84
|
if ("content" in block && typeof block.content === "string") {
|
|
84
|
-
|
|
85
|
+
combined += block.content;
|
|
85
86
|
}
|
|
86
87
|
if (block.type === "tool" &&
|
|
87
88
|
block.parameters &&
|
|
88
89
|
typeof block.parameters === "string") {
|
|
89
|
-
|
|
90
|
+
combined += block.parameters;
|
|
90
91
|
}
|
|
91
92
|
if (block.type === "tool" && block.result) {
|
|
92
|
-
|
|
93
|
+
combined += block.result;
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
return
|
|
97
|
+
return estimateStrTokens(combined);
|
|
97
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAyBnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;
|
|
1
|
+
{"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAyBnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;YAyHN,oBAAoB;CAyCpC"}
|
|
@@ -67,6 +67,7 @@ export class OpenAIClient {
|
|
|
67
67
|
}
|
|
68
68
|
if (attempt < MAX_RETRIES) {
|
|
69
69
|
logger.warn("OpenAI API network error, retrying...", {
|
|
70
|
+
model: params.model,
|
|
70
71
|
attempt: attempt + 1,
|
|
71
72
|
error: e,
|
|
72
73
|
});
|
|
@@ -106,6 +107,7 @@ export class OpenAIClient {
|
|
|
106
107
|
if (retryableStatus && attempt < MAX_RETRIES) {
|
|
107
108
|
lastRetryAfter = response.headers.get("retry-after");
|
|
108
109
|
logger.warn("OpenAI API error, retrying...", {
|
|
110
|
+
model: params.model,
|
|
109
111
|
attempt: attempt + 1,
|
|
110
112
|
status: response.status,
|
|
111
113
|
retryAfter: lastRetryAfter,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CJK-aware token estimation without external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* The naive `length / 4` heuristic under-estimates CJK text by ~4x because
|
|
5
|
+
* each Chinese/Japanese/Korean character is typically 1-2 tokens, not 0.25.
|
|
6
|
+
* This function separates CJK characters from other text and applies
|
|
7
|
+
* different ratios:
|
|
8
|
+
*
|
|
9
|
+
* - CJK characters: 1 char ≈ 1 token
|
|
10
|
+
* - Other characters: 4 chars ≈ 1 token (2 for JSON/JSONL/JSONC)
|
|
11
|
+
*
|
|
12
|
+
* The estimate intentionally leans high for CJK (safe direction for limit
|
|
13
|
+
* checks — better to reject than to let oversized content through).
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Estimate token count for a string, with CJK-awareness.
|
|
17
|
+
*
|
|
18
|
+
* @param content - The text content to estimate
|
|
19
|
+
* @param ext - File extension (without dot), e.g. "ts", "json". JSON/JSONL/JSONC
|
|
20
|
+
* files use a tighter ratio (2 chars/token) for non-CJK text.
|
|
21
|
+
* @returns Estimated token count
|
|
22
|
+
*/
|
|
23
|
+
export declare function estimateTokens(content: string, ext?: string): number;
|
|
24
|
+
//# sourceMappingURL=tokenEstimate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenEstimate.d.ts","sourceRoot":"","sources":["../../src/utils/tokenEstimate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAMpE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CJK-aware token estimation without external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* The naive `length / 4` heuristic under-estimates CJK text by ~4x because
|
|
5
|
+
* each Chinese/Japanese/Korean character is typically 1-2 tokens, not 0.25.
|
|
6
|
+
* This function separates CJK characters from other text and applies
|
|
7
|
+
* different ratios:
|
|
8
|
+
*
|
|
9
|
+
* - CJK characters: 1 char ≈ 1 token
|
|
10
|
+
* - Other characters: 4 chars ≈ 1 token (2 for JSON/JSONL/JSONC)
|
|
11
|
+
*
|
|
12
|
+
* The estimate intentionally leans high for CJK (safe direction for limit
|
|
13
|
+
* checks — better to reject than to let oversized content through).
|
|
14
|
+
*/
|
|
15
|
+
// CJK Unified Ideographs + Extension A + Hiragana + Katakana + Hangul Syllables
|
|
16
|
+
const CJK_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g;
|
|
17
|
+
/**
|
|
18
|
+
* Estimate token count for a string, with CJK-awareness.
|
|
19
|
+
*
|
|
20
|
+
* @param content - The text content to estimate
|
|
21
|
+
* @param ext - File extension (without dot), e.g. "ts", "json". JSON/JSONL/JSONC
|
|
22
|
+
* files use a tighter ratio (2 chars/token) for non-CJK text.
|
|
23
|
+
* @returns Estimated token count
|
|
24
|
+
*/
|
|
25
|
+
export function estimateTokens(content, ext) {
|
|
26
|
+
const cjkCount = (content.match(CJK_REGEX) || []).length;
|
|
27
|
+
const otherCount = content.length - cjkCount;
|
|
28
|
+
const bytesPerToken = ext === "json" || ext === "jsonl" || ext === "jsonc" ? 2 : 4;
|
|
29
|
+
return Math.ceil(cjkCount + otherCount / bytesPerToken);
|
|
30
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktreeUtils.d.ts","sourceRoot":"","sources":["../../src/utils/worktreeUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"worktreeUtils.d.ts","sourceRoot":"","sources":["../../src/utils/worktreeUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBvD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CA6B7C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAgKtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAmEvD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,GAAG,SAAS,GACrC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsClD"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
|
-
import { getGitMainRepoRoot, getDefaultRemoteBranch } from "./gitUtils.js";
|
|
8
|
+
import { getGitMainRepoRoot, getDefaultRemoteBranch, ensureWaveRuntimeFilesExcluded, } from "./gitUtils.js";
|
|
9
9
|
import { logger } from "./globalLogger.js";
|
|
10
10
|
/**
|
|
11
11
|
* Validate a worktree name to prevent path traversal and invalid characters.
|
|
@@ -79,6 +79,8 @@ export function createWorktree(name, cwd) {
|
|
|
79
79
|
const worktreePath = path.join(repoRoot, ".wave", "worktrees", name);
|
|
80
80
|
const branchName = `worktree-${name}`;
|
|
81
81
|
const baseBranch = getDefaultRemoteBranch(cwd);
|
|
82
|
+
// Ensure Wave runtime files are git-excluded in this repo
|
|
83
|
+
ensureWaveRuntimeFilesExcluded(cwd);
|
|
82
84
|
// Ensure parent directory exists
|
|
83
85
|
const parentDir = path.dirname(worktreePath);
|
|
84
86
|
if (!fs.existsSync(parentDir)) {
|
package/package.json
CHANGED
|
@@ -9,18 +9,6 @@ const __dirname = path.dirname(__filename);
|
|
|
9
9
|
const MANIFEST_PATH = path.resolve(__dirname, "../bin/rg");
|
|
10
10
|
const VENDOR_DIR = path.resolve(__dirname, "../vendor/ripgrep");
|
|
11
11
|
|
|
12
|
-
function getCurrentPlatform() {
|
|
13
|
-
const platform = process.platform;
|
|
14
|
-
const arch = process.arch;
|
|
15
|
-
if (platform === "darwin")
|
|
16
|
-
return `macos-${arch === "arm64" ? "aarch64" : "x86_64"}`;
|
|
17
|
-
if (platform === "linux")
|
|
18
|
-
return `linux-${arch === "arm64" ? "aarch64" : "x86_64"}`;
|
|
19
|
-
if (platform === "win32")
|
|
20
|
-
return `windows-${arch === "arm64" ? "aarch64" : "x86_64"}`;
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
12
|
async function main() {
|
|
25
13
|
if (!fs.existsSync(MANIFEST_PATH)) {
|
|
26
14
|
console.error(`Manifest not found: ${MANIFEST_PATH}`);
|
|
@@ -30,15 +18,7 @@ async function main() {
|
|
|
30
18
|
const manifestContent = fs.readFileSync(MANIFEST_PATH, "utf-8");
|
|
31
19
|
const jsonContent = manifestContent.replace(/^#!.*\n/, "");
|
|
32
20
|
const manifest = JSON.parse(jsonContent);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
// In CI, only download for the current platform
|
|
36
|
-
const isCI = process.env.CI === "true";
|
|
37
|
-
const currentPlatform = isCI ? getCurrentPlatform() : null;
|
|
38
|
-
const platforms =
|
|
39
|
-
currentPlatform && currentPlatform in allPlatforms
|
|
40
|
-
? { [currentPlatform]: allPlatforms[currentPlatform] }
|
|
41
|
-
: allPlatforms;
|
|
21
|
+
const platforms = manifest.platforms;
|
|
42
22
|
|
|
43
23
|
if (!fs.existsSync(VENDOR_DIR)) {
|
|
44
24
|
fs.mkdirSync(VENDOR_DIR, { recursive: true });
|