@joshski/dust 0.1.90 → 0.1.91
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/bucket/tool-execution-protocol.d.ts +48 -0
- package/dist/dust.js +65 -24
- package/dist/types.d.ts +2 -0
- package/dist/validation.js +12 -4
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool execution protocol types for the WebSocket messages between
|
|
3
|
+
* dust clients and dustbucket servers.
|
|
4
|
+
*
|
|
5
|
+
* These types define the wire format. Both sides must agree on this protocol.
|
|
6
|
+
* Import from '@joshski/dust/types' for downstream implementations.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Client-to-server message requesting tool execution.
|
|
10
|
+
*
|
|
11
|
+
* Sent over the bucket WebSocket when an agent invokes `dust bucket tool <name>`.
|
|
12
|
+
* The `tool` field identifies the server-defined tool by name.
|
|
13
|
+
* The `arguments` field contains named parameters matching the tool definition.
|
|
14
|
+
* The `repositoryId` identifies the repository context (numeric server-side ID).
|
|
15
|
+
*/
|
|
16
|
+
export interface ToolExecutionRequestMessage {
|
|
17
|
+
type: 'tool-execution-request';
|
|
18
|
+
requestId: string;
|
|
19
|
+
tool: string;
|
|
20
|
+
repositoryId: number;
|
|
21
|
+
arguments: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
export interface ToolExecutionSuccessResult {
|
|
24
|
+
type: 'success';
|
|
25
|
+
data: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface ToolExecutionToolNotFoundResult {
|
|
28
|
+
type: 'tool-not-found';
|
|
29
|
+
message: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ToolExecutionErrorResult {
|
|
32
|
+
type: 'error';
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
export type ToolExecutionResult = ToolExecutionSuccessResult | ToolExecutionToolNotFoundResult | ToolExecutionErrorResult;
|
|
36
|
+
/**
|
|
37
|
+
* Server-to-client message with the result of a tool execution request.
|
|
38
|
+
*
|
|
39
|
+
* The `requestId` correlates this response to the original request.
|
|
40
|
+
* The `result` is a discriminated union on the `type` field.
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolExecutionResultMessage {
|
|
43
|
+
type: 'tool-execution-result';
|
|
44
|
+
requestId: string;
|
|
45
|
+
result: ToolExecutionResult;
|
|
46
|
+
}
|
|
47
|
+
export declare function isToolExecutionResultMessage(payload: unknown): payload is ToolExecutionResultMessage;
|
|
48
|
+
export declare function isToolExecutionRequestMessage(payload: unknown): payload is ToolExecutionRequestMessage;
|
package/dist/dust.js
CHANGED
|
@@ -500,7 +500,7 @@ async function loadSettings(cwd, fileSystem) {
|
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
// lib/version.ts
|
|
503
|
-
var DUST_VERSION = "0.1.
|
|
503
|
+
var DUST_VERSION = "0.1.91";
|
|
504
504
|
|
|
505
505
|
// lib/session.ts
|
|
506
506
|
var DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
@@ -4570,8 +4570,11 @@ function formatToolsSection(tools) {
|
|
|
4570
4570
|
return "";
|
|
4571
4571
|
}
|
|
4572
4572
|
const lines = [];
|
|
4573
|
+
lines.push("");
|
|
4573
4574
|
lines.push("## Available Tools");
|
|
4574
4575
|
lines.push("");
|
|
4576
|
+
lines.push("Use these tools where it makes sense in the execution of this task:");
|
|
4577
|
+
lines.push("");
|
|
4575
4578
|
for (const tool of tools) {
|
|
4576
4579
|
lines.push(formatTool(tool));
|
|
4577
4580
|
lines.push("");
|
|
@@ -5440,6 +5443,18 @@ var SGR_MOUSE_RE2 = new RegExp(String.raw`^\x1b\[<(\d+);\d+;\d+[Mm]$`);
|
|
|
5440
5443
|
function isRecord3(value) {
|
|
5441
5444
|
return typeof value === "object" && value !== null;
|
|
5442
5445
|
}
|
|
5446
|
+
function isValidResultType(value) {
|
|
5447
|
+
return value === "success" || value === "tool-not-found" || value === "error";
|
|
5448
|
+
}
|
|
5449
|
+
function isValidResult(value) {
|
|
5450
|
+
if (!isRecord3(value))
|
|
5451
|
+
return false;
|
|
5452
|
+
if (!isValidResultType(value.type))
|
|
5453
|
+
return false;
|
|
5454
|
+
if (value.type === "success")
|
|
5455
|
+
return true;
|
|
5456
|
+
return typeof value.message === "string";
|
|
5457
|
+
}
|
|
5443
5458
|
function isToolExecutionResultMessage(payload) {
|
|
5444
5459
|
if (!isRecord3(payload))
|
|
5445
5460
|
return false;
|
|
@@ -5448,16 +5463,7 @@ function isToolExecutionResultMessage(payload) {
|
|
|
5448
5463
|
if (typeof payload.requestId !== "string" || payload.requestId.length === 0) {
|
|
5449
5464
|
return false;
|
|
5450
5465
|
}
|
|
5451
|
-
|
|
5452
|
-
return false;
|
|
5453
|
-
}
|
|
5454
|
-
if (payload.output !== undefined && typeof payload.output !== "string") {
|
|
5455
|
-
return false;
|
|
5456
|
-
}
|
|
5457
|
-
if (payload.error !== undefined && typeof payload.error !== "string") {
|
|
5458
|
-
return false;
|
|
5459
|
-
}
|
|
5460
|
-
return true;
|
|
5466
|
+
return isValidResult(payload.result);
|
|
5461
5467
|
}
|
|
5462
5468
|
|
|
5463
5469
|
// lib/cli/commands/bucket.ts
|
|
@@ -6147,12 +6153,23 @@ async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDepend
|
|
|
6147
6153
|
});
|
|
6148
6154
|
}
|
|
6149
6155
|
const requestId = crypto.randomUUID();
|
|
6156
|
+
const toolDef = state.tools.find((t) => t.name === request.toolName);
|
|
6157
|
+
const namedArgs = {};
|
|
6158
|
+
if (toolDef) {
|
|
6159
|
+
for (let i = 0;i < toolDef.parameters.length && i < request.arguments.length; i++) {
|
|
6160
|
+
namedArgs[toolDef.parameters[i].name] = request.arguments[i];
|
|
6161
|
+
}
|
|
6162
|
+
} else {
|
|
6163
|
+
for (let i = 0;i < request.arguments.length; i++) {
|
|
6164
|
+
namedArgs[`arg${i}`] = request.arguments[i];
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6150
6167
|
const message = {
|
|
6151
6168
|
type: "tool-execution-request",
|
|
6152
6169
|
requestId,
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6170
|
+
tool: request.toolName,
|
|
6171
|
+
repositoryId: Number(request.repositoryId),
|
|
6172
|
+
arguments: namedArgs
|
|
6156
6173
|
};
|
|
6157
6174
|
log10(`forwarding tool execution: ${request.toolName} requestId=${requestId}`);
|
|
6158
6175
|
return new Promise((resolve, reject) => {
|
|
@@ -6198,14 +6215,30 @@ async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDepend
|
|
|
6198
6215
|
log10(`received tool execution result for unknown requestId=${message.requestId}`);
|
|
6199
6216
|
return;
|
|
6200
6217
|
}
|
|
6201
|
-
|
|
6218
|
+
const resultType = message.result.type;
|
|
6219
|
+
log10(`received tool execution result: requestId=${message.requestId} status=${resultType}`);
|
|
6202
6220
|
clearTimeout(pending.timeoutId);
|
|
6203
6221
|
pendingToolExecutions.delete(message.requestId);
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6222
|
+
switch (message.result.type) {
|
|
6223
|
+
case "success":
|
|
6224
|
+
pending.resolve({
|
|
6225
|
+
status: "success",
|
|
6226
|
+
output: typeof message.result.data === "string" ? message.result.data : JSON.stringify(message.result.data)
|
|
6227
|
+
});
|
|
6228
|
+
break;
|
|
6229
|
+
case "tool-not-found":
|
|
6230
|
+
pending.resolve({
|
|
6231
|
+
status: "tool-not-found",
|
|
6232
|
+
error: message.result.message
|
|
6233
|
+
});
|
|
6234
|
+
break;
|
|
6235
|
+
case "error":
|
|
6236
|
+
pending.resolve({
|
|
6237
|
+
status: "error",
|
|
6238
|
+
error: message.result.message
|
|
6239
|
+
});
|
|
6240
|
+
break;
|
|
6241
|
+
}
|
|
6209
6242
|
}, forwardToolExecution);
|
|
6210
6243
|
if (!useTUI) {
|
|
6211
6244
|
context.stdout(" Press q or Ctrl+C to exit");
|
|
@@ -6895,14 +6928,22 @@ function validateLinks(filePath, content, fileSystem) {
|
|
|
6895
6928
|
while (match) {
|
|
6896
6929
|
const linkTarget = match[2];
|
|
6897
6930
|
if (!linkTarget.startsWith("http://") && !linkTarget.startsWith("https://") && !linkTarget.startsWith("#")) {
|
|
6898
|
-
|
|
6899
|
-
const resolvedPath = resolve(fileDir, targetPath);
|
|
6900
|
-
if (!fileSystem.exists(resolvedPath)) {
|
|
6931
|
+
if (linkTarget.startsWith("/")) {
|
|
6901
6932
|
violations.push({
|
|
6902
6933
|
file: filePath,
|
|
6903
|
-
message: `
|
|
6934
|
+
message: `Absolute link not allowed: "${linkTarget}" (use a relative path instead)`,
|
|
6904
6935
|
line: i + 1
|
|
6905
6936
|
});
|
|
6937
|
+
} else {
|
|
6938
|
+
const targetPath = linkTarget.split("#")[0];
|
|
6939
|
+
const resolvedPath = resolve(fileDir, targetPath);
|
|
6940
|
+
if (!fileSystem.exists(resolvedPath)) {
|
|
6941
|
+
violations.push({
|
|
6942
|
+
file: filePath,
|
|
6943
|
+
message: `Broken link: "${linkTarget}"`,
|
|
6944
|
+
line: i + 1
|
|
6945
|
+
});
|
|
6946
|
+
}
|
|
6906
6947
|
}
|
|
6907
6948
|
}
|
|
6908
6949
|
match = linkPattern.exec(line);
|
package/dist/types.d.ts
CHANGED
|
@@ -10,3 +10,5 @@ export type { ArtifactType, TaskGraph, TaskGraphNode } from './artifacts/index';
|
|
|
10
10
|
export type { Task } from './artifacts/tasks';
|
|
11
11
|
export type { CreateIdeaTransitionTaskResult, DecomposeIdeaOptions, IdeaInProgress, OpenQuestionResponse, ParsedCaptureIdeaTask, WorkflowTaskMatch, WorkflowTaskType, } from './artifacts/workflow-tasks';
|
|
12
12
|
export type { Repository } from './bucket/repository';
|
|
13
|
+
export type { ToolExecutionErrorResult, ToolExecutionRequestMessage, ToolExecutionResult, ToolExecutionResultMessage, ToolExecutionSuccessResult, ToolExecutionToolNotFoundResult, } from './bucket/tool-execution-protocol';
|
|
14
|
+
export { isToolExecutionRequestMessage, isToolExecutionResultMessage, } from './bucket/tool-execution-protocol';
|
package/dist/validation.js
CHANGED
|
@@ -451,14 +451,22 @@ function validateLinks(filePath, content, fileSystem) {
|
|
|
451
451
|
while (match) {
|
|
452
452
|
const linkTarget = match[2];
|
|
453
453
|
if (!linkTarget.startsWith("http://") && !linkTarget.startsWith("https://") && !linkTarget.startsWith("#")) {
|
|
454
|
-
|
|
455
|
-
const resolvedPath = resolve(fileDir, targetPath);
|
|
456
|
-
if (!fileSystem.exists(resolvedPath)) {
|
|
454
|
+
if (linkTarget.startsWith("/")) {
|
|
457
455
|
violations.push({
|
|
458
456
|
file: filePath,
|
|
459
|
-
message: `
|
|
457
|
+
message: `Absolute link not allowed: "${linkTarget}" (use a relative path instead)`,
|
|
460
458
|
line: i + 1
|
|
461
459
|
});
|
|
460
|
+
} else {
|
|
461
|
+
const targetPath = linkTarget.split("#")[0];
|
|
462
|
+
const resolvedPath = resolve(fileDir, targetPath);
|
|
463
|
+
if (!fileSystem.exists(resolvedPath)) {
|
|
464
|
+
violations.push({
|
|
465
|
+
file: filePath,
|
|
466
|
+
message: `Broken link: "${linkTarget}"`,
|
|
467
|
+
line: i + 1
|
|
468
|
+
});
|
|
469
|
+
}
|
|
462
470
|
}
|
|
463
471
|
}
|
|
464
472
|
match = linkPattern.exec(line);
|