@brainervirus/workit-codex 1.0.11 → 1.0.12
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/.codex-plugin/plugin.json +1 -1
- package/dist/launch-mcp.js +2185 -2081
- package/dist/workit-hook.js +330 -206
- package/package.json +3 -3
package/dist/launch-mcp.js
CHANGED
|
@@ -6625,9 +6625,9 @@ import { existsSync as existsSync8, realpathSync as realpathSync8, statSync as s
|
|
|
6625
6625
|
import path15 from "node:path";
|
|
6626
6626
|
|
|
6627
6627
|
// packages/workit-core/src/core.ts
|
|
6628
|
-
import { spawnSync as
|
|
6629
|
-
import { existsSync as
|
|
6630
|
-
import
|
|
6628
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
6629
|
+
import { existsSync as existsSync5, realpathSync as realpathSync6 } from "node:fs";
|
|
6630
|
+
import path10 from "node:path";
|
|
6631
6631
|
|
|
6632
6632
|
// packages/workit-core/src/core/task-contract.ts
|
|
6633
6633
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -14201,6 +14201,89 @@ var refSchema = discriminatedUnion("kind", [
|
|
|
14201
14201
|
object({ kind: literal("host"), host: hostSchema, handle: nonEmpty }).strict(),
|
|
14202
14202
|
object({ kind: literal("external"), url: text.url() }).strict()
|
|
14203
14203
|
]);
|
|
14204
|
+
var rewriteUnknown = (value, map) => {
|
|
14205
|
+
if (Array.isArray(value)) {
|
|
14206
|
+
const out = [];
|
|
14207
|
+
for (const item of value) {
|
|
14208
|
+
const rewritten = rewriteUnknown(item, map);
|
|
14209
|
+
if (!rewritten.drop)
|
|
14210
|
+
out.push(rewritten.value);
|
|
14211
|
+
}
|
|
14212
|
+
return { drop: false, value: out };
|
|
14213
|
+
}
|
|
14214
|
+
if (typeof value === "object" && value !== null) {
|
|
14215
|
+
if (refSchema.safeParse(value).success) {
|
|
14216
|
+
const mapped = map(value);
|
|
14217
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
14218
|
+
}
|
|
14219
|
+
const out = {};
|
|
14220
|
+
for (const [key, item] of Object.entries(value)) {
|
|
14221
|
+
const rewritten = rewriteUnknown(item, map);
|
|
14222
|
+
out[key] = rewritten.drop ? null : rewritten.value;
|
|
14223
|
+
}
|
|
14224
|
+
return { drop: false, value: out };
|
|
14225
|
+
}
|
|
14226
|
+
return { drop: false, value };
|
|
14227
|
+
};
|
|
14228
|
+
var rewriteNode = (value, schema, map) => {
|
|
14229
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && refSchema.safeParse(value).success) {
|
|
14230
|
+
const mapped = map(value);
|
|
14231
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
14232
|
+
}
|
|
14233
|
+
let node = schema;
|
|
14234
|
+
while (node instanceof ZodNullable || node instanceof ZodOptional || node instanceof ZodDefault) {
|
|
14235
|
+
node = node.unwrap();
|
|
14236
|
+
}
|
|
14237
|
+
if (node === refSchema) {
|
|
14238
|
+
if (!refSchema.safeParse(value).success)
|
|
14239
|
+
return { drop: false, value };
|
|
14240
|
+
const mapped = map(value);
|
|
14241
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
14242
|
+
}
|
|
14243
|
+
if (node instanceof ZodArray) {
|
|
14244
|
+
if (!Array.isArray(value))
|
|
14245
|
+
return { drop: false, value };
|
|
14246
|
+
const out = [];
|
|
14247
|
+
for (const item of value) {
|
|
14248
|
+
const rewritten = rewriteNode(item, node.element, map);
|
|
14249
|
+
if (!rewritten.drop)
|
|
14250
|
+
out.push(rewritten.value);
|
|
14251
|
+
}
|
|
14252
|
+
return { drop: false, value: out };
|
|
14253
|
+
}
|
|
14254
|
+
if (node instanceof ZodObject) {
|
|
14255
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
14256
|
+
return { drop: false, value };
|
|
14257
|
+
const shape = node.shape;
|
|
14258
|
+
const record = value;
|
|
14259
|
+
const out = {};
|
|
14260
|
+
for (const [key, item] of Object.entries(record)) {
|
|
14261
|
+
if (!(key in shape)) {
|
|
14262
|
+
const scrubbed = rewriteUnknown(item, map);
|
|
14263
|
+
out[key] = scrubbed.drop ? null : scrubbed.value;
|
|
14264
|
+
continue;
|
|
14265
|
+
}
|
|
14266
|
+
const child = shape[key];
|
|
14267
|
+
const rewritten = rewriteNode(item, child, map);
|
|
14268
|
+
if (rewritten.drop) {
|
|
14269
|
+
if (child instanceof ZodOptional || child instanceof ZodDefault)
|
|
14270
|
+
continue;
|
|
14271
|
+
if (child instanceof ZodNullable) {
|
|
14272
|
+
out[key] = null;
|
|
14273
|
+
continue;
|
|
14274
|
+
}
|
|
14275
|
+
return { drop: true };
|
|
14276
|
+
}
|
|
14277
|
+
out[key] = rewritten.value;
|
|
14278
|
+
}
|
|
14279
|
+
return { drop: false, value: out };
|
|
14280
|
+
}
|
|
14281
|
+
return { drop: false, value };
|
|
14282
|
+
};
|
|
14283
|
+
var rewriteRecordRefs = (value, schema, map) => {
|
|
14284
|
+
const rewritten = rewriteNode(value, schema, map);
|
|
14285
|
+
return rewritten.drop ? null : rewritten.value;
|
|
14286
|
+
};
|
|
14204
14287
|
var provenanceSchema = object({
|
|
14205
14288
|
kind: _enum(["host_observed", "agent_reported", "imported"]),
|
|
14206
14289
|
host: hostSchema,
|
|
@@ -15912,11 +15995,11 @@ class TaskStore {
|
|
|
15912
15995
|
return workspace;
|
|
15913
15996
|
if (!workspace.data)
|
|
15914
15997
|
return failure("not_found", "workspace not found");
|
|
15915
|
-
const
|
|
15916
|
-
if (!
|
|
15998
|
+
const expected = input.expectedRevision;
|
|
15999
|
+
if (!expected)
|
|
15917
16000
|
return failure("invalid_input", "task revision is required");
|
|
15918
|
-
if (task.data.revision !==
|
|
15919
|
-
return this.conflict(
|
|
16001
|
+
if (task.data.revision !== expected)
|
|
16002
|
+
return this.conflict(expected, task.data.revision);
|
|
15920
16003
|
if (workspace.data.revision !== input.expectedWorkspaceRevision)
|
|
15921
16004
|
return this.conflict(input.expectedWorkspaceRevision, workspace.data.revision);
|
|
15922
16005
|
const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
|
|
@@ -16450,6 +16533,7 @@ var same = (left, right) => {
|
|
|
16450
16533
|
};
|
|
16451
16534
|
var UNCERTAIN_WORKER_STATES = ["dispatching", "running", "cancelling", "unknown"];
|
|
16452
16535
|
var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
16536
|
+
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
16453
16537
|
var callerSession = (caller) => caller.session ?? { kind: "host", host: caller.host, handle: caller.actor };
|
|
16454
16538
|
var validPath = (value) => typeof value === "string" && value.length > 0 && ![...value].some((char) => {
|
|
16455
16539
|
const code = char.charCodeAt(0);
|
|
@@ -16511,6 +16595,36 @@ var trustedAuthority = (kind, provenance, expected, binding, caller) => {
|
|
|
16511
16595
|
verifiedAuthorities.set(token, { kind, provenance, ...expected, ...binding, caller });
|
|
16512
16596
|
return token;
|
|
16513
16597
|
};
|
|
16598
|
+
var chainStepKey = (step) => step.kind === "commit" ? step.message : step.kind === "branch" ? `branch:${step.target}` : "pr";
|
|
16599
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16600
|
+
var normalizeChainSteps = (steps) => {
|
|
16601
|
+
if (!Array.isArray(steps) || steps.length === 0 || steps.length > 32)
|
|
16602
|
+
return null;
|
|
16603
|
+
const normalized = [];
|
|
16604
|
+
for (const step of steps) {
|
|
16605
|
+
if (typeof step === "string") {
|
|
16606
|
+
if (!step.trim())
|
|
16607
|
+
return null;
|
|
16608
|
+
normalized.push({ kind: "commit", message: step });
|
|
16609
|
+
continue;
|
|
16610
|
+
}
|
|
16611
|
+
if (!isRecord(step))
|
|
16612
|
+
return null;
|
|
16613
|
+
if (typeof step.branch === "string" && step.branch.trim() && Object.keys(step).length === 1) {
|
|
16614
|
+
normalized.push({ kind: "branch", target: step.branch });
|
|
16615
|
+
continue;
|
|
16616
|
+
}
|
|
16617
|
+
if (step.pr === true && Object.keys(step).length === 1) {
|
|
16618
|
+
normalized.push({ kind: "pr" });
|
|
16619
|
+
continue;
|
|
16620
|
+
}
|
|
16621
|
+
return null;
|
|
16622
|
+
}
|
|
16623
|
+
const keys = normalized.map(chainStepKey);
|
|
16624
|
+
if (new Set(keys).size !== keys.length)
|
|
16625
|
+
return null;
|
|
16626
|
+
return normalized;
|
|
16627
|
+
};
|
|
16514
16628
|
var scopeEqual = (left, right) => canonicalJson(left) === canonicalJson(right);
|
|
16515
16629
|
var parseSteps = (content) => {
|
|
16516
16630
|
let value;
|
|
@@ -16522,7 +16636,10 @@ var parseSteps = (content) => {
|
|
|
16522
16636
|
if (typeof value !== "object" || value === null || !("steps" in value))
|
|
16523
16637
|
return [];
|
|
16524
16638
|
const steps = value.steps;
|
|
16525
|
-
|
|
16639
|
+
if (!Array.isArray(steps))
|
|
16640
|
+
return null;
|
|
16641
|
+
const normalized = normalizeChainSteps(steps);
|
|
16642
|
+
return normalized;
|
|
16526
16643
|
};
|
|
16527
16644
|
var decisionMatches = (entry, purpose, binding) => {
|
|
16528
16645
|
const decision = entry.data;
|
|
@@ -16713,14 +16830,12 @@ var validateAction = (store, task, workspaceId, input, authority) => {
|
|
|
16713
16830
|
return content;
|
|
16714
16831
|
const requestedSteps = parseSteps(decision.binding.approvedContent);
|
|
16715
16832
|
if (requestedSteps === null)
|
|
16716
|
-
return failure("invalid_input", "bounded action steps must be a
|
|
16717
|
-
if (input.steps && canonicalJson(input.steps) !== canonicalJson(requestedSteps))
|
|
16833
|
+
return failure("invalid_input", "bounded action steps must be a unique non-empty array");
|
|
16834
|
+
if (input.steps && canonicalJson(input.steps) !== canonicalJson(requestedSteps.map(chainStepKey)))
|
|
16718
16835
|
return failure("permission_denied", "bounded action steps do not match approved content");
|
|
16719
|
-
if (requestedSteps.some((step) => !step || typeof step !== "string") || new Set(requestedSteps).size !== requestedSteps.length)
|
|
16720
|
-
return failure("invalid_input", "bounded action steps must be unique and non-empty");
|
|
16721
16836
|
const stored = task.actionProgress?.find((item) => item.decisionId === input.decisionId);
|
|
16722
|
-
const workflow = stored ? { steps: stored.steps, completed: stored.completedSteps } : { steps: requestedSteps, completed: [] };
|
|
16723
|
-
if (workflow.steps.length && requestedSteps.length && canonicalJson(workflow.steps) !== canonicalJson(requestedSteps))
|
|
16837
|
+
const workflow = stored ? { steps: stored.steps, completed: stored.completedSteps } : { steps: requestedSteps.map(chainStepKey), completed: [] };
|
|
16838
|
+
if (workflow.steps.length && requestedSteps.length && canonicalJson(workflow.steps) !== canonicalJson(requestedSteps.map(chainStepKey)))
|
|
16724
16839
|
return failure("permission_denied", "bounded action scope changed");
|
|
16725
16840
|
return success(null, null, { entry, workflow });
|
|
16726
16841
|
};
|
|
@@ -17275,13 +17390,28 @@ function evaluateEvidence(task, candidate) {
|
|
|
17275
17390
|
});
|
|
17276
17391
|
}
|
|
17277
17392
|
var scopeCovers2 = scopeCovers;
|
|
17393
|
+
var checkPin = (assignment, beforeCandidateId, candidateId) => {
|
|
17394
|
+
const pin = assignment.candidateId ?? null;
|
|
17395
|
+
if (pin === null)
|
|
17396
|
+
return true;
|
|
17397
|
+
return (beforeCandidateId ?? null) === pin || (candidateId ?? null) === pin;
|
|
17398
|
+
};
|
|
17399
|
+
var resolveBinding = (evidence, pin, currentCandidateId) => {
|
|
17400
|
+
const bound = evidence.kind === "check" || evidence.kind === "review";
|
|
17401
|
+
const fallback = bound ? pin ?? currentCandidateId : null;
|
|
17402
|
+
return {
|
|
17403
|
+
beforeCandidateId: evidence.beforeCandidateId ?? fallback,
|
|
17404
|
+
candidateId: evidence.candidateId ?? fallback
|
|
17405
|
+
};
|
|
17406
|
+
};
|
|
17407
|
+
var findingVerificationPasses = (findingCandidateId, evidence) => evidence.status === "passed" && (evidence.kind === "check" || evidence.kind === "review") && ((findingCandidateId ?? null) === null || evidence.candidateId === findingCandidateId);
|
|
17278
17408
|
var applicableDecision2 = (task, workspace, requirement, checkoutRoot) => task.decisions.filter((entry) => entry.provenance.kind !== "imported").map((entry) => entry.data).filter((decision) => decision.purpose === "limitation" && decision.response === "approved" && decision.revoked === null && decision.binding.taskId === task.id && decision.binding.workspaceId === workspace.id && decision.requirementIds.includes(requirement.id) && decision.binding.scope && scopeCovers2(decision.binding.scope, requirement.scope) && decision.digest === decisionDigest(decision) && (checkoutRoot ? verifyDecisionContentAtRoot(checkoutRoot, decision.binding).ok : decision.binding.contentRefs.every((reference) => reference.kind !== "file")));
|
|
17279
17409
|
var applicableRequirementDecision = (task, workspace, requirement, checkoutRoot) => task.decisions.filter(({ data, provenance }) => provenance.kind !== "imported" && data.purpose !== "limitation" && (data.response === "approved" || data.response === "stated") && data.revoked === null && data.binding.taskId === task.id && data.binding.workspaceId === workspace.id && data.requirementIds.includes(requirement.id) && scopeCovers2(data.binding.scope, requirement.scope) && data.digest === decisionDigest(data) && (checkoutRoot ? verifyDecisionContentAtRoot(checkoutRoot, data.binding).ok : data.binding.contentRefs.every((reference) => reference.kind !== "file"))).map(({ id }) => ({ id }));
|
|
17280
|
-
var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
|
|
17410
|
+
var evidenceMatchesRequirement = (kind, evidenceKind, dimension, ruleId) => {
|
|
17281
17411
|
if (kind !== "passed")
|
|
17282
17412
|
return false;
|
|
17283
17413
|
if (dimension === "testing" || dimension === "verification")
|
|
17284
|
-
return evidenceKind === "check";
|
|
17414
|
+
return evidenceKind === "check" || ruleId === "pre-pr-cleanup" && evidenceKind === "artifact";
|
|
17285
17415
|
if (dimension === "review")
|
|
17286
17416
|
return evidenceKind === "review";
|
|
17287
17417
|
if (dimension === "investigation" || dimension === "challenge")
|
|
@@ -17290,6 +17420,21 @@ var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
|
|
|
17290
17420
|
return evidenceKind === "artifact";
|
|
17291
17421
|
return false;
|
|
17292
17422
|
};
|
|
17423
|
+
var expectedKinds = (dimension, ruleId) => {
|
|
17424
|
+
if (dimension === "testing")
|
|
17425
|
+
return "check";
|
|
17426
|
+
if (dimension === "verification")
|
|
17427
|
+
return ruleId === "pre-pr-cleanup" ? "check or artifact" : "check";
|
|
17428
|
+
if (dimension === "review")
|
|
17429
|
+
return "review";
|
|
17430
|
+
if (dimension === "investigation" || dimension === "challenge")
|
|
17431
|
+
return "investigation";
|
|
17432
|
+
if (dimension === "artifacts" || dimension === "continuity")
|
|
17433
|
+
return "artifact";
|
|
17434
|
+
if (dimension === "decisions")
|
|
17435
|
+
return "decision";
|
|
17436
|
+
return "worker report";
|
|
17437
|
+
};
|
|
17293
17438
|
function evaluateRequirements(task, workspace, capabilities, candidate, checkoutRoot, _caller) {
|
|
17294
17439
|
const evidence = evaluateEvidence(task, candidate);
|
|
17295
17440
|
if (task.policy && task.policy.policyVersion !== POLICY_VERSION)
|
|
@@ -17303,7 +17448,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17303
17448
|
return (task.policy?.requirements ?? []).map((requirement) => {
|
|
17304
17449
|
const related = task.evidence.map((entry, index) => ({ entry, evaluation: evidence[index] })).filter(({ entry }) => entry.data.requirementIds.includes(requirement.id));
|
|
17305
17450
|
const passed = related.filter(({ entry, evaluation }) => {
|
|
17306
|
-
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension))
|
|
17451
|
+
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension, requirement.ruleId))
|
|
17307
17452
|
return false;
|
|
17308
17453
|
if ((entry.data.kind === "check" || entry.data.kind === "review") && (!entry.data.beforeCandidateId || !entry.data.candidateId || entry.data.beforeCandidateId !== entry.data.candidateId))
|
|
17309
17454
|
return false;
|
|
@@ -17311,11 +17456,12 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17311
17456
|
return true;
|
|
17312
17457
|
const reviewSession = sessionFromRef(entry.data.reviewContext);
|
|
17313
17458
|
const sameImplementation = sameSession(reviewSession, task.intent.provenance.session);
|
|
17314
|
-
const sameEvidenceSession =
|
|
17459
|
+
const sameEvidenceSession = related.some(({ entry: other }) => other.id !== entry.id && other.data.kind === "review" && other.data.candidateId !== null && other.data.candidateId === entry.data.candidateId && sameSession(reviewSession, other.provenance.session));
|
|
17315
17460
|
return entry.data.kind === "review" && reviewSession !== null && sameSession(reviewSession, entry.provenance.session) && (requirement.ruleId === "self-review" || !sameImplementation && !sameEvidenceSession);
|
|
17316
17461
|
});
|
|
17317
17462
|
if (passed.length) {
|
|
17318
|
-
const
|
|
17463
|
+
const currentId = candidate?.id ?? null;
|
|
17464
|
+
const withRed = requirement.dimension === "testing" ? passed.filter(({ entry }) => related.some((other) => other.entry.data.kind === "check" && other.evaluation.status === "failed" && other.entry.data.requirementIds.includes(requirement.id) && other.entry.recordedAt <= entry.recordedAt) || related.some((baseline) => baseline.entry.id !== entry.id && baseline.entry.data.kind === "check" && baseline.entry.data.result === "passed" && baseline.entry.data.candidateId !== null && currentId !== null && baseline.entry.data.candidateId !== currentId)) : passed;
|
|
17319
17465
|
if (withRed.length)
|
|
17320
17466
|
return {
|
|
17321
17467
|
requirementId: requirement.id,
|
|
@@ -17364,6 +17510,14 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17364
17510
|
reason: "an applicable approved limitation permits the missing evidence"
|
|
17365
17511
|
};
|
|
17366
17512
|
const unavailable = capabilities.some((capability) => capability.assurance === "unavailable" && (capability.name === requirement.dimension || capability.surface === requirement.dimension));
|
|
17513
|
+
if (!unavailable && related.length > 0 && !passed.length)
|
|
17514
|
+
return {
|
|
17515
|
+
requirementId: requirement.id,
|
|
17516
|
+
status: "unsatisfied",
|
|
17517
|
+
evidenceIds: related.map(({ entry }) => entry.id),
|
|
17518
|
+
decisionIds: [],
|
|
17519
|
+
reason: `no passing evidence (needs kind:${expectedKinds(requirement.dimension, requirement.ruleId)})`
|
|
17520
|
+
};
|
|
17367
17521
|
return {
|
|
17368
17522
|
requirementId: requirement.id,
|
|
17369
17523
|
status: unavailable ? "unavailable" : "unsatisfied",
|
|
@@ -17388,7 +17542,13 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
17388
17542
|
if (entry.data.disposition === "fixed") {
|
|
17389
17543
|
const verified = entry.data.resolution?.evidenceIds.some((id) => {
|
|
17390
17544
|
const evidence = view.task.evidence.find((item) => item.id === id);
|
|
17391
|
-
|
|
17545
|
+
if (!evidence)
|
|
17546
|
+
return false;
|
|
17547
|
+
return findingVerificationPasses(entry.data.candidateId, {
|
|
17548
|
+
kind: evidence.data.kind,
|
|
17549
|
+
candidateId: evidence.data.candidateId,
|
|
17550
|
+
status: evidenceById.get(id) ?? "missing"
|
|
17551
|
+
});
|
|
17392
17552
|
});
|
|
17393
17553
|
if (!verified)
|
|
17394
17554
|
return failure("requirements_unsatisfied", "fixed findings require current verification");
|
|
@@ -17404,7 +17564,12 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
17404
17564
|
}
|
|
17405
17565
|
}
|
|
17406
17566
|
}
|
|
17407
|
-
const blocking = evaluations.filter((item) =>
|
|
17567
|
+
const blocking = evaluations.filter((item) => {
|
|
17568
|
+
if (item.status !== "unsatisfied" && item.status !== "unavailable")
|
|
17569
|
+
return false;
|
|
17570
|
+
const requirement = view.task.policy?.requirements.find((candidate) => candidate.id === item.requirementId);
|
|
17571
|
+
return !requirement || requirement.before === "close";
|
|
17572
|
+
});
|
|
17408
17573
|
if (requestedOutcome !== "stopped" && blocking.length)
|
|
17409
17574
|
return failure("requirements_unsatisfied", "applicable requirements are unsatisfied", {
|
|
17410
17575
|
requirementIds: blocking.map((item) => item.requirementId),
|
|
@@ -17473,197 +17638,755 @@ var exportDigest = (bundle) => sha256({
|
|
|
17473
17638
|
sourceWorkspaceId: bundle.sourceWorkspaceId,
|
|
17474
17639
|
task: bundle.task
|
|
17475
17640
|
});
|
|
17476
|
-
// packages/workit-core/src/core/
|
|
17477
|
-
|
|
17478
|
-
|
|
17479
|
-
|
|
17480
|
-
|
|
17481
|
-
|
|
17482
|
-
|
|
17483
|
-
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
}
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
|
|
17493
|
-
}).strict()
|
|
17494
|
-
}).strict(),
|
|
17495
|
-
object({
|
|
17496
|
-
operation: literal("git.push"),
|
|
17497
|
-
payload: object({ branch: string2().min(1).optional() }).strict()
|
|
17498
|
-
}).strict(),
|
|
17499
|
-
object({
|
|
17500
|
-
operation: literal("hosting.pull_request"),
|
|
17501
|
-
payload: object({
|
|
17502
|
-
title: string2().min(1),
|
|
17503
|
-
body: string2().optional(),
|
|
17504
|
-
draft: boolean2().optional(),
|
|
17505
|
-
target_branch: string2().optional(),
|
|
17506
|
-
babysit: boolean2().optional()
|
|
17507
|
-
}).strict()
|
|
17508
|
-
}).strict(),
|
|
17509
|
-
object({
|
|
17510
|
-
operation: literal("youtrack.update"),
|
|
17511
|
-
payload: object({
|
|
17512
|
-
issueId: string2().min(1),
|
|
17513
|
-
markdown: string2().min(1),
|
|
17514
|
-
minutes: number2().positive().optional()
|
|
17515
|
-
}).strict()
|
|
17516
|
-
}).strict(),
|
|
17517
|
-
object({
|
|
17518
|
-
operation: literal("youtrack.time"),
|
|
17519
|
-
payload: object({
|
|
17520
|
-
issueId: string2().min(1),
|
|
17521
|
-
minutes: number2().positive(),
|
|
17522
|
-
text: string2().optional(),
|
|
17523
|
-
dateMs: number2().finite().optional()
|
|
17524
|
-
}).strict()
|
|
17525
|
-
}).strict(),
|
|
17526
|
-
object({
|
|
17527
|
-
operation: literal("youtrack.meeting"),
|
|
17528
|
-
payload: object({
|
|
17529
|
-
issueId: string2().min(1),
|
|
17530
|
-
minutes: number2().positive(),
|
|
17531
|
-
text: string2().min(1)
|
|
17532
|
-
}).strict()
|
|
17533
|
-
}).strict(),
|
|
17534
|
-
object({
|
|
17535
|
-
operation: literal("changelog.apply"),
|
|
17536
|
-
payload: object({
|
|
17537
|
-
entries: union([
|
|
17538
|
-
record(string2(), array(string2())),
|
|
17539
|
-
array(object({ category: string2().min(1), text: string2().min(1) }).strict())
|
|
17540
|
-
]).optional(),
|
|
17541
|
-
path: string2().optional(),
|
|
17542
|
-
normalize_only: boolean2().optional()
|
|
17543
|
-
}).strict()
|
|
17544
|
-
}).strict(),
|
|
17545
|
-
object({
|
|
17546
|
-
operation: literal("context.read"),
|
|
17547
|
-
payload: object({
|
|
17548
|
-
kind: _enum([
|
|
17549
|
-
"git",
|
|
17550
|
-
"pr",
|
|
17551
|
-
"youtrack",
|
|
17552
|
-
"github_issue",
|
|
17553
|
-
"gitlab_issue",
|
|
17554
|
-
"changelog",
|
|
17555
|
-
"release",
|
|
17556
|
-
"affected"
|
|
17557
|
-
]),
|
|
17558
|
-
range: string2().optional(),
|
|
17559
|
-
issueId: string2().optional(),
|
|
17560
|
-
issueUrl: string2().optional(),
|
|
17561
|
-
issueRef: string2().optional(),
|
|
17562
|
-
mode: string2().optional(),
|
|
17563
|
-
specPath: string2().optional(),
|
|
17564
|
-
planPath: string2().optional()
|
|
17565
|
-
}).strict()
|
|
17566
|
-
}).strict()
|
|
17567
|
-
]);
|
|
17568
|
-
// packages/workit-core/src/core/task-engine.ts
|
|
17569
|
-
import { realpathSync as realpathSync4 } from "node:fs";
|
|
17570
|
-
|
|
17571
|
-
// packages/workit-core/src/core/policy-resolver.ts
|
|
17572
|
-
var resolverInputSchema = object({
|
|
17573
|
-
intent: intentSchema,
|
|
17574
|
-
assessment: assessmentSchema,
|
|
17575
|
-
constraints: array(constraintSchema),
|
|
17576
|
-
prior: object({
|
|
17577
|
-
decisions: array(decisionSchema),
|
|
17578
|
-
findings: array(findingSchema),
|
|
17579
|
-
requirements: array(requirementSchema)
|
|
17580
|
-
}).strict(),
|
|
17581
|
-
preferences: object({ fast: boolean2().optional(), thorough: boolean2().optional() }).strict().optional()
|
|
17582
|
-
}).strict();
|
|
17583
|
-
var compareCodeUnits3 = (left, right) => {
|
|
17584
|
-
const length = Math.min(left.length, right.length);
|
|
17585
|
-
for (let index = 0;index < length; index += 1) {
|
|
17586
|
-
const difference = left.charCodeAt(index) - right.charCodeAt(index);
|
|
17587
|
-
if (difference !== 0)
|
|
17588
|
-
return difference;
|
|
17641
|
+
// packages/workit-core/src/core/git.ts
|
|
17642
|
+
import { execFileSync } from "node:child_process";
|
|
17643
|
+
var run = (cwd, args) => {
|
|
17644
|
+
try {
|
|
17645
|
+
const stdout = execFileSync("git", args, {
|
|
17646
|
+
cwd,
|
|
17647
|
+
encoding: "utf8",
|
|
17648
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
17649
|
+
});
|
|
17650
|
+
return { stdout: stdout.trimEnd(), stderr: "", exitCode: 0 };
|
|
17651
|
+
} catch (error) {
|
|
17652
|
+
const e = error;
|
|
17653
|
+
return {
|
|
17654
|
+
stdout: (e.stdout ?? "").trimEnd(),
|
|
17655
|
+
stderr: (e.stderr ?? "").trimEnd(),
|
|
17656
|
+
exitCode: e.status ?? 1
|
|
17657
|
+
};
|
|
17589
17658
|
}
|
|
17590
|
-
return left.length - right.length;
|
|
17591
17659
|
};
|
|
17592
|
-
var
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
}
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
]
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
}
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
|
|
17650
|
-
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
|
|
17665
|
-
|
|
17666
|
-
|
|
17660
|
+
var gitContext = (workspaceRoot, paths = []) => {
|
|
17661
|
+
const cwd = workspaceRoot;
|
|
17662
|
+
let failure;
|
|
17663
|
+
const runHere = (args) => {
|
|
17664
|
+
const result = run(cwd, args);
|
|
17665
|
+
if (!failure && result.exitCode !== 0) {
|
|
17666
|
+
failure = { stderr: result.stderr, exitCode: result.exitCode };
|
|
17667
|
+
}
|
|
17668
|
+
return result.stdout;
|
|
17669
|
+
};
|
|
17670
|
+
const branch = runHere(["rev-parse", "--abbrev-ref", "HEAD"]) || "unknown";
|
|
17671
|
+
const status_short = runHere(["status", "--porcelain"]);
|
|
17672
|
+
const staged = [];
|
|
17673
|
+
const unstaged = [];
|
|
17674
|
+
const untracked = [];
|
|
17675
|
+
for (const line of status_short.split(`
|
|
17676
|
+
`).filter(Boolean)) {
|
|
17677
|
+
const code = line.slice(0, 2);
|
|
17678
|
+
const file = line.slice(3);
|
|
17679
|
+
if (code === "??") {
|
|
17680
|
+
untracked.push(file);
|
|
17681
|
+
} else {
|
|
17682
|
+
if (code[0] !== " " && code[0] !== "?")
|
|
17683
|
+
staged.push(file);
|
|
17684
|
+
if (code[1] !== " " && code[1] !== "?")
|
|
17685
|
+
unstaged.push(file);
|
|
17686
|
+
}
|
|
17687
|
+
}
|
|
17688
|
+
const pathArgs = paths.length ? ["--", ...paths] : [];
|
|
17689
|
+
const diff_stat = runHere(["diff", "--stat", ...pathArgs]);
|
|
17690
|
+
const cached_stat = runHere(["diff", "--cached", "--stat", ...pathArgs]);
|
|
17691
|
+
const stagedSet = new Set(staged);
|
|
17692
|
+
const unstagedSet = new Set(unstaged);
|
|
17693
|
+
const partial_staged = [...stagedSet].filter((f) => unstagedSet.has(f));
|
|
17694
|
+
return {
|
|
17695
|
+
workspace_root: cwd,
|
|
17696
|
+
branch,
|
|
17697
|
+
status_short,
|
|
17698
|
+
staged,
|
|
17699
|
+
unstaged,
|
|
17700
|
+
untracked,
|
|
17701
|
+
diff_stat: [diff_stat, cached_stat].filter(Boolean).join(`
|
|
17702
|
+
`),
|
|
17703
|
+
partial_staged: partial_staged.length > 0,
|
|
17704
|
+
partial_staged_files: partial_staged,
|
|
17705
|
+
...failure ? { stderr: failure.stderr, exitCode: failure.exitCode } : {}
|
|
17706
|
+
};
|
|
17707
|
+
};
|
|
17708
|
+
|
|
17709
|
+
// packages/workit-core/src/core/config.ts
|
|
17710
|
+
import {
|
|
17711
|
+
copyFileSync,
|
|
17712
|
+
cpSync,
|
|
17713
|
+
existsSync as existsSync4,
|
|
17714
|
+
mkdirSync as mkdirSync2,
|
|
17715
|
+
readFileSync as readFileSync4,
|
|
17716
|
+
readdirSync as readdirSync3,
|
|
17717
|
+
writeFileSync as writeFileSync2
|
|
17718
|
+
} from "node:fs";
|
|
17719
|
+
import os from "node:os";
|
|
17720
|
+
import path7 from "node:path";
|
|
17721
|
+
|
|
17722
|
+
// packages/workit-core/src/core/boundary.ts
|
|
17723
|
+
import { statSync } from "node:fs";
|
|
17724
|
+
var EVENT = {
|
|
17725
|
+
initialization: "initialization",
|
|
17726
|
+
provenance: "provenance",
|
|
17727
|
+
assets: "assets",
|
|
17728
|
+
configurationSource: "configuration_source",
|
|
17729
|
+
hooks: "hooks",
|
|
17730
|
+
mcpConnection: "mcp_connection",
|
|
17731
|
+
migration: "migration",
|
|
17732
|
+
installSteps: "install_steps",
|
|
17733
|
+
uncaughtFailure: "uncaught_failure",
|
|
17734
|
+
toolsFailed: "tools_failed",
|
|
17735
|
+
doctor: "doctor"
|
|
17736
|
+
};
|
|
17737
|
+
var errorDetail = (err) => {
|
|
17738
|
+
if (err instanceof Error) {
|
|
17739
|
+
return { error_name: err.name, error: err.message };
|
|
17740
|
+
}
|
|
17741
|
+
return { error_name: "unknown", error: String(err) };
|
|
17742
|
+
};
|
|
17743
|
+
var markSourcesLoaded = (files, loadedAt = Date.now()) => ({
|
|
17744
|
+
loadedAt,
|
|
17745
|
+
files: [...files]
|
|
17746
|
+
});
|
|
17747
|
+
var changedSourcesSinceLoad = (marker) => {
|
|
17748
|
+
const changed = [];
|
|
17749
|
+
for (const file of marker.files) {
|
|
17750
|
+
try {
|
|
17751
|
+
if (statSync(file).mtimeMs > marker.loadedAt)
|
|
17752
|
+
changed.push(file);
|
|
17753
|
+
} catch {}
|
|
17754
|
+
}
|
|
17755
|
+
return changed;
|
|
17756
|
+
};
|
|
17757
|
+
|
|
17758
|
+
// packages/workit-core/src/core/config.ts
|
|
17759
|
+
var diagnosticLogger;
|
|
17760
|
+
var PRESETS = {
|
|
17761
|
+
gitflow: {
|
|
17762
|
+
allowed: ["feature/*", "bugfix/*", "hotfix/*", "release/*"],
|
|
17763
|
+
protected: ["main", "develop", "master", "prod", "production"]
|
|
17764
|
+
},
|
|
17765
|
+
"github-flow": { allowed: ["*"], protected: ["main"] },
|
|
17766
|
+
"trunk-based": { allowed: ["*"], protected: ["main"] },
|
|
17767
|
+
custom: { allowed: [], protected: [] }
|
|
17768
|
+
};
|
|
17769
|
+
var mergePreset = (preset, input = {}, current = {
|
|
17770
|
+
branchPolicy: { preset, allowed: [], protected: [] }
|
|
17771
|
+
}) => {
|
|
17772
|
+
const defs = PRESETS[preset];
|
|
17773
|
+
return {
|
|
17774
|
+
preset,
|
|
17775
|
+
allowed: preset === "custom" ? input.allowed ?? current.branchPolicy.allowed : [...defs.allowed],
|
|
17776
|
+
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
17777
|
+
};
|
|
17778
|
+
};
|
|
17779
|
+
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path7.join(process.env.XDG_CONFIG_HOME || path7.join(os.homedir(), ".config"), "workit");
|
|
17780
|
+
var migratedDir = null;
|
|
17781
|
+
var migrationFailed = false;
|
|
17782
|
+
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
17783
|
+
if (migratedDir === dir)
|
|
17784
|
+
return dir;
|
|
17785
|
+
if (process.env.WORKFLOW_TOOLKIT_CONFIG || process.env.WORKFLOW_TOOLKIT_CONFIG_DIR) {
|
|
17786
|
+
migratedDir = dir;
|
|
17787
|
+
return dir;
|
|
17788
|
+
}
|
|
17789
|
+
const legacy = path7.join(process.env.XDG_CONFIG_HOME || path7.join(os.homedir(), ".config"), "workflow-toolkit");
|
|
17790
|
+
if (!existsSync4(legacy)) {
|
|
17791
|
+
migratedDir = dir;
|
|
17792
|
+
return dir;
|
|
17793
|
+
}
|
|
17794
|
+
if (!migrationFailed && existsSync4(dir)) {
|
|
17795
|
+
migratedDir = dir;
|
|
17796
|
+
return dir;
|
|
17797
|
+
}
|
|
17798
|
+
migrationFailed = false;
|
|
17799
|
+
mkdirSync2(dir, { recursive: true });
|
|
17800
|
+
diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
|
|
17801
|
+
for (const entry of readdirSync3(legacy, { withFileTypes: true })) {
|
|
17802
|
+
const src = path7.join(legacy, entry.name);
|
|
17803
|
+
const dest = path7.join(dir, entry.name);
|
|
17804
|
+
if (existsSync4(dest))
|
|
17805
|
+
continue;
|
|
17806
|
+
try {
|
|
17807
|
+
if (entry.isDirectory())
|
|
17808
|
+
cpSync(src, dest, { recursive: true });
|
|
17809
|
+
else if (entry.isFile())
|
|
17810
|
+
copyFileSync(src, dest);
|
|
17811
|
+
} catch (err) {
|
|
17812
|
+
migrationFailed = true;
|
|
17813
|
+
diagnosticLogger?.warn(EVENT.migration, { from: src, ok: false, ...errorDetail(err) });
|
|
17814
|
+
console.warn(`[workit] config migration: a file could not be copied to ${dir}; it will be retried on the next run`);
|
|
17815
|
+
}
|
|
17816
|
+
}
|
|
17817
|
+
if (!migrationFailed)
|
|
17818
|
+
migratedDir = dir;
|
|
17819
|
+
return dir;
|
|
17820
|
+
};
|
|
17821
|
+
var configDir = () => ensureConfigDir();
|
|
17822
|
+
var LOCALE_RE = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
|
|
17823
|
+
var DEFAULTS = {
|
|
17824
|
+
locale: "en",
|
|
17825
|
+
localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
|
|
17826
|
+
timezone: "America/Santiago",
|
|
17827
|
+
branchPolicy: {
|
|
17828
|
+
preset: "gitflow",
|
|
17829
|
+
allowed: [...PRESETS.gitflow.allowed],
|
|
17830
|
+
protected: [...PRESETS.gitflow.protected]
|
|
17831
|
+
},
|
|
17832
|
+
commitPolicy: { preset: "conventional" }
|
|
17833
|
+
};
|
|
17834
|
+
var readSafe = (p) => {
|
|
17835
|
+
try {
|
|
17836
|
+
return readFileSync4(p, "utf8");
|
|
17837
|
+
} catch {
|
|
17838
|
+
return null;
|
|
17839
|
+
}
|
|
17840
|
+
};
|
|
17841
|
+
var isConfigObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17842
|
+
var parseConfigResult = (raw, file) => {
|
|
17843
|
+
if (raw === null)
|
|
17844
|
+
return { status: "missing", path: file };
|
|
17845
|
+
let parsed;
|
|
17846
|
+
try {
|
|
17847
|
+
parsed = JSON.parse(raw);
|
|
17848
|
+
} catch {
|
|
17849
|
+
return { status: "malformed", path: file, error: `${file} is not valid JSON` };
|
|
17850
|
+
}
|
|
17851
|
+
if (!isConfigObject(parsed)) {
|
|
17852
|
+
return { status: "malformed", path: file, error: `${file} is not a JSON object` };
|
|
17853
|
+
}
|
|
17854
|
+
const input = parsed;
|
|
17855
|
+
const locale = LOCALE_RE.test(String(input.locale ?? "")) ? input.locale : DEFAULTS.locale;
|
|
17856
|
+
const preset = Object.hasOwn(PRESETS, input.branchPolicy?.preset) ? input.branchPolicy?.preset : "gitflow";
|
|
17857
|
+
const commitPreset = COMMIT_PRESETS.includes(String(input.commitPolicy?.preset ?? "")) ? input.commitPolicy?.preset : "conventional";
|
|
17858
|
+
return {
|
|
17859
|
+
status: "valid",
|
|
17860
|
+
path: file,
|
|
17861
|
+
config: {
|
|
17862
|
+
locale,
|
|
17863
|
+
localeOptions: Array.isArray(input.localeOptions) ? input.localeOptions : DEFAULTS.localeOptions,
|
|
17864
|
+
timezone: input.timezone ?? DEFAULTS.timezone,
|
|
17865
|
+
branchPolicy: mergePreset(preset, {
|
|
17866
|
+
allowed: Array.isArray(input.branchPolicy?.allowed) ? input.branchPolicy.allowed : undefined,
|
|
17867
|
+
protectedNames: Array.isArray(input.branchPolicy?.protected) ? input.branchPolicy.protected : undefined
|
|
17868
|
+
}, DEFAULTS),
|
|
17869
|
+
commitPolicy: {
|
|
17870
|
+
preset: commitPreset,
|
|
17871
|
+
...typeof input.commitPolicy?.pattern === "string" ? { pattern: input.commitPolicy.pattern } : {}
|
|
17872
|
+
}
|
|
17873
|
+
}
|
|
17874
|
+
};
|
|
17875
|
+
};
|
|
17876
|
+
var readConfigTyped = (dir) => {
|
|
17877
|
+
const file = path7.join(dir ?? configDir(), "config.json");
|
|
17878
|
+
return parseConfigResult(readSafe(file), file);
|
|
17879
|
+
};
|
|
17880
|
+
var readConfig = () => {
|
|
17881
|
+
const result = readConfigTyped();
|
|
17882
|
+
if (result.status === "malformed")
|
|
17883
|
+
throw new Error(result.error);
|
|
17884
|
+
return result.config ?? DEFAULTS;
|
|
17885
|
+
};
|
|
17886
|
+
var resolveBranchPolicy = (config, workspace) => {
|
|
17887
|
+
const wp = workspace?.branchPolicy ?? {};
|
|
17888
|
+
const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
|
|
17889
|
+
const merged = mergePreset(preset, {
|
|
17890
|
+
allowed: wp.allowed,
|
|
17891
|
+
protectedNames: wp.protected
|
|
17892
|
+
}, config);
|
|
17893
|
+
const allowed = merged.allowed.map((p) => new RegExp(`^${p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"));
|
|
17894
|
+
return {
|
|
17895
|
+
preset,
|
|
17896
|
+
allowed,
|
|
17897
|
+
protected: new Set(merged.protected.map((p) => p.toLowerCase())),
|
|
17898
|
+
integration: wp.integration === "merge" ? "merge" : "pr",
|
|
17899
|
+
defaultTargetBranch: preset === "github-flow" ? "main" : preset === "trunk-based" ? "master" : "develop"
|
|
17900
|
+
};
|
|
17901
|
+
};
|
|
17902
|
+
var COMMIT_PRESETS = [
|
|
17903
|
+
"conventional",
|
|
17904
|
+
"gitmoji",
|
|
17905
|
+
"ticket-prefix",
|
|
17906
|
+
"freeform",
|
|
17907
|
+
"custom",
|
|
17908
|
+
"auto"
|
|
17909
|
+
];
|
|
17910
|
+
|
|
17911
|
+
// packages/workit-core/src/core/workspaces.ts
|
|
17912
|
+
import { readFileSync as readFileSync5, realpathSync as realpathSync4 } from "node:fs";
|
|
17913
|
+
import path8 from "node:path";
|
|
17914
|
+
var readWorkspacesResult = (dir = configDir()) => {
|
|
17915
|
+
const file = path8.join(dir, "workspaces.json");
|
|
17916
|
+
let raw;
|
|
17917
|
+
try {
|
|
17918
|
+
raw = readFileSync5(file, "utf8");
|
|
17919
|
+
} catch {
|
|
17920
|
+
return { status: "missing", path: file, entries: [] };
|
|
17921
|
+
}
|
|
17922
|
+
let parsed;
|
|
17923
|
+
try {
|
|
17924
|
+
parsed = JSON.parse(raw);
|
|
17925
|
+
} catch {
|
|
17926
|
+
return { status: "malformed", path: file, entries: [], error: `${file} is not valid JSON` };
|
|
17927
|
+
}
|
|
17928
|
+
if (!isConfigObject(parsed)) {
|
|
17929
|
+
return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
|
|
17930
|
+
}
|
|
17931
|
+
const list = parsed.workspaces;
|
|
17932
|
+
return {
|
|
17933
|
+
status: "valid",
|
|
17934
|
+
path: file,
|
|
17935
|
+
entries: Array.isArray(list) ? list : []
|
|
17936
|
+
};
|
|
17937
|
+
};
|
|
17938
|
+
var loadWorkspacesFrom = (dir) => readWorkspacesResult(dir).entries;
|
|
17939
|
+
var globToRegExp = (glob) => {
|
|
17940
|
+
let out = "";
|
|
17941
|
+
for (let i = 0;i < glob.length; i++) {
|
|
17942
|
+
const c = glob[i];
|
|
17943
|
+
if (c === "*") {
|
|
17944
|
+
if (glob[i + 1] === "*") {
|
|
17945
|
+
if (glob[i + 2] === "/") {
|
|
17946
|
+
if (out === "")
|
|
17947
|
+
out += "/?";
|
|
17948
|
+
out += "(?:[^/]+/)*";
|
|
17949
|
+
i += 2;
|
|
17950
|
+
} else {
|
|
17951
|
+
if (i + 2 >= glob.length) {
|
|
17952
|
+
if (out.endsWith("/")) {
|
|
17953
|
+
out = out.slice(0, -1);
|
|
17954
|
+
out += "(?:/.*)?";
|
|
17955
|
+
} else {
|
|
17956
|
+
out += ".*";
|
|
17957
|
+
}
|
|
17958
|
+
} else {
|
|
17959
|
+
out += ".*";
|
|
17960
|
+
}
|
|
17961
|
+
i++;
|
|
17962
|
+
}
|
|
17963
|
+
} else {
|
|
17964
|
+
out += "[^/]*";
|
|
17965
|
+
}
|
|
17966
|
+
} else {
|
|
17967
|
+
out += c.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
17968
|
+
}
|
|
17969
|
+
}
|
|
17970
|
+
return new RegExp(`^${out}$`);
|
|
17971
|
+
};
|
|
17972
|
+
var matchWorkspace = (glob, target) => globToRegExp(glob.replaceAll("\\", "/")).test(target.replaceAll("\\", "/"));
|
|
17973
|
+
var realpathOf = (p) => {
|
|
17974
|
+
const real = realpathSync4.native ?? realpathSync4;
|
|
17975
|
+
try {
|
|
17976
|
+
return real(p);
|
|
17977
|
+
} catch {
|
|
17978
|
+
return p;
|
|
17979
|
+
}
|
|
17980
|
+
};
|
|
17981
|
+
var canonicalGlob = (glob) => {
|
|
17982
|
+
const m = /[*?[\]{]/.exec(glob);
|
|
17983
|
+
const prefix = m ? glob.slice(0, m.index) : glob;
|
|
17984
|
+
const rest = m ? glob.slice(m.index) : "";
|
|
17985
|
+
if (!prefix)
|
|
17986
|
+
return glob;
|
|
17987
|
+
const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
|
|
17988
|
+
return real + (prefix.endsWith("/") ? "/" : "") + rest;
|
|
17989
|
+
};
|
|
17990
|
+
var resolveWorkspaceFrom = (cwd, dir) => {
|
|
17991
|
+
const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
|
|
17992
|
+
for (const entry of loadWorkspacesFrom(dir)) {
|
|
17993
|
+
if (!entry || typeof entry !== "object")
|
|
17994
|
+
continue;
|
|
17995
|
+
const ws = entry;
|
|
17996
|
+
if (typeof ws.glob !== "string" || !ws.glob)
|
|
17997
|
+
continue;
|
|
17998
|
+
const glob = ws.glob.replaceAll("\\", "/");
|
|
17999
|
+
const canonical = canonicalGlob(glob);
|
|
18000
|
+
for (const target of targets) {
|
|
18001
|
+
if (matchWorkspace(glob, target))
|
|
18002
|
+
return ws;
|
|
18003
|
+
if (canonical !== glob && matchWorkspace(canonical, target))
|
|
18004
|
+
return ws;
|
|
18005
|
+
}
|
|
18006
|
+
}
|
|
18007
|
+
return null;
|
|
18008
|
+
};
|
|
18009
|
+
var resolveWorkspace = (cwd) => resolveWorkspaceFrom(cwd, configDir());
|
|
18010
|
+
|
|
18011
|
+
// packages/workit-core/src/core/vcs-config.ts
|
|
18012
|
+
import fs7 from "node:fs";
|
|
18013
|
+
import path9 from "node:path";
|
|
18014
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
18015
|
+
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
18016
|
+
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path9.join(configDir(), "vcs.json");
|
|
18017
|
+
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
18018
|
+
var remoteProvider = (cwd) => {
|
|
18019
|
+
const r = spawnSync2("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
18020
|
+
if (r.status !== 0)
|
|
18021
|
+
return null;
|
|
18022
|
+
const url = (r.stdout ?? "").trim();
|
|
18023
|
+
if (/github\.com[:/]/.test(url))
|
|
18024
|
+
return "github";
|
|
18025
|
+
if (/gitlab\.com[:/]/.test(url))
|
|
18026
|
+
return "gitlab";
|
|
18027
|
+
return null;
|
|
18028
|
+
};
|
|
18029
|
+
var readVcsConfig = () => {
|
|
18030
|
+
const file = vcsConfigPath();
|
|
18031
|
+
let raw;
|
|
18032
|
+
try {
|
|
18033
|
+
raw = fs7.readFileSync(file, "utf8");
|
|
18034
|
+
} catch {
|
|
18035
|
+
return { status: "missing", path: file, config: {} };
|
|
18036
|
+
}
|
|
18037
|
+
let parsed;
|
|
18038
|
+
try {
|
|
18039
|
+
parsed = JSON.parse(raw);
|
|
18040
|
+
} catch {
|
|
18041
|
+
return { status: "malformed", path: file, config: {}, error: `${file} is not valid JSON` };
|
|
18042
|
+
}
|
|
18043
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
18044
|
+
return { status: "valid", path: file, config: parsed };
|
|
18045
|
+
}
|
|
18046
|
+
return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
|
|
18047
|
+
};
|
|
18048
|
+
function vcsConfig(mode, cwd) {
|
|
18049
|
+
const ws = resolveWorkspace(vcsCwd(cwd));
|
|
18050
|
+
const wsVcs = ws?.vcs ?? {};
|
|
18051
|
+
const wsYt = ws?.youtrack ?? {};
|
|
18052
|
+
const wsIssues = ws?.issues ?? {};
|
|
18053
|
+
const { status: cfgStatus, path: cfgPath, config: cfg, error: cfgError } = readVcsConfig();
|
|
18054
|
+
const root = vcsCwd(cwd);
|
|
18055
|
+
const determinateRoot = cwd !== undefined || process.env.WORKFLOW_WORKSPACE_ROOT !== undefined;
|
|
18056
|
+
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
18057
|
+
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
18058
|
+
const wp = ws?.branchPolicy ?? {};
|
|
18059
|
+
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
18060
|
+
const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
|
|
18061
|
+
const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
|
|
18062
|
+
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
18063
|
+
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
18064
|
+
let issuesProvider = null;
|
|
18065
|
+
let linkOnPr = null;
|
|
18066
|
+
if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
|
|
18067
|
+
issuesProvider = "github";
|
|
18068
|
+
linkOnPr = typeof wsIssues.link_on_pr === "boolean" ? wsIssues.link_on_pr : null;
|
|
18069
|
+
}
|
|
18070
|
+
if (mode === "resolve") {
|
|
18071
|
+
if (cfgStatus === "malformed")
|
|
18072
|
+
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
18073
|
+
return {
|
|
18074
|
+
ok: true,
|
|
18075
|
+
workspace_name: ws?.name ?? null,
|
|
18076
|
+
provider,
|
|
18077
|
+
defaultTargetBranch: defaultTarget,
|
|
18078
|
+
link_issues: linkIssues,
|
|
18079
|
+
youtrack_base_url: youtrackBaseUrl,
|
|
18080
|
+
issues_provider: issuesProvider,
|
|
18081
|
+
link_on_pr: linkOnPr
|
|
18082
|
+
};
|
|
18083
|
+
}
|
|
18084
|
+
if (cfgStatus === "malformed") {
|
|
18085
|
+
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
18086
|
+
}
|
|
18087
|
+
if (cfgStatus === "missing") {
|
|
18088
|
+
return { ok: false, error: `vcs.json is missing: ${cfgPath}`, configPath: cfgPath };
|
|
18089
|
+
}
|
|
18090
|
+
if (provider === null) {
|
|
18091
|
+
return {
|
|
18092
|
+
ok: false,
|
|
18093
|
+
error: `no vcs provider configured (set vcs.provider in ${cfgPath}, match a workspace entry, or run inside a checkout with a recognized origin remote)`,
|
|
18094
|
+
configPath: cfgPath
|
|
18095
|
+
};
|
|
18096
|
+
}
|
|
18097
|
+
const prov = cfg[provider] ?? {};
|
|
18098
|
+
const wsTokenFile = typeof wsVcs.tokenFile === "string" && wsVcs.tokenFile.trim() !== "" ? wsVcs.tokenFile : null;
|
|
18099
|
+
const tokenFile = String(wsTokenFile ?? prov.tokenFile ?? path9.join(configDir(), `${provider}.token`));
|
|
18100
|
+
const tokenPath = path9.resolve(tokenFile);
|
|
18101
|
+
let tokenOk = false;
|
|
18102
|
+
if (fs7.existsSync(tokenPath)) {
|
|
18103
|
+
const token = fs7.readFileSync(tokenPath, "utf8").trim();
|
|
18104
|
+
const placeholder = !token || token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER);
|
|
18105
|
+
tokenOk = !placeholder;
|
|
18106
|
+
}
|
|
18107
|
+
const out = {
|
|
18108
|
+
ok: true,
|
|
18109
|
+
configPath: path9.resolve(cfgPath),
|
|
18110
|
+
provider,
|
|
18111
|
+
defaultTargetBranch: defaultTarget,
|
|
18112
|
+
pr: cfg.pr ?? {},
|
|
18113
|
+
tokenPath,
|
|
18114
|
+
tokenPresent: fs7.existsSync(tokenPath),
|
|
18115
|
+
tokenReady: tokenOk,
|
|
18116
|
+
workspace_name: ws?.name ?? null,
|
|
18117
|
+
link_issues: linkIssues,
|
|
18118
|
+
youtrack_base_url: youtrackBaseUrl,
|
|
18119
|
+
issues_provider: issuesProvider,
|
|
18120
|
+
link_on_pr: linkOnPr
|
|
18121
|
+
};
|
|
18122
|
+
if (provider === "gitlab") {
|
|
18123
|
+
out.gitlab = {
|
|
18124
|
+
host: prov.host ?? "gitlab.com",
|
|
18125
|
+
apiUrl: prov.apiUrl ?? "https://gitlab.com/api/v4"
|
|
18126
|
+
};
|
|
18127
|
+
} else if (provider === "github") {
|
|
18128
|
+
out.github = { host: prov.host ?? "github.com" };
|
|
18129
|
+
}
|
|
18130
|
+
if (mode === "summary")
|
|
18131
|
+
delete out.tokenPath;
|
|
18132
|
+
return out;
|
|
18133
|
+
}
|
|
18134
|
+
function mergedPrStyle(limit = 6, cwd) {
|
|
18135
|
+
const cfg = vcsConfig("load", cwd);
|
|
18136
|
+
if (!cfg.ok || !cfg.tokenReady)
|
|
18137
|
+
return { ok: false, error: "vcs not configured" };
|
|
18138
|
+
const provider = cfg.provider;
|
|
18139
|
+
const token = fs7.readFileSync(cfg.tokenPath, "utf8").trim();
|
|
18140
|
+
const examples = [];
|
|
18141
|
+
const descInfo = (desc, caseInsensitiveNotes = false) => ({
|
|
18142
|
+
hasNotesSection: caseInsensitiveNotes ? /##\s*notes/i.test(desc) : /##\s*Notes/.test(desc),
|
|
18143
|
+
sections: desc.split(`
|
|
18144
|
+
`).filter((l) => l.startsWith("## ")).map((l) => l.trim()),
|
|
18145
|
+
descriptionPreview: desc.slice(0, 600)
|
|
18146
|
+
});
|
|
18147
|
+
if (provider === "gitlab") {
|
|
18148
|
+
const remote = spawnSync2("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
18149
|
+
if (remote.status !== 0)
|
|
18150
|
+
return { ok: false, error: "no origin remote" };
|
|
18151
|
+
const url = (remote.stdout ?? "").trim();
|
|
18152
|
+
const m = /gitlab\.com[:/](.+?)(?:\.git)?$/.exec(url);
|
|
18153
|
+
if (!m)
|
|
18154
|
+
return { ok: false, error: "not a gitlab.com origin" };
|
|
18155
|
+
const project = m[1];
|
|
18156
|
+
const env = { ...process.env, GITLAB_TOKEN: token };
|
|
18157
|
+
const run = (args) => spawnSync2("glab", ["api", ...args], { cwd, encoding: "utf8", env });
|
|
18158
|
+
let r = run([
|
|
18159
|
+
`projects/${project.replaceAll("/", "%2F")}/merge_requests?state=merged&per_page=${limit}&order_by=updated_at&sort=desc`
|
|
18160
|
+
]);
|
|
18161
|
+
if (r.status !== 0) {
|
|
18162
|
+
r = run([`merge_requests?state=merged&per_page=${limit}&order_by=updated_at&sort=desc`]);
|
|
18163
|
+
}
|
|
18164
|
+
if (r.status !== 0)
|
|
18165
|
+
return { ok: false, error: "could not list merge requests" };
|
|
18166
|
+
for (const mr of JSON.parse(r.stdout ?? "[]")) {
|
|
18167
|
+
const desc = String(mr.description ?? "").trim();
|
|
18168
|
+
examples.push({
|
|
18169
|
+
title: mr.title,
|
|
18170
|
+
url: mr.web_url,
|
|
18171
|
+
squash: mr.squash,
|
|
18172
|
+
...descInfo(desc, true)
|
|
18173
|
+
});
|
|
18174
|
+
}
|
|
18175
|
+
} else if (provider === "github") {
|
|
18176
|
+
const r = spawnSync2("gh", ["pr", "list", "--state", "merged", "--limit", String(limit), "--json", "title,url,body"], { cwd, encoding: "utf8", env: { ...process.env, GH_TOKEN: token } });
|
|
18177
|
+
if (r.status !== 0)
|
|
18178
|
+
return { ok: false, error: "could not list pull requests" };
|
|
18179
|
+
for (const pr of JSON.parse(r.stdout ?? "[]")) {
|
|
18180
|
+
const desc = String(pr.body ?? "").trim();
|
|
18181
|
+
examples.push({ title: pr.title, url: pr.url, ...descInfo(desc) });
|
|
18182
|
+
}
|
|
18183
|
+
}
|
|
18184
|
+
return {
|
|
18185
|
+
ok: true,
|
|
18186
|
+
provider,
|
|
18187
|
+
count: examples.length,
|
|
18188
|
+
styleHints: [
|
|
18189
|
+
"Prefer ## Summary bullets + ## Validation or ## Test plan only",
|
|
18190
|
+
"Do not add ## Notes with branch names, commit counts, or diff stats",
|
|
18191
|
+
"Do not paste commit log or diff stat into the body"
|
|
18192
|
+
],
|
|
18193
|
+
examples
|
|
18194
|
+
};
|
|
18195
|
+
}
|
|
18196
|
+
|
|
18197
|
+
// packages/workit-core/src/core/branch.ts
|
|
18198
|
+
var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig(), resolveWorkspace(workspaceRoot));
|
|
18199
|
+
// packages/workit-core/src/core/external-action.ts
|
|
18200
|
+
var externalActionSchema = discriminatedUnion("operation", [
|
|
18201
|
+
object({
|
|
18202
|
+
operation: literal("git.branch_setup"),
|
|
18203
|
+
payload: object({
|
|
18204
|
+
action: _enum(["setup", "reapply_stash"]).optional(),
|
|
18205
|
+
sdd_dir: string2().optional(),
|
|
18206
|
+
target_branch: string2().optional(),
|
|
18207
|
+
stash: _enum(["yes", "no"]).optional()
|
|
18208
|
+
}).strict()
|
|
18209
|
+
}).strict(),
|
|
18210
|
+
object({
|
|
18211
|
+
operation: literal("git.commit"),
|
|
18212
|
+
payload: object({
|
|
18213
|
+
message: string2().min(1).optional(),
|
|
18214
|
+
plan_steps: array(string2().min(1)).optional(),
|
|
18215
|
+
plan_branch: string2().min(1).optional()
|
|
18216
|
+
}).strict()
|
|
18217
|
+
}).strict(),
|
|
18218
|
+
object({
|
|
18219
|
+
operation: literal("git.push"),
|
|
18220
|
+
payload: object({ branch: string2().min(1).optional() }).strict()
|
|
18221
|
+
}).strict(),
|
|
18222
|
+
object({
|
|
18223
|
+
operation: literal("hosting.pull_request"),
|
|
18224
|
+
payload: object({
|
|
18225
|
+
title: string2().min(1),
|
|
18226
|
+
body: string2().optional(),
|
|
18227
|
+
draft: boolean2().optional(),
|
|
18228
|
+
target_branch: string2().optional(),
|
|
18229
|
+
babysit: boolean2().optional()
|
|
18230
|
+
}).strict()
|
|
18231
|
+
}).strict(),
|
|
18232
|
+
object({
|
|
18233
|
+
operation: literal("youtrack.update"),
|
|
18234
|
+
payload: object({
|
|
18235
|
+
issueId: string2().min(1),
|
|
18236
|
+
markdown: string2().min(1),
|
|
18237
|
+
minutes: number2().positive().optional()
|
|
18238
|
+
}).strict()
|
|
18239
|
+
}).strict(),
|
|
18240
|
+
object({
|
|
18241
|
+
operation: literal("youtrack.time"),
|
|
18242
|
+
payload: object({
|
|
18243
|
+
issueId: string2().min(1),
|
|
18244
|
+
minutes: number2().positive(),
|
|
18245
|
+
text: string2().optional(),
|
|
18246
|
+
dateMs: number2().finite().optional()
|
|
18247
|
+
}).strict()
|
|
18248
|
+
}).strict(),
|
|
18249
|
+
object({
|
|
18250
|
+
operation: literal("youtrack.meeting"),
|
|
18251
|
+
payload: object({
|
|
18252
|
+
issueId: string2().min(1),
|
|
18253
|
+
minutes: number2().positive(),
|
|
18254
|
+
text: string2().min(1)
|
|
18255
|
+
}).strict()
|
|
18256
|
+
}).strict(),
|
|
18257
|
+
object({
|
|
18258
|
+
operation: literal("changelog.apply"),
|
|
18259
|
+
payload: object({
|
|
18260
|
+
entries: union([
|
|
18261
|
+
record(string2(), array(string2())),
|
|
18262
|
+
array(object({ category: string2().min(1), text: string2().min(1) }).strict())
|
|
18263
|
+
]).optional(),
|
|
18264
|
+
path: string2().optional(),
|
|
18265
|
+
normalize_only: boolean2().optional()
|
|
18266
|
+
}).strict()
|
|
18267
|
+
}).strict(),
|
|
18268
|
+
object({
|
|
18269
|
+
operation: literal("context.read"),
|
|
18270
|
+
payload: object({
|
|
18271
|
+
kind: _enum([
|
|
18272
|
+
"git",
|
|
18273
|
+
"pr",
|
|
18274
|
+
"youtrack",
|
|
18275
|
+
"github_issue",
|
|
18276
|
+
"gitlab_issue",
|
|
18277
|
+
"changelog",
|
|
18278
|
+
"release",
|
|
18279
|
+
"affected"
|
|
18280
|
+
]),
|
|
18281
|
+
range: string2().optional(),
|
|
18282
|
+
issueId: string2().optional(),
|
|
18283
|
+
issueUrl: string2().optional(),
|
|
18284
|
+
issueRef: string2().optional(),
|
|
18285
|
+
mode: string2().optional(),
|
|
18286
|
+
specPath: string2().optional(),
|
|
18287
|
+
planPath: string2().optional()
|
|
18288
|
+
}).strict()
|
|
18289
|
+
}).strict()
|
|
18290
|
+
]);
|
|
18291
|
+
// packages/workit-core/src/core/task-engine.ts
|
|
18292
|
+
import { realpathSync as realpathSync5 } from "node:fs";
|
|
18293
|
+
|
|
18294
|
+
// packages/workit-core/src/core/policy-resolver.ts
|
|
18295
|
+
var resolverInputSchema = object({
|
|
18296
|
+
intent: intentSchema,
|
|
18297
|
+
assessment: assessmentSchema,
|
|
18298
|
+
constraints: array(constraintSchema),
|
|
18299
|
+
prior: object({
|
|
18300
|
+
decisions: array(decisionSchema),
|
|
18301
|
+
findings: array(findingSchema),
|
|
18302
|
+
requirements: array(requirementSchema)
|
|
18303
|
+
}).strict(),
|
|
18304
|
+
preferences: object({ fast: boolean2().optional(), thorough: boolean2().optional() }).strict().optional()
|
|
18305
|
+
}).strict();
|
|
18306
|
+
var compareCodeUnits3 = (left, right) => {
|
|
18307
|
+
const length = Math.min(left.length, right.length);
|
|
18308
|
+
for (let index = 0;index < length; index += 1) {
|
|
18309
|
+
const difference = left.charCodeAt(index) - right.charCodeAt(index);
|
|
18310
|
+
if (difference !== 0)
|
|
18311
|
+
return difference;
|
|
18312
|
+
}
|
|
18313
|
+
return left.length - right.length;
|
|
18314
|
+
};
|
|
18315
|
+
var stableUnique = (values) => [...new Set(values)].sort(compareCodeUnits3);
|
|
18316
|
+
var stableList = (values) => [...values].sort((left, right) => compareCodeUnits3(canonicalJson(left), canonicalJson(right)));
|
|
18317
|
+
var normalizedScope = (scope) => ({
|
|
18318
|
+
description: scope.description,
|
|
18319
|
+
paths: stableUnique(scope.paths),
|
|
18320
|
+
exclusions: stableUnique(scope.exclusions)
|
|
18321
|
+
});
|
|
18322
|
+
var normalizedRefList = (values) => stableList(values);
|
|
18323
|
+
var normalizeAssessment = (assessment) => ({
|
|
18324
|
+
facts: stableList(assessment.facts.map((fact) => ({ ...fact, refs: normalizedRefList(fact.refs) }))),
|
|
18325
|
+
signals: Object.fromEntries(Object.entries(assessment.signals).map(([name, signal]) => [
|
|
18326
|
+
name,
|
|
18327
|
+
{ ...signal, refs: normalizedRefList(signal.refs) }
|
|
18328
|
+
])),
|
|
18329
|
+
consequences: stableList(assessment.consequences.map((consequence) => ({
|
|
18330
|
+
...consequence,
|
|
18331
|
+
fact: { ...consequence.fact, refs: normalizedRefList(consequence.fact.refs) }
|
|
18332
|
+
}))),
|
|
18333
|
+
verification: stableList(assessment.verification.map((verification) => ({
|
|
18334
|
+
...verification,
|
|
18335
|
+
scope: normalizedScope(verification.scope),
|
|
18336
|
+
availableChecks: normalizedRefList(verification.availableChecks),
|
|
18337
|
+
gaps: stableUnique(verification.gaps)
|
|
18338
|
+
})))
|
|
18339
|
+
});
|
|
18340
|
+
var normalizeConstraint = (constraint) => ({
|
|
18341
|
+
...constraint,
|
|
18342
|
+
source: constraint.source,
|
|
18343
|
+
requires: stableList(constraint.requires.map((requirement) => ({
|
|
18344
|
+
...requirement,
|
|
18345
|
+
scope: normalizedScope(requirement.scope),
|
|
18346
|
+
refs: normalizedRefList(requirement.refs)
|
|
18347
|
+
})))
|
|
18348
|
+
});
|
|
18349
|
+
var normalizeDecision = (decision) => ({
|
|
18350
|
+
...decision,
|
|
18351
|
+
binding: {
|
|
18352
|
+
...decision.binding,
|
|
18353
|
+
scope: normalizedScope(decision.binding.scope),
|
|
18354
|
+
contentRefs: normalizedRefList(decision.binding.contentRefs)
|
|
18355
|
+
},
|
|
18356
|
+
requirementIds: stableUnique(decision.requirementIds)
|
|
18357
|
+
});
|
|
18358
|
+
var normalizeIntent = (intent) => ({
|
|
18359
|
+
...intent,
|
|
18360
|
+
scope: normalizedScope(intent.scope),
|
|
18361
|
+
authorityRefs: normalizedRefList(intent.authorityRefs)
|
|
18362
|
+
});
|
|
18363
|
+
var normalizePrior = (prior) => ({
|
|
18364
|
+
decisions: stableList(prior.decisions.map(normalizeDecision)),
|
|
18365
|
+
findings: stableList(prior.findings.map((finding) => ({
|
|
18366
|
+
...finding,
|
|
18367
|
+
scope: normalizedScope(finding.scope),
|
|
18368
|
+
refs: normalizedRefList(finding.refs),
|
|
18369
|
+
resolution: finding.resolution ? {
|
|
18370
|
+
...finding.resolution,
|
|
18371
|
+
evidenceIds: stableUnique(finding.resolution.evidenceIds),
|
|
18372
|
+
decisionIds: stableUnique(finding.resolution.decisionIds)
|
|
18373
|
+
} : null
|
|
18374
|
+
}))),
|
|
18375
|
+
requirements: stableList(prior.requirements.map((requirement) => ({
|
|
18376
|
+
...requirement,
|
|
18377
|
+
scope: normalizedScope(requirement.scope)
|
|
18378
|
+
})))
|
|
18379
|
+
});
|
|
18380
|
+
var invalidFields = (error) => ({
|
|
18381
|
+
fields: error.issues.map((issue) => ({
|
|
18382
|
+
path: issue.code === "unrecognized_keys" ? issue.keys.join(".") : issue.path.join("."),
|
|
18383
|
+
reason: issue.message
|
|
18384
|
+
}))
|
|
18385
|
+
});
|
|
18386
|
+
function normalizeResolverInput(input) {
|
|
18387
|
+
const parsed = resolverInputSchema.safeParse(input);
|
|
18388
|
+
if (!parsed.success)
|
|
18389
|
+
return failure("invalid_input", "resolver input is invalid", invalidFields(parsed.error));
|
|
17667
18390
|
const value = parsed.data;
|
|
17668
18391
|
const signals = value.assessment.signals;
|
|
17669
18392
|
if (signals.behaviorChange.value === true && signals.mechanicalLowRisk.value === true)
|
|
@@ -18010,6 +18733,8 @@ var applyWorkerLifecycle = (input) => {
|
|
|
18010
18733
|
if (task.data.status === "paused" && (input.state === "running" || input.state === "cancelling"))
|
|
18011
18734
|
return failure("invalid_transition", "paused task cannot run a worker");
|
|
18012
18735
|
const notStarted = input.dispatch === true;
|
|
18736
|
+
if (notStarted && entry.data.state === "stopped" && input.session === null)
|
|
18737
|
+
return success(task.data.revision, workspace.data.revision, entry);
|
|
18013
18738
|
if (notStarted && (input.state !== "stopped" || input.session !== null))
|
|
18014
18739
|
return failure("invalid_input", "a never-dispatched worker stops with no session");
|
|
18015
18740
|
if (notStarted && entry.data.session !== null)
|
|
@@ -18041,7 +18766,7 @@ var applyWorkerLifecycle = (input) => {
|
|
|
18041
18766
|
return success(task.data.revision, workspace.data.revision, entry);
|
|
18042
18767
|
const changed = input.store.mutateTaskAndWorkspace({
|
|
18043
18768
|
taskId: task.data.id,
|
|
18044
|
-
|
|
18769
|
+
expectedRevision: input.expectedRevision,
|
|
18045
18770
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
18046
18771
|
now: input.now,
|
|
18047
18772
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -18089,90 +18814,22 @@ var importedProvenance = (context) => ({
|
|
|
18089
18814
|
receipts: []
|
|
18090
18815
|
});
|
|
18091
18816
|
var portableTask = (task) => {
|
|
18092
|
-
const
|
|
18093
|
-
|
|
18094
|
-
|
|
18095
|
-
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18104
|
-
|
|
18105
|
-
|
|
18106
|
-
for (const entry of
|
|
18107
|
-
entry.
|
|
18108
|
-
for (const worker of clone.workers)
|
|
18109
|
-
worker.data.session = null;
|
|
18110
|
-
clone.intent = {
|
|
18111
|
-
...clone.intent,
|
|
18112
|
-
data: { ...clone.intent.data, authorityRefs: portableRefs(clone.intent.data.authorityRefs) }
|
|
18113
|
-
};
|
|
18114
|
-
clone.constraints = clone.constraints.flatMap((constraint) => {
|
|
18115
|
-
const source = portableRef(constraint.source);
|
|
18116
|
-
return source ? [
|
|
18117
|
-
{
|
|
18118
|
-
...constraint,
|
|
18119
|
-
source,
|
|
18120
|
-
requires: constraint.requires.map((requirement) => ({
|
|
18121
|
-
...requirement,
|
|
18122
|
-
refs: portableRefs(requirement.refs)
|
|
18123
|
-
}))
|
|
18124
|
-
}
|
|
18125
|
-
] : [];
|
|
18126
|
-
});
|
|
18127
|
-
clone.assessments = clone.assessments.map((entry) => ({
|
|
18128
|
-
...entry,
|
|
18129
|
-
data: {
|
|
18130
|
-
...entry.data,
|
|
18131
|
-
facts: entry.data.facts.map(portableFact),
|
|
18132
|
-
signals: Object.fromEntries(Object.entries(entry.data.signals).map(([name, signal]) => [name, portableSignal(signal)])),
|
|
18133
|
-
consequences: entry.data.consequences.map((consequence) => ({
|
|
18134
|
-
...consequence,
|
|
18135
|
-
fact: portableFact(consequence.fact)
|
|
18136
|
-
})),
|
|
18137
|
-
verification: entry.data.verification.map((verification) => ({
|
|
18138
|
-
...verification,
|
|
18139
|
-
availableChecks: portableRefs(verification.availableChecks)
|
|
18140
|
-
}))
|
|
18141
|
-
}
|
|
18142
|
-
}));
|
|
18143
|
-
clone.progress = {
|
|
18144
|
-
...clone.progress,
|
|
18145
|
-
blockers: clone.progress.blockers.map((blocker) => ({
|
|
18146
|
-
...blocker,
|
|
18147
|
-
refs: portableRefs(blocker.refs)
|
|
18148
|
-
}))
|
|
18149
|
-
};
|
|
18150
|
-
clone.evidence = clone.evidence.map((entry) => ({
|
|
18151
|
-
...entry,
|
|
18152
|
-
data: {
|
|
18153
|
-
...entry.data,
|
|
18154
|
-
refs: portableRefs(entry.data.refs),
|
|
18155
|
-
reviewContext: portableRef(entry.data.reviewContext)
|
|
18156
|
-
}
|
|
18157
|
-
}));
|
|
18158
|
-
clone.decisions = clone.decisions.map((entry) => ({
|
|
18159
|
-
...entry,
|
|
18160
|
-
data: {
|
|
18161
|
-
...entry.data,
|
|
18162
|
-
consumption: entry.data.consumption ? portableRef(entry.data.consumption.actionRef) ? {
|
|
18163
|
-
...entry.data.consumption,
|
|
18164
|
-
actionRef: portableRef(entry.data.consumption.actionRef)
|
|
18165
|
-
} : null : null,
|
|
18166
|
-
binding: {
|
|
18167
|
-
...entry.data.binding,
|
|
18168
|
-
contentRefs: portableRefs(entry.data.binding.contentRefs)
|
|
18169
|
-
}
|
|
18170
|
-
}
|
|
18171
|
-
}));
|
|
18172
|
-
clone.findings = clone.findings.map((entry) => ({
|
|
18173
|
-
...entry,
|
|
18174
|
-
data: { ...entry.data, refs: portableRefs(entry.data.refs) }
|
|
18175
|
-
}));
|
|
18817
|
+
const stripped = rewriteRecordRefs(task, taskRecordSchema, portableRef);
|
|
18818
|
+
if (typeof stripped !== "object" || stripped === null || Array.isArray(stripped))
|
|
18819
|
+
throw new TypeError("portable task rewrite produced a non-record");
|
|
18820
|
+
const clone = structuredClone(stripped);
|
|
18821
|
+
const demote = (facts, signals, consequences) => {
|
|
18822
|
+
for (const fact of facts)
|
|
18823
|
+
Object.assign(fact, portableFact(fact));
|
|
18824
|
+
for (const name of Object.keys(signals)) {
|
|
18825
|
+
const signal = signals[name];
|
|
18826
|
+
Object.assign(signal, portableSignal(signal));
|
|
18827
|
+
}
|
|
18828
|
+
for (const consequence of consequences)
|
|
18829
|
+
Object.assign(consequence.fact, portableFact(consequence.fact));
|
|
18830
|
+
};
|
|
18831
|
+
for (const entry of clone.assessments)
|
|
18832
|
+
demote(entry.data.facts, entry.data.signals, entry.data.consequences);
|
|
18176
18833
|
clone.candidates = [];
|
|
18177
18834
|
return clone;
|
|
18178
18835
|
};
|
|
@@ -18197,15 +18854,13 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18197
18854
|
allocate(entry.id);
|
|
18198
18855
|
const fresh = (id) => allocate(id);
|
|
18199
18856
|
const provenance = importedProvenance(context);
|
|
18857
|
+
const remap = (ref) => mapRef(ref, ids);
|
|
18200
18858
|
const intent = {
|
|
18201
18859
|
...source.intent,
|
|
18202
18860
|
id: fresh(source.intent.id),
|
|
18203
18861
|
recordedAt: timestamp,
|
|
18204
18862
|
provenance,
|
|
18205
|
-
data:
|
|
18206
|
-
...source.intent.data,
|
|
18207
|
-
authorityRefs: source.intent.data.authorityRefs.map((ref) => mapRef(ref, ids))
|
|
18208
|
-
}
|
|
18863
|
+
data: rewriteRecordRefs(source.intent.data, intentSchema, remap)
|
|
18209
18864
|
};
|
|
18210
18865
|
const assessments = source.assessments.map((entry) => {
|
|
18211
18866
|
const data = entry.data;
|
|
@@ -18214,62 +18869,39 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18214
18869
|
id: fresh(entry.id),
|
|
18215
18870
|
recordedAt: timestamp,
|
|
18216
18871
|
provenance,
|
|
18217
|
-
data:
|
|
18218
|
-
...data,
|
|
18219
|
-
facts: data.facts.map((fact) => ({
|
|
18220
|
-
...fact,
|
|
18221
|
-
refs: fact.refs.map((ref) => mapRef(ref, ids))
|
|
18222
|
-
})),
|
|
18223
|
-
signals: Object.fromEntries(Object.entries(data.signals).map(([name, signal]) => [
|
|
18224
|
-
name,
|
|
18225
|
-
{ ...signal, refs: signal.refs.map((ref) => mapRef(ref, ids)) }
|
|
18226
|
-
])),
|
|
18227
|
-
consequences: data.consequences.map((consequence) => ({
|
|
18228
|
-
...consequence,
|
|
18229
|
-
fact: {
|
|
18230
|
-
...consequence.fact,
|
|
18231
|
-
refs: consequence.fact.refs.map((ref) => mapRef(ref, ids))
|
|
18232
|
-
}
|
|
18233
|
-
})),
|
|
18234
|
-
verification: data.verification.map((verification) => ({
|
|
18235
|
-
...verification,
|
|
18236
|
-
availableChecks: verification.availableChecks.map((ref) => mapRef(ref, ids))
|
|
18237
|
-
}))
|
|
18238
|
-
}
|
|
18872
|
+
data: rewriteRecordRefs(data, assessmentSchema, remap)
|
|
18239
18873
|
};
|
|
18240
18874
|
});
|
|
18241
18875
|
const evidence = source.evidence.map((entry) => ({
|
|
18242
18876
|
...entry,
|
|
18243
18877
|
id: fresh(entry.id),
|
|
18244
18878
|
recordedAt: timestamp,
|
|
18245
|
-
provenance,
|
|
18246
|
-
data:
|
|
18247
|
-
...entry.data,
|
|
18248
|
-
refs: entry.data.refs.map((ref) => mapRef(ref, ids)),
|
|
18249
|
-
reviewContext: entry.data.reviewContext ? mapRef(entry.data.reviewContext, ids) : null
|
|
18250
|
-
}
|
|
18251
|
-
}));
|
|
18252
|
-
const decisions = source.decisions.map((entry) => ({
|
|
18253
|
-
...entry,
|
|
18254
|
-
id: fresh(entry.id),
|
|
18255
|
-
recordedAt: timestamp,
|
|
18256
|
-
provenance
|
|
18879
|
+
provenance,
|
|
18880
|
+
data: rewriteRecordRefs(entry.data, evidenceSchema, remap)
|
|
18257
18881
|
}));
|
|
18258
|
-
const
|
|
18882
|
+
const decisions = source.decisions.map((entry) => ({
|
|
18259
18883
|
...entry,
|
|
18260
18884
|
id: fresh(entry.id),
|
|
18261
18885
|
recordedAt: timestamp,
|
|
18262
|
-
provenance
|
|
18263
|
-
data: {
|
|
18264
|
-
...entry.data,
|
|
18265
|
-
refs: entry.data.refs.map((ref) => mapRef(ref, ids)),
|
|
18266
|
-
resolution: entry.data.resolution ? {
|
|
18267
|
-
...entry.data.resolution,
|
|
18268
|
-
evidenceIds: entry.data.resolution.evidenceIds.map((id) => ids.get(id) ?? id),
|
|
18269
|
-
decisionIds: entry.data.resolution.decisionIds.map((id) => ids.get(id) ?? id)
|
|
18270
|
-
} : null
|
|
18271
|
-
}
|
|
18886
|
+
provenance
|
|
18272
18887
|
}));
|
|
18888
|
+
const findings = source.findings.map((entry) => {
|
|
18889
|
+
const data = rewriteRecordRefs(entry.data, findingSchema, remap);
|
|
18890
|
+
return {
|
|
18891
|
+
...entry,
|
|
18892
|
+
id: fresh(entry.id),
|
|
18893
|
+
recordedAt: timestamp,
|
|
18894
|
+
provenance,
|
|
18895
|
+
data: {
|
|
18896
|
+
...data,
|
|
18897
|
+
resolution: data.resolution ? {
|
|
18898
|
+
...data.resolution,
|
|
18899
|
+
evidenceIds: data.resolution.evidenceIds.map((id) => ids.get(id) ?? id),
|
|
18900
|
+
decisionIds: data.resolution.decisionIds.map((id) => ids.get(id) ?? id)
|
|
18901
|
+
} : null
|
|
18902
|
+
}
|
|
18903
|
+
};
|
|
18904
|
+
});
|
|
18273
18905
|
const workers = source.workers.map((entry) => ({
|
|
18274
18906
|
...entry,
|
|
18275
18907
|
id: fresh(entry.id),
|
|
@@ -18312,19 +18944,21 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18312
18944
|
closure: null,
|
|
18313
18945
|
assessments,
|
|
18314
18946
|
evidence,
|
|
18315
|
-
decisions: decisions.map((entry) =>
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
...entry
|
|
18319
|
-
|
|
18320
|
-
...
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18947
|
+
decisions: decisions.map((entry) => {
|
|
18948
|
+
const data = rewriteRecordRefs(entry.data, decisionSchema, remap);
|
|
18949
|
+
return {
|
|
18950
|
+
...entry,
|
|
18951
|
+
data: {
|
|
18952
|
+
...data,
|
|
18953
|
+
binding: {
|
|
18954
|
+
...data.binding,
|
|
18955
|
+
taskId: "",
|
|
18956
|
+
workspaceId: destinationWorkspaceId
|
|
18957
|
+
},
|
|
18958
|
+
consumption: null
|
|
18959
|
+
}
|
|
18960
|
+
};
|
|
18961
|
+
}),
|
|
18328
18962
|
...actionProgress ? { actionProgress } : {},
|
|
18329
18963
|
findings,
|
|
18330
18964
|
workers,
|
|
@@ -18362,7 +18996,7 @@ class WorkitCore {
|
|
|
18362
18996
|
}
|
|
18363
18997
|
contextRootError() {
|
|
18364
18998
|
try {
|
|
18365
|
-
if (
|
|
18999
|
+
if (realpathSync5(this.context.root) !== this.store.root)
|
|
18366
19000
|
return failure("invalid_input", "operation context root does not match the task store root");
|
|
18367
19001
|
} catch {
|
|
18368
19002
|
return failure("invalid_input", "operation context root cannot be resolved");
|
|
@@ -18407,7 +19041,7 @@ class WorkitCore {
|
|
|
18407
19041
|
activeWorkerBlocker(task, workspace) {
|
|
18408
19042
|
if (workspace.writer)
|
|
18409
19043
|
return failure("recovery_required", "writer ownership must be released first");
|
|
18410
|
-
if (task.workers.some((entry) =>
|
|
19044
|
+
if (task.workers.some((entry) => workerBlocksTransition("close", entry.data.state)))
|
|
18411
19045
|
return failure("recovery_required", "worker state requires reconciliation");
|
|
18412
19046
|
return null;
|
|
18413
19047
|
}
|
|
@@ -18653,37 +19287,33 @@ class WorkitCore {
|
|
|
18653
19287
|
const currentCandidate = captureCandidate(this.store.root, task.data.intent.data.scope, environment());
|
|
18654
19288
|
if (!currentCandidate.ok)
|
|
18655
19289
|
return currentCandidate;
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
evidence.candidateId ??= currentCandidate.data.id;
|
|
18659
|
-
} else {
|
|
18660
|
-
evidence.beforeCandidateId ??= null;
|
|
18661
|
-
evidence.candidateId ??= null;
|
|
18662
|
-
}
|
|
19290
|
+
const pin = helper && helper.ok ? helper.data.data.assignment.candidateId : null;
|
|
19291
|
+
const bound = resolveBinding(evidence, pin, currentCandidate.data.id);
|
|
18663
19292
|
if (helper?.ok) {
|
|
18664
19293
|
const assignment = helper.data.data.assignment;
|
|
18665
|
-
if (evidence.requirementIds.some((id) => !assignment.requirementIds.includes(id)) || assignment
|
|
19294
|
+
if (evidence.requirementIds.some((id) => !assignment.requirementIds.includes(id)) || !checkPin(assignment, bound.beforeCandidateId, bound.candidateId) || !refsWithinScope(evidence.refs, assignment.scope) || !refsWithinScope(evidence.refs, task.data.intent.data.scope))
|
|
18666
19295
|
return failure("permission_denied", "evidence is outside the worker assignment");
|
|
18667
19296
|
}
|
|
18668
19297
|
const knownCandidates = new Set(task.data.candidates.map((candidate) => candidate.id));
|
|
18669
|
-
for (const candidateId of [
|
|
19298
|
+
for (const candidateId of [bound.beforeCandidateId, bound.candidateId]) {
|
|
18670
19299
|
if (candidateId && candidateId !== currentCandidate.data.id && !knownCandidates.has(candidateId))
|
|
18671
19300
|
return failure("invalid_input", "evidence candidate is not a captured candidate");
|
|
18672
19301
|
}
|
|
19302
|
+
const boundEvidence = { ...evidence, ...bound };
|
|
18673
19303
|
const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
|
|
18674
19304
|
const candidates = current.candidates.some((item) => item.id === currentCandidate.data.id) ? current.candidates : [...current.candidates, currentCandidate.data];
|
|
18675
19305
|
const entry = {
|
|
18676
19306
|
id: newId(),
|
|
18677
19307
|
recordedAt: mutation.now,
|
|
18678
19308
|
provenance: provenance(this.context, "agent_reported"),
|
|
18679
|
-
data:
|
|
19309
|
+
data: boundEvidence
|
|
18680
19310
|
};
|
|
18681
19311
|
return success(mutation.revision, null, {
|
|
18682
19312
|
...current,
|
|
18683
19313
|
candidates,
|
|
18684
19314
|
evidence: [...current.evidence, entry],
|
|
18685
19315
|
findings: current.findings.map((finding) => {
|
|
18686
|
-
if (finding.data.disposition === "open" ||
|
|
19316
|
+
if (finding.data.disposition === "open" || boundEvidence.result === "skipped")
|
|
18687
19317
|
return finding;
|
|
18688
19318
|
if (finding.data.disposition !== "fixed")
|
|
18689
19319
|
return finding;
|
|
@@ -18692,8 +19322,12 @@ class WorkitCore {
|
|
|
18692
19322
|
item.evidenceId,
|
|
18693
19323
|
item.status
|
|
18694
19324
|
]));
|
|
18695
|
-
const verified = withEntry.evidence.some((item) =>
|
|
18696
|
-
|
|
19325
|
+
const verified = withEntry.evidence.some((item) => findingVerificationPasses(finding.data.candidateId, {
|
|
19326
|
+
kind: item.data.kind,
|
|
19327
|
+
candidateId: item.data.candidateId,
|
|
19328
|
+
status: statuses.get(item.id) ?? "missing"
|
|
19329
|
+
}));
|
|
19330
|
+
const contradicted = boundEvidence.result === "failed" && finding.data.refs.some((left) => boundEvidence.refs.some((right) => sameValue(left, right)));
|
|
18697
19331
|
return verified && !contradicted ? finding : { ...finding, data: { ...finding.data, disposition: "open", resolution: null } };
|
|
18698
19332
|
})
|
|
18699
19333
|
});
|
|
@@ -18851,7 +19485,7 @@ class WorkitCore {
|
|
|
18851
19485
|
if (input.action === "record") {
|
|
18852
19486
|
if (helper?.ok) {
|
|
18853
19487
|
const assignment = helper.data.data.assignment;
|
|
18854
|
-
if (!bindingCovers(assignment.scope, input.scope) || !bindingCovers(task.data.intent.data.scope, input.scope) || assignment
|
|
19488
|
+
if (!bindingCovers(assignment.scope, input.scope) || !bindingCovers(task.data.intent.data.scope, input.scope) || !checkPin(assignment, null, input.candidateId ?? null) || !refsWithinScope(input.refs, assignment.scope) || !refsWithinScope(input.refs, task.data.intent.data.scope))
|
|
18855
19489
|
return failure("permission_denied", "finding is outside the worker assignment");
|
|
18856
19490
|
}
|
|
18857
19491
|
if (input.candidateId && !task.data.candidates.some((candidate) => candidate.id === input.candidateId))
|
|
@@ -18898,7 +19532,11 @@ class WorkitCore {
|
|
|
18898
19532
|
const evaluations = evaluateEvidence(task.data, current.data);
|
|
18899
19533
|
const verified = evidence.some((entry) => {
|
|
18900
19534
|
const evaluation = evaluations.find((item) => item.evidenceId === entry.id);
|
|
18901
|
-
return
|
|
19535
|
+
return findingVerificationPasses(finding.data.candidateId, {
|
|
19536
|
+
kind: entry.data.kind,
|
|
19537
|
+
candidateId: entry.data.candidateId,
|
|
19538
|
+
status: evaluation?.status ?? "missing"
|
|
19539
|
+
});
|
|
18902
19540
|
});
|
|
18903
19541
|
if (!verified)
|
|
18904
19542
|
return failure("permission_denied", "fixed findings require passing verification evidence");
|
|
@@ -18910,7 +19548,7 @@ class WorkitCore {
|
|
|
18910
19548
|
if (entry.data.result === "missing" || entry.data.result === "skipped")
|
|
18911
19549
|
return false;
|
|
18912
19550
|
const candidateMatches = finding.data.candidateId === null ? entry.data.candidateId === null : entry.data.candidateId === finding.data.candidateId || entry.data.beforeCandidateId === finding.data.candidateId;
|
|
18913
|
-
const referenceMatches = finding.data.refs.some((left) => entry.data.refs.some((right) =>
|
|
19551
|
+
const referenceMatches = finding.data.refs.some((left) => entry.data.refs.some((right) => sameValue(left, right)));
|
|
18914
19552
|
return candidateMatches && (referenceMatches || entry.data.claim === finding.data.claim);
|
|
18915
19553
|
});
|
|
18916
19554
|
if (!relevant)
|
|
@@ -18988,7 +19626,7 @@ class WorkitCore {
|
|
|
18988
19626
|
const workerId = newId();
|
|
18989
19627
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
18990
19628
|
taskId: task.data.id,
|
|
18991
|
-
|
|
19629
|
+
expectedRevision: input.expectedRevision,
|
|
18992
19630
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
18993
19631
|
now: trustedNow(this.context),
|
|
18994
19632
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19026,7 +19664,7 @@ class WorkitCore {
|
|
|
19026
19664
|
return failure("permission_denied", "worker report is outside the worker assignment");
|
|
19027
19665
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19028
19666
|
taskId: task.data.id,
|
|
19029
|
-
|
|
19667
|
+
expectedRevision: input.expectedRevision,
|
|
19030
19668
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19031
19669
|
now: trustedNow(this.context),
|
|
19032
19670
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19050,24 +19688,25 @@ class WorkitCore {
|
|
|
19050
19688
|
return failure("invalid_transition", "closed task cannot cancel workers");
|
|
19051
19689
|
if (entry.data.state === "unknown")
|
|
19052
19690
|
return failure("recovery_required", "worker state requires recovery");
|
|
19053
|
-
if (entry.data.state === "stopped")
|
|
19054
|
-
|
|
19055
|
-
|
|
19691
|
+
if (entry.data.state === "stopped") {
|
|
19692
|
+
const stopped = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
19693
|
+
return success(task.data.revision, workspace.data.revision, stopped);
|
|
19694
|
+
}
|
|
19056
19695
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19057
19696
|
taskId: task.data.id,
|
|
19058
|
-
|
|
19697
|
+
expectedRevision: input.expectedRevision,
|
|
19059
19698
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19060
19699
|
now: trustedNow(this.context),
|
|
19061
|
-
workspace: (current, mutation) => success(mutation.revision, mutation.revision,
|
|
19700
|
+
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
19701
|
+
...current,
|
|
19702
|
+
writer: current.writer?.owner.workerId === input.workerId ? null : current.writer
|
|
19703
|
+
}),
|
|
19062
19704
|
task: (current, mutation) => success(mutation.revision, null, {
|
|
19063
19705
|
...current,
|
|
19064
19706
|
workers: current.workers.map((candidate) => candidate.id === input.workerId ? {
|
|
19065
19707
|
...candidate,
|
|
19066
19708
|
recordedAt: mutation.now,
|
|
19067
|
-
data: {
|
|
19068
|
-
...candidate.data,
|
|
19069
|
-
state: settles ? "stopped" : "cancelling"
|
|
19070
|
-
}
|
|
19709
|
+
data: { ...candidate.data, state: "stopped" }
|
|
19071
19710
|
} : candidate)
|
|
19072
19711
|
})
|
|
19073
19712
|
});
|
|
@@ -19164,7 +19803,7 @@ class WorkitCore {
|
|
|
19164
19803
|
return attested;
|
|
19165
19804
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19166
19805
|
taskId: task.data.id,
|
|
19167
|
-
|
|
19806
|
+
expectedRevision: input.expectedRevision,
|
|
19168
19807
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19169
19808
|
now: trustedNow(this.context),
|
|
19170
19809
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19330,6 +19969,12 @@ class WorkitCore {
|
|
|
19330
19969
|
if (!sameSession2(helper.data.data.session, this.context))
|
|
19331
19970
|
return failure("permission_denied", "worker session does not match the caller");
|
|
19332
19971
|
}
|
|
19972
|
+
const gate = this.view(task.data);
|
|
19973
|
+
if (gate.ok) {
|
|
19974
|
+
const writeGates = (task.data.policy?.requirements ?? []).filter((requirement) => requirement.before === "write" && gate.data.requirements.some((evaluation) => evaluation.requirementId === requirement.id && (evaluation.status === "unsatisfied" || evaluation.status === "unavailable")));
|
|
19975
|
+
if (writeGates.length)
|
|
19976
|
+
return failure("requirements_unsatisfied", "writer ownership is gated by unsatisfied requirements; record their evidence or an approved limitation waiver first", { requirementIds: writeGates.map((requirement) => requirement.id) });
|
|
19977
|
+
}
|
|
19333
19978
|
const owner = {
|
|
19334
19979
|
taskId: task.data.id,
|
|
19335
19980
|
workerId: helperId,
|
|
@@ -19341,7 +19986,7 @@ class WorkitCore {
|
|
|
19341
19986
|
};
|
|
19342
19987
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19343
19988
|
taskId: task.data.id,
|
|
19344
|
-
|
|
19989
|
+
expectedRevision: input.expectedRevision,
|
|
19345
19990
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19346
19991
|
now: trustedNow(this.context),
|
|
19347
19992
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -19372,7 +20017,7 @@ class WorkitCore {
|
|
|
19372
20017
|
}
|
|
19373
20018
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19374
20019
|
taskId: task.data.id,
|
|
19375
|
-
|
|
20020
|
+
expectedRevision: input.expectedRevision,
|
|
19376
20021
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19377
20022
|
now: trustedNow(this.context),
|
|
19378
20023
|
workspace: (currentWorkspace, mutation) => success(mutation.revision, mutation.revision, { ...currentWorkspace, writer: null }),
|
|
@@ -19604,7 +20249,7 @@ class WorkitCore {
|
|
|
19604
20249
|
if (view.task.workspaceId !== view.workspace.id)
|
|
19605
20250
|
return failure("invalid_input", "task and workspace bindings are invalid");
|
|
19606
20251
|
try {
|
|
19607
|
-
if (
|
|
20252
|
+
if (realpathSync5(view.workspace.root) !== this.store.root)
|
|
19608
20253
|
return failure("invalid_input", "task view root does not match the task store");
|
|
19609
20254
|
} catch {
|
|
19610
20255
|
return failure("invalid_input", "task view root cannot be resolved");
|
|
@@ -19621,7 +20266,15 @@ class WorkitCore {
|
|
|
19621
20266
|
if (seen.has(observation.workerId))
|
|
19622
20267
|
return failure("invalid_input", "worker observations must be unique");
|
|
19623
20268
|
seen.add(observation.workerId);
|
|
19624
|
-
|
|
20269
|
+
const freshTask = this.store.readTask(view.task.id);
|
|
20270
|
+
const freshWorkspace = this.store.readWorkspace();
|
|
20271
|
+
if (!freshTask.ok)
|
|
20272
|
+
return freshTask;
|
|
20273
|
+
if (!freshWorkspace.ok)
|
|
20274
|
+
return freshWorkspace;
|
|
20275
|
+
if (!freshWorkspace.data)
|
|
20276
|
+
return failure("not_found", "workspace not found");
|
|
20277
|
+
if (observation.taskId !== view.task.id || observation.expectedRevision !== freshTask.data.revision || observation.expectedWorkspaceRevision !== freshWorkspace.data.revision)
|
|
19625
20278
|
return failure("revision_conflict", "worker observation is stale");
|
|
19626
20279
|
if (!view.task.workers.some((entry) => entry.id === observation.workerId))
|
|
19627
20280
|
return failure("permission_denied", "worker observation is not assigned");
|
|
@@ -19707,19 +20360,26 @@ class WorkitCore {
|
|
|
19707
20360
|
return failure("permission_denied", "imported resume requires native destination approval");
|
|
19708
20361
|
resumeCandidate = current.data.candidate;
|
|
19709
20362
|
}
|
|
19710
|
-
const blocker = this.activeWorkerBlocker(task.data, workspace.data);
|
|
20363
|
+
const blocker = status === "paused" ? workspace.data.writer ? failure("recovery_required", "writer ownership must be released first") : null : this.activeWorkerBlocker(task.data, workspace.data);
|
|
19711
20364
|
if (blocker)
|
|
19712
20365
|
return blocker;
|
|
20366
|
+
let pauseCandidate = null;
|
|
20367
|
+
if (status === "paused") {
|
|
20368
|
+
const captured = captureCandidate(this.store.root, task.data.intent.data.scope, environment());
|
|
20369
|
+
if (!captured.ok)
|
|
20370
|
+
return captured;
|
|
20371
|
+
pauseCandidate = captured.data;
|
|
20372
|
+
}
|
|
19713
20373
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19714
20374
|
taskId: task.data.id,
|
|
19715
|
-
|
|
20375
|
+
expectedRevision: input.expectedRevision,
|
|
19716
20376
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19717
20377
|
now: trustedNow(this.context),
|
|
19718
20378
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
19719
20379
|
task: (current, context) => success(context.revision, null, {
|
|
19720
20380
|
...current,
|
|
19721
20381
|
status,
|
|
19722
|
-
candidates: resumeCandidate && !current.candidates.some((candidate) => candidate.id === resumeCandidate.id) ? [...current.candidates, resumeCandidate] : current.candidates,
|
|
20382
|
+
candidates: (resumeCandidate ?? pauseCandidate) && !current.candidates.some((candidate) => candidate.id === (resumeCandidate ?? pauseCandidate).id) ? [...current.candidates, resumeCandidate ?? pauseCandidate] : current.candidates,
|
|
19723
20383
|
progress: current.progress,
|
|
19724
20384
|
pauseReason: status === "paused" ? input.reason ?? null : null
|
|
19725
20385
|
})
|
|
@@ -19757,12 +20417,13 @@ class WorkitCore {
|
|
|
19757
20417
|
return workspace;
|
|
19758
20418
|
if (!workspace.data)
|
|
19759
20419
|
return failure("not_found", "workspace not found");
|
|
19760
|
-
|
|
19761
|
-
|
|
20420
|
+
const revisionBlocker = this.activeWorkerBlocker(task.data, workspace.data);
|
|
20421
|
+
if (revisionBlocker)
|
|
20422
|
+
return revisionBlocker;
|
|
19762
20423
|
this.fillRevisions(input, task.data, workspace.data);
|
|
19763
20424
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19764
20425
|
taskId: task.data.id,
|
|
19765
|
-
|
|
20426
|
+
expectedRevision: input.expectedRevision,
|
|
19766
20427
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19767
20428
|
now: trustedNow(this.context),
|
|
19768
20429
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
@@ -19818,7 +20479,7 @@ class WorkitCore {
|
|
|
19818
20479
|
return closure;
|
|
19819
20480
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19820
20481
|
taskId: task.data.id,
|
|
19821
|
-
|
|
20482
|
+
expectedRevision: input.expectedRevision,
|
|
19822
20483
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19823
20484
|
now: trustedNow(this.context),
|
|
19824
20485
|
workspace: (value, context) => success(context.revision, context.revision, value),
|
|
@@ -19855,7 +20516,7 @@ function gitRevisionParts(value) {
|
|
|
19855
20516
|
}
|
|
19856
20517
|
function resolveGitRevision(root, value) {
|
|
19857
20518
|
for (const part of gitRevisionParts(value)) {
|
|
19858
|
-
const result =
|
|
20519
|
+
const result = run2(root, "git", [
|
|
19859
20520
|
"rev-parse",
|
|
19860
20521
|
"--verify",
|
|
19861
20522
|
"--quiet",
|
|
@@ -19867,23 +20528,23 @@ function resolveGitRevision(root, value) {
|
|
|
19867
20528
|
}
|
|
19868
20529
|
}
|
|
19869
20530
|
function resolveInside(root, candidate) {
|
|
19870
|
-
const base =
|
|
19871
|
-
const target =
|
|
19872
|
-
if (target !== base && !target.startsWith(base +
|
|
20531
|
+
const base = realpathSync6(root);
|
|
20532
|
+
const target = path10.resolve(base, candidate);
|
|
20533
|
+
if (target !== base && !target.startsWith(base + path10.sep)) {
|
|
19873
20534
|
throw new Error("path must stay inside repository root");
|
|
19874
20535
|
}
|
|
19875
20536
|
let ancestor = target;
|
|
19876
|
-
while (!
|
|
19877
|
-
ancestor =
|
|
19878
|
-
const canonicalAncestor =
|
|
19879
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
20537
|
+
while (!existsSync5(ancestor))
|
|
20538
|
+
ancestor = path10.dirname(ancestor);
|
|
20539
|
+
const canonicalAncestor = realpathSync6(ancestor);
|
|
20540
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path10.sep)) {
|
|
19880
20541
|
throw new Error("path must stay inside repository root");
|
|
19881
20542
|
}
|
|
19882
20543
|
return target;
|
|
19883
20544
|
}
|
|
19884
|
-
function
|
|
19885
|
-
const cwd =
|
|
19886
|
-
const result =
|
|
20545
|
+
function run2(root, executable, args, env = {}) {
|
|
20546
|
+
const cwd = realpathSync6(root);
|
|
20547
|
+
const result = spawnSync3(executable, args, {
|
|
19887
20548
|
cwd,
|
|
19888
20549
|
encoding: "utf8",
|
|
19889
20550
|
env: { ...process.env, ...env }
|
|
@@ -24523,1029 +25184,707 @@ class Protocol {
|
|
|
24523
25184
|
this._onrequest(message, extra);
|
|
24524
25185
|
} else if (isJSONRPCNotification(message)) {
|
|
24525
25186
|
this._onnotification(message);
|
|
24526
|
-
} else {
|
|
24527
|
-
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
24528
|
-
}
|
|
24529
|
-
};
|
|
24530
|
-
await this._transport.start();
|
|
24531
|
-
}
|
|
24532
|
-
_onclose() {
|
|
24533
|
-
const responseHandlers = this._responseHandlers;
|
|
24534
|
-
this._responseHandlers = new Map;
|
|
24535
|
-
this._progressHandlers.clear();
|
|
24536
|
-
this._taskProgressTokens.clear();
|
|
24537
|
-
this._pendingDebouncedNotifications.clear();
|
|
24538
|
-
for (const info of this._timeoutInfo.values()) {
|
|
24539
|
-
clearTimeout(info.timeoutId);
|
|
24540
|
-
}
|
|
24541
|
-
this._timeoutInfo.clear();
|
|
24542
|
-
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
24543
|
-
controller.abort();
|
|
24544
|
-
}
|
|
24545
|
-
this._requestHandlerAbortControllers.clear();
|
|
24546
|
-
const error = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
24547
|
-
this._transport = undefined;
|
|
24548
|
-
this.onclose?.();
|
|
24549
|
-
for (const handler of responseHandlers.values()) {
|
|
24550
|
-
handler(error);
|
|
24551
|
-
}
|
|
24552
|
-
}
|
|
24553
|
-
_onerror(error) {
|
|
24554
|
-
this.onerror?.(error);
|
|
24555
|
-
}
|
|
24556
|
-
_onnotification(notification) {
|
|
24557
|
-
const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler;
|
|
24558
|
-
if (handler === undefined) {
|
|
24559
|
-
return;
|
|
24560
|
-
}
|
|
24561
|
-
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
24562
|
-
}
|
|
24563
|
-
_onrequest(request, extra) {
|
|
24564
|
-
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
24565
|
-
const capturedTransport = this._transport;
|
|
24566
|
-
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
24567
|
-
if (handler === undefined) {
|
|
24568
|
-
const errorResponse = {
|
|
24569
|
-
jsonrpc: "2.0",
|
|
24570
|
-
id: request.id,
|
|
24571
|
-
error: {
|
|
24572
|
-
code: ErrorCode.MethodNotFound,
|
|
24573
|
-
message: "Method not found"
|
|
24574
|
-
}
|
|
24575
|
-
};
|
|
24576
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24577
|
-
this._enqueueTaskMessage(relatedTaskId, {
|
|
24578
|
-
type: "error",
|
|
24579
|
-
message: errorResponse,
|
|
24580
|
-
timestamp: Date.now()
|
|
24581
|
-
}, capturedTransport?.sessionId).catch((error) => this._onerror(new Error(`Failed to enqueue error response: ${error}`)));
|
|
24582
|
-
} else {
|
|
24583
|
-
capturedTransport?.send(errorResponse).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
24584
|
-
}
|
|
24585
|
-
return;
|
|
24586
|
-
}
|
|
24587
|
-
const abortController = new AbortController;
|
|
24588
|
-
this._requestHandlerAbortControllers.set(request.id, abortController);
|
|
24589
|
-
const taskCreationParams = isTaskAugmentedRequestParams(request.params) ? request.params.task : undefined;
|
|
24590
|
-
const taskStore = this._taskStore ? this.requestTaskStore(request, capturedTransport?.sessionId) : undefined;
|
|
24591
|
-
const fullExtra = {
|
|
24592
|
-
signal: abortController.signal,
|
|
24593
|
-
sessionId: capturedTransport?.sessionId,
|
|
24594
|
-
_meta: request.params?._meta,
|
|
24595
|
-
sendNotification: async (notification) => {
|
|
24596
|
-
if (abortController.signal.aborted)
|
|
24597
|
-
return;
|
|
24598
|
-
const notificationOptions = { relatedRequestId: request.id };
|
|
24599
|
-
if (relatedTaskId) {
|
|
24600
|
-
notificationOptions.relatedTask = { taskId: relatedTaskId };
|
|
24601
|
-
}
|
|
24602
|
-
await this.notification(notification, notificationOptions);
|
|
24603
|
-
},
|
|
24604
|
-
sendRequest: async (r, resultSchema, options) => {
|
|
24605
|
-
if (abortController.signal.aborted) {
|
|
24606
|
-
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
24607
|
-
}
|
|
24608
|
-
const requestOptions = { ...options, relatedRequestId: request.id };
|
|
24609
|
-
if (relatedTaskId && !requestOptions.relatedTask) {
|
|
24610
|
-
requestOptions.relatedTask = { taskId: relatedTaskId };
|
|
24611
|
-
}
|
|
24612
|
-
const effectiveTaskId = requestOptions.relatedTask?.taskId ?? relatedTaskId;
|
|
24613
|
-
if (effectiveTaskId && taskStore) {
|
|
24614
|
-
await taskStore.updateTaskStatus(effectiveTaskId, "input_required");
|
|
24615
|
-
}
|
|
24616
|
-
return await this.request(r, resultSchema, requestOptions);
|
|
24617
|
-
},
|
|
24618
|
-
authInfo: extra?.authInfo,
|
|
24619
|
-
requestId: request.id,
|
|
24620
|
-
requestInfo: extra?.requestInfo,
|
|
24621
|
-
taskId: relatedTaskId,
|
|
24622
|
-
taskStore,
|
|
24623
|
-
taskRequestedTtl: taskCreationParams?.ttl,
|
|
24624
|
-
closeSSEStream: extra?.closeSSEStream,
|
|
24625
|
-
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
24626
|
-
};
|
|
24627
|
-
Promise.resolve().then(() => {
|
|
24628
|
-
if (taskCreationParams) {
|
|
24629
|
-
this.assertTaskHandlerCapability(request.method);
|
|
24630
|
-
}
|
|
24631
|
-
}).then(() => handler(request, fullExtra)).then(async (result) => {
|
|
24632
|
-
if (abortController.signal.aborted) {
|
|
24633
|
-
return;
|
|
24634
|
-
}
|
|
24635
|
-
const response = {
|
|
24636
|
-
result,
|
|
24637
|
-
jsonrpc: "2.0",
|
|
24638
|
-
id: request.id
|
|
24639
|
-
};
|
|
24640
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24641
|
-
await this._enqueueTaskMessage(relatedTaskId, {
|
|
24642
|
-
type: "response",
|
|
24643
|
-
message: response,
|
|
24644
|
-
timestamp: Date.now()
|
|
24645
|
-
}, capturedTransport?.sessionId);
|
|
24646
|
-
} else {
|
|
24647
|
-
await capturedTransport?.send(response);
|
|
24648
|
-
}
|
|
24649
|
-
}, async (error) => {
|
|
24650
|
-
if (abortController.signal.aborted) {
|
|
24651
|
-
return;
|
|
24652
|
-
}
|
|
24653
|
-
const errorResponse = {
|
|
24654
|
-
jsonrpc: "2.0",
|
|
24655
|
-
id: request.id,
|
|
24656
|
-
error: {
|
|
24657
|
-
code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
|
|
24658
|
-
message: error.message ?? "Internal error",
|
|
24659
|
-
...error["data"] !== undefined && { data: error["data"] }
|
|
24660
|
-
}
|
|
24661
|
-
};
|
|
24662
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24663
|
-
await this._enqueueTaskMessage(relatedTaskId, {
|
|
24664
|
-
type: "error",
|
|
24665
|
-
message: errorResponse,
|
|
24666
|
-
timestamp: Date.now()
|
|
24667
|
-
}, capturedTransport?.sessionId);
|
|
24668
|
-
} else {
|
|
24669
|
-
await capturedTransport?.send(errorResponse);
|
|
24670
|
-
}
|
|
24671
|
-
}).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
|
|
24672
|
-
if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
|
|
24673
|
-
this._requestHandlerAbortControllers.delete(request.id);
|
|
24674
|
-
}
|
|
24675
|
-
});
|
|
24676
|
-
}
|
|
24677
|
-
_onprogress(notification) {
|
|
24678
|
-
const { progressToken, ...params } = notification.params;
|
|
24679
|
-
const messageId = Number(progressToken);
|
|
24680
|
-
const handler = this._progressHandlers.get(messageId);
|
|
24681
|
-
if (!handler) {
|
|
24682
|
-
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
|
24683
|
-
return;
|
|
24684
|
-
}
|
|
24685
|
-
const responseHandler = this._responseHandlers.get(messageId);
|
|
24686
|
-
const timeoutInfo = this._timeoutInfo.get(messageId);
|
|
24687
|
-
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
|
|
24688
|
-
try {
|
|
24689
|
-
this._resetTimeout(messageId);
|
|
24690
|
-
} catch (error) {
|
|
24691
|
-
this._responseHandlers.delete(messageId);
|
|
24692
|
-
this._progressHandlers.delete(messageId);
|
|
24693
|
-
this._cleanupTimeout(messageId);
|
|
24694
|
-
responseHandler(error);
|
|
24695
|
-
return;
|
|
24696
|
-
}
|
|
24697
|
-
}
|
|
24698
|
-
handler(params);
|
|
24699
|
-
}
|
|
24700
|
-
_onresponse(response) {
|
|
24701
|
-
const messageId = Number(response.id);
|
|
24702
|
-
const resolver = this._requestResolvers.get(messageId);
|
|
24703
|
-
if (resolver) {
|
|
24704
|
-
this._requestResolvers.delete(messageId);
|
|
24705
|
-
if (isJSONRPCResultResponse(response)) {
|
|
24706
|
-
resolver(response);
|
|
24707
|
-
} else {
|
|
24708
|
-
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
|
24709
|
-
resolver(error);
|
|
24710
|
-
}
|
|
24711
|
-
return;
|
|
24712
|
-
}
|
|
24713
|
-
const handler = this._responseHandlers.get(messageId);
|
|
24714
|
-
if (handler === undefined) {
|
|
24715
|
-
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
|
24716
|
-
return;
|
|
24717
|
-
}
|
|
24718
|
-
this._responseHandlers.delete(messageId);
|
|
24719
|
-
this._cleanupTimeout(messageId);
|
|
24720
|
-
let isTaskResponse = false;
|
|
24721
|
-
if (isJSONRPCResultResponse(response) && response.result && typeof response.result === "object") {
|
|
24722
|
-
const result = response.result;
|
|
24723
|
-
if (result.task && typeof result.task === "object") {
|
|
24724
|
-
const task = result.task;
|
|
24725
|
-
if (typeof task.taskId === "string") {
|
|
24726
|
-
isTaskResponse = true;
|
|
24727
|
-
this._taskProgressTokens.set(task.taskId, messageId);
|
|
24728
|
-
}
|
|
25187
|
+
} else {
|
|
25188
|
+
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
24729
25189
|
}
|
|
25190
|
+
};
|
|
25191
|
+
await this._transport.start();
|
|
25192
|
+
}
|
|
25193
|
+
_onclose() {
|
|
25194
|
+
const responseHandlers = this._responseHandlers;
|
|
25195
|
+
this._responseHandlers = new Map;
|
|
25196
|
+
this._progressHandlers.clear();
|
|
25197
|
+
this._taskProgressTokens.clear();
|
|
25198
|
+
this._pendingDebouncedNotifications.clear();
|
|
25199
|
+
for (const info of this._timeoutInfo.values()) {
|
|
25200
|
+
clearTimeout(info.timeoutId);
|
|
24730
25201
|
}
|
|
24731
|
-
|
|
24732
|
-
|
|
25202
|
+
this._timeoutInfo.clear();
|
|
25203
|
+
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
25204
|
+
controller.abort();
|
|
24733
25205
|
}
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
|
|
25206
|
+
this._requestHandlerAbortControllers.clear();
|
|
25207
|
+
const error = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
25208
|
+
this._transport = undefined;
|
|
25209
|
+
this.onclose?.();
|
|
25210
|
+
for (const handler of responseHandlers.values()) {
|
|
24738
25211
|
handler(error);
|
|
24739
25212
|
}
|
|
24740
25213
|
}
|
|
24741
|
-
|
|
24742
|
-
|
|
24743
|
-
}
|
|
24744
|
-
async close() {
|
|
24745
|
-
await this._transport?.close();
|
|
25214
|
+
_onerror(error) {
|
|
25215
|
+
this.onerror?.(error);
|
|
24746
25216
|
}
|
|
24747
|
-
|
|
24748
|
-
const
|
|
24749
|
-
if (
|
|
24750
|
-
try {
|
|
24751
|
-
const result = await this.request(request, resultSchema, options);
|
|
24752
|
-
yield { type: "result", result };
|
|
24753
|
-
} catch (error) {
|
|
24754
|
-
yield {
|
|
24755
|
-
type: "error",
|
|
24756
|
-
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
24757
|
-
};
|
|
24758
|
-
}
|
|
25217
|
+
_onnotification(notification) {
|
|
25218
|
+
const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler;
|
|
25219
|
+
if (handler === undefined) {
|
|
24759
25220
|
return;
|
|
24760
25221
|
}
|
|
24761
|
-
|
|
24762
|
-
try {
|
|
24763
|
-
const createResult = await this.request(request, CreateTaskResultSchema, options);
|
|
24764
|
-
if (createResult.task) {
|
|
24765
|
-
taskId = createResult.task.taskId;
|
|
24766
|
-
yield { type: "taskCreated", task: createResult.task };
|
|
24767
|
-
} else {
|
|
24768
|
-
throw new McpError(ErrorCode.InternalError, "Task creation did not return a task");
|
|
24769
|
-
}
|
|
24770
|
-
while (true) {
|
|
24771
|
-
const task = await this.getTask({ taskId }, options);
|
|
24772
|
-
yield { type: "taskStatus", task };
|
|
24773
|
-
if (isTerminal(task.status)) {
|
|
24774
|
-
if (task.status === "completed") {
|
|
24775
|
-
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
24776
|
-
yield { type: "result", result };
|
|
24777
|
-
} else if (task.status === "failed") {
|
|
24778
|
-
yield {
|
|
24779
|
-
type: "error",
|
|
24780
|
-
error: new McpError(ErrorCode.InternalError, `Task ${taskId} failed`)
|
|
24781
|
-
};
|
|
24782
|
-
} else if (task.status === "cancelled") {
|
|
24783
|
-
yield {
|
|
24784
|
-
type: "error",
|
|
24785
|
-
error: new McpError(ErrorCode.InternalError, `Task ${taskId} was cancelled`)
|
|
24786
|
-
};
|
|
24787
|
-
}
|
|
24788
|
-
return;
|
|
24789
|
-
}
|
|
24790
|
-
if (task.status === "input_required") {
|
|
24791
|
-
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
24792
|
-
yield { type: "result", result };
|
|
24793
|
-
return;
|
|
24794
|
-
}
|
|
24795
|
-
const pollInterval = task.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
24796
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
24797
|
-
options?.signal?.throwIfAborted();
|
|
24798
|
-
}
|
|
24799
|
-
} catch (error) {
|
|
24800
|
-
yield {
|
|
24801
|
-
type: "error",
|
|
24802
|
-
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
24803
|
-
};
|
|
24804
|
-
}
|
|
25222
|
+
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
24805
25223
|
}
|
|
24806
|
-
|
|
24807
|
-
const
|
|
24808
|
-
|
|
24809
|
-
|
|
24810
|
-
|
|
24811
|
-
|
|
24812
|
-
if (!this._transport) {
|
|
24813
|
-
earlyReject(new Error("Not connected"));
|
|
24814
|
-
return;
|
|
24815
|
-
}
|
|
24816
|
-
if (this._options?.enforceStrictCapabilities === true) {
|
|
24817
|
-
try {
|
|
24818
|
-
this.assertCapabilityForMethod(request.method);
|
|
24819
|
-
if (task) {
|
|
24820
|
-
this.assertTaskCapability(request.method);
|
|
24821
|
-
}
|
|
24822
|
-
} catch (e) {
|
|
24823
|
-
earlyReject(e);
|
|
24824
|
-
return;
|
|
24825
|
-
}
|
|
24826
|
-
}
|
|
24827
|
-
options?.signal?.throwIfAborted();
|
|
24828
|
-
const messageId = this._requestMessageId++;
|
|
24829
|
-
const jsonrpcRequest = {
|
|
24830
|
-
...request,
|
|
25224
|
+
_onrequest(request, extra) {
|
|
25225
|
+
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
25226
|
+
const capturedTransport = this._transport;
|
|
25227
|
+
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
25228
|
+
if (handler === undefined) {
|
|
25229
|
+
const errorResponse = {
|
|
24831
25230
|
jsonrpc: "2.0",
|
|
24832
|
-
id:
|
|
25231
|
+
id: request.id,
|
|
25232
|
+
error: {
|
|
25233
|
+
code: ErrorCode.MethodNotFound,
|
|
25234
|
+
message: "Method not found"
|
|
25235
|
+
}
|
|
24833
25236
|
};
|
|
24834
|
-
if (
|
|
24835
|
-
this.
|
|
24836
|
-
|
|
24837
|
-
|
|
24838
|
-
|
|
24839
|
-
|
|
24840
|
-
|
|
24841
|
-
|
|
24842
|
-
};
|
|
24843
|
-
}
|
|
24844
|
-
if (task) {
|
|
24845
|
-
jsonrpcRequest.params = {
|
|
24846
|
-
...jsonrpcRequest.params,
|
|
24847
|
-
task
|
|
24848
|
-
};
|
|
24849
|
-
}
|
|
24850
|
-
if (relatedTask) {
|
|
24851
|
-
jsonrpcRequest.params = {
|
|
24852
|
-
...jsonrpcRequest.params,
|
|
24853
|
-
_meta: {
|
|
24854
|
-
...jsonrpcRequest.params?._meta || {},
|
|
24855
|
-
[RELATED_TASK_META_KEY]: relatedTask
|
|
24856
|
-
}
|
|
24857
|
-
};
|
|
25237
|
+
if (relatedTaskId && this._taskMessageQueue) {
|
|
25238
|
+
this._enqueueTaskMessage(relatedTaskId, {
|
|
25239
|
+
type: "error",
|
|
25240
|
+
message: errorResponse,
|
|
25241
|
+
timestamp: Date.now()
|
|
25242
|
+
}, capturedTransport?.sessionId).catch((error) => this._onerror(new Error(`Failed to enqueue error response: ${error}`)));
|
|
25243
|
+
} else {
|
|
25244
|
+
capturedTransport?.send(errorResponse).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
24858
25245
|
}
|
|
24859
|
-
|
|
24860
|
-
|
|
24861
|
-
|
|
24862
|
-
|
|
24863
|
-
|
|
24864
|
-
|
|
24865
|
-
|
|
24866
|
-
|
|
24867
|
-
|
|
24868
|
-
|
|
24869
|
-
|
|
24870
|
-
|
|
24871
|
-
const error = reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason));
|
|
24872
|
-
reject(error);
|
|
24873
|
-
};
|
|
24874
|
-
this._responseHandlers.set(messageId, (response) => {
|
|
24875
|
-
if (options?.signal?.aborted) {
|
|
25246
|
+
return;
|
|
25247
|
+
}
|
|
25248
|
+
const abortController = new AbortController;
|
|
25249
|
+
this._requestHandlerAbortControllers.set(request.id, abortController);
|
|
25250
|
+
const taskCreationParams = isTaskAugmentedRequestParams(request.params) ? request.params.task : undefined;
|
|
25251
|
+
const taskStore = this._taskStore ? this.requestTaskStore(request, capturedTransport?.sessionId) : undefined;
|
|
25252
|
+
const fullExtra = {
|
|
25253
|
+
signal: abortController.signal,
|
|
25254
|
+
sessionId: capturedTransport?.sessionId,
|
|
25255
|
+
_meta: request.params?._meta,
|
|
25256
|
+
sendNotification: async (notification) => {
|
|
25257
|
+
if (abortController.signal.aborted)
|
|
24876
25258
|
return;
|
|
25259
|
+
const notificationOptions = { relatedRequestId: request.id };
|
|
25260
|
+
if (relatedTaskId) {
|
|
25261
|
+
notificationOptions.relatedTask = { taskId: relatedTaskId };
|
|
24877
25262
|
}
|
|
24878
|
-
|
|
24879
|
-
|
|
25263
|
+
await this.notification(notification, notificationOptions);
|
|
25264
|
+
},
|
|
25265
|
+
sendRequest: async (r, resultSchema, options) => {
|
|
25266
|
+
if (abortController.signal.aborted) {
|
|
25267
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
24880
25268
|
}
|
|
24881
|
-
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
reject(parseResult.error);
|
|
24885
|
-
} else {
|
|
24886
|
-
resolve(parseResult.data);
|
|
24887
|
-
}
|
|
24888
|
-
} catch (error) {
|
|
24889
|
-
reject(error);
|
|
25269
|
+
const requestOptions = { ...options, relatedRequestId: request.id };
|
|
25270
|
+
if (relatedTaskId && !requestOptions.relatedTask) {
|
|
25271
|
+
requestOptions.relatedTask = { taskId: relatedTaskId };
|
|
24890
25272
|
}
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
|
|
24906
|
-
|
|
24907
|
-
|
|
24908
|
-
this.
|
|
24909
|
-
|
|
24910
|
-
|
|
24911
|
-
|
|
25273
|
+
const effectiveTaskId = requestOptions.relatedTask?.taskId ?? relatedTaskId;
|
|
25274
|
+
if (effectiveTaskId && taskStore) {
|
|
25275
|
+
await taskStore.updateTaskStatus(effectiveTaskId, "input_required");
|
|
25276
|
+
}
|
|
25277
|
+
return await this.request(r, resultSchema, requestOptions);
|
|
25278
|
+
},
|
|
25279
|
+
authInfo: extra?.authInfo,
|
|
25280
|
+
requestId: request.id,
|
|
25281
|
+
requestInfo: extra?.requestInfo,
|
|
25282
|
+
taskId: relatedTaskId,
|
|
25283
|
+
taskStore,
|
|
25284
|
+
taskRequestedTtl: taskCreationParams?.ttl,
|
|
25285
|
+
closeSSEStream: extra?.closeSSEStream,
|
|
25286
|
+
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
25287
|
+
};
|
|
25288
|
+
Promise.resolve().then(() => {
|
|
25289
|
+
if (taskCreationParams) {
|
|
25290
|
+
this.assertTaskHandlerCapability(request.method);
|
|
25291
|
+
}
|
|
25292
|
+
}).then(() => handler(request, fullExtra)).then(async (result) => {
|
|
25293
|
+
if (abortController.signal.aborted) {
|
|
25294
|
+
return;
|
|
25295
|
+
}
|
|
25296
|
+
const response = {
|
|
25297
|
+
result,
|
|
25298
|
+
jsonrpc: "2.0",
|
|
25299
|
+
id: request.id
|
|
25300
|
+
};
|
|
25301
|
+
if (relatedTaskId && this._taskMessageQueue) {
|
|
25302
|
+
await this._enqueueTaskMessage(relatedTaskId, {
|
|
25303
|
+
type: "response",
|
|
25304
|
+
message: response,
|
|
24912
25305
|
timestamp: Date.now()
|
|
24913
|
-
})
|
|
24914
|
-
this._cleanupTimeout(messageId);
|
|
24915
|
-
reject(error);
|
|
24916
|
-
});
|
|
25306
|
+
}, capturedTransport?.sessionId);
|
|
24917
25307
|
} else {
|
|
24918
|
-
|
|
24919
|
-
this._cleanupTimeout(messageId);
|
|
24920
|
-
reject(error);
|
|
24921
|
-
});
|
|
25308
|
+
await capturedTransport?.send(response);
|
|
24922
25309
|
}
|
|
24923
|
-
})
|
|
24924
|
-
|
|
24925
|
-
|
|
24926
|
-
|
|
24927
|
-
|
|
24928
|
-
async getTaskResult(params, resultSchema, options) {
|
|
24929
|
-
return this.request({ method: "tasks/result", params }, resultSchema, options);
|
|
24930
|
-
}
|
|
24931
|
-
async listTasks(params, options) {
|
|
24932
|
-
return this.request({ method: "tasks/list", params }, ListTasksResultSchema, options);
|
|
24933
|
-
}
|
|
24934
|
-
async cancelTask(params, options) {
|
|
24935
|
-
return this.request({ method: "tasks/cancel", params }, CancelTaskResultSchema, options);
|
|
24936
|
-
}
|
|
24937
|
-
async notification(notification, options) {
|
|
24938
|
-
if (!this._transport) {
|
|
24939
|
-
throw new Error("Not connected");
|
|
24940
|
-
}
|
|
24941
|
-
this.assertNotificationCapability(notification.method);
|
|
24942
|
-
const relatedTaskId = options?.relatedTask?.taskId;
|
|
24943
|
-
if (relatedTaskId) {
|
|
24944
|
-
const jsonrpcNotification = {
|
|
24945
|
-
...notification,
|
|
25310
|
+
}, async (error) => {
|
|
25311
|
+
if (abortController.signal.aborted) {
|
|
25312
|
+
return;
|
|
25313
|
+
}
|
|
25314
|
+
const errorResponse = {
|
|
24946
25315
|
jsonrpc: "2.0",
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
}
|
|
25316
|
+
id: request.id,
|
|
25317
|
+
error: {
|
|
25318
|
+
code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
|
|
25319
|
+
message: error.message ?? "Internal error",
|
|
25320
|
+
...error["data"] !== undefined && { data: error["data"] }
|
|
24953
25321
|
}
|
|
24954
25322
|
};
|
|
24955
|
-
|
|
24956
|
-
|
|
24957
|
-
|
|
24958
|
-
|
|
24959
|
-
|
|
25323
|
+
if (relatedTaskId && this._taskMessageQueue) {
|
|
25324
|
+
await this._enqueueTaskMessage(relatedTaskId, {
|
|
25325
|
+
type: "error",
|
|
25326
|
+
message: errorResponse,
|
|
25327
|
+
timestamp: Date.now()
|
|
25328
|
+
}, capturedTransport?.sessionId);
|
|
25329
|
+
} else {
|
|
25330
|
+
await capturedTransport?.send(errorResponse);
|
|
25331
|
+
}
|
|
25332
|
+
}).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
|
|
25333
|
+
if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
|
|
25334
|
+
this._requestHandlerAbortControllers.delete(request.id);
|
|
25335
|
+
}
|
|
25336
|
+
});
|
|
25337
|
+
}
|
|
25338
|
+
_onprogress(notification) {
|
|
25339
|
+
const { progressToken, ...params } = notification.params;
|
|
25340
|
+
const messageId = Number(progressToken);
|
|
25341
|
+
const handler = this._progressHandlers.get(messageId);
|
|
25342
|
+
if (!handler) {
|
|
25343
|
+
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
|
24960
25344
|
return;
|
|
24961
25345
|
}
|
|
24962
|
-
const
|
|
24963
|
-
const
|
|
24964
|
-
if (
|
|
24965
|
-
|
|
25346
|
+
const responseHandler = this._responseHandlers.get(messageId);
|
|
25347
|
+
const timeoutInfo = this._timeoutInfo.get(messageId);
|
|
25348
|
+
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
|
|
25349
|
+
try {
|
|
25350
|
+
this._resetTimeout(messageId);
|
|
25351
|
+
} catch (error) {
|
|
25352
|
+
this._responseHandlers.delete(messageId);
|
|
25353
|
+
this._progressHandlers.delete(messageId);
|
|
25354
|
+
this._cleanupTimeout(messageId);
|
|
25355
|
+
responseHandler(error);
|
|
24966
25356
|
return;
|
|
24967
25357
|
}
|
|
24968
|
-
|
|
24969
|
-
|
|
24970
|
-
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
24978
|
-
|
|
24979
|
-
|
|
24980
|
-
|
|
24981
|
-
|
|
24982
|
-
...jsonrpcNotification.params,
|
|
24983
|
-
_meta: {
|
|
24984
|
-
...jsonrpcNotification.params?._meta || {},
|
|
24985
|
-
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
24986
|
-
}
|
|
24987
|
-
}
|
|
24988
|
-
};
|
|
24989
|
-
}
|
|
24990
|
-
this._transport?.send(jsonrpcNotification, options).catch((error) => this._onerror(error));
|
|
24991
|
-
});
|
|
25358
|
+
}
|
|
25359
|
+
handler(params);
|
|
25360
|
+
}
|
|
25361
|
+
_onresponse(response) {
|
|
25362
|
+
const messageId = Number(response.id);
|
|
25363
|
+
const resolver = this._requestResolvers.get(messageId);
|
|
25364
|
+
if (resolver) {
|
|
25365
|
+
this._requestResolvers.delete(messageId);
|
|
25366
|
+
if (isJSONRPCResultResponse(response)) {
|
|
25367
|
+
resolver(response);
|
|
25368
|
+
} else {
|
|
25369
|
+
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
|
25370
|
+
resolver(error);
|
|
25371
|
+
}
|
|
24992
25372
|
return;
|
|
24993
25373
|
}
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25374
|
+
const handler = this._responseHandlers.get(messageId);
|
|
25375
|
+
if (handler === undefined) {
|
|
25376
|
+
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
|
25377
|
+
return;
|
|
25378
|
+
}
|
|
25379
|
+
this._responseHandlers.delete(messageId);
|
|
25380
|
+
this._cleanupTimeout(messageId);
|
|
25381
|
+
let isTaskResponse = false;
|
|
25382
|
+
if (isJSONRPCResultResponse(response) && response.result && typeof response.result === "object") {
|
|
25383
|
+
const result = response.result;
|
|
25384
|
+
if (result.task && typeof result.task === "object") {
|
|
25385
|
+
const task = result.task;
|
|
25386
|
+
if (typeof task.taskId === "string") {
|
|
25387
|
+
isTaskResponse = true;
|
|
25388
|
+
this._taskProgressTokens.set(task.taskId, messageId);
|
|
25007
25389
|
}
|
|
25008
|
-
}
|
|
25390
|
+
}
|
|
25009
25391
|
}
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
const
|
|
25017
|
-
|
|
25018
|
-
});
|
|
25019
|
-
}
|
|
25020
|
-
removeRequestHandler(method) {
|
|
25021
|
-
this._requestHandlers.delete(method);
|
|
25022
|
-
}
|
|
25023
|
-
assertCanSetRequestHandler(method) {
|
|
25024
|
-
if (this._requestHandlers.has(method)) {
|
|
25025
|
-
throw new Error(`A request handler for ${method} already exists, which would be overridden`);
|
|
25392
|
+
if (!isTaskResponse) {
|
|
25393
|
+
this._progressHandlers.delete(messageId);
|
|
25394
|
+
}
|
|
25395
|
+
if (isJSONRPCResultResponse(response)) {
|
|
25396
|
+
handler(response);
|
|
25397
|
+
} else {
|
|
25398
|
+
const error = McpError.fromError(response.error.code, response.error.message, response.error.data);
|
|
25399
|
+
handler(error);
|
|
25026
25400
|
}
|
|
25027
25401
|
}
|
|
25028
|
-
|
|
25029
|
-
|
|
25030
|
-
this._notificationHandlers.set(method, (notification) => {
|
|
25031
|
-
const parsed = parseWithCompat(notificationSchema, notification);
|
|
25032
|
-
return Promise.resolve(handler(parsed));
|
|
25033
|
-
});
|
|
25034
|
-
}
|
|
25035
|
-
removeNotificationHandler(method) {
|
|
25036
|
-
this._notificationHandlers.delete(method);
|
|
25402
|
+
get transport() {
|
|
25403
|
+
return this._transport;
|
|
25037
25404
|
}
|
|
25038
|
-
|
|
25039
|
-
|
|
25040
|
-
if (progressToken !== undefined) {
|
|
25041
|
-
this._progressHandlers.delete(progressToken);
|
|
25042
|
-
this._taskProgressTokens.delete(taskId);
|
|
25043
|
-
}
|
|
25405
|
+
async close() {
|
|
25406
|
+
await this._transport?.close();
|
|
25044
25407
|
}
|
|
25045
|
-
async
|
|
25046
|
-
|
|
25047
|
-
|
|
25408
|
+
async* requestStream(request, resultSchema, options) {
|
|
25409
|
+
const { task } = options ?? {};
|
|
25410
|
+
if (!task) {
|
|
25411
|
+
try {
|
|
25412
|
+
const result = await this.request(request, resultSchema, options);
|
|
25413
|
+
yield { type: "result", result };
|
|
25414
|
+
} catch (error) {
|
|
25415
|
+
yield {
|
|
25416
|
+
type: "error",
|
|
25417
|
+
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
25418
|
+
};
|
|
25419
|
+
}
|
|
25420
|
+
return;
|
|
25048
25421
|
}
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25422
|
+
let taskId;
|
|
25423
|
+
try {
|
|
25424
|
+
const createResult = await this.request(request, CreateTaskResultSchema, options);
|
|
25425
|
+
if (createResult.task) {
|
|
25426
|
+
taskId = createResult.task.taskId;
|
|
25427
|
+
yield { type: "taskCreated", task: createResult.task };
|
|
25428
|
+
} else {
|
|
25429
|
+
throw new McpError(ErrorCode.InternalError, "Task creation did not return a task");
|
|
25430
|
+
}
|
|
25431
|
+
while (true) {
|
|
25432
|
+
const task = await this.getTask({ taskId }, options);
|
|
25433
|
+
yield { type: "taskStatus", task };
|
|
25434
|
+
if (isTerminal(task.status)) {
|
|
25435
|
+
if (task.status === "completed") {
|
|
25436
|
+
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
25437
|
+
yield { type: "result", result };
|
|
25438
|
+
} else if (task.status === "failed") {
|
|
25439
|
+
yield {
|
|
25440
|
+
type: "error",
|
|
25441
|
+
error: new McpError(ErrorCode.InternalError, `Task ${taskId} failed`)
|
|
25442
|
+
};
|
|
25443
|
+
} else if (task.status === "cancelled") {
|
|
25444
|
+
yield {
|
|
25445
|
+
type: "error",
|
|
25446
|
+
error: new McpError(ErrorCode.InternalError, `Task ${taskId} was cancelled`)
|
|
25447
|
+
};
|
|
25064
25448
|
}
|
|
25449
|
+
return;
|
|
25450
|
+
}
|
|
25451
|
+
if (task.status === "input_required") {
|
|
25452
|
+
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
25453
|
+
yield { type: "result", result };
|
|
25454
|
+
return;
|
|
25065
25455
|
}
|
|
25456
|
+
const pollInterval = task.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
25457
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
25458
|
+
options?.signal?.throwIfAborted();
|
|
25066
25459
|
}
|
|
25460
|
+
} catch (error) {
|
|
25461
|
+
yield {
|
|
25462
|
+
type: "error",
|
|
25463
|
+
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
25464
|
+
};
|
|
25067
25465
|
}
|
|
25068
25466
|
}
|
|
25069
|
-
|
|
25070
|
-
|
|
25071
|
-
try {
|
|
25072
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
25073
|
-
if (task?.pollInterval) {
|
|
25074
|
-
interval = task.pollInterval;
|
|
25075
|
-
}
|
|
25076
|
-
} catch {}
|
|
25467
|
+
request(request, resultSchema, options) {
|
|
25468
|
+
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
25077
25469
|
return new Promise((resolve, reject) => {
|
|
25078
|
-
|
|
25079
|
-
reject(
|
|
25470
|
+
const earlyReject = (error) => {
|
|
25471
|
+
reject(error);
|
|
25472
|
+
};
|
|
25473
|
+
if (!this._transport) {
|
|
25474
|
+
earlyReject(new Error("Not connected"));
|
|
25080
25475
|
return;
|
|
25081
25476
|
}
|
|
25082
|
-
|
|
25083
|
-
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
25087
|
-
});
|
|
25088
|
-
}
|
|
25089
|
-
requestTaskStore(request, sessionId) {
|
|
25090
|
-
const taskStore = this._taskStore;
|
|
25091
|
-
if (!taskStore) {
|
|
25092
|
-
throw new Error("No task store configured");
|
|
25093
|
-
}
|
|
25094
|
-
return {
|
|
25095
|
-
createTask: async (taskParams) => {
|
|
25096
|
-
if (!request) {
|
|
25097
|
-
throw new Error("No request provided");
|
|
25098
|
-
}
|
|
25099
|
-
return await taskStore.createTask(taskParams, request.id, {
|
|
25100
|
-
method: request.method,
|
|
25101
|
-
params: request.params
|
|
25102
|
-
}, sessionId);
|
|
25103
|
-
},
|
|
25104
|
-
getTask: async (taskId) => {
|
|
25105
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25106
|
-
if (!task) {
|
|
25107
|
-
throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
25108
|
-
}
|
|
25109
|
-
return task;
|
|
25110
|
-
},
|
|
25111
|
-
storeTaskResult: async (taskId, status, result) => {
|
|
25112
|
-
await taskStore.storeTaskResult(taskId, status, result, sessionId);
|
|
25113
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25114
|
-
if (task) {
|
|
25115
|
-
const notification = TaskStatusNotificationSchema.parse({
|
|
25116
|
-
method: "notifications/tasks/status",
|
|
25117
|
-
params: task
|
|
25118
|
-
});
|
|
25119
|
-
await this.notification(notification);
|
|
25120
|
-
if (isTerminal(task.status)) {
|
|
25121
|
-
this._cleanupTaskProgressHandler(taskId);
|
|
25122
|
-
}
|
|
25123
|
-
}
|
|
25124
|
-
},
|
|
25125
|
-
getTaskResult: (taskId) => {
|
|
25126
|
-
return taskStore.getTaskResult(taskId, sessionId);
|
|
25127
|
-
},
|
|
25128
|
-
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
25129
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25130
|
-
if (!task) {
|
|
25131
|
-
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
25132
|
-
}
|
|
25133
|
-
if (isTerminal(task.status)) {
|
|
25134
|
-
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
25135
|
-
}
|
|
25136
|
-
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
|
|
25137
|
-
const updatedTask = await taskStore.getTask(taskId, sessionId);
|
|
25138
|
-
if (updatedTask) {
|
|
25139
|
-
const notification = TaskStatusNotificationSchema.parse({
|
|
25140
|
-
method: "notifications/tasks/status",
|
|
25141
|
-
params: updatedTask
|
|
25142
|
-
});
|
|
25143
|
-
await this.notification(notification);
|
|
25144
|
-
if (isTerminal(updatedTask.status)) {
|
|
25145
|
-
this._cleanupTaskProgressHandler(taskId);
|
|
25477
|
+
if (this._options?.enforceStrictCapabilities === true) {
|
|
25478
|
+
try {
|
|
25479
|
+
this.assertCapabilityForMethod(request.method);
|
|
25480
|
+
if (task) {
|
|
25481
|
+
this.assertTaskCapability(request.method);
|
|
25146
25482
|
}
|
|
25483
|
+
} catch (e) {
|
|
25484
|
+
earlyReject(e);
|
|
25485
|
+
return;
|
|
25147
25486
|
}
|
|
25148
|
-
},
|
|
25149
|
-
listTasks: (cursor) => {
|
|
25150
|
-
return taskStore.listTasks(cursor, sessionId);
|
|
25151
25487
|
}
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
|
|
25165
|
-
|
|
25166
|
-
|
|
25167
|
-
result[k] = { ...baseValue, ...addValue };
|
|
25168
|
-
} else {
|
|
25169
|
-
result[k] = addValue;
|
|
25170
|
-
}
|
|
25171
|
-
}
|
|
25172
|
-
return result;
|
|
25173
|
-
}
|
|
25174
|
-
|
|
25175
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
25176
|
-
var import_ajv = __toESM(require_ajv(), 1);
|
|
25177
|
-
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
25178
|
-
function createDefaultAjvInstance() {
|
|
25179
|
-
const ajv = new import_ajv.default({
|
|
25180
|
-
strict: false,
|
|
25181
|
-
validateFormats: true,
|
|
25182
|
-
validateSchema: false,
|
|
25183
|
-
allErrors: true
|
|
25184
|
-
});
|
|
25185
|
-
const addFormats = import_ajv_formats.default;
|
|
25186
|
-
addFormats(ajv);
|
|
25187
|
-
return ajv;
|
|
25188
|
-
}
|
|
25189
|
-
|
|
25190
|
-
class AjvJsonSchemaValidator {
|
|
25191
|
-
constructor(ajv) {
|
|
25192
|
-
this._ajv = ajv ?? createDefaultAjvInstance();
|
|
25193
|
-
}
|
|
25194
|
-
getValidator(schema) {
|
|
25195
|
-
const ajvValidator = "$id" in schema && typeof schema.$id === "string" ? this._ajv.getSchema(schema.$id) ?? this._ajv.compile(schema) : this._ajv.compile(schema);
|
|
25196
|
-
return (input) => {
|
|
25197
|
-
const valid = ajvValidator(input);
|
|
25198
|
-
if (valid) {
|
|
25199
|
-
return {
|
|
25200
|
-
valid: true,
|
|
25201
|
-
data: input,
|
|
25202
|
-
errorMessage: undefined
|
|
25488
|
+
options?.signal?.throwIfAborted();
|
|
25489
|
+
const messageId = this._requestMessageId++;
|
|
25490
|
+
const jsonrpcRequest = {
|
|
25491
|
+
...request,
|
|
25492
|
+
jsonrpc: "2.0",
|
|
25493
|
+
id: messageId
|
|
25494
|
+
};
|
|
25495
|
+
if (options?.onprogress) {
|
|
25496
|
+
this._progressHandlers.set(messageId, options.onprogress);
|
|
25497
|
+
jsonrpcRequest.params = {
|
|
25498
|
+
...request.params,
|
|
25499
|
+
_meta: {
|
|
25500
|
+
...request.params?._meta || {},
|
|
25501
|
+
progressToken: messageId
|
|
25502
|
+
}
|
|
25203
25503
|
};
|
|
25204
|
-
}
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25504
|
+
}
|
|
25505
|
+
if (task) {
|
|
25506
|
+
jsonrpcRequest.params = {
|
|
25507
|
+
...jsonrpcRequest.params,
|
|
25508
|
+
task
|
|
25209
25509
|
};
|
|
25210
25510
|
}
|
|
25211
|
-
|
|
25212
|
-
|
|
25213
|
-
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
}
|
|
25220
|
-
requestStream(request, resultSchema, options) {
|
|
25221
|
-
return this._server.requestStream(request, resultSchema, options);
|
|
25222
|
-
}
|
|
25223
|
-
createMessageStream(params, options) {
|
|
25224
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
25225
|
-
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
25226
|
-
throw new Error("Client does not support sampling tools capability.");
|
|
25227
|
-
}
|
|
25228
|
-
if (params.messages.length > 0) {
|
|
25229
|
-
const lastMessage = params.messages[params.messages.length - 1];
|
|
25230
|
-
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
25231
|
-
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
25232
|
-
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
|
|
25233
|
-
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
25234
|
-
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
25235
|
-
if (hasToolResults) {
|
|
25236
|
-
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
25237
|
-
throw new Error("The last message must contain only tool_result content if any is present");
|
|
25238
|
-
}
|
|
25239
|
-
if (!hasPreviousToolUse) {
|
|
25240
|
-
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
25241
|
-
}
|
|
25511
|
+
if (relatedTask) {
|
|
25512
|
+
jsonrpcRequest.params = {
|
|
25513
|
+
...jsonrpcRequest.params,
|
|
25514
|
+
_meta: {
|
|
25515
|
+
...jsonrpcRequest.params?._meta || {},
|
|
25516
|
+
[RELATED_TASK_META_KEY]: relatedTask
|
|
25517
|
+
}
|
|
25518
|
+
};
|
|
25242
25519
|
}
|
|
25243
|
-
|
|
25244
|
-
|
|
25245
|
-
|
|
25246
|
-
|
|
25247
|
-
|
|
25520
|
+
const cancel = (reason) => {
|
|
25521
|
+
this._responseHandlers.delete(messageId);
|
|
25522
|
+
this._progressHandlers.delete(messageId);
|
|
25523
|
+
this._cleanupTimeout(messageId);
|
|
25524
|
+
this._transport?.send({
|
|
25525
|
+
jsonrpc: "2.0",
|
|
25526
|
+
method: "notifications/cancelled",
|
|
25527
|
+
params: {
|
|
25528
|
+
requestId: messageId,
|
|
25529
|
+
reason: String(reason)
|
|
25530
|
+
}
|
|
25531
|
+
}, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
|
|
25532
|
+
const error = reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason));
|
|
25533
|
+
reject(error);
|
|
25534
|
+
};
|
|
25535
|
+
this._responseHandlers.set(messageId, (response) => {
|
|
25536
|
+
if (options?.signal?.aborted) {
|
|
25537
|
+
return;
|
|
25248
25538
|
}
|
|
25249
|
-
|
|
25250
|
-
|
|
25251
|
-
return this.requestStream({
|
|
25252
|
-
method: "sampling/createMessage",
|
|
25253
|
-
params
|
|
25254
|
-
}, CreateMessageResultSchema, options);
|
|
25255
|
-
}
|
|
25256
|
-
elicitInputStream(params, options) {
|
|
25257
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
25258
|
-
const mode = params.mode ?? "form";
|
|
25259
|
-
switch (mode) {
|
|
25260
|
-
case "url": {
|
|
25261
|
-
if (!clientCapabilities?.elicitation?.url) {
|
|
25262
|
-
throw new Error("Client does not support url elicitation.");
|
|
25539
|
+
if (response instanceof Error) {
|
|
25540
|
+
return reject(response);
|
|
25263
25541
|
}
|
|
25264
|
-
|
|
25265
|
-
|
|
25266
|
-
|
|
25267
|
-
|
|
25268
|
-
|
|
25542
|
+
try {
|
|
25543
|
+
const parseResult = safeParse4(resultSchema, response.result);
|
|
25544
|
+
if (!parseResult.success) {
|
|
25545
|
+
reject(parseResult.error);
|
|
25546
|
+
} else {
|
|
25547
|
+
resolve(parseResult.data);
|
|
25548
|
+
}
|
|
25549
|
+
} catch (error) {
|
|
25550
|
+
reject(error);
|
|
25269
25551
|
}
|
|
25270
|
-
|
|
25552
|
+
});
|
|
25553
|
+
options?.signal?.addEventListener("abort", () => {
|
|
25554
|
+
cancel(options?.signal?.reason);
|
|
25555
|
+
});
|
|
25556
|
+
const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC;
|
|
25557
|
+
const timeoutHandler = () => cancel(McpError.fromError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
|
|
25558
|
+
this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false);
|
|
25559
|
+
const relatedTaskId = relatedTask?.taskId;
|
|
25560
|
+
if (relatedTaskId) {
|
|
25561
|
+
const responseResolver = (response) => {
|
|
25562
|
+
const handler = this._responseHandlers.get(messageId);
|
|
25563
|
+
if (handler) {
|
|
25564
|
+
handler(response);
|
|
25565
|
+
} else {
|
|
25566
|
+
this._onerror(new Error(`Response handler missing for side-channeled request ${messageId}`));
|
|
25567
|
+
}
|
|
25568
|
+
};
|
|
25569
|
+
this._requestResolvers.set(messageId, responseResolver);
|
|
25570
|
+
this._enqueueTaskMessage(relatedTaskId, {
|
|
25571
|
+
type: "request",
|
|
25572
|
+
message: jsonrpcRequest,
|
|
25573
|
+
timestamp: Date.now()
|
|
25574
|
+
}).catch((error) => {
|
|
25575
|
+
this._cleanupTimeout(messageId);
|
|
25576
|
+
reject(error);
|
|
25577
|
+
});
|
|
25578
|
+
} else {
|
|
25579
|
+
this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => {
|
|
25580
|
+
this._cleanupTimeout(messageId);
|
|
25581
|
+
reject(error);
|
|
25582
|
+
});
|
|
25271
25583
|
}
|
|
25272
|
-
}
|
|
25273
|
-
const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
|
|
25274
|
-
return this.requestStream({
|
|
25275
|
-
method: "elicitation/create",
|
|
25276
|
-
params: normalizedParams
|
|
25277
|
-
}, ElicitResultSchema, options);
|
|
25278
|
-
}
|
|
25279
|
-
async getTask(taskId, options) {
|
|
25280
|
-
return this._server.getTask({ taskId }, options);
|
|
25281
|
-
}
|
|
25282
|
-
async getTaskResult(taskId, resultSchema, options) {
|
|
25283
|
-
return this._server.getTaskResult({ taskId }, resultSchema, options);
|
|
25284
|
-
}
|
|
25285
|
-
async listTasks(cursor, options) {
|
|
25286
|
-
return this._server.listTasks(cursor ? { cursor } : undefined, options);
|
|
25287
|
-
}
|
|
25288
|
-
async cancelTask(taskId, options) {
|
|
25289
|
-
return this._server.cancelTask({ taskId }, options);
|
|
25584
|
+
});
|
|
25290
25585
|
}
|
|
25291
|
-
|
|
25292
|
-
|
|
25293
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
25294
|
-
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
25295
|
-
if (!requests) {
|
|
25296
|
-
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
25586
|
+
async getTask(params, options) {
|
|
25587
|
+
return this.request({ method: "tasks/get", params }, GetTaskResultSchema, options);
|
|
25297
25588
|
}
|
|
25298
|
-
|
|
25299
|
-
|
|
25300
|
-
if (!requests.tools?.call) {
|
|
25301
|
-
throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
|
|
25302
|
-
}
|
|
25303
|
-
break;
|
|
25304
|
-
default:
|
|
25305
|
-
break;
|
|
25589
|
+
async getTaskResult(params, resultSchema, options) {
|
|
25590
|
+
return this.request({ method: "tasks/result", params }, resultSchema, options);
|
|
25306
25591
|
}
|
|
25307
|
-
|
|
25308
|
-
|
|
25309
|
-
if (!requests) {
|
|
25310
|
-
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
25592
|
+
async listTasks(params, options) {
|
|
25593
|
+
return this.request({ method: "tasks/list", params }, ListTasksResultSchema, options);
|
|
25311
25594
|
}
|
|
25312
|
-
|
|
25313
|
-
|
|
25314
|
-
if (!requests.sampling?.createMessage) {
|
|
25315
|
-
throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
|
|
25316
|
-
}
|
|
25317
|
-
break;
|
|
25318
|
-
case "elicitation/create":
|
|
25319
|
-
if (!requests.elicitation?.create) {
|
|
25320
|
-
throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
|
|
25321
|
-
}
|
|
25322
|
-
break;
|
|
25323
|
-
default:
|
|
25324
|
-
break;
|
|
25595
|
+
async cancelTask(params, options) {
|
|
25596
|
+
return this.request({ method: "tasks/cancel", params }, CancelTaskResultSchema, options);
|
|
25325
25597
|
}
|
|
25326
|
-
|
|
25327
|
-
|
|
25328
|
-
|
|
25329
|
-
class Server extends Protocol {
|
|
25330
|
-
constructor(_serverInfo, options) {
|
|
25331
|
-
super(options);
|
|
25332
|
-
this._serverInfo = _serverInfo;
|
|
25333
|
-
this._loggingLevels = new Map;
|
|
25334
|
-
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
25335
|
-
this.isMessageIgnored = (level, sessionId) => {
|
|
25336
|
-
const currentLevel = this._loggingLevels.get(sessionId);
|
|
25337
|
-
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
25338
|
-
};
|
|
25339
|
-
this._capabilities = options?.capabilities ?? {};
|
|
25340
|
-
this._instructions = options?.instructions;
|
|
25341
|
-
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator;
|
|
25342
|
-
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
|
25343
|
-
this.setNotificationHandler(InitializedNotificationSchema, () => this.oninitialized?.());
|
|
25344
|
-
if (this._capabilities.logging) {
|
|
25345
|
-
this.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {
|
|
25346
|
-
const transportSessionId = extra.sessionId || extra.requestInfo?.headers["mcp-session-id"] || undefined;
|
|
25347
|
-
const { level } = request.params;
|
|
25348
|
-
const parseResult = LoggingLevelSchema.safeParse(level);
|
|
25349
|
-
if (parseResult.success) {
|
|
25350
|
-
this._loggingLevels.set(transportSessionId, parseResult.data);
|
|
25351
|
-
}
|
|
25352
|
-
return {};
|
|
25353
|
-
});
|
|
25598
|
+
async notification(notification, options) {
|
|
25599
|
+
if (!this._transport) {
|
|
25600
|
+
throw new Error("Not connected");
|
|
25354
25601
|
}
|
|
25355
|
-
|
|
25356
|
-
|
|
25357
|
-
if (
|
|
25358
|
-
|
|
25359
|
-
|
|
25602
|
+
this.assertNotificationCapability(notification.method);
|
|
25603
|
+
const relatedTaskId = options?.relatedTask?.taskId;
|
|
25604
|
+
if (relatedTaskId) {
|
|
25605
|
+
const jsonrpcNotification = {
|
|
25606
|
+
...notification,
|
|
25607
|
+
jsonrpc: "2.0",
|
|
25608
|
+
params: {
|
|
25609
|
+
...notification.params,
|
|
25610
|
+
_meta: {
|
|
25611
|
+
...notification.params?._meta || {},
|
|
25612
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
25613
|
+
}
|
|
25614
|
+
}
|
|
25360
25615
|
};
|
|
25616
|
+
await this._enqueueTaskMessage(relatedTaskId, {
|
|
25617
|
+
type: "notification",
|
|
25618
|
+
message: jsonrpcNotification,
|
|
25619
|
+
timestamp: Date.now()
|
|
25620
|
+
});
|
|
25621
|
+
return;
|
|
25361
25622
|
}
|
|
25362
|
-
|
|
25363
|
-
|
|
25364
|
-
|
|
25365
|
-
|
|
25366
|
-
|
|
25367
|
-
|
|
25368
|
-
|
|
25369
|
-
|
|
25370
|
-
|
|
25371
|
-
|
|
25372
|
-
|
|
25373
|
-
if (!methodSchema) {
|
|
25374
|
-
throw new Error("Schema is missing a method literal");
|
|
25375
|
-
}
|
|
25376
|
-
const methodValue = getLiteralValue(methodSchema);
|
|
25377
|
-
if (typeof methodValue !== "string") {
|
|
25378
|
-
throw new Error("Schema method literal must be a string");
|
|
25379
|
-
}
|
|
25380
|
-
const method = methodValue;
|
|
25381
|
-
if (method === "tools/call") {
|
|
25382
|
-
const wrappedHandler = async (request, extra) => {
|
|
25383
|
-
const validatedRequest = safeParse4(CallToolRequestSchema, request);
|
|
25384
|
-
if (!validatedRequest.success) {
|
|
25385
|
-
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
25386
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage}`);
|
|
25623
|
+
const debouncedMethods = this._options?.debouncedNotificationMethods ?? [];
|
|
25624
|
+
const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !options?.relatedRequestId && !options?.relatedTask;
|
|
25625
|
+
if (canDebounce) {
|
|
25626
|
+
if (this._pendingDebouncedNotifications.has(notification.method)) {
|
|
25627
|
+
return;
|
|
25628
|
+
}
|
|
25629
|
+
this._pendingDebouncedNotifications.add(notification.method);
|
|
25630
|
+
Promise.resolve().then(() => {
|
|
25631
|
+
this._pendingDebouncedNotifications.delete(notification.method);
|
|
25632
|
+
if (!this._transport) {
|
|
25633
|
+
return;
|
|
25387
25634
|
}
|
|
25388
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
25391
|
-
|
|
25392
|
-
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
25396
|
-
|
|
25635
|
+
let jsonrpcNotification = {
|
|
25636
|
+
...notification,
|
|
25637
|
+
jsonrpc: "2.0"
|
|
25638
|
+
};
|
|
25639
|
+
if (options?.relatedTask) {
|
|
25640
|
+
jsonrpcNotification = {
|
|
25641
|
+
...jsonrpcNotification,
|
|
25642
|
+
params: {
|
|
25643
|
+
...jsonrpcNotification.params,
|
|
25644
|
+
_meta: {
|
|
25645
|
+
...jsonrpcNotification.params?._meta || {},
|
|
25646
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
25647
|
+
}
|
|
25648
|
+
}
|
|
25649
|
+
};
|
|
25397
25650
|
}
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
|
|
25401
|
-
|
|
25651
|
+
this._transport?.send(jsonrpcNotification, options).catch((error) => this._onerror(error));
|
|
25652
|
+
});
|
|
25653
|
+
return;
|
|
25654
|
+
}
|
|
25655
|
+
let jsonrpcNotification = {
|
|
25656
|
+
...notification,
|
|
25657
|
+
jsonrpc: "2.0"
|
|
25658
|
+
};
|
|
25659
|
+
if (options?.relatedTask) {
|
|
25660
|
+
jsonrpcNotification = {
|
|
25661
|
+
...jsonrpcNotification,
|
|
25662
|
+
params: {
|
|
25663
|
+
...jsonrpcNotification.params,
|
|
25664
|
+
_meta: {
|
|
25665
|
+
...jsonrpcNotification.params?._meta || {},
|
|
25666
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
25667
|
+
}
|
|
25402
25668
|
}
|
|
25403
|
-
return validationResult.data;
|
|
25404
25669
|
};
|
|
25405
|
-
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
25406
25670
|
}
|
|
25407
|
-
|
|
25671
|
+
await this._transport.send(jsonrpcNotification, options);
|
|
25408
25672
|
}
|
|
25409
|
-
|
|
25410
|
-
|
|
25411
|
-
|
|
25412
|
-
|
|
25413
|
-
|
|
25414
|
-
|
|
25415
|
-
|
|
25416
|
-
|
|
25417
|
-
|
|
25418
|
-
|
|
25419
|
-
|
|
25420
|
-
|
|
25421
|
-
|
|
25422
|
-
|
|
25423
|
-
throw new Error(`Client does not support listing roots (required for ${method})`);
|
|
25424
|
-
}
|
|
25425
|
-
break;
|
|
25426
|
-
case "ping":
|
|
25427
|
-
break;
|
|
25673
|
+
setRequestHandler(requestSchema, handler) {
|
|
25674
|
+
const method = getMethodLiteral(requestSchema);
|
|
25675
|
+
this.assertRequestHandlerCapability(method);
|
|
25676
|
+
this._requestHandlers.set(method, (request, extra) => {
|
|
25677
|
+
const parsed = parseWithCompat(requestSchema, request);
|
|
25678
|
+
return Promise.resolve(handler(parsed, extra));
|
|
25679
|
+
});
|
|
25680
|
+
}
|
|
25681
|
+
removeRequestHandler(method) {
|
|
25682
|
+
this._requestHandlers.delete(method);
|
|
25683
|
+
}
|
|
25684
|
+
assertCanSetRequestHandler(method) {
|
|
25685
|
+
if (this._requestHandlers.has(method)) {
|
|
25686
|
+
throw new Error(`A request handler for ${method} already exists, which would be overridden`);
|
|
25428
25687
|
}
|
|
25429
25688
|
}
|
|
25430
|
-
|
|
25431
|
-
|
|
25432
|
-
|
|
25433
|
-
|
|
25434
|
-
|
|
25435
|
-
|
|
25436
|
-
|
|
25437
|
-
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25445
|
-
|
|
25446
|
-
|
|
25447
|
-
|
|
25448
|
-
|
|
25449
|
-
|
|
25450
|
-
|
|
25451
|
-
|
|
25452
|
-
|
|
25453
|
-
|
|
25454
|
-
|
|
25455
|
-
|
|
25689
|
+
setNotificationHandler(notificationSchema, handler) {
|
|
25690
|
+
const method = getMethodLiteral(notificationSchema);
|
|
25691
|
+
this._notificationHandlers.set(method, (notification) => {
|
|
25692
|
+
const parsed = parseWithCompat(notificationSchema, notification);
|
|
25693
|
+
return Promise.resolve(handler(parsed));
|
|
25694
|
+
});
|
|
25695
|
+
}
|
|
25696
|
+
removeNotificationHandler(method) {
|
|
25697
|
+
this._notificationHandlers.delete(method);
|
|
25698
|
+
}
|
|
25699
|
+
_cleanupTaskProgressHandler(taskId) {
|
|
25700
|
+
const progressToken = this._taskProgressTokens.get(taskId);
|
|
25701
|
+
if (progressToken !== undefined) {
|
|
25702
|
+
this._progressHandlers.delete(progressToken);
|
|
25703
|
+
this._taskProgressTokens.delete(taskId);
|
|
25704
|
+
}
|
|
25705
|
+
}
|
|
25706
|
+
async _enqueueTaskMessage(taskId, message, sessionId) {
|
|
25707
|
+
if (!this._taskStore || !this._taskMessageQueue) {
|
|
25708
|
+
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
25709
|
+
}
|
|
25710
|
+
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
25711
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
25712
|
+
}
|
|
25713
|
+
async _clearTaskQueue(taskId, sessionId) {
|
|
25714
|
+
if (this._taskMessageQueue) {
|
|
25715
|
+
const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
|
|
25716
|
+
for (const message of messages) {
|
|
25717
|
+
if (message.type === "request" && isJSONRPCRequest(message.message)) {
|
|
25718
|
+
const requestId = message.message.id;
|
|
25719
|
+
const resolver = this._requestResolvers.get(requestId);
|
|
25720
|
+
if (resolver) {
|
|
25721
|
+
resolver(new McpError(ErrorCode.InternalError, "Task cancelled or completed"));
|
|
25722
|
+
this._requestResolvers.delete(requestId);
|
|
25723
|
+
} else {
|
|
25724
|
+
this._onerror(new Error(`Resolver missing for request ${requestId} during task ${taskId} cleanup`));
|
|
25725
|
+
}
|
|
25456
25726
|
}
|
|
25457
|
-
|
|
25458
|
-
case "notifications/cancelled":
|
|
25459
|
-
break;
|
|
25460
|
-
case "notifications/progress":
|
|
25461
|
-
break;
|
|
25727
|
+
}
|
|
25462
25728
|
}
|
|
25463
25729
|
}
|
|
25464
|
-
|
|
25465
|
-
|
|
25466
|
-
|
|
25730
|
+
async _waitForTaskUpdate(taskId, signal) {
|
|
25731
|
+
let interval = this._options?.defaultTaskPollInterval ?? 1000;
|
|
25732
|
+
try {
|
|
25733
|
+
const task = await this._taskStore?.getTask(taskId);
|
|
25734
|
+
if (task?.pollInterval) {
|
|
25735
|
+
interval = task.pollInterval;
|
|
25736
|
+
}
|
|
25737
|
+
} catch {}
|
|
25738
|
+
return new Promise((resolve, reject) => {
|
|
25739
|
+
if (signal.aborted) {
|
|
25740
|
+
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
25741
|
+
return;
|
|
25742
|
+
}
|
|
25743
|
+
const timeoutId = setTimeout(resolve, interval);
|
|
25744
|
+
signal.addEventListener("abort", () => {
|
|
25745
|
+
clearTimeout(timeoutId);
|
|
25746
|
+
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
25747
|
+
}, { once: true });
|
|
25748
|
+
});
|
|
25749
|
+
}
|
|
25750
|
+
requestTaskStore(request, sessionId) {
|
|
25751
|
+
const taskStore = this._taskStore;
|
|
25752
|
+
if (!taskStore) {
|
|
25753
|
+
throw new Error("No task store configured");
|
|
25467
25754
|
}
|
|
25468
|
-
|
|
25469
|
-
|
|
25470
|
-
if (!
|
|
25471
|
-
throw new Error(
|
|
25755
|
+
return {
|
|
25756
|
+
createTask: async (taskParams) => {
|
|
25757
|
+
if (!request) {
|
|
25758
|
+
throw new Error("No request provided");
|
|
25472
25759
|
}
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
|
|
25760
|
+
return await taskStore.createTask(taskParams, request.id, {
|
|
25761
|
+
method: request.method,
|
|
25762
|
+
params: request.params
|
|
25763
|
+
}, sessionId);
|
|
25764
|
+
},
|
|
25765
|
+
getTask: async (taskId) => {
|
|
25766
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
25767
|
+
if (!task) {
|
|
25768
|
+
throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
25477
25769
|
}
|
|
25478
|
-
|
|
25479
|
-
|
|
25480
|
-
|
|
25481
|
-
|
|
25482
|
-
|
|
25770
|
+
return task;
|
|
25771
|
+
},
|
|
25772
|
+
storeTaskResult: async (taskId, status, result) => {
|
|
25773
|
+
await taskStore.storeTaskResult(taskId, status, result, sessionId);
|
|
25774
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
25775
|
+
if (task) {
|
|
25776
|
+
const notification = TaskStatusNotificationSchema.parse({
|
|
25777
|
+
method: "notifications/tasks/status",
|
|
25778
|
+
params: task
|
|
25779
|
+
});
|
|
25780
|
+
await this.notification(notification);
|
|
25781
|
+
if (isTerminal(task.status)) {
|
|
25782
|
+
this._cleanupTaskProgressHandler(taskId);
|
|
25783
|
+
}
|
|
25483
25784
|
}
|
|
25484
|
-
|
|
25485
|
-
|
|
25486
|
-
|
|
25487
|
-
|
|
25488
|
-
|
|
25489
|
-
|
|
25785
|
+
},
|
|
25786
|
+
getTaskResult: (taskId) => {
|
|
25787
|
+
return taskStore.getTaskResult(taskId, sessionId);
|
|
25788
|
+
},
|
|
25789
|
+
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
25790
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
25791
|
+
if (!task) {
|
|
25792
|
+
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
25490
25793
|
}
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
case "tools/list":
|
|
25494
|
-
if (!this._capabilities.tools) {
|
|
25495
|
-
throw new Error(`Server does not support tools (required for ${method})`);
|
|
25794
|
+
if (isTerminal(task.status)) {
|
|
25795
|
+
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
25496
25796
|
}
|
|
25497
|
-
|
|
25498
|
-
|
|
25499
|
-
|
|
25500
|
-
|
|
25501
|
-
|
|
25502
|
-
|
|
25503
|
-
|
|
25797
|
+
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
|
|
25798
|
+
const updatedTask = await taskStore.getTask(taskId, sessionId);
|
|
25799
|
+
if (updatedTask) {
|
|
25800
|
+
const notification = TaskStatusNotificationSchema.parse({
|
|
25801
|
+
method: "notifications/tasks/status",
|
|
25802
|
+
params: updatedTask
|
|
25803
|
+
});
|
|
25804
|
+
await this.notification(notification);
|
|
25805
|
+
if (isTerminal(updatedTask.status)) {
|
|
25806
|
+
this._cleanupTaskProgressHandler(taskId);
|
|
25807
|
+
}
|
|
25504
25808
|
}
|
|
25505
|
-
|
|
25506
|
-
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
}
|
|
25510
|
-
}
|
|
25511
|
-
assertTaskCapability(method) {
|
|
25512
|
-
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
25513
|
-
}
|
|
25514
|
-
assertTaskHandlerCapability(method) {
|
|
25515
|
-
if (!this._capabilities) {
|
|
25516
|
-
return;
|
|
25517
|
-
}
|
|
25518
|
-
assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
|
|
25519
|
-
}
|
|
25520
|
-
async _oninitialize(request) {
|
|
25521
|
-
const requestedVersion = request.params.protocolVersion;
|
|
25522
|
-
this._clientCapabilities = request.params.capabilities;
|
|
25523
|
-
this._clientVersion = request.params.clientInfo;
|
|
25524
|
-
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : LATEST_PROTOCOL_VERSION;
|
|
25525
|
-
return {
|
|
25526
|
-
protocolVersion,
|
|
25527
|
-
capabilities: this.getCapabilities(),
|
|
25528
|
-
serverInfo: this._serverInfo,
|
|
25529
|
-
...this._instructions && { instructions: this._instructions }
|
|
25809
|
+
},
|
|
25810
|
+
listTasks: (cursor) => {
|
|
25811
|
+
return taskStore.listTasks(cursor, sessionId);
|
|
25812
|
+
}
|
|
25530
25813
|
};
|
|
25531
25814
|
}
|
|
25532
|
-
|
|
25533
|
-
|
|
25815
|
+
}
|
|
25816
|
+
function isPlainObject3(value) {
|
|
25817
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
25818
|
+
}
|
|
25819
|
+
function mergeCapabilities(base, additional) {
|
|
25820
|
+
const result = { ...base };
|
|
25821
|
+
for (const key in additional) {
|
|
25822
|
+
const k = key;
|
|
25823
|
+
const addValue = additional[k];
|
|
25824
|
+
if (addValue === undefined)
|
|
25825
|
+
continue;
|
|
25826
|
+
const baseValue = result[k];
|
|
25827
|
+
if (isPlainObject3(baseValue) && isPlainObject3(addValue)) {
|
|
25828
|
+
result[k] = { ...baseValue, ...addValue };
|
|
25829
|
+
} else {
|
|
25830
|
+
result[k] = addValue;
|
|
25831
|
+
}
|
|
25832
|
+
}
|
|
25833
|
+
return result;
|
|
25834
|
+
}
|
|
25835
|
+
|
|
25836
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
25837
|
+
var import_ajv = __toESM(require_ajv(), 1);
|
|
25838
|
+
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
25839
|
+
function createDefaultAjvInstance() {
|
|
25840
|
+
const ajv = new import_ajv.default({
|
|
25841
|
+
strict: false,
|
|
25842
|
+
validateFormats: true,
|
|
25843
|
+
validateSchema: false,
|
|
25844
|
+
allErrors: true
|
|
25845
|
+
});
|
|
25846
|
+
const addFormats = import_ajv_formats.default;
|
|
25847
|
+
addFormats(ajv);
|
|
25848
|
+
return ajv;
|
|
25849
|
+
}
|
|
25850
|
+
|
|
25851
|
+
class AjvJsonSchemaValidator {
|
|
25852
|
+
constructor(ajv) {
|
|
25853
|
+
this._ajv = ajv ?? createDefaultAjvInstance();
|
|
25534
25854
|
}
|
|
25535
|
-
|
|
25536
|
-
|
|
25855
|
+
getValidator(schema) {
|
|
25856
|
+
const ajvValidator = "$id" in schema && typeof schema.$id === "string" ? this._ajv.getSchema(schema.$id) ?? this._ajv.compile(schema) : this._ajv.compile(schema);
|
|
25857
|
+
return (input) => {
|
|
25858
|
+
const valid = ajvValidator(input);
|
|
25859
|
+
if (valid) {
|
|
25860
|
+
return {
|
|
25861
|
+
valid: true,
|
|
25862
|
+
data: input,
|
|
25863
|
+
errorMessage: undefined
|
|
25864
|
+
};
|
|
25865
|
+
} else {
|
|
25866
|
+
return {
|
|
25867
|
+
valid: false,
|
|
25868
|
+
data: undefined,
|
|
25869
|
+
errorMessage: this._ajv.errorsText(ajvValidator.errors)
|
|
25870
|
+
};
|
|
25871
|
+
}
|
|
25872
|
+
};
|
|
25537
25873
|
}
|
|
25538
|
-
|
|
25539
|
-
|
|
25874
|
+
}
|
|
25875
|
+
|
|
25876
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
25877
|
+
class ExperimentalServerTasks {
|
|
25878
|
+
constructor(_server) {
|
|
25879
|
+
this._server = _server;
|
|
25540
25880
|
}
|
|
25541
|
-
|
|
25542
|
-
return this.request
|
|
25881
|
+
requestStream(request, resultSchema, options) {
|
|
25882
|
+
return this._server.requestStream(request, resultSchema, options);
|
|
25543
25883
|
}
|
|
25544
|
-
|
|
25545
|
-
|
|
25546
|
-
|
|
25547
|
-
|
|
25548
|
-
}
|
|
25884
|
+
createMessageStream(params, options) {
|
|
25885
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
25886
|
+
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
25887
|
+
throw new Error("Client does not support sampling tools capability.");
|
|
25549
25888
|
}
|
|
25550
25889
|
if (params.messages.length > 0) {
|
|
25551
25890
|
const lastMessage = params.messages[params.messages.length - 1];
|
|
@@ -25570,807 +25909,572 @@ class Server extends Protocol {
|
|
|
25570
25909
|
}
|
|
25571
25910
|
}
|
|
25572
25911
|
}
|
|
25573
|
-
|
|
25574
|
-
|
|
25575
|
-
|
|
25576
|
-
|
|
25912
|
+
return this.requestStream({
|
|
25913
|
+
method: "sampling/createMessage",
|
|
25914
|
+
params
|
|
25915
|
+
}, CreateMessageResultSchema, options);
|
|
25577
25916
|
}
|
|
25578
|
-
|
|
25917
|
+
elicitInputStream(params, options) {
|
|
25918
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
25579
25919
|
const mode = params.mode ?? "form";
|
|
25580
25920
|
switch (mode) {
|
|
25581
25921
|
case "url": {
|
|
25582
|
-
if (!
|
|
25922
|
+
if (!clientCapabilities?.elicitation?.url) {
|
|
25583
25923
|
throw new Error("Client does not support url elicitation.");
|
|
25584
25924
|
}
|
|
25585
|
-
|
|
25586
|
-
return this.request({ method: "elicitation/create", params: urlParams }, ElicitResultSchema, options);
|
|
25925
|
+
break;
|
|
25587
25926
|
}
|
|
25588
25927
|
case "form": {
|
|
25589
|
-
if (!
|
|
25928
|
+
if (!clientCapabilities?.elicitation?.form) {
|
|
25590
25929
|
throw new Error("Client does not support form elicitation.");
|
|
25591
25930
|
}
|
|
25592
|
-
|
|
25593
|
-
const result = await this.request({ method: "elicitation/create", params: formParams }, ElicitResultSchema, options);
|
|
25594
|
-
if (result.action === "accept" && result.content && formParams.requestedSchema) {
|
|
25595
|
-
try {
|
|
25596
|
-
const validator = this._jsonSchemaValidator.getValidator(formParams.requestedSchema);
|
|
25597
|
-
const validationResult = validator(result.content);
|
|
25598
|
-
if (!validationResult.valid) {
|
|
25599
|
-
throw new McpError(ErrorCode.InvalidParams, `Elicitation response content does not match requested schema: ${validationResult.errorMessage}`);
|
|
25600
|
-
}
|
|
25601
|
-
} catch (error) {
|
|
25602
|
-
if (error instanceof McpError) {
|
|
25603
|
-
throw error;
|
|
25604
|
-
}
|
|
25605
|
-
throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error instanceof Error ? error.message : String(error)}`);
|
|
25606
|
-
}
|
|
25607
|
-
}
|
|
25608
|
-
return result;
|
|
25609
|
-
}
|
|
25610
|
-
}
|
|
25611
|
-
}
|
|
25612
|
-
createElicitationCompletionNotifier(elicitationId, options) {
|
|
25613
|
-
if (!this._clientCapabilities?.elicitation?.url) {
|
|
25614
|
-
throw new Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");
|
|
25615
|
-
}
|
|
25616
|
-
return () => this.notification({
|
|
25617
|
-
method: "notifications/elicitation/complete",
|
|
25618
|
-
params: {
|
|
25619
|
-
elicitationId
|
|
25620
|
-
}
|
|
25621
|
-
}, options);
|
|
25622
|
-
}
|
|
25623
|
-
async listRoots(params, options) {
|
|
25624
|
-
return this.request({ method: "roots/list", params }, ListRootsResultSchema, options);
|
|
25625
|
-
}
|
|
25626
|
-
async sendLoggingMessage(params, sessionId) {
|
|
25627
|
-
if (this._capabilities.logging) {
|
|
25628
|
-
if (!this.isMessageIgnored(params.level, sessionId)) {
|
|
25629
|
-
return this.notification({ method: "notifications/message", params });
|
|
25931
|
+
break;
|
|
25630
25932
|
}
|
|
25631
25933
|
}
|
|
25934
|
+
const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
|
|
25935
|
+
return this.requestStream({
|
|
25936
|
+
method: "elicitation/create",
|
|
25937
|
+
params: normalizedParams
|
|
25938
|
+
}, ElicitResultSchema, options);
|
|
25632
25939
|
}
|
|
25633
|
-
async
|
|
25634
|
-
return this.
|
|
25635
|
-
method: "notifications/resources/updated",
|
|
25636
|
-
params
|
|
25637
|
-
});
|
|
25638
|
-
}
|
|
25639
|
-
async sendResourceListChanged() {
|
|
25640
|
-
return this.notification({
|
|
25641
|
-
method: "notifications/resources/list_changed"
|
|
25642
|
-
});
|
|
25643
|
-
}
|
|
25644
|
-
async sendToolListChanged() {
|
|
25645
|
-
return this.notification({ method: "notifications/tools/list_changed" });
|
|
25646
|
-
}
|
|
25647
|
-
async sendPromptListChanged() {
|
|
25648
|
-
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
25649
|
-
}
|
|
25650
|
-
}
|
|
25651
|
-
|
|
25652
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
25653
|
-
import process3 from "node:process";
|
|
25654
|
-
|
|
25655
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
25656
|
-
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
25657
|
-
|
|
25658
|
-
class ReadBuffer {
|
|
25659
|
-
constructor(options) {
|
|
25660
|
-
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
25940
|
+
async getTask(taskId, options) {
|
|
25941
|
+
return this._server.getTask({ taskId }, options);
|
|
25661
25942
|
}
|
|
25662
|
-
|
|
25663
|
-
|
|
25664
|
-
if (newSize > this._maxBufferSize) {
|
|
25665
|
-
this.clear();
|
|
25666
|
-
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
25667
|
-
}
|
|
25668
|
-
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
25943
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
25944
|
+
return this._server.getTaskResult({ taskId }, resultSchema, options);
|
|
25669
25945
|
}
|
|
25670
|
-
|
|
25671
|
-
|
|
25672
|
-
return null;
|
|
25673
|
-
}
|
|
25674
|
-
const index = this._buffer.indexOf(`
|
|
25675
|
-
`);
|
|
25676
|
-
if (index === -1) {
|
|
25677
|
-
return null;
|
|
25678
|
-
}
|
|
25679
|
-
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
25680
|
-
this._buffer = this._buffer.subarray(index + 1);
|
|
25681
|
-
return deserializeMessage(line);
|
|
25946
|
+
async listTasks(cursor, options) {
|
|
25947
|
+
return this._server.listTasks(cursor ? { cursor } : undefined, options);
|
|
25682
25948
|
}
|
|
25683
|
-
|
|
25684
|
-
this.
|
|
25949
|
+
async cancelTask(taskId, options) {
|
|
25950
|
+
return this._server.cancelTask({ taskId }, options);
|
|
25685
25951
|
}
|
|
25686
25952
|
}
|
|
25687
|
-
function deserializeMessage(line) {
|
|
25688
|
-
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
25689
|
-
}
|
|
25690
|
-
function serializeMessage(message) {
|
|
25691
|
-
return JSON.stringify(message) + `
|
|
25692
|
-
`;
|
|
25693
|
-
}
|
|
25694
25953
|
|
|
25695
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
this._stdout = _stdout;
|
|
25700
|
-
this._started = false;
|
|
25701
|
-
this._ondata = (chunk) => {
|
|
25702
|
-
try {
|
|
25703
|
-
this._readBuffer.append(chunk);
|
|
25704
|
-
this.processReadBuffer();
|
|
25705
|
-
} catch (error) {
|
|
25706
|
-
this.onerror?.(error);
|
|
25707
|
-
this.close().catch(() => {});
|
|
25708
|
-
}
|
|
25709
|
-
};
|
|
25710
|
-
this._onerror = (error) => {
|
|
25711
|
-
this.onerror?.(error);
|
|
25712
|
-
};
|
|
25713
|
-
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
25714
|
-
}
|
|
25715
|
-
async start() {
|
|
25716
|
-
if (this._started) {
|
|
25717
|
-
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
25718
|
-
}
|
|
25719
|
-
this._started = true;
|
|
25720
|
-
this._stdin.on("data", this._ondata);
|
|
25721
|
-
this._stdin.on("error", this._onerror);
|
|
25722
|
-
}
|
|
25723
|
-
processReadBuffer() {
|
|
25724
|
-
while (true) {
|
|
25725
|
-
try {
|
|
25726
|
-
const message = this._readBuffer.readMessage();
|
|
25727
|
-
if (message === null) {
|
|
25728
|
-
break;
|
|
25729
|
-
}
|
|
25730
|
-
this.onmessage?.(message);
|
|
25731
|
-
} catch (error) {
|
|
25732
|
-
this.onerror?.(error);
|
|
25733
|
-
}
|
|
25734
|
-
}
|
|
25735
|
-
}
|
|
25736
|
-
async close() {
|
|
25737
|
-
this._stdin.off("data", this._ondata);
|
|
25738
|
-
this._stdin.off("error", this._onerror);
|
|
25739
|
-
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
25740
|
-
if (remainingDataListeners === 0) {
|
|
25741
|
-
this._stdin.pause();
|
|
25742
|
-
}
|
|
25743
|
-
this._readBuffer.clear();
|
|
25744
|
-
this.onclose?.();
|
|
25954
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
25955
|
+
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
25956
|
+
if (!requests) {
|
|
25957
|
+
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
25745
25958
|
}
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
25750
|
-
resolve();
|
|
25751
|
-
} else {
|
|
25752
|
-
this._stdout.once("drain", resolve);
|
|
25959
|
+
switch (method) {
|
|
25960
|
+
case "tools/call":
|
|
25961
|
+
if (!requests.tools?.call) {
|
|
25962
|
+
throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
|
|
25753
25963
|
}
|
|
25754
|
-
|
|
25964
|
+
break;
|
|
25965
|
+
default:
|
|
25966
|
+
break;
|
|
25755
25967
|
}
|
|
25756
25968
|
}
|
|
25757
|
-
|
|
25758
|
-
|
|
25759
|
-
|
|
25760
|
-
|
|
25761
|
-
// packages/workit-core/src/core/boundary.ts
|
|
25762
|
-
import { statSync } from "node:fs";
|
|
25763
|
-
var EVENT = {
|
|
25764
|
-
initialization: "initialization",
|
|
25765
|
-
provenance: "provenance",
|
|
25766
|
-
assets: "assets",
|
|
25767
|
-
configurationSource: "configuration_source",
|
|
25768
|
-
hooks: "hooks",
|
|
25769
|
-
mcpConnection: "mcp_connection",
|
|
25770
|
-
migration: "migration",
|
|
25771
|
-
installSteps: "install_steps",
|
|
25772
|
-
uncaughtFailure: "uncaught_failure",
|
|
25773
|
-
toolsFailed: "tools_failed",
|
|
25774
|
-
doctor: "doctor"
|
|
25775
|
-
};
|
|
25776
|
-
var errorDetail = (err) => {
|
|
25777
|
-
if (err instanceof Error) {
|
|
25778
|
-
return { error_name: err.name, error: err.message };
|
|
25969
|
+
function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
25970
|
+
if (!requests) {
|
|
25971
|
+
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
25779
25972
|
}
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
|
|
25786
|
-
|
|
25787
|
-
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25791
|
-
|
|
25792
|
-
|
|
25973
|
+
switch (method) {
|
|
25974
|
+
case "sampling/createMessage":
|
|
25975
|
+
if (!requests.sampling?.createMessage) {
|
|
25976
|
+
throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
|
|
25977
|
+
}
|
|
25978
|
+
break;
|
|
25979
|
+
case "elicitation/create":
|
|
25980
|
+
if (!requests.elicitation?.create) {
|
|
25981
|
+
throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
|
|
25982
|
+
}
|
|
25983
|
+
break;
|
|
25984
|
+
default:
|
|
25985
|
+
break;
|
|
25793
25986
|
}
|
|
25794
|
-
|
|
25795
|
-
};
|
|
25796
|
-
|
|
25797
|
-
// packages/workit-core/src/core/logger.ts
|
|
25798
|
-
import os from "node:os";
|
|
25799
|
-
var REDACTED = "[REDACTED]";
|
|
25800
|
-
var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
|
|
25801
|
-
var KEY_EQ_VALUE = /\b([A-Za-z0-9_-]*(?:token|secret|password|passwd|apikey|api[_-]?key|authorization|credential|bearer)[A-Za-z0-9_-]*)([:=]\s*).+/gi;
|
|
25802
|
-
var URL_QUERY = /(https?:\/\/[^?#\s]+)\?[^#\s]*/g;
|
|
25803
|
-
var SENSITIVE_WORDS = new Set([
|
|
25804
|
-
"token",
|
|
25805
|
-
"secret",
|
|
25806
|
-
"password",
|
|
25807
|
-
"passwd",
|
|
25808
|
-
"authorization",
|
|
25809
|
-
"credential",
|
|
25810
|
-
"credentials",
|
|
25811
|
-
"cookie",
|
|
25812
|
-
"api",
|
|
25813
|
-
"apikey",
|
|
25814
|
-
"apitoken",
|
|
25815
|
-
"accesstoken",
|
|
25816
|
-
"clientsecret",
|
|
25817
|
-
"refreshtoken",
|
|
25818
|
-
"key",
|
|
25819
|
-
"bearer",
|
|
25820
|
-
"prompt",
|
|
25821
|
-
"message",
|
|
25822
|
-
"messages",
|
|
25823
|
-
"content",
|
|
25824
|
-
"body",
|
|
25825
|
-
"args",
|
|
25826
|
-
"argument",
|
|
25827
|
-
"result",
|
|
25828
|
-
"results",
|
|
25829
|
-
"output",
|
|
25830
|
-
"issue",
|
|
25831
|
-
"description",
|
|
25832
|
-
"summary",
|
|
25833
|
-
"payload",
|
|
25834
|
-
"script",
|
|
25835
|
-
"command",
|
|
25836
|
-
"text",
|
|
25837
|
-
"query"
|
|
25838
|
-
]);
|
|
25839
|
-
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
25840
|
-
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25841
|
-
var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
25842
|
-
var applyPatterns = (value) => {
|
|
25843
|
-
let out = value;
|
|
25844
|
-
out = out.replace(SECRET_VALUE, REDACTED);
|
|
25845
|
-
out = out.replace(KEY_EQ_VALUE, "$1$2[REDACTED]");
|
|
25846
|
-
out = out.replace(URL_QUERY, "$1?[REDACTED]");
|
|
25847
|
-
out = out.replace(homePattern, "~");
|
|
25848
|
-
if (process.platform === "win32")
|
|
25849
|
-
out = out.replace(/\\/g, "/");
|
|
25850
|
-
return out;
|
|
25851
|
-
};
|
|
25852
|
-
var redactSecrets = (value) => applyPatterns(value);
|
|
25987
|
+
}
|
|
25853
25988
|
|
|
25854
|
-
//
|
|
25855
|
-
|
|
25856
|
-
|
|
25857
|
-
|
|
25858
|
-
|
|
25859
|
-
|
|
25860
|
-
|
|
25861
|
-
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
} catch (error) {
|
|
25865
|
-
const e = error;
|
|
25866
|
-
return {
|
|
25867
|
-
stdout: (e.stdout ?? "").trimEnd(),
|
|
25868
|
-
stderr: (e.stderr ?? "").trimEnd(),
|
|
25869
|
-
exitCode: e.status ?? 1
|
|
25989
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
25990
|
+
class Server extends Protocol {
|
|
25991
|
+
constructor(_serverInfo, options) {
|
|
25992
|
+
super(options);
|
|
25993
|
+
this._serverInfo = _serverInfo;
|
|
25994
|
+
this._loggingLevels = new Map;
|
|
25995
|
+
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
25996
|
+
this.isMessageIgnored = (level, sessionId) => {
|
|
25997
|
+
const currentLevel = this._loggingLevels.get(sessionId);
|
|
25998
|
+
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
25870
25999
|
};
|
|
25871
|
-
|
|
25872
|
-
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
const unstaged = [];
|
|
25887
|
-
const untracked = [];
|
|
25888
|
-
for (const line of status_short.split(`
|
|
25889
|
-
`).filter(Boolean)) {
|
|
25890
|
-
const code = line.slice(0, 2);
|
|
25891
|
-
const file = line.slice(3);
|
|
25892
|
-
if (code === "??") {
|
|
25893
|
-
untracked.push(file);
|
|
25894
|
-
} else {
|
|
25895
|
-
if (code[0] !== " " && code[0] !== "?")
|
|
25896
|
-
staged.push(file);
|
|
25897
|
-
if (code[1] !== " " && code[1] !== "?")
|
|
25898
|
-
unstaged.push(file);
|
|
26000
|
+
this._capabilities = options?.capabilities ?? {};
|
|
26001
|
+
this._instructions = options?.instructions;
|
|
26002
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator;
|
|
26003
|
+
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
|
26004
|
+
this.setNotificationHandler(InitializedNotificationSchema, () => this.oninitialized?.());
|
|
26005
|
+
if (this._capabilities.logging) {
|
|
26006
|
+
this.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {
|
|
26007
|
+
const transportSessionId = extra.sessionId || extra.requestInfo?.headers["mcp-session-id"] || undefined;
|
|
26008
|
+
const { level } = request.params;
|
|
26009
|
+
const parseResult = LoggingLevelSchema.safeParse(level);
|
|
26010
|
+
if (parseResult.success) {
|
|
26011
|
+
this._loggingLevels.set(transportSessionId, parseResult.data);
|
|
26012
|
+
}
|
|
26013
|
+
return {};
|
|
26014
|
+
});
|
|
25899
26015
|
}
|
|
25900
26016
|
}
|
|
25901
|
-
|
|
25902
|
-
|
|
25903
|
-
|
|
25904
|
-
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
workspace_root: cwd,
|
|
25909
|
-
branch,
|
|
25910
|
-
status_short,
|
|
25911
|
-
staged,
|
|
25912
|
-
unstaged,
|
|
25913
|
-
untracked,
|
|
25914
|
-
diff_stat: [diff_stat, cached_stat].filter(Boolean).join(`
|
|
25915
|
-
`),
|
|
25916
|
-
partial_staged: partial_staged.length > 0,
|
|
25917
|
-
partial_staged_files: partial_staged,
|
|
25918
|
-
...failure ? { stderr: failure.stderr, exitCode: failure.exitCode } : {}
|
|
25919
|
-
};
|
|
25920
|
-
};
|
|
25921
|
-
|
|
25922
|
-
// packages/workit-core/src/core/config.ts
|
|
25923
|
-
import {
|
|
25924
|
-
copyFileSync,
|
|
25925
|
-
cpSync,
|
|
25926
|
-
existsSync as existsSync5,
|
|
25927
|
-
mkdirSync as mkdirSync2,
|
|
25928
|
-
readFileSync as readFileSync4,
|
|
25929
|
-
readdirSync as readdirSync3,
|
|
25930
|
-
writeFileSync as writeFileSync2
|
|
25931
|
-
} from "node:fs";
|
|
25932
|
-
import os2 from "node:os";
|
|
25933
|
-
import path8 from "node:path";
|
|
25934
|
-
var diagnosticLogger;
|
|
25935
|
-
var PRESETS = {
|
|
25936
|
-
gitflow: {
|
|
25937
|
-
allowed: ["feature/*", "bugfix/*", "hotfix/*", "release/*"],
|
|
25938
|
-
protected: ["main", "develop", "master", "prod", "production"]
|
|
25939
|
-
},
|
|
25940
|
-
"github-flow": { allowed: ["*"], protected: ["main"] },
|
|
25941
|
-
"trunk-based": { allowed: ["*"], protected: ["main"] },
|
|
25942
|
-
custom: { allowed: [], protected: [] }
|
|
25943
|
-
};
|
|
25944
|
-
var mergePreset = (preset, input = {}, current = {
|
|
25945
|
-
branchPolicy: { preset, allowed: [], protected: [] }
|
|
25946
|
-
}) => {
|
|
25947
|
-
const defs = PRESETS[preset];
|
|
25948
|
-
return {
|
|
25949
|
-
preset,
|
|
25950
|
-
allowed: preset === "custom" ? input.allowed ?? current.branchPolicy.allowed : [...defs.allowed],
|
|
25951
|
-
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
25952
|
-
};
|
|
25953
|
-
};
|
|
25954
|
-
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path8.join(process.env.XDG_CONFIG_HOME || path8.join(os2.homedir(), ".config"), "workit");
|
|
25955
|
-
var migratedDir = null;
|
|
25956
|
-
var migrationFailed = false;
|
|
25957
|
-
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
25958
|
-
if (migratedDir === dir)
|
|
25959
|
-
return dir;
|
|
25960
|
-
if (process.env.WORKFLOW_TOOLKIT_CONFIG || process.env.WORKFLOW_TOOLKIT_CONFIG_DIR) {
|
|
25961
|
-
migratedDir = dir;
|
|
25962
|
-
return dir;
|
|
26017
|
+
get experimental() {
|
|
26018
|
+
if (!this._experimental) {
|
|
26019
|
+
this._experimental = {
|
|
26020
|
+
tasks: new ExperimentalServerTasks(this)
|
|
26021
|
+
};
|
|
26022
|
+
}
|
|
26023
|
+
return this._experimental;
|
|
25963
26024
|
}
|
|
25964
|
-
|
|
25965
|
-
|
|
25966
|
-
|
|
25967
|
-
|
|
26025
|
+
registerCapabilities(capabilities) {
|
|
26026
|
+
if (this.transport) {
|
|
26027
|
+
throw new Error("Cannot register capabilities after connecting to transport");
|
|
26028
|
+
}
|
|
26029
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
25968
26030
|
}
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
26031
|
+
setRequestHandler(requestSchema, handler) {
|
|
26032
|
+
const shape = getObjectShape(requestSchema);
|
|
26033
|
+
const methodSchema = shape?.method;
|
|
26034
|
+
if (!methodSchema) {
|
|
26035
|
+
throw new Error("Schema is missing a method literal");
|
|
26036
|
+
}
|
|
26037
|
+
const methodValue = getLiteralValue(methodSchema);
|
|
26038
|
+
if (typeof methodValue !== "string") {
|
|
26039
|
+
throw new Error("Schema method literal must be a string");
|
|
26040
|
+
}
|
|
26041
|
+
const method = methodValue;
|
|
26042
|
+
if (method === "tools/call") {
|
|
26043
|
+
const wrappedHandler = async (request, extra) => {
|
|
26044
|
+
const validatedRequest = safeParse4(CallToolRequestSchema, request);
|
|
26045
|
+
if (!validatedRequest.success) {
|
|
26046
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
26047
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage}`);
|
|
26048
|
+
}
|
|
26049
|
+
const { params } = validatedRequest.data;
|
|
26050
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
26051
|
+
if (params.task) {
|
|
26052
|
+
const taskValidationResult = safeParse4(CreateTaskResultSchema, result);
|
|
26053
|
+
if (!taskValidationResult.success) {
|
|
26054
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
26055
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
26056
|
+
}
|
|
26057
|
+
return taskValidationResult.data;
|
|
26058
|
+
}
|
|
26059
|
+
const validationResult = safeParse4(CallToolResultSchema, result);
|
|
26060
|
+
if (!validationResult.success) {
|
|
26061
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
26062
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage}`);
|
|
26063
|
+
}
|
|
26064
|
+
return validationResult.data;
|
|
26065
|
+
};
|
|
26066
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
26067
|
+
}
|
|
26068
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
25972
26069
|
}
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
25976
|
-
|
|
25977
|
-
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
|
|
25986
|
-
|
|
25987
|
-
|
|
25988
|
-
|
|
25989
|
-
|
|
26070
|
+
assertCapabilityForMethod(method) {
|
|
26071
|
+
switch (method) {
|
|
26072
|
+
case "sampling/createMessage":
|
|
26073
|
+
if (!this._clientCapabilities?.sampling) {
|
|
26074
|
+
throw new Error(`Client does not support sampling (required for ${method})`);
|
|
26075
|
+
}
|
|
26076
|
+
break;
|
|
26077
|
+
case "elicitation/create":
|
|
26078
|
+
if (!this._clientCapabilities?.elicitation) {
|
|
26079
|
+
throw new Error(`Client does not support elicitation (required for ${method})`);
|
|
26080
|
+
}
|
|
26081
|
+
break;
|
|
26082
|
+
case "roots/list":
|
|
26083
|
+
if (!this._clientCapabilities?.roots) {
|
|
26084
|
+
throw new Error(`Client does not support listing roots (required for ${method})`);
|
|
26085
|
+
}
|
|
26086
|
+
break;
|
|
26087
|
+
case "ping":
|
|
26088
|
+
break;
|
|
25990
26089
|
}
|
|
25991
26090
|
}
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
|
|
26004
|
-
|
|
26005
|
-
|
|
26006
|
-
|
|
26007
|
-
|
|
26008
|
-
}
|
|
26009
|
-
|
|
26010
|
-
|
|
26011
|
-
|
|
26012
|
-
|
|
26013
|
-
|
|
26091
|
+
assertNotificationCapability(method) {
|
|
26092
|
+
switch (method) {
|
|
26093
|
+
case "notifications/message":
|
|
26094
|
+
if (!this._capabilities.logging) {
|
|
26095
|
+
throw new Error(`Server does not support logging (required for ${method})`);
|
|
26096
|
+
}
|
|
26097
|
+
break;
|
|
26098
|
+
case "notifications/resources/updated":
|
|
26099
|
+
case "notifications/resources/list_changed":
|
|
26100
|
+
if (!this._capabilities.resources) {
|
|
26101
|
+
throw new Error(`Server does not support notifying about resources (required for ${method})`);
|
|
26102
|
+
}
|
|
26103
|
+
break;
|
|
26104
|
+
case "notifications/tools/list_changed":
|
|
26105
|
+
if (!this._capabilities.tools) {
|
|
26106
|
+
throw new Error(`Server does not support notifying of tool list changes (required for ${method})`);
|
|
26107
|
+
}
|
|
26108
|
+
break;
|
|
26109
|
+
case "notifications/prompts/list_changed":
|
|
26110
|
+
if (!this._capabilities.prompts) {
|
|
26111
|
+
throw new Error(`Server does not support notifying of prompt list changes (required for ${method})`);
|
|
26112
|
+
}
|
|
26113
|
+
break;
|
|
26114
|
+
case "notifications/elicitation/complete":
|
|
26115
|
+
if (!this._clientCapabilities?.elicitation?.url) {
|
|
26116
|
+
throw new Error(`Client does not support URL elicitation (required for ${method})`);
|
|
26117
|
+
}
|
|
26118
|
+
break;
|
|
26119
|
+
case "notifications/cancelled":
|
|
26120
|
+
break;
|
|
26121
|
+
case "notifications/progress":
|
|
26122
|
+
break;
|
|
26123
|
+
}
|
|
26014
26124
|
}
|
|
26015
|
-
|
|
26016
|
-
|
|
26017
|
-
|
|
26018
|
-
|
|
26019
|
-
|
|
26020
|
-
|
|
26021
|
-
|
|
26022
|
-
|
|
26023
|
-
|
|
26024
|
-
|
|
26125
|
+
assertRequestHandlerCapability(method) {
|
|
26126
|
+
if (!this._capabilities) {
|
|
26127
|
+
return;
|
|
26128
|
+
}
|
|
26129
|
+
switch (method) {
|
|
26130
|
+
case "completion/complete":
|
|
26131
|
+
if (!this._capabilities.completions) {
|
|
26132
|
+
throw new Error(`Server does not support completions (required for ${method})`);
|
|
26133
|
+
}
|
|
26134
|
+
break;
|
|
26135
|
+
case "logging/setLevel":
|
|
26136
|
+
if (!this._capabilities.logging) {
|
|
26137
|
+
throw new Error(`Server does not support logging (required for ${method})`);
|
|
26138
|
+
}
|
|
26139
|
+
break;
|
|
26140
|
+
case "prompts/get":
|
|
26141
|
+
case "prompts/list":
|
|
26142
|
+
if (!this._capabilities.prompts) {
|
|
26143
|
+
throw new Error(`Server does not support prompts (required for ${method})`);
|
|
26144
|
+
}
|
|
26145
|
+
break;
|
|
26146
|
+
case "resources/list":
|
|
26147
|
+
case "resources/templates/list":
|
|
26148
|
+
case "resources/read":
|
|
26149
|
+
if (!this._capabilities.resources) {
|
|
26150
|
+
throw new Error(`Server does not support resources (required for ${method})`);
|
|
26151
|
+
}
|
|
26152
|
+
break;
|
|
26153
|
+
case "tools/call":
|
|
26154
|
+
case "tools/list":
|
|
26155
|
+
if (!this._capabilities.tools) {
|
|
26156
|
+
throw new Error(`Server does not support tools (required for ${method})`);
|
|
26157
|
+
}
|
|
26158
|
+
break;
|
|
26159
|
+
case "tasks/get":
|
|
26160
|
+
case "tasks/list":
|
|
26161
|
+
case "tasks/result":
|
|
26162
|
+
case "tasks/cancel":
|
|
26163
|
+
if (!this._capabilities.tasks) {
|
|
26164
|
+
throw new Error(`Server does not support tasks capability (required for ${method})`);
|
|
26165
|
+
}
|
|
26166
|
+
break;
|
|
26167
|
+
case "ping":
|
|
26168
|
+
case "initialize":
|
|
26169
|
+
break;
|
|
26170
|
+
}
|
|
26025
26171
|
}
|
|
26026
|
-
|
|
26027
|
-
|
|
26172
|
+
assertTaskCapability(method) {
|
|
26173
|
+
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
26028
26174
|
}
|
|
26029
|
-
|
|
26030
|
-
|
|
26031
|
-
|
|
26032
|
-
|
|
26033
|
-
|
|
26034
|
-
status: "valid",
|
|
26035
|
-
path: file,
|
|
26036
|
-
config: {
|
|
26037
|
-
locale,
|
|
26038
|
-
localeOptions: Array.isArray(input.localeOptions) ? input.localeOptions : DEFAULTS.localeOptions,
|
|
26039
|
-
timezone: input.timezone ?? DEFAULTS.timezone,
|
|
26040
|
-
branchPolicy: mergePreset(preset, {
|
|
26041
|
-
allowed: Array.isArray(input.branchPolicy?.allowed) ? input.branchPolicy.allowed : undefined,
|
|
26042
|
-
protectedNames: Array.isArray(input.branchPolicy?.protected) ? input.branchPolicy.protected : undefined
|
|
26043
|
-
}, DEFAULTS),
|
|
26044
|
-
commitPolicy: {
|
|
26045
|
-
preset: commitPreset,
|
|
26046
|
-
...typeof input.commitPolicy?.pattern === "string" ? { pattern: input.commitPolicy.pattern } : {}
|
|
26047
|
-
}
|
|
26048
|
-
}
|
|
26049
|
-
};
|
|
26050
|
-
};
|
|
26051
|
-
var readConfigTyped = (dir) => {
|
|
26052
|
-
const file = path8.join(dir ?? configDir(), "config.json");
|
|
26053
|
-
return parseConfigResult(readSafe(file), file);
|
|
26054
|
-
};
|
|
26055
|
-
var readConfig = () => {
|
|
26056
|
-
const result = readConfigTyped();
|
|
26057
|
-
if (result.status === "malformed")
|
|
26058
|
-
throw new Error(result.error);
|
|
26059
|
-
return result.config ?? DEFAULTS;
|
|
26060
|
-
};
|
|
26061
|
-
var resolveBranchPolicy = (config, workspace) => {
|
|
26062
|
-
const wp = workspace?.branchPolicy ?? {};
|
|
26063
|
-
const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
|
|
26064
|
-
const merged = mergePreset(preset, {
|
|
26065
|
-
allowed: wp.allowed,
|
|
26066
|
-
protectedNames: wp.protected
|
|
26067
|
-
}, config);
|
|
26068
|
-
const allowed = merged.allowed.map((p) => new RegExp(`^${p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"));
|
|
26069
|
-
return {
|
|
26070
|
-
preset,
|
|
26071
|
-
allowed,
|
|
26072
|
-
protected: new Set(merged.protected.map((p) => p.toLowerCase())),
|
|
26073
|
-
integration: wp.integration === "merge" ? "merge" : "pr",
|
|
26074
|
-
defaultTargetBranch: preset === "github-flow" ? "main" : preset === "trunk-based" ? "master" : "develop"
|
|
26075
|
-
};
|
|
26076
|
-
};
|
|
26077
|
-
var COMMIT_PRESETS = [
|
|
26078
|
-
"conventional",
|
|
26079
|
-
"gitmoji",
|
|
26080
|
-
"ticket-prefix",
|
|
26081
|
-
"freeform",
|
|
26082
|
-
"custom",
|
|
26083
|
-
"auto"
|
|
26084
|
-
];
|
|
26085
|
-
|
|
26086
|
-
// packages/workit-core/src/core/workspaces.ts
|
|
26087
|
-
import { readFileSync as readFileSync5, realpathSync as realpathSync6 } from "node:fs";
|
|
26088
|
-
import path9 from "node:path";
|
|
26089
|
-
var readWorkspacesResult = (dir = configDir()) => {
|
|
26090
|
-
const file = path9.join(dir, "workspaces.json");
|
|
26091
|
-
let raw;
|
|
26092
|
-
try {
|
|
26093
|
-
raw = readFileSync5(file, "utf8");
|
|
26094
|
-
} catch {
|
|
26095
|
-
return { status: "missing", path: file, entries: [] };
|
|
26175
|
+
assertTaskHandlerCapability(method) {
|
|
26176
|
+
if (!this._capabilities) {
|
|
26177
|
+
return;
|
|
26178
|
+
}
|
|
26179
|
+
assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
|
|
26096
26180
|
}
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
|
|
26181
|
+
async _oninitialize(request) {
|
|
26182
|
+
const requestedVersion = request.params.protocolVersion;
|
|
26183
|
+
this._clientCapabilities = request.params.capabilities;
|
|
26184
|
+
this._clientVersion = request.params.clientInfo;
|
|
26185
|
+
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : LATEST_PROTOCOL_VERSION;
|
|
26186
|
+
return {
|
|
26187
|
+
protocolVersion,
|
|
26188
|
+
capabilities: this.getCapabilities(),
|
|
26189
|
+
serverInfo: this._serverInfo,
|
|
26190
|
+
...this._instructions && { instructions: this._instructions }
|
|
26191
|
+
};
|
|
26102
26192
|
}
|
|
26103
|
-
|
|
26104
|
-
return
|
|
26193
|
+
getClientCapabilities() {
|
|
26194
|
+
return this._clientCapabilities;
|
|
26105
26195
|
}
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
}
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
26118
|
-
|
|
26119
|
-
|
|
26120
|
-
|
|
26121
|
-
|
|
26122
|
-
|
|
26123
|
-
|
|
26124
|
-
|
|
26125
|
-
|
|
26126
|
-
|
|
26127
|
-
|
|
26128
|
-
|
|
26129
|
-
|
|
26130
|
-
|
|
26131
|
-
|
|
26196
|
+
getClientVersion() {
|
|
26197
|
+
return this._clientVersion;
|
|
26198
|
+
}
|
|
26199
|
+
getCapabilities() {
|
|
26200
|
+
return this._capabilities;
|
|
26201
|
+
}
|
|
26202
|
+
async ping() {
|
|
26203
|
+
return this.request({ method: "ping" }, EmptyResultSchema);
|
|
26204
|
+
}
|
|
26205
|
+
async createMessage(params, options) {
|
|
26206
|
+
if (params.tools || params.toolChoice) {
|
|
26207
|
+
if (!this._clientCapabilities?.sampling?.tools) {
|
|
26208
|
+
throw new Error("Client does not support sampling tools capability.");
|
|
26209
|
+
}
|
|
26210
|
+
}
|
|
26211
|
+
if (params.messages.length > 0) {
|
|
26212
|
+
const lastMessage = params.messages[params.messages.length - 1];
|
|
26213
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
26214
|
+
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
26215
|
+
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
|
|
26216
|
+
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
26217
|
+
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
26218
|
+
if (hasToolResults) {
|
|
26219
|
+
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
26220
|
+
throw new Error("The last message must contain only tool_result content if any is present");
|
|
26221
|
+
}
|
|
26222
|
+
if (!hasPreviousToolUse) {
|
|
26223
|
+
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
26224
|
+
}
|
|
26225
|
+
}
|
|
26226
|
+
if (hasPreviousToolUse) {
|
|
26227
|
+
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
26228
|
+
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
26229
|
+
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
|
|
26230
|
+
throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
|
|
26231
|
+
}
|
|
26232
|
+
}
|
|
26233
|
+
}
|
|
26234
|
+
if (params.tools) {
|
|
26235
|
+
return this.request({ method: "sampling/createMessage", params }, CreateMessageResultWithToolsSchema, options);
|
|
26236
|
+
}
|
|
26237
|
+
return this.request({ method: "sampling/createMessage", params }, CreateMessageResultSchema, options);
|
|
26238
|
+
}
|
|
26239
|
+
async elicitInput(params, options) {
|
|
26240
|
+
const mode = params.mode ?? "form";
|
|
26241
|
+
switch (mode) {
|
|
26242
|
+
case "url": {
|
|
26243
|
+
if (!this._clientCapabilities?.elicitation?.url) {
|
|
26244
|
+
throw new Error("Client does not support url elicitation.");
|
|
26245
|
+
}
|
|
26246
|
+
const urlParams = params;
|
|
26247
|
+
return this.request({ method: "elicitation/create", params: urlParams }, ElicitResultSchema, options);
|
|
26248
|
+
}
|
|
26249
|
+
case "form": {
|
|
26250
|
+
if (!this._clientCapabilities?.elicitation?.form) {
|
|
26251
|
+
throw new Error("Client does not support form elicitation.");
|
|
26252
|
+
}
|
|
26253
|
+
const formParams = params.mode === "form" ? params : { ...params, mode: "form" };
|
|
26254
|
+
const result = await this.request({ method: "elicitation/create", params: formParams }, ElicitResultSchema, options);
|
|
26255
|
+
if (result.action === "accept" && result.content && formParams.requestedSchema) {
|
|
26256
|
+
try {
|
|
26257
|
+
const validator = this._jsonSchemaValidator.getValidator(formParams.requestedSchema);
|
|
26258
|
+
const validationResult = validator(result.content);
|
|
26259
|
+
if (!validationResult.valid) {
|
|
26260
|
+
throw new McpError(ErrorCode.InvalidParams, `Elicitation response content does not match requested schema: ${validationResult.errorMessage}`);
|
|
26132
26261
|
}
|
|
26133
|
-
}
|
|
26134
|
-
|
|
26262
|
+
} catch (error) {
|
|
26263
|
+
if (error instanceof McpError) {
|
|
26264
|
+
throw error;
|
|
26265
|
+
}
|
|
26266
|
+
throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error instanceof Error ? error.message : String(error)}`);
|
|
26135
26267
|
}
|
|
26136
|
-
i++;
|
|
26137
26268
|
}
|
|
26138
|
-
|
|
26139
|
-
out += "[^/]*";
|
|
26269
|
+
return result;
|
|
26140
26270
|
}
|
|
26141
|
-
} else {
|
|
26142
|
-
out += c.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
26143
26271
|
}
|
|
26144
26272
|
}
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
var realpathOf = (p) => {
|
|
26149
|
-
const real = realpathSync6.native ?? realpathSync6;
|
|
26150
|
-
try {
|
|
26151
|
-
return real(p);
|
|
26152
|
-
} catch {
|
|
26153
|
-
return p;
|
|
26154
|
-
}
|
|
26155
|
-
};
|
|
26156
|
-
var canonicalGlob = (glob) => {
|
|
26157
|
-
const m = /[*?[\]{]/.exec(glob);
|
|
26158
|
-
const prefix = m ? glob.slice(0, m.index) : glob;
|
|
26159
|
-
const rest = m ? glob.slice(m.index) : "";
|
|
26160
|
-
if (!prefix)
|
|
26161
|
-
return glob;
|
|
26162
|
-
const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
|
|
26163
|
-
return real + (prefix.endsWith("/") ? "/" : "") + rest;
|
|
26164
|
-
};
|
|
26165
|
-
var resolveWorkspaceFrom = (cwd, dir) => {
|
|
26166
|
-
const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
|
|
26167
|
-
for (const entry of loadWorkspacesFrom(dir)) {
|
|
26168
|
-
if (!entry || typeof entry !== "object")
|
|
26169
|
-
continue;
|
|
26170
|
-
const ws = entry;
|
|
26171
|
-
if (typeof ws.glob !== "string" || !ws.glob)
|
|
26172
|
-
continue;
|
|
26173
|
-
const glob = ws.glob.replaceAll("\\", "/");
|
|
26174
|
-
const canonical = canonicalGlob(glob);
|
|
26175
|
-
for (const target of targets) {
|
|
26176
|
-
if (matchWorkspace(glob, target))
|
|
26177
|
-
return ws;
|
|
26178
|
-
if (canonical !== glob && matchWorkspace(canonical, target))
|
|
26179
|
-
return ws;
|
|
26273
|
+
createElicitationCompletionNotifier(elicitationId, options) {
|
|
26274
|
+
if (!this._clientCapabilities?.elicitation?.url) {
|
|
26275
|
+
throw new Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");
|
|
26180
26276
|
}
|
|
26277
|
+
return () => this.notification({
|
|
26278
|
+
method: "notifications/elicitation/complete",
|
|
26279
|
+
params: {
|
|
26280
|
+
elicitationId
|
|
26281
|
+
}
|
|
26282
|
+
}, options);
|
|
26181
26283
|
}
|
|
26182
|
-
|
|
26183
|
-
};
|
|
26184
|
-
var resolveWorkspace = (cwd) => resolveWorkspaceFrom(cwd, configDir());
|
|
26185
|
-
|
|
26186
|
-
// packages/workit-core/src/core/vcs-config.ts
|
|
26187
|
-
import fs7 from "node:fs";
|
|
26188
|
-
import path10 from "node:path";
|
|
26189
|
-
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
26190
|
-
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
26191
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
|
|
26192
|
-
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
26193
|
-
var remoteProvider = (cwd) => {
|
|
26194
|
-
const r = spawnSync3("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
26195
|
-
if (r.status !== 0)
|
|
26196
|
-
return null;
|
|
26197
|
-
const url = (r.stdout ?? "").trim();
|
|
26198
|
-
if (/github\.com[:/]/.test(url))
|
|
26199
|
-
return "github";
|
|
26200
|
-
if (/gitlab\.com[:/]/.test(url))
|
|
26201
|
-
return "gitlab";
|
|
26202
|
-
return null;
|
|
26203
|
-
};
|
|
26204
|
-
var readVcsConfig = () => {
|
|
26205
|
-
const file = vcsConfigPath();
|
|
26206
|
-
let raw;
|
|
26207
|
-
try {
|
|
26208
|
-
raw = fs7.readFileSync(file, "utf8");
|
|
26209
|
-
} catch {
|
|
26210
|
-
return { status: "missing", path: file, config: {} };
|
|
26284
|
+
async listRoots(params, options) {
|
|
26285
|
+
return this.request({ method: "roots/list", params }, ListRootsResultSchema, options);
|
|
26211
26286
|
}
|
|
26212
|
-
|
|
26213
|
-
|
|
26214
|
-
|
|
26215
|
-
|
|
26216
|
-
|
|
26287
|
+
async sendLoggingMessage(params, sessionId) {
|
|
26288
|
+
if (this._capabilities.logging) {
|
|
26289
|
+
if (!this.isMessageIgnored(params.level, sessionId)) {
|
|
26290
|
+
return this.notification({ method: "notifications/message", params });
|
|
26291
|
+
}
|
|
26292
|
+
}
|
|
26217
26293
|
}
|
|
26218
|
-
|
|
26219
|
-
return {
|
|
26294
|
+
async sendResourceUpdated(params) {
|
|
26295
|
+
return this.notification({
|
|
26296
|
+
method: "notifications/resources/updated",
|
|
26297
|
+
params
|
|
26298
|
+
});
|
|
26220
26299
|
}
|
|
26221
|
-
|
|
26222
|
-
|
|
26223
|
-
|
|
26224
|
-
|
|
26225
|
-
const wsVcs = ws?.vcs ?? {};
|
|
26226
|
-
const wsYt = ws?.youtrack ?? {};
|
|
26227
|
-
const wsIssues = ws?.issues ?? {};
|
|
26228
|
-
const { status: cfgStatus, path: cfgPath, config: cfg, error: cfgError } = readVcsConfig();
|
|
26229
|
-
const root = vcsCwd(cwd);
|
|
26230
|
-
const determinateRoot = cwd !== undefined || process.env.WORKFLOW_WORKSPACE_ROOT !== undefined;
|
|
26231
|
-
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
26232
|
-
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
26233
|
-
const wp = ws?.branchPolicy ?? {};
|
|
26234
|
-
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
26235
|
-
const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
|
|
26236
|
-
const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
|
|
26237
|
-
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
26238
|
-
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
26239
|
-
let issuesProvider = null;
|
|
26240
|
-
let linkOnPr = null;
|
|
26241
|
-
if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
|
|
26242
|
-
issuesProvider = "github";
|
|
26243
|
-
linkOnPr = typeof wsIssues.link_on_pr === "boolean" ? wsIssues.link_on_pr : null;
|
|
26300
|
+
async sendResourceListChanged() {
|
|
26301
|
+
return this.notification({
|
|
26302
|
+
method: "notifications/resources/list_changed"
|
|
26303
|
+
});
|
|
26244
26304
|
}
|
|
26245
|
-
|
|
26246
|
-
|
|
26247
|
-
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
26248
|
-
return {
|
|
26249
|
-
ok: true,
|
|
26250
|
-
workspace_name: ws?.name ?? null,
|
|
26251
|
-
provider,
|
|
26252
|
-
defaultTargetBranch: defaultTarget,
|
|
26253
|
-
link_issues: linkIssues,
|
|
26254
|
-
youtrack_base_url: youtrackBaseUrl,
|
|
26255
|
-
issues_provider: issuesProvider,
|
|
26256
|
-
link_on_pr: linkOnPr
|
|
26257
|
-
};
|
|
26305
|
+
async sendToolListChanged() {
|
|
26306
|
+
return this.notification({ method: "notifications/tools/list_changed" });
|
|
26258
26307
|
}
|
|
26259
|
-
|
|
26260
|
-
return {
|
|
26308
|
+
async sendPromptListChanged() {
|
|
26309
|
+
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
26261
26310
|
}
|
|
26262
|
-
|
|
26263
|
-
|
|
26311
|
+
}
|
|
26312
|
+
|
|
26313
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
26314
|
+
import process3 from "node:process";
|
|
26315
|
+
|
|
26316
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
26317
|
+
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
26318
|
+
|
|
26319
|
+
class ReadBuffer {
|
|
26320
|
+
constructor(options) {
|
|
26321
|
+
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
26264
26322
|
}
|
|
26265
|
-
|
|
26266
|
-
|
|
26267
|
-
|
|
26268
|
-
|
|
26269
|
-
|
|
26270
|
-
}
|
|
26323
|
+
append(chunk) {
|
|
26324
|
+
const newSize = (this._buffer?.length ?? 0) + chunk.length;
|
|
26325
|
+
if (newSize > this._maxBufferSize) {
|
|
26326
|
+
this.clear();
|
|
26327
|
+
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
26328
|
+
}
|
|
26329
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
26271
26330
|
}
|
|
26272
|
-
|
|
26273
|
-
|
|
26274
|
-
|
|
26275
|
-
|
|
26276
|
-
|
|
26277
|
-
|
|
26278
|
-
|
|
26279
|
-
|
|
26280
|
-
|
|
26331
|
+
readMessage() {
|
|
26332
|
+
if (!this._buffer) {
|
|
26333
|
+
return null;
|
|
26334
|
+
}
|
|
26335
|
+
const index = this._buffer.indexOf(`
|
|
26336
|
+
`);
|
|
26337
|
+
if (index === -1) {
|
|
26338
|
+
return null;
|
|
26339
|
+
}
|
|
26340
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
26341
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
26342
|
+
return deserializeMessage(line);
|
|
26281
26343
|
}
|
|
26282
|
-
|
|
26283
|
-
|
|
26284
|
-
configPath: path10.resolve(cfgPath),
|
|
26285
|
-
provider,
|
|
26286
|
-
defaultTargetBranch: defaultTarget,
|
|
26287
|
-
pr: cfg.pr ?? {},
|
|
26288
|
-
tokenPath,
|
|
26289
|
-
tokenPresent: fs7.existsSync(tokenPath),
|
|
26290
|
-
tokenReady: tokenOk,
|
|
26291
|
-
workspace_name: ws?.name ?? null,
|
|
26292
|
-
link_issues: linkIssues,
|
|
26293
|
-
youtrack_base_url: youtrackBaseUrl,
|
|
26294
|
-
issues_provider: issuesProvider,
|
|
26295
|
-
link_on_pr: linkOnPr
|
|
26296
|
-
};
|
|
26297
|
-
if (provider === "gitlab") {
|
|
26298
|
-
out.gitlab = {
|
|
26299
|
-
host: prov.host ?? "gitlab.com",
|
|
26300
|
-
apiUrl: prov.apiUrl ?? "https://gitlab.com/api/v4"
|
|
26301
|
-
};
|
|
26302
|
-
} else if (provider === "github") {
|
|
26303
|
-
out.github = { host: prov.host ?? "github.com" };
|
|
26344
|
+
clear() {
|
|
26345
|
+
this._buffer = undefined;
|
|
26304
26346
|
}
|
|
26305
|
-
if (mode === "summary")
|
|
26306
|
-
delete out.tokenPath;
|
|
26307
|
-
return out;
|
|
26308
26347
|
}
|
|
26309
|
-
function
|
|
26310
|
-
|
|
26311
|
-
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26322
|
-
|
|
26323
|
-
|
|
26324
|
-
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26331
|
-
|
|
26332
|
-
|
|
26333
|
-
|
|
26334
|
-
|
|
26335
|
-
|
|
26336
|
-
|
|
26337
|
-
|
|
26348
|
+
function deserializeMessage(line) {
|
|
26349
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
26350
|
+
}
|
|
26351
|
+
function serializeMessage(message) {
|
|
26352
|
+
return JSON.stringify(message) + `
|
|
26353
|
+
`;
|
|
26354
|
+
}
|
|
26355
|
+
|
|
26356
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
26357
|
+
class StdioServerTransport {
|
|
26358
|
+
constructor(_stdin = process3.stdin, _stdout = process3.stdout, options) {
|
|
26359
|
+
this._stdin = _stdin;
|
|
26360
|
+
this._stdout = _stdout;
|
|
26361
|
+
this._started = false;
|
|
26362
|
+
this._ondata = (chunk) => {
|
|
26363
|
+
try {
|
|
26364
|
+
this._readBuffer.append(chunk);
|
|
26365
|
+
this.processReadBuffer();
|
|
26366
|
+
} catch (error) {
|
|
26367
|
+
this.onerror?.(error);
|
|
26368
|
+
this.close().catch(() => {});
|
|
26369
|
+
}
|
|
26370
|
+
};
|
|
26371
|
+
this._onerror = (error) => {
|
|
26372
|
+
this.onerror?.(error);
|
|
26373
|
+
};
|
|
26374
|
+
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
26375
|
+
}
|
|
26376
|
+
async start() {
|
|
26377
|
+
if (this._started) {
|
|
26378
|
+
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
26338
26379
|
}
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
|
|
26346
|
-
|
|
26347
|
-
|
|
26348
|
-
|
|
26380
|
+
this._started = true;
|
|
26381
|
+
this._stdin.on("data", this._ondata);
|
|
26382
|
+
this._stdin.on("error", this._onerror);
|
|
26383
|
+
}
|
|
26384
|
+
processReadBuffer() {
|
|
26385
|
+
while (true) {
|
|
26386
|
+
try {
|
|
26387
|
+
const message = this._readBuffer.readMessage();
|
|
26388
|
+
if (message === null) {
|
|
26389
|
+
break;
|
|
26390
|
+
}
|
|
26391
|
+
this.onmessage?.(message);
|
|
26392
|
+
} catch (error) {
|
|
26393
|
+
this.onerror?.(error);
|
|
26394
|
+
}
|
|
26349
26395
|
}
|
|
26350
|
-
}
|
|
26351
|
-
|
|
26352
|
-
|
|
26353
|
-
|
|
26354
|
-
|
|
26355
|
-
|
|
26356
|
-
|
|
26396
|
+
}
|
|
26397
|
+
async close() {
|
|
26398
|
+
this._stdin.off("data", this._ondata);
|
|
26399
|
+
this._stdin.off("error", this._onerror);
|
|
26400
|
+
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
26401
|
+
if (remainingDataListeners === 0) {
|
|
26402
|
+
this._stdin.pause();
|
|
26357
26403
|
}
|
|
26404
|
+
this._readBuffer.clear();
|
|
26405
|
+
this.onclose?.();
|
|
26406
|
+
}
|
|
26407
|
+
send(message) {
|
|
26408
|
+
return new Promise((resolve) => {
|
|
26409
|
+
const json = serializeMessage(message);
|
|
26410
|
+
if (this._stdout.write(json)) {
|
|
26411
|
+
resolve();
|
|
26412
|
+
} else {
|
|
26413
|
+
this._stdout.once("drain", resolve);
|
|
26414
|
+
}
|
|
26415
|
+
});
|
|
26358
26416
|
}
|
|
26359
|
-
return {
|
|
26360
|
-
ok: true,
|
|
26361
|
-
provider,
|
|
26362
|
-
count: examples.length,
|
|
26363
|
-
styleHints: [
|
|
26364
|
-
"Prefer ## Summary bullets + ## Validation or ## Test plan only",
|
|
26365
|
-
"Do not add ## Notes with branch names, commit counts, or diff stats",
|
|
26366
|
-
"Do not paste commit log or diff stat into the body"
|
|
26367
|
-
],
|
|
26368
|
-
examples
|
|
26369
|
-
};
|
|
26370
26417
|
}
|
|
26371
26418
|
|
|
26372
|
-
// packages/workit-
|
|
26373
|
-
|
|
26419
|
+
// packages/workit-mcp/src/server.ts
|
|
26420
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26421
|
+
|
|
26422
|
+
// packages/workit-core/src/core/logger.ts
|
|
26423
|
+
import os2 from "node:os";
|
|
26424
|
+
var REDACTED = "[REDACTED]";
|
|
26425
|
+
var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
|
|
26426
|
+
var KEY_EQ_VALUE = /\b([A-Za-z0-9_-]*(?:token|secret|password|passwd|apikey|api[_-]?key|authorization|credential|bearer)[A-Za-z0-9_-]*)([:=]\s*).+/gi;
|
|
26427
|
+
var URL_QUERY = /(https?:\/\/[^?#\s]+)\?[^#\s]*/g;
|
|
26428
|
+
var SENSITIVE_WORDS = new Set([
|
|
26429
|
+
"token",
|
|
26430
|
+
"secret",
|
|
26431
|
+
"password",
|
|
26432
|
+
"passwd",
|
|
26433
|
+
"authorization",
|
|
26434
|
+
"credential",
|
|
26435
|
+
"credentials",
|
|
26436
|
+
"cookie",
|
|
26437
|
+
"api",
|
|
26438
|
+
"apikey",
|
|
26439
|
+
"apitoken",
|
|
26440
|
+
"accesstoken",
|
|
26441
|
+
"clientsecret",
|
|
26442
|
+
"refreshtoken",
|
|
26443
|
+
"key",
|
|
26444
|
+
"bearer",
|
|
26445
|
+
"prompt",
|
|
26446
|
+
"message",
|
|
26447
|
+
"messages",
|
|
26448
|
+
"content",
|
|
26449
|
+
"body",
|
|
26450
|
+
"args",
|
|
26451
|
+
"argument",
|
|
26452
|
+
"result",
|
|
26453
|
+
"results",
|
|
26454
|
+
"output",
|
|
26455
|
+
"issue",
|
|
26456
|
+
"description",
|
|
26457
|
+
"summary",
|
|
26458
|
+
"payload",
|
|
26459
|
+
"script",
|
|
26460
|
+
"command",
|
|
26461
|
+
"text",
|
|
26462
|
+
"query"
|
|
26463
|
+
]);
|
|
26464
|
+
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
26465
|
+
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26466
|
+
var homePattern = new RegExp(`${escapeRegExp(os2.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
26467
|
+
var applyPatterns = (value) => {
|
|
26468
|
+
let out = value;
|
|
26469
|
+
out = out.replace(SECRET_VALUE, REDACTED);
|
|
26470
|
+
out = out.replace(KEY_EQ_VALUE, "$1$2[REDACTED]");
|
|
26471
|
+
out = out.replace(URL_QUERY, "$1?[REDACTED]");
|
|
26472
|
+
out = out.replace(homePattern, "~");
|
|
26473
|
+
if (process.platform === "win32")
|
|
26474
|
+
out = out.replace(/\\/g, "/");
|
|
26475
|
+
return out;
|
|
26476
|
+
};
|
|
26477
|
+
var redactSecrets = (value) => applyPatterns(value);
|
|
26374
26478
|
|
|
26375
26479
|
// packages/workit-core/src/core/pr-create.ts
|
|
26376
26480
|
import fs8 from "node:fs";
|