@joshski/dust 0.1.90 → 0.1.92
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 +115 -46
- 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.92";
|
|
504
504
|
|
|
505
505
|
// lib/session.ts
|
|
506
506
|
var DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
@@ -2072,6 +2072,7 @@ import { spawn as nodeSpawn5 } from "node:child_process";
|
|
|
2072
2072
|
import { accessSync, statSync } from "node:fs";
|
|
2073
2073
|
import { chmod, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2074
2074
|
import { homedir as homedir2 } from "node:os";
|
|
2075
|
+
import { basename as basename2, resolve } from "node:path";
|
|
2075
2076
|
|
|
2076
2077
|
// lib/bucket/auth.ts
|
|
2077
2078
|
import { join as join5 } from "node:path";
|
|
@@ -4570,8 +4571,11 @@ function formatToolsSection(tools) {
|
|
|
4570
4571
|
return "";
|
|
4571
4572
|
}
|
|
4572
4573
|
const lines = [];
|
|
4574
|
+
lines.push("");
|
|
4573
4575
|
lines.push("## Available Tools");
|
|
4574
4576
|
lines.push("");
|
|
4577
|
+
lines.push("Use these tools where it makes sense in the execution of this task:");
|
|
4578
|
+
lines.push("");
|
|
4575
4579
|
for (const tool of tools) {
|
|
4576
4580
|
lines.push(formatTool(tool));
|
|
4577
4581
|
lines.push("");
|
|
@@ -5440,6 +5444,18 @@ var SGR_MOUSE_RE2 = new RegExp(String.raw`^\x1b\[<(\d+);\d+;\d+[Mm]$`);
|
|
|
5440
5444
|
function isRecord3(value) {
|
|
5441
5445
|
return typeof value === "object" && value !== null;
|
|
5442
5446
|
}
|
|
5447
|
+
function isValidResultType(value) {
|
|
5448
|
+
return value === "success" || value === "tool-not-found" || value === "error";
|
|
5449
|
+
}
|
|
5450
|
+
function isValidResult(value) {
|
|
5451
|
+
if (!isRecord3(value))
|
|
5452
|
+
return false;
|
|
5453
|
+
if (!isValidResultType(value.type))
|
|
5454
|
+
return false;
|
|
5455
|
+
if (value.type === "success")
|
|
5456
|
+
return true;
|
|
5457
|
+
return typeof value.message === "string";
|
|
5458
|
+
}
|
|
5443
5459
|
function isToolExecutionResultMessage(payload) {
|
|
5444
5460
|
if (!isRecord3(payload))
|
|
5445
5461
|
return false;
|
|
@@ -5448,16 +5464,7 @@ function isToolExecutionResultMessage(payload) {
|
|
|
5448
5464
|
if (typeof payload.requestId !== "string" || payload.requestId.length === 0) {
|
|
5449
5465
|
return false;
|
|
5450
5466
|
}
|
|
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;
|
|
5467
|
+
return isValidResult(payload.result);
|
|
5461
5468
|
}
|
|
5462
5469
|
|
|
5463
5470
|
// lib/cli/commands/bucket.ts
|
|
@@ -5594,7 +5601,7 @@ function createDefaultBucketDependencies() {
|
|
|
5594
5601
|
getTerminalSize: defaultGetTerminalSize,
|
|
5595
5602
|
writeStdout: defaultWriteStdout,
|
|
5596
5603
|
isTTY: process.stdout.isTTY ?? false,
|
|
5597
|
-
sleep: (ms) => new Promise((
|
|
5604
|
+
sleep: (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)),
|
|
5598
5605
|
getReposDir: () => getReposDir(process.env, homedir2()),
|
|
5599
5606
|
auth: {
|
|
5600
5607
|
createServer: createLocalServer,
|
|
@@ -5738,8 +5745,8 @@ function createTUIContext(state, context, useTUI) {
|
|
|
5738
5745
|
function waitForConnection(token, bucketDeps) {
|
|
5739
5746
|
const wsUrl = getWebSocketUrl();
|
|
5740
5747
|
const ws = bucketDeps.createWebSocket(wsUrl, token);
|
|
5741
|
-
return new Promise((
|
|
5742
|
-
ws.onopen = () =>
|
|
5748
|
+
return new Promise((resolve2, reject) => {
|
|
5749
|
+
ws.onopen = () => resolve2(ws);
|
|
5743
5750
|
ws.onerror = (error) => reject(new Error(error.message));
|
|
5744
5751
|
ws.onclose = (event) => reject(new Error(`Connection closed (code ${event.code})`));
|
|
5745
5752
|
});
|
|
@@ -6134,35 +6141,73 @@ async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDepend
|
|
|
6134
6141
|
} catch {
|
|
6135
6142
|
state.ui.connectedHost = wsUrl;
|
|
6136
6143
|
}
|
|
6144
|
+
function findRepoPathByRepositoryId(repositories, repositoryId) {
|
|
6145
|
+
for (const repoState of repositories.values()) {
|
|
6146
|
+
if (repoState.repository.id === repositoryId) {
|
|
6147
|
+
return repoState.path;
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
return;
|
|
6151
|
+
}
|
|
6137
6152
|
let tuiHandle;
|
|
6138
6153
|
let cleanupKeypress;
|
|
6139
6154
|
let cleanupSignals;
|
|
6140
|
-
const forwardToolExecution = (request) => {
|
|
6155
|
+
const forwardToolExecution = async (request) => {
|
|
6141
6156
|
const ws = state.ws;
|
|
6142
6157
|
if (!ws || ws.readyState !== WS_OPEN) {
|
|
6143
6158
|
log10(`tool execution rejected: ${request.toolName} (WebSocket not connected)`);
|
|
6144
|
-
return
|
|
6159
|
+
return {
|
|
6145
6160
|
status: "error",
|
|
6146
6161
|
error: "Bucket session is not connected"
|
|
6147
|
-
}
|
|
6162
|
+
};
|
|
6148
6163
|
}
|
|
6149
6164
|
const requestId = crypto.randomUUID();
|
|
6165
|
+
const repoPath = findRepoPathByRepositoryId(state.repositories, Number(request.repositoryId));
|
|
6166
|
+
const toolDef = state.tools.find((t) => t.name === request.toolName);
|
|
6167
|
+
const namedArgs = {};
|
|
6168
|
+
if (toolDef) {
|
|
6169
|
+
for (let i = 0;i < toolDef.parameters.length && i < request.arguments.length; i++) {
|
|
6170
|
+
const param = toolDef.parameters[i];
|
|
6171
|
+
const value = request.arguments[i];
|
|
6172
|
+
if (param.type === "file" && typeof value === "string") {
|
|
6173
|
+
const filePath = repoPath ? resolve(repoPath, value) : value;
|
|
6174
|
+
try {
|
|
6175
|
+
const data = await readFile(filePath);
|
|
6176
|
+
namedArgs[param.name] = {
|
|
6177
|
+
filename: basename2(value),
|
|
6178
|
+
data: data.toString("base64")
|
|
6179
|
+
};
|
|
6180
|
+
} catch {
|
|
6181
|
+
return {
|
|
6182
|
+
status: "error",
|
|
6183
|
+
error: `Unable to read file: ${value}`
|
|
6184
|
+
};
|
|
6185
|
+
}
|
|
6186
|
+
} else {
|
|
6187
|
+
namedArgs[param.name] = value;
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
} else {
|
|
6191
|
+
for (let i = 0;i < request.arguments.length; i++) {
|
|
6192
|
+
namedArgs[`arg${i}`] = request.arguments[i];
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6150
6195
|
const message = {
|
|
6151
6196
|
type: "tool-execution-request",
|
|
6152
6197
|
requestId,
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6198
|
+
tool: request.toolName,
|
|
6199
|
+
repositoryId: Number(request.repositoryId),
|
|
6200
|
+
arguments: namedArgs
|
|
6156
6201
|
};
|
|
6157
6202
|
log10(`forwarding tool execution: ${request.toolName} requestId=${requestId}`);
|
|
6158
|
-
return new Promise((
|
|
6203
|
+
return new Promise((resolve2, reject) => {
|
|
6159
6204
|
const timeoutId = setTimeout(() => {
|
|
6160
6205
|
pendingToolExecutions.delete(requestId);
|
|
6161
6206
|
log10(`tool execution timed out: ${request.toolName} requestId=${requestId}`);
|
|
6162
6207
|
reject(new Error("Timed out waiting for tool execution result"));
|
|
6163
6208
|
}, 30000);
|
|
6164
6209
|
pendingToolExecutions.set(requestId, {
|
|
6165
|
-
resolve,
|
|
6210
|
+
resolve: resolve2,
|
|
6166
6211
|
reject,
|
|
6167
6212
|
timeoutId
|
|
6168
6213
|
});
|
|
@@ -6180,10 +6225,10 @@ async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDepend
|
|
|
6180
6225
|
if (useTUI) {
|
|
6181
6226
|
tuiHandle = setupTUI(state, bucketDeps);
|
|
6182
6227
|
}
|
|
6183
|
-
await new Promise((
|
|
6228
|
+
await new Promise((resolve2) => {
|
|
6184
6229
|
const doShutdown = async () => {
|
|
6185
6230
|
await shutdown(state, bucketDeps, context);
|
|
6186
|
-
|
|
6231
|
+
resolve2();
|
|
6187
6232
|
};
|
|
6188
6233
|
const onKey = createKeypressHandler(useTUI, state, () => {
|
|
6189
6234
|
doShutdown();
|
|
@@ -6198,14 +6243,30 @@ async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDepend
|
|
|
6198
6243
|
log10(`received tool execution result for unknown requestId=${message.requestId}`);
|
|
6199
6244
|
return;
|
|
6200
6245
|
}
|
|
6201
|
-
|
|
6246
|
+
const resultType = message.result.type;
|
|
6247
|
+
log10(`received tool execution result: requestId=${message.requestId} status=${resultType}`);
|
|
6202
6248
|
clearTimeout(pending.timeoutId);
|
|
6203
6249
|
pendingToolExecutions.delete(message.requestId);
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6250
|
+
switch (message.result.type) {
|
|
6251
|
+
case "success":
|
|
6252
|
+
pending.resolve({
|
|
6253
|
+
status: "success",
|
|
6254
|
+
output: typeof message.result.data === "string" ? message.result.data : JSON.stringify(message.result.data)
|
|
6255
|
+
});
|
|
6256
|
+
break;
|
|
6257
|
+
case "tool-not-found":
|
|
6258
|
+
pending.resolve({
|
|
6259
|
+
status: "tool-not-found",
|
|
6260
|
+
error: message.result.message
|
|
6261
|
+
});
|
|
6262
|
+
break;
|
|
6263
|
+
case "error":
|
|
6264
|
+
pending.resolve({
|
|
6265
|
+
status: "error",
|
|
6266
|
+
error: message.result.message
|
|
6267
|
+
});
|
|
6268
|
+
break;
|
|
6269
|
+
}
|
|
6209
6270
|
}, forwardToolExecution);
|
|
6210
6271
|
if (!useTUI) {
|
|
6211
6272
|
context.stdout(" Press q or Ctrl+C to exit");
|
|
@@ -6372,7 +6433,7 @@ function createGitRunner(spawnFn) {
|
|
|
6372
6433
|
}
|
|
6373
6434
|
var defaultGitRunner = createGitRunner(spawn);
|
|
6374
6435
|
function runBufferedProcess(spawnFn, command, commandArguments, cwd, shell, timeoutMs) {
|
|
6375
|
-
return new Promise((
|
|
6436
|
+
return new Promise((resolve2) => {
|
|
6376
6437
|
const proc = spawnFn(command, commandArguments, { cwd, shell });
|
|
6377
6438
|
const chunks = [];
|
|
6378
6439
|
let resolved = false;
|
|
@@ -6384,7 +6445,7 @@ function runBufferedProcess(spawnFn, command, commandArguments, cwd, shell, time
|
|
|
6384
6445
|
proc.stdout?.destroy();
|
|
6385
6446
|
proc.stderr?.destroy();
|
|
6386
6447
|
proc.unref();
|
|
6387
|
-
|
|
6448
|
+
resolve2({
|
|
6388
6449
|
exitCode: 1,
|
|
6389
6450
|
output: chunks.join(""),
|
|
6390
6451
|
timedOut: true
|
|
@@ -6402,14 +6463,14 @@ function runBufferedProcess(spawnFn, command, commandArguments, cwd, shell, time
|
|
|
6402
6463
|
return;
|
|
6403
6464
|
if (timer !== undefined)
|
|
6404
6465
|
clearTimeout(timer);
|
|
6405
|
-
|
|
6466
|
+
resolve2({ exitCode: code ?? 1, output: chunks.join("") });
|
|
6406
6467
|
});
|
|
6407
6468
|
proc.on("error", (error) => {
|
|
6408
6469
|
if (resolved)
|
|
6409
6470
|
return;
|
|
6410
6471
|
if (timer !== undefined)
|
|
6411
6472
|
clearTimeout(timer);
|
|
6412
|
-
|
|
6473
|
+
resolve2({ exitCode: 1, output: error.message });
|
|
6413
6474
|
});
|
|
6414
6475
|
});
|
|
6415
6476
|
}
|
|
@@ -6870,7 +6931,7 @@ function validateWorkflowTaskBodySection(filePath, content, ideasPath, fileSyste
|
|
|
6870
6931
|
}
|
|
6871
6932
|
|
|
6872
6933
|
// lib/lint/validators/link-validator.ts
|
|
6873
|
-
import { dirname as dirname3, resolve } from "node:path";
|
|
6934
|
+
import { dirname as dirname3, resolve as resolve2 } from "node:path";
|
|
6874
6935
|
var SEMANTIC_RULES = [
|
|
6875
6936
|
{
|
|
6876
6937
|
section: "## Principles",
|
|
@@ -6895,14 +6956,22 @@ function validateLinks(filePath, content, fileSystem) {
|
|
|
6895
6956
|
while (match) {
|
|
6896
6957
|
const linkTarget = match[2];
|
|
6897
6958
|
if (!linkTarget.startsWith("http://") && !linkTarget.startsWith("https://") && !linkTarget.startsWith("#")) {
|
|
6898
|
-
|
|
6899
|
-
const resolvedPath = resolve(fileDir, targetPath);
|
|
6900
|
-
if (!fileSystem.exists(resolvedPath)) {
|
|
6959
|
+
if (linkTarget.startsWith("/")) {
|
|
6901
6960
|
violations.push({
|
|
6902
6961
|
file: filePath,
|
|
6903
|
-
message: `
|
|
6962
|
+
message: `Absolute link not allowed: "${linkTarget}" (use a relative path instead)`,
|
|
6904
6963
|
line: i + 1
|
|
6905
6964
|
});
|
|
6965
|
+
} else {
|
|
6966
|
+
const targetPath = linkTarget.split("#")[0];
|
|
6967
|
+
const resolvedPath = resolve2(fileDir, targetPath);
|
|
6968
|
+
if (!fileSystem.exists(resolvedPath)) {
|
|
6969
|
+
violations.push({
|
|
6970
|
+
file: filePath,
|
|
6971
|
+
message: `Broken link: "${linkTarget}"`,
|
|
6972
|
+
line: i + 1
|
|
6973
|
+
});
|
|
6974
|
+
}
|
|
6906
6975
|
}
|
|
6907
6976
|
}
|
|
6908
6977
|
match = linkPattern.exec(line);
|
|
@@ -6948,7 +7017,7 @@ function validateSemanticLinks(filePath, content) {
|
|
|
6948
7017
|
continue;
|
|
6949
7018
|
}
|
|
6950
7019
|
const targetPath = linkTarget.split("#")[0];
|
|
6951
|
-
const resolvedPath =
|
|
7020
|
+
const resolvedPath = resolve2(fileDir, targetPath);
|
|
6952
7021
|
if (!resolvedPath.includes(rule.requiredPath)) {
|
|
6953
7022
|
violations.push({
|
|
6954
7023
|
file: filePath,
|
|
@@ -6999,7 +7068,7 @@ function validatePrincipleHierarchyLinks(filePath, content) {
|
|
|
6999
7068
|
continue;
|
|
7000
7069
|
}
|
|
7001
7070
|
const targetPath = linkTarget.split("#")[0];
|
|
7002
|
-
const resolvedPath =
|
|
7071
|
+
const resolvedPath = resolve2(fileDir, targetPath);
|
|
7003
7072
|
if (!resolvedPath.includes("/.dust/principles/")) {
|
|
7004
7073
|
violations.push({
|
|
7005
7074
|
file: filePath,
|
|
@@ -7014,7 +7083,7 @@ function validatePrincipleHierarchyLinks(filePath, content) {
|
|
|
7014
7083
|
}
|
|
7015
7084
|
|
|
7016
7085
|
// lib/lint/validators/principle-hierarchy.ts
|
|
7017
|
-
import { dirname as dirname4, resolve as
|
|
7086
|
+
import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
7018
7087
|
var REQUIRED_PRINCIPLE_HEADINGS = ["## Parent Principle", "## Sub-Principles"];
|
|
7019
7088
|
function validatePrincipleHierarchySections(filePath, content) {
|
|
7020
7089
|
const violations = [];
|
|
@@ -7049,7 +7118,7 @@ function extractPrincipleRelationships(filePath, content) {
|
|
|
7049
7118
|
const linkTarget = match[2];
|
|
7050
7119
|
if (!linkTarget.startsWith("#") && !linkTarget.startsWith("http://") && !linkTarget.startsWith("https://")) {
|
|
7051
7120
|
const targetPath = linkTarget.split("#")[0];
|
|
7052
|
-
const resolvedPath =
|
|
7121
|
+
const resolvedPath = resolve3(fileDir, targetPath);
|
|
7053
7122
|
if (resolvedPath.includes("/.dust/principles/")) {
|
|
7054
7123
|
if (currentSection === "## Parent Principle") {
|
|
7055
7124
|
parentPrinciples.push(resolvedPath);
|
|
@@ -7701,7 +7770,7 @@ async function init(dependencies) {
|
|
|
7701
7770
|
}
|
|
7702
7771
|
|
|
7703
7772
|
// lib/cli/commands/list.ts
|
|
7704
|
-
import { basename as
|
|
7773
|
+
import { basename as basename3 } from "node:path";
|
|
7705
7774
|
function workflowTypeToStatus(type) {
|
|
7706
7775
|
switch (type) {
|
|
7707
7776
|
case "refine-idea":
|
|
@@ -7734,7 +7803,7 @@ async function buildPrincipleHierarchy(principlesPath, fileSystem) {
|
|
|
7734
7803
|
const filePath = `${principlesPath}/${file}`;
|
|
7735
7804
|
const content = await fileSystem.readFile(filePath);
|
|
7736
7805
|
relationships.push(extractPrincipleRelationships(filePath, content));
|
|
7737
|
-
const title = extractTitle(content) ||
|
|
7806
|
+
const title = extractTitle(content) || basename3(file, ".md");
|
|
7738
7807
|
titleMap.set(filePath, title);
|
|
7739
7808
|
}
|
|
7740
7809
|
const relMap = new Map;
|
|
@@ -7752,7 +7821,7 @@ async function buildPrincipleHierarchy(principlesPath, fileSystem) {
|
|
|
7752
7821
|
}
|
|
7753
7822
|
return {
|
|
7754
7823
|
filePath,
|
|
7755
|
-
title: titleMap.get(filePath) ||
|
|
7824
|
+
title: titleMap.get(filePath) || basename3(filePath, ".md"),
|
|
7756
7825
|
children
|
|
7757
7826
|
};
|
|
7758
7827
|
}
|
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);
|