clinkx 1.1.2 → 1.2.0
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/CHANGELOG.md +31 -0
- package/README.md +63 -12
- package/clinkx-workflows/dist/allowed-roots.js +2 -0
- package/clinkx-workflows/dist/allowed-roots.js.map +1 -1
- package/clinkx-workflows/dist/child-env.d.ts +3 -1
- package/clinkx-workflows/dist/child-env.js +6 -2
- package/clinkx-workflows/dist/child-env.js.map +1 -1
- package/clinkx-workflows/dist/config.d.ts +28 -5
- package/clinkx-workflows/dist/config.js +137 -20
- package/clinkx-workflows/dist/config.js.map +1 -1
- package/clinkx-workflows/dist/contained-file.js +9 -0
- package/clinkx-workflows/dist/contained-file.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/session-log-identity.js +2 -1
- package/clinkx-workflows/dist/dashboard/session-log-identity.js.map +1 -1
- package/clinkx-workflows/dist/root-path-validation.d.ts +12 -0
- package/clinkx-workflows/dist/root-path-validation.js +63 -0
- package/clinkx-workflows/dist/root-path-validation.js.map +1 -0
- package/clinkx-workflows/dist/rosters.d.ts +1 -0
- package/clinkx-workflows/dist/rosters.js +16 -6
- package/clinkx-workflows/dist/rosters.js.map +1 -1
- package/clinkx-workflows/dist/server.js +5 -2
- package/clinkx-workflows/dist/server.js.map +1 -1
- package/clinkx-workflows/dist/state-schema.d.ts +13 -0
- package/clinkx-workflows/dist/state.d.ts +7 -1
- package/clinkx-workflows/dist/state.js +74 -13
- package/clinkx-workflows/dist/state.js.map +1 -1
- package/clinkx-workflows/dist/workflow-completion.d.ts +83 -0
- package/clinkx-workflows/dist/workflow-completion.js +250 -0
- package/clinkx-workflows/dist/workflow-completion.js.map +1 -0
- package/clinkx-workflows/dist/workflow-tools.d.ts +4 -3
- package/clinkx-workflows/dist/workflow-tools.js +341 -34
- package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
- package/dist/allowed-roots.d.ts +1 -1
- package/dist/allowed-roots.js +124 -14
- package/dist/allowed-roots.js.map +1 -1
- package/dist/context-builder/config.d.ts +1 -0
- package/dist/context-builder/config.js +21 -9
- package/dist/context-builder/config.js.map +1 -1
- package/dist/context-builder/mutation-lock.d.ts +4 -0
- package/dist/context-builder/mutation-lock.js +7 -1
- package/dist/context-builder/mutation-lock.js.map +1 -1
- package/dist/context-builder/storage.d.ts +10 -2
- package/dist/context-builder/storage.js +213 -16
- package/dist/context-builder/storage.js.map +1 -1
- package/dist/dashboard-cli.d.ts +6 -0
- package/dist/dashboard-cli.js +8 -29
- package/dist/dashboard-cli.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +5 -1
- package/dist/registry.js.map +1 -1
- package/dist/server.js +12 -5
- package/dist/server.js.map +1 -1
- package/docs/configuration.md +157 -12
- package/docs/security.md +3 -0
- package/package.json +1 -1
- package/scripts/provider-doctor-core.mjs +21 -5
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { readContainedRelativeFile } from "./contained-file.js";
|
|
4
|
+
import { DEFAULT_DASHBOARD_MAX_STATE_BYTES } from "./config.js";
|
|
5
|
+
import { readSessionLogGeneration } from "./dashboard/session-log-identity.js";
|
|
6
|
+
import { WorkflowCancellationError } from "./errors.js";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
export const WORKFLOW_WAIT_BUDGET_MS = 30_000;
|
|
9
|
+
export const SETTLED_LIMIT = 128;
|
|
10
|
+
/** sha256 over the exact bytes read from state.json (never a decoded string). */
|
|
11
|
+
function fingerprintStateBytes(bytes) {
|
|
12
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Provenance only: result bodies and unfinished promise callbacks are never cached.
|
|
16
|
+
* An execution exists here only once its owner has bound a created/resumed
|
|
17
|
+
* store, so a request rejected during admission can never displace one.
|
|
18
|
+
*/
|
|
19
|
+
export class WorkflowCompletionRegistry {
|
|
20
|
+
latest = new Map();
|
|
21
|
+
byId = new Map();
|
|
22
|
+
minted = new WeakSet();
|
|
23
|
+
settledIds = [];
|
|
24
|
+
bind(runId, runDir, generation) {
|
|
25
|
+
const listeners = new Set();
|
|
26
|
+
const record = {
|
|
27
|
+
executionId: randomUUID(),
|
|
28
|
+
runId,
|
|
29
|
+
runDir: resolve(runDir),
|
|
30
|
+
generation,
|
|
31
|
+
publication: undefined,
|
|
32
|
+
settled: false,
|
|
33
|
+
stamped: false,
|
|
34
|
+
observers: 0,
|
|
35
|
+
listeners,
|
|
36
|
+
get listenerCount() { return listeners.size; },
|
|
37
|
+
};
|
|
38
|
+
this.minted.add(record);
|
|
39
|
+
this.byId.set(record.executionId, record);
|
|
40
|
+
this.latest.set(record.runDir, record);
|
|
41
|
+
return record;
|
|
42
|
+
}
|
|
43
|
+
owner(runId, runDir) {
|
|
44
|
+
let entry;
|
|
45
|
+
let boundStore;
|
|
46
|
+
return {
|
|
47
|
+
get entry() { return entry; },
|
|
48
|
+
bind: (store) => {
|
|
49
|
+
if (entry !== undefined) {
|
|
50
|
+
if (boundStore !== store)
|
|
51
|
+
throw new Error(`workflow run ${runId} is already bound to a different state store`);
|
|
52
|
+
return entry;
|
|
53
|
+
}
|
|
54
|
+
entry = this.bind(runId, runDir, store.sessionLogGeneration);
|
|
55
|
+
boundStore = store;
|
|
56
|
+
return entry;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
select(runDir, expected) {
|
|
61
|
+
const latest = this.latest.get(resolve(runDir));
|
|
62
|
+
if (expected === undefined)
|
|
63
|
+
return latest;
|
|
64
|
+
const entry = this.byId.get(expected);
|
|
65
|
+
if (entry === undefined)
|
|
66
|
+
return "identity_unavailable";
|
|
67
|
+
if (entry.runDir !== resolve(runDir) || latest !== entry)
|
|
68
|
+
return "identity_changed";
|
|
69
|
+
return entry;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Capture the terminal publication while ownership still prevents local
|
|
73
|
+
* re-admission. Only a terminal state of the bound directory incarnation counts.
|
|
74
|
+
*/
|
|
75
|
+
async recordPublication(entry) {
|
|
76
|
+
const record = this.own(entry);
|
|
77
|
+
if (record.settled || record.generation === undefined)
|
|
78
|
+
return;
|
|
79
|
+
const publication = await inspectPublication(record.runDir);
|
|
80
|
+
if (publication?.generation === record.generation && publication.terminal) {
|
|
81
|
+
record.publication = publication;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
markStamped(entry) {
|
|
85
|
+
this.own(entry).stamped = true;
|
|
86
|
+
}
|
|
87
|
+
settle(entry) {
|
|
88
|
+
const record = this.own(entry);
|
|
89
|
+
if (record.settled)
|
|
90
|
+
return;
|
|
91
|
+
record.settled = true;
|
|
92
|
+
this.settledIds.push(record.executionId);
|
|
93
|
+
this.prune();
|
|
94
|
+
for (const listener of [...record.listeners])
|
|
95
|
+
listener();
|
|
96
|
+
}
|
|
97
|
+
/** Protect provenance through the handler's final filesystem rereads. */
|
|
98
|
+
retain(entry) {
|
|
99
|
+
const record = this.own(entry);
|
|
100
|
+
record.observers += 1;
|
|
101
|
+
return () => {
|
|
102
|
+
record.observers -= 1;
|
|
103
|
+
this.prune();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Execution fence around a projection. `observedDigest` is the fingerprint of
|
|
108
|
+
* the state bytes the projection actually parsed (null: unreadable); pass it
|
|
109
|
+
* only when the entry was already settled before that projection began.
|
|
110
|
+
* Without it, only provenance and directory incarnation are checked, which
|
|
111
|
+
* is correct for an active execution that legitimately republishes state.
|
|
112
|
+
*/
|
|
113
|
+
async check(entry, observedDigest) {
|
|
114
|
+
const record = this.own(entry);
|
|
115
|
+
const before = this.selectionFailure(record);
|
|
116
|
+
if (before !== undefined)
|
|
117
|
+
return before;
|
|
118
|
+
if (record.generation === undefined)
|
|
119
|
+
return "identity_unavailable";
|
|
120
|
+
const generation = await readSessionLogGeneration(record.runDir);
|
|
121
|
+
// Recheck after the I/O: a replacement may bind while the read is pending.
|
|
122
|
+
const after = this.selectionFailure(record);
|
|
123
|
+
if (after !== undefined)
|
|
124
|
+
return after;
|
|
125
|
+
if (generation.kind !== "available")
|
|
126
|
+
return "identity_unavailable";
|
|
127
|
+
if (generation.sessionLogGeneration !== record.generation)
|
|
128
|
+
return "identity_changed";
|
|
129
|
+
if (record.settled && record.publication === undefined)
|
|
130
|
+
return "identity_unavailable";
|
|
131
|
+
if (observedDigest !== undefined) {
|
|
132
|
+
if (record.publication === undefined || observedDigest === null)
|
|
133
|
+
return "identity_unavailable";
|
|
134
|
+
if (observedDigest !== record.publication.fingerprint)
|
|
135
|
+
return "identity_changed";
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
wait(entry, signal) {
|
|
140
|
+
const record = this.own(entry);
|
|
141
|
+
if (signal.aborted)
|
|
142
|
+
return Promise.reject(new WorkflowCancellationError());
|
|
143
|
+
if (record.settled)
|
|
144
|
+
return Promise.resolve("settled");
|
|
145
|
+
return new Promise((resolveWait, reject) => {
|
|
146
|
+
let timer;
|
|
147
|
+
const cleanup = () => {
|
|
148
|
+
if (timer !== undefined)
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
record.listeners.delete(onComplete);
|
|
151
|
+
signal.removeEventListener("abort", onAbort);
|
|
152
|
+
};
|
|
153
|
+
const onComplete = () => {
|
|
154
|
+
cleanup();
|
|
155
|
+
resolveWait("settled");
|
|
156
|
+
};
|
|
157
|
+
const onAbort = () => {
|
|
158
|
+
cleanup();
|
|
159
|
+
reject(new WorkflowCancellationError());
|
|
160
|
+
};
|
|
161
|
+
record.listeners.add(onComplete);
|
|
162
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
163
|
+
timer = setTimeout(() => {
|
|
164
|
+
cleanup();
|
|
165
|
+
resolveWait("budget_elapsed");
|
|
166
|
+
}, WORKFLOW_WAIT_BUDGET_MS);
|
|
167
|
+
// A pending observation must not keep an otherwise idle process alive.
|
|
168
|
+
timer.unref?.();
|
|
169
|
+
// Inspect after registration, so a fast completion cannot strand a waiter.
|
|
170
|
+
if (record.settled)
|
|
171
|
+
onComplete();
|
|
172
|
+
else if (signal.aborted)
|
|
173
|
+
onAbort();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
selectionFailure(record) {
|
|
177
|
+
const selected = this.select(record.runDir, record.executionId);
|
|
178
|
+
if (typeof selected === "string")
|
|
179
|
+
return selected;
|
|
180
|
+
return selected === record ? undefined : "identity_unavailable";
|
|
181
|
+
}
|
|
182
|
+
own(entry) {
|
|
183
|
+
if (!this.minted.has(entry))
|
|
184
|
+
throw new Error("workflow completion was not bound by this registry");
|
|
185
|
+
return entry;
|
|
186
|
+
}
|
|
187
|
+
prune() {
|
|
188
|
+
while (this.settledIds.length > SETTLED_LIMIT) {
|
|
189
|
+
const index = this.settledIds.findIndex((id) => this.byId.get(id)?.observers === 0);
|
|
190
|
+
if (index === -1)
|
|
191
|
+
return;
|
|
192
|
+
const id = this.settledIds.splice(index, 1)[0];
|
|
193
|
+
const retired = this.byId.get(id);
|
|
194
|
+
this.byId.delete(id);
|
|
195
|
+
if (retired !== undefined && this.latest.get(retired.runDir) === retired) {
|
|
196
|
+
this.latest.delete(retired.runDir);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function isTerminalStatus(status) {
|
|
202
|
+
return status === "succeeded" || status === "failed" || status === "cancelled";
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Persisted provenance for a pin this process retains no record for. Only a
|
|
206
|
+
* terminal state stamped with exactly that id, whose run.lock is released
|
|
207
|
+
* (`stale_or_absent`), counts as its settlement: a live or unknown lock means
|
|
208
|
+
* an owner may still be inside its cleanup fence, and a non-terminal match has
|
|
209
|
+
* no local owner whose fence could be witnessed.
|
|
210
|
+
*/
|
|
211
|
+
export function persistedIdentityFailure(state, lock, runId, expected) {
|
|
212
|
+
if (typeof state.executionId !== "string" || state.runId !== runId)
|
|
213
|
+
return "identity_unavailable";
|
|
214
|
+
if (state.executionId !== expected)
|
|
215
|
+
return "identity_changed";
|
|
216
|
+
if (!isTerminalStatus(state.status) || lock !== "stale_or_absent")
|
|
217
|
+
return "identity_unavailable";
|
|
218
|
+
return typeof state.completedAt === "string" && state.executionCompletedAt === state.completedAt
|
|
219
|
+
? undefined
|
|
220
|
+
: "identity_unavailable";
|
|
221
|
+
}
|
|
222
|
+
export async function inspectPublication(runDir) {
|
|
223
|
+
try {
|
|
224
|
+
const before = await readSessionLogGeneration(runDir);
|
|
225
|
+
if (before.kind !== "available")
|
|
226
|
+
return undefined;
|
|
227
|
+
const file = await readContainedRelativeFile(runDir, "state.json", {
|
|
228
|
+
wantBytes: true,
|
|
229
|
+
requireRegular: true,
|
|
230
|
+
requireExactRequestedPath: true,
|
|
231
|
+
maxBytes: DEFAULT_DASHBOARD_MAX_STATE_BYTES,
|
|
232
|
+
});
|
|
233
|
+
const state = JSON.parse(file.bytes.toString("utf-8"));
|
|
234
|
+
const after = await readSessionLogGeneration(runDir);
|
|
235
|
+
if (after.kind !== "available" || after.sessionLogGeneration !== before.sessionLogGeneration) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
generation: before.sessionLogGeneration,
|
|
240
|
+
fingerprint: fingerprintStateBytes(file.bytes),
|
|
241
|
+
terminal: isTerminalStatus(state.status),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
// Class only: messages can carry paths or state values.
|
|
246
|
+
logger.debug({ errClass: error instanceof Error ? error.constructor.name : typeof error, runDir }, "workflow publication identity unavailable");
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=workflow-completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-completion.js","sourceRoot":"","sources":["../src/workflow-completion.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* - Standalone STDIO server (ClinkSession child process backend)
|
|
6
6
|
* - In-process integration (LocalClinkBackend via root ClinkX)
|
|
7
7
|
*
|
|
8
|
-
* The `registerWorkflowTools()` function registers
|
|
8
|
+
* The `registerWorkflowTools()` function registers six tools on a Server:
|
|
9
9
|
* - run_workflow: start a new workflow execution
|
|
10
10
|
* - resume_workflow: resume a failed/cancelled run
|
|
11
11
|
* - list_workflows: list available workflow definitions
|
|
12
12
|
* - workflow_run_status: read workflow run progress/result
|
|
13
|
+
* - workflow_run_wait: observe local execution settlement
|
|
13
14
|
* - cancel_workflow: cancel a live or orphaned workflow run
|
|
14
15
|
*
|
|
15
16
|
* The caller provides a `createBackend` factory that determines how clink
|
|
@@ -194,8 +195,8 @@ export declare function handleWorkflowToolCall(server: Server, options: Workflow
|
|
|
194
195
|
* Register workflow tools on an MCP Server instance.
|
|
195
196
|
*
|
|
196
197
|
* This is the reusable core extracted from createWorkflowServer().
|
|
197
|
-
* It registers
|
|
198
|
-
* workflow_run_status, cancel_workflow.
|
|
198
|
+
* It registers six tools: run_workflow, resume_workflow, list_workflows,
|
|
199
|
+
* workflow_run_status, workflow_run_wait, cancel_workflow.
|
|
199
200
|
*
|
|
200
201
|
* The `options.createBackend` factory determines how clink calls are
|
|
201
202
|
* dispatched — callers provide either a child-process or in-process backend.
|