@brainervirus/workit-codex 1.0.10 → 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 +2197 -2087
- package/dist/workit-hook.js +360 -213
- 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,
|
|
@@ -14420,10 +14503,11 @@ var decisionSchema = object({
|
|
|
14420
14503
|
presented: text,
|
|
14421
14504
|
approvedContent: text,
|
|
14422
14505
|
displayed: text.optional(),
|
|
14423
|
-
contentRefs: array(refSchema)
|
|
14506
|
+
contentRefs: array(refSchema),
|
|
14507
|
+
statedChoice: object({ ref: text, text }).strict().optional()
|
|
14424
14508
|
}).strict(),
|
|
14425
14509
|
digest,
|
|
14426
|
-
response: _enum(["approved", "rejected"]),
|
|
14510
|
+
response: _enum(["approved", "rejected", "stated"]),
|
|
14427
14511
|
requirementIds: array(digest),
|
|
14428
14512
|
revoked: object({ at: utc, reason: text }).strict().nullable(),
|
|
14429
14513
|
consumption: object({
|
|
@@ -15911,11 +15995,11 @@ class TaskStore {
|
|
|
15911
15995
|
return workspace;
|
|
15912
15996
|
if (!workspace.data)
|
|
15913
15997
|
return failure("not_found", "workspace not found");
|
|
15914
|
-
const
|
|
15915
|
-
if (!
|
|
15998
|
+
const expected = input.expectedRevision;
|
|
15999
|
+
if (!expected)
|
|
15916
16000
|
return failure("invalid_input", "task revision is required");
|
|
15917
|
-
if (task.data.revision !==
|
|
15918
|
-
return this.conflict(
|
|
16001
|
+
if (task.data.revision !== expected)
|
|
16002
|
+
return this.conflict(expected, task.data.revision);
|
|
15919
16003
|
if (workspace.data.revision !== input.expectedWorkspaceRevision)
|
|
15920
16004
|
return this.conflict(input.expectedWorkspaceRevision, workspace.data.revision);
|
|
15921
16005
|
const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
|
|
@@ -16449,6 +16533,7 @@ var same = (left, right) => {
|
|
|
16449
16533
|
};
|
|
16450
16534
|
var UNCERTAIN_WORKER_STATES = ["dispatching", "running", "cancelling", "unknown"];
|
|
16451
16535
|
var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
16536
|
+
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
16452
16537
|
var callerSession = (caller) => caller.session ?? { kind: "host", host: caller.host, handle: caller.actor };
|
|
16453
16538
|
var validPath = (value) => typeof value === "string" && value.length > 0 && ![...value].some((char) => {
|
|
16454
16539
|
const code = char.charCodeAt(0);
|
|
@@ -16510,6 +16595,36 @@ var trustedAuthority = (kind, provenance, expected, binding, caller) => {
|
|
|
16510
16595
|
verifiedAuthorities.set(token, { kind, provenance, ...expected, ...binding, caller });
|
|
16511
16596
|
return token;
|
|
16512
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
|
+
};
|
|
16513
16628
|
var scopeEqual = (left, right) => canonicalJson(left) === canonicalJson(right);
|
|
16514
16629
|
var parseSteps = (content) => {
|
|
16515
16630
|
let value;
|
|
@@ -16521,7 +16636,10 @@ var parseSteps = (content) => {
|
|
|
16521
16636
|
if (typeof value !== "object" || value === null || !("steps" in value))
|
|
16522
16637
|
return [];
|
|
16523
16638
|
const steps = value.steps;
|
|
16524
|
-
|
|
16639
|
+
if (!Array.isArray(steps))
|
|
16640
|
+
return null;
|
|
16641
|
+
const normalized = normalizeChainSteps(steps);
|
|
16642
|
+
return normalized;
|
|
16525
16643
|
};
|
|
16526
16644
|
var decisionMatches = (entry, purpose, binding) => {
|
|
16527
16645
|
const decision = entry.data;
|
|
@@ -16712,14 +16830,12 @@ var validateAction = (store, task, workspaceId, input, authority) => {
|
|
|
16712
16830
|
return content;
|
|
16713
16831
|
const requestedSteps = parseSteps(decision.binding.approvedContent);
|
|
16714
16832
|
if (requestedSteps === null)
|
|
16715
|
-
return failure("invalid_input", "bounded action steps must be a
|
|
16716
|
-
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)))
|
|
16717
16835
|
return failure("permission_denied", "bounded action steps do not match approved content");
|
|
16718
|
-
if (requestedSteps.some((step) => !step || typeof step !== "string") || new Set(requestedSteps).size !== requestedSteps.length)
|
|
16719
|
-
return failure("invalid_input", "bounded action steps must be unique and non-empty");
|
|
16720
16836
|
const stored = task.actionProgress?.find((item) => item.decisionId === input.decisionId);
|
|
16721
|
-
const workflow = stored ? { steps: stored.steps, completed: stored.completedSteps } : { steps: requestedSteps, completed: [] };
|
|
16722
|
-
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)))
|
|
16723
16839
|
return failure("permission_denied", "bounded action scope changed");
|
|
16724
16840
|
return success(null, null, { entry, workflow });
|
|
16725
16841
|
};
|
|
@@ -17274,13 +17390,28 @@ function evaluateEvidence(task, candidate) {
|
|
|
17274
17390
|
});
|
|
17275
17391
|
}
|
|
17276
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);
|
|
17277
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")));
|
|
17278
|
-
var applicableRequirementDecision = (task, workspace, requirement, checkoutRoot) => task.decisions.filter(({ data, provenance }) => provenance.kind !== "imported" && data.purpose !== "limitation" && data.response === "approved" && 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 }));
|
|
17279
|
-
var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
|
|
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 }));
|
|
17410
|
+
var evidenceMatchesRequirement = (kind, evidenceKind, dimension, ruleId) => {
|
|
17280
17411
|
if (kind !== "passed")
|
|
17281
17412
|
return false;
|
|
17282
17413
|
if (dimension === "testing" || dimension === "verification")
|
|
17283
|
-
return evidenceKind === "check";
|
|
17414
|
+
return evidenceKind === "check" || ruleId === "pre-pr-cleanup" && evidenceKind === "artifact";
|
|
17284
17415
|
if (dimension === "review")
|
|
17285
17416
|
return evidenceKind === "review";
|
|
17286
17417
|
if (dimension === "investigation" || dimension === "challenge")
|
|
@@ -17289,6 +17420,21 @@ var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
|
|
|
17289
17420
|
return evidenceKind === "artifact";
|
|
17290
17421
|
return false;
|
|
17291
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
|
+
};
|
|
17292
17438
|
function evaluateRequirements(task, workspace, capabilities, candidate, checkoutRoot, _caller) {
|
|
17293
17439
|
const evidence = evaluateEvidence(task, candidate);
|
|
17294
17440
|
if (task.policy && task.policy.policyVersion !== POLICY_VERSION)
|
|
@@ -17302,7 +17448,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17302
17448
|
return (task.policy?.requirements ?? []).map((requirement) => {
|
|
17303
17449
|
const related = task.evidence.map((entry, index) => ({ entry, evaluation: evidence[index] })).filter(({ entry }) => entry.data.requirementIds.includes(requirement.id));
|
|
17304
17450
|
const passed = related.filter(({ entry, evaluation }) => {
|
|
17305
|
-
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension))
|
|
17451
|
+
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension, requirement.ruleId))
|
|
17306
17452
|
return false;
|
|
17307
17453
|
if ((entry.data.kind === "check" || entry.data.kind === "review") && (!entry.data.beforeCandidateId || !entry.data.candidateId || entry.data.beforeCandidateId !== entry.data.candidateId))
|
|
17308
17454
|
return false;
|
|
@@ -17310,11 +17456,12 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17310
17456
|
return true;
|
|
17311
17457
|
const reviewSession = sessionFromRef(entry.data.reviewContext);
|
|
17312
17458
|
const sameImplementation = sameSession(reviewSession, task.intent.provenance.session);
|
|
17313
|
-
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));
|
|
17314
17460
|
return entry.data.kind === "review" && reviewSession !== null && sameSession(reviewSession, entry.provenance.session) && (requirement.ruleId === "self-review" || !sameImplementation && !sameEvidenceSession);
|
|
17315
17461
|
});
|
|
17316
17462
|
if (passed.length) {
|
|
17317
|
-
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;
|
|
17318
17465
|
if (withRed.length)
|
|
17319
17466
|
return {
|
|
17320
17467
|
requirementId: requirement.id,
|
|
@@ -17351,7 +17498,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17351
17498
|
status: "satisfied",
|
|
17352
17499
|
evidenceIds: [],
|
|
17353
17500
|
decisionIds: decisions.map((decision) => decision.id),
|
|
17354
|
-
reason: "an applicable approved decision satisfies the requirement"
|
|
17501
|
+
reason: "an applicable approved or stated decision satisfies the requirement"
|
|
17355
17502
|
};
|
|
17356
17503
|
const limitations = requirement.acceptanceAllowed ? applicableDecision2(task, workspace, requirement, checkoutRoot) : [];
|
|
17357
17504
|
if (limitations.length)
|
|
@@ -17363,6 +17510,14 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
17363
17510
|
reason: "an applicable approved limitation permits the missing evidence"
|
|
17364
17511
|
};
|
|
17365
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
|
+
};
|
|
17366
17521
|
return {
|
|
17367
17522
|
requirementId: requirement.id,
|
|
17368
17523
|
status: unavailable ? "unavailable" : "unsatisfied",
|
|
@@ -17387,7 +17542,13 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
17387
17542
|
if (entry.data.disposition === "fixed") {
|
|
17388
17543
|
const verified = entry.data.resolution?.evidenceIds.some((id) => {
|
|
17389
17544
|
const evidence = view.task.evidence.find((item) => item.id === id);
|
|
17390
|
-
|
|
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
|
+
});
|
|
17391
17552
|
});
|
|
17392
17553
|
if (!verified)
|
|
17393
17554
|
return failure("requirements_unsatisfied", "fixed findings require current verification");
|
|
@@ -17403,7 +17564,12 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
17403
17564
|
}
|
|
17404
17565
|
}
|
|
17405
17566
|
}
|
|
17406
|
-
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
|
+
});
|
|
17407
17573
|
if (requestedOutcome !== "stopped" && blocking.length)
|
|
17408
17574
|
return failure("requirements_unsatisfied", "applicable requirements are unsatisfied", {
|
|
17409
17575
|
requirementIds: blocking.map((item) => item.requirementId),
|
|
@@ -17472,197 +17638,755 @@ var exportDigest = (bundle) => sha256({
|
|
|
17472
17638
|
sourceWorkspaceId: bundle.sourceWorkspaceId,
|
|
17473
17639
|
task: bundle.task
|
|
17474
17640
|
});
|
|
17475
|
-
// packages/workit-core/src/core/
|
|
17476
|
-
|
|
17477
|
-
|
|
17478
|
-
|
|
17479
|
-
|
|
17480
|
-
|
|
17481
|
-
|
|
17482
|
-
|
|
17483
|
-
|
|
17484
|
-
|
|
17485
|
-
}
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
}).strict()
|
|
17493
|
-
}).strict(),
|
|
17494
|
-
object({
|
|
17495
|
-
operation: literal("git.push"),
|
|
17496
|
-
payload: object({ branch: string2().min(1).optional() }).strict()
|
|
17497
|
-
}).strict(),
|
|
17498
|
-
object({
|
|
17499
|
-
operation: literal("hosting.pull_request"),
|
|
17500
|
-
payload: object({
|
|
17501
|
-
title: string2().min(1),
|
|
17502
|
-
body: string2().optional(),
|
|
17503
|
-
draft: boolean2().optional(),
|
|
17504
|
-
target_branch: string2().optional(),
|
|
17505
|
-
babysit: boolean2().optional()
|
|
17506
|
-
}).strict()
|
|
17507
|
-
}).strict(),
|
|
17508
|
-
object({
|
|
17509
|
-
operation: literal("youtrack.update"),
|
|
17510
|
-
payload: object({
|
|
17511
|
-
issueId: string2().min(1),
|
|
17512
|
-
markdown: string2().min(1),
|
|
17513
|
-
minutes: number2().positive().optional()
|
|
17514
|
-
}).strict()
|
|
17515
|
-
}).strict(),
|
|
17516
|
-
object({
|
|
17517
|
-
operation: literal("youtrack.time"),
|
|
17518
|
-
payload: object({
|
|
17519
|
-
issueId: string2().min(1),
|
|
17520
|
-
minutes: number2().positive(),
|
|
17521
|
-
text: string2().optional(),
|
|
17522
|
-
dateMs: number2().finite().optional()
|
|
17523
|
-
}).strict()
|
|
17524
|
-
}).strict(),
|
|
17525
|
-
object({
|
|
17526
|
-
operation: literal("youtrack.meeting"),
|
|
17527
|
-
payload: object({
|
|
17528
|
-
issueId: string2().min(1),
|
|
17529
|
-
minutes: number2().positive(),
|
|
17530
|
-
text: string2().min(1)
|
|
17531
|
-
}).strict()
|
|
17532
|
-
}).strict(),
|
|
17533
|
-
object({
|
|
17534
|
-
operation: literal("changelog.apply"),
|
|
17535
|
-
payload: object({
|
|
17536
|
-
entries: union([
|
|
17537
|
-
record(string2(), array(string2())),
|
|
17538
|
-
array(object({ category: string2().min(1), text: string2().min(1) }).strict())
|
|
17539
|
-
]).optional(),
|
|
17540
|
-
path: string2().optional(),
|
|
17541
|
-
normalize_only: boolean2().optional()
|
|
17542
|
-
}).strict()
|
|
17543
|
-
}).strict(),
|
|
17544
|
-
object({
|
|
17545
|
-
operation: literal("context.read"),
|
|
17546
|
-
payload: object({
|
|
17547
|
-
kind: _enum([
|
|
17548
|
-
"git",
|
|
17549
|
-
"pr",
|
|
17550
|
-
"youtrack",
|
|
17551
|
-
"github_issue",
|
|
17552
|
-
"gitlab_issue",
|
|
17553
|
-
"changelog",
|
|
17554
|
-
"release",
|
|
17555
|
-
"affected"
|
|
17556
|
-
]),
|
|
17557
|
-
range: string2().optional(),
|
|
17558
|
-
issueId: string2().optional(),
|
|
17559
|
-
issueUrl: string2().optional(),
|
|
17560
|
-
issueRef: string2().optional(),
|
|
17561
|
-
mode: string2().optional(),
|
|
17562
|
-
specPath: string2().optional(),
|
|
17563
|
-
planPath: string2().optional()
|
|
17564
|
-
}).strict()
|
|
17565
|
-
}).strict()
|
|
17566
|
-
]);
|
|
17567
|
-
// packages/workit-core/src/core/task-engine.ts
|
|
17568
|
-
import { realpathSync as realpathSync4 } from "node:fs";
|
|
17569
|
-
|
|
17570
|
-
// packages/workit-core/src/core/policy-resolver.ts
|
|
17571
|
-
var resolverInputSchema = object({
|
|
17572
|
-
intent: intentSchema,
|
|
17573
|
-
assessment: assessmentSchema,
|
|
17574
|
-
constraints: array(constraintSchema),
|
|
17575
|
-
prior: object({
|
|
17576
|
-
decisions: array(decisionSchema),
|
|
17577
|
-
findings: array(findingSchema),
|
|
17578
|
-
requirements: array(requirementSchema)
|
|
17579
|
-
}).strict(),
|
|
17580
|
-
preferences: object({ fast: boolean2().optional(), thorough: boolean2().optional() }).strict().optional()
|
|
17581
|
-
}).strict();
|
|
17582
|
-
var compareCodeUnits3 = (left, right) => {
|
|
17583
|
-
const length = Math.min(left.length, right.length);
|
|
17584
|
-
for (let index = 0;index < length; index += 1) {
|
|
17585
|
-
const difference = left.charCodeAt(index) - right.charCodeAt(index);
|
|
17586
|
-
if (difference !== 0)
|
|
17587
|
-
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
|
+
};
|
|
17588
17658
|
}
|
|
17589
|
-
return left.length - right.length;
|
|
17590
17659
|
};
|
|
17591
|
-
var
|
|
17592
|
-
|
|
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
|
-
|
|
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));
|
|
17666
18390
|
const value = parsed.data;
|
|
17667
18391
|
const signals = value.assessment.signals;
|
|
17668
18392
|
if (signals.behaviorChange.value === true && signals.mechanicalLowRisk.value === true)
|
|
@@ -18009,6 +18733,8 @@ var applyWorkerLifecycle = (input) => {
|
|
|
18009
18733
|
if (task.data.status === "paused" && (input.state === "running" || input.state === "cancelling"))
|
|
18010
18734
|
return failure("invalid_transition", "paused task cannot run a worker");
|
|
18011
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);
|
|
18012
18738
|
if (notStarted && (input.state !== "stopped" || input.session !== null))
|
|
18013
18739
|
return failure("invalid_input", "a never-dispatched worker stops with no session");
|
|
18014
18740
|
if (notStarted && entry.data.session !== null)
|
|
@@ -18040,7 +18766,7 @@ var applyWorkerLifecycle = (input) => {
|
|
|
18040
18766
|
return success(task.data.revision, workspace.data.revision, entry);
|
|
18041
18767
|
const changed = input.store.mutateTaskAndWorkspace({
|
|
18042
18768
|
taskId: task.data.id,
|
|
18043
|
-
|
|
18769
|
+
expectedRevision: input.expectedRevision,
|
|
18044
18770
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
18045
18771
|
now: input.now,
|
|
18046
18772
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -18088,90 +18814,22 @@ var importedProvenance = (context) => ({
|
|
|
18088
18814
|
receipts: []
|
|
18089
18815
|
});
|
|
18090
18816
|
var portableTask = (task) => {
|
|
18091
|
-
const
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
|
|
18095
|
-
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18104
|
-
|
|
18105
|
-
for (const entry of
|
|
18106
|
-
entry.
|
|
18107
|
-
for (const worker of clone.workers)
|
|
18108
|
-
worker.data.session = null;
|
|
18109
|
-
clone.intent = {
|
|
18110
|
-
...clone.intent,
|
|
18111
|
-
data: { ...clone.intent.data, authorityRefs: portableRefs(clone.intent.data.authorityRefs) }
|
|
18112
|
-
};
|
|
18113
|
-
clone.constraints = clone.constraints.flatMap((constraint) => {
|
|
18114
|
-
const source = portableRef(constraint.source);
|
|
18115
|
-
return source ? [
|
|
18116
|
-
{
|
|
18117
|
-
...constraint,
|
|
18118
|
-
source,
|
|
18119
|
-
requires: constraint.requires.map((requirement) => ({
|
|
18120
|
-
...requirement,
|
|
18121
|
-
refs: portableRefs(requirement.refs)
|
|
18122
|
-
}))
|
|
18123
|
-
}
|
|
18124
|
-
] : [];
|
|
18125
|
-
});
|
|
18126
|
-
clone.assessments = clone.assessments.map((entry) => ({
|
|
18127
|
-
...entry,
|
|
18128
|
-
data: {
|
|
18129
|
-
...entry.data,
|
|
18130
|
-
facts: entry.data.facts.map(portableFact),
|
|
18131
|
-
signals: Object.fromEntries(Object.entries(entry.data.signals).map(([name, signal]) => [name, portableSignal(signal)])),
|
|
18132
|
-
consequences: entry.data.consequences.map((consequence) => ({
|
|
18133
|
-
...consequence,
|
|
18134
|
-
fact: portableFact(consequence.fact)
|
|
18135
|
-
})),
|
|
18136
|
-
verification: entry.data.verification.map((verification) => ({
|
|
18137
|
-
...verification,
|
|
18138
|
-
availableChecks: portableRefs(verification.availableChecks)
|
|
18139
|
-
}))
|
|
18140
|
-
}
|
|
18141
|
-
}));
|
|
18142
|
-
clone.progress = {
|
|
18143
|
-
...clone.progress,
|
|
18144
|
-
blockers: clone.progress.blockers.map((blocker) => ({
|
|
18145
|
-
...blocker,
|
|
18146
|
-
refs: portableRefs(blocker.refs)
|
|
18147
|
-
}))
|
|
18148
|
-
};
|
|
18149
|
-
clone.evidence = clone.evidence.map((entry) => ({
|
|
18150
|
-
...entry,
|
|
18151
|
-
data: {
|
|
18152
|
-
...entry.data,
|
|
18153
|
-
refs: portableRefs(entry.data.refs),
|
|
18154
|
-
reviewContext: portableRef(entry.data.reviewContext)
|
|
18155
|
-
}
|
|
18156
|
-
}));
|
|
18157
|
-
clone.decisions = clone.decisions.map((entry) => ({
|
|
18158
|
-
...entry,
|
|
18159
|
-
data: {
|
|
18160
|
-
...entry.data,
|
|
18161
|
-
consumption: entry.data.consumption ? portableRef(entry.data.consumption.actionRef) ? {
|
|
18162
|
-
...entry.data.consumption,
|
|
18163
|
-
actionRef: portableRef(entry.data.consumption.actionRef)
|
|
18164
|
-
} : null : null,
|
|
18165
|
-
binding: {
|
|
18166
|
-
...entry.data.binding,
|
|
18167
|
-
contentRefs: portableRefs(entry.data.binding.contentRefs)
|
|
18168
|
-
}
|
|
18169
|
-
}
|
|
18170
|
-
}));
|
|
18171
|
-
clone.findings = clone.findings.map((entry) => ({
|
|
18172
|
-
...entry,
|
|
18173
|
-
data: { ...entry.data, refs: portableRefs(entry.data.refs) }
|
|
18174
|
-
}));
|
|
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);
|
|
18175
18833
|
clone.candidates = [];
|
|
18176
18834
|
return clone;
|
|
18177
18835
|
};
|
|
@@ -18196,15 +18854,13 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18196
18854
|
allocate(entry.id);
|
|
18197
18855
|
const fresh = (id) => allocate(id);
|
|
18198
18856
|
const provenance = importedProvenance(context);
|
|
18857
|
+
const remap = (ref) => mapRef(ref, ids);
|
|
18199
18858
|
const intent = {
|
|
18200
18859
|
...source.intent,
|
|
18201
18860
|
id: fresh(source.intent.id),
|
|
18202
18861
|
recordedAt: timestamp,
|
|
18203
18862
|
provenance,
|
|
18204
|
-
data:
|
|
18205
|
-
...source.intent.data,
|
|
18206
|
-
authorityRefs: source.intent.data.authorityRefs.map((ref) => mapRef(ref, ids))
|
|
18207
|
-
}
|
|
18863
|
+
data: rewriteRecordRefs(source.intent.data, intentSchema, remap)
|
|
18208
18864
|
};
|
|
18209
18865
|
const assessments = source.assessments.map((entry) => {
|
|
18210
18866
|
const data = entry.data;
|
|
@@ -18213,62 +18869,39 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18213
18869
|
id: fresh(entry.id),
|
|
18214
18870
|
recordedAt: timestamp,
|
|
18215
18871
|
provenance,
|
|
18216
|
-
data:
|
|
18217
|
-
...data,
|
|
18218
|
-
facts: data.facts.map((fact) => ({
|
|
18219
|
-
...fact,
|
|
18220
|
-
refs: fact.refs.map((ref) => mapRef(ref, ids))
|
|
18221
|
-
})),
|
|
18222
|
-
signals: Object.fromEntries(Object.entries(data.signals).map(([name, signal]) => [
|
|
18223
|
-
name,
|
|
18224
|
-
{ ...signal, refs: signal.refs.map((ref) => mapRef(ref, ids)) }
|
|
18225
|
-
])),
|
|
18226
|
-
consequences: data.consequences.map((consequence) => ({
|
|
18227
|
-
...consequence,
|
|
18228
|
-
fact: {
|
|
18229
|
-
...consequence.fact,
|
|
18230
|
-
refs: consequence.fact.refs.map((ref) => mapRef(ref, ids))
|
|
18231
|
-
}
|
|
18232
|
-
})),
|
|
18233
|
-
verification: data.verification.map((verification) => ({
|
|
18234
|
-
...verification,
|
|
18235
|
-
availableChecks: verification.availableChecks.map((ref) => mapRef(ref, ids))
|
|
18236
|
-
}))
|
|
18237
|
-
}
|
|
18872
|
+
data: rewriteRecordRefs(data, assessmentSchema, remap)
|
|
18238
18873
|
};
|
|
18239
18874
|
});
|
|
18240
18875
|
const evidence = source.evidence.map((entry) => ({
|
|
18241
18876
|
...entry,
|
|
18242
18877
|
id: fresh(entry.id),
|
|
18243
18878
|
recordedAt: timestamp,
|
|
18244
|
-
provenance,
|
|
18245
|
-
data:
|
|
18246
|
-
...entry.data,
|
|
18247
|
-
refs: entry.data.refs.map((ref) => mapRef(ref, ids)),
|
|
18248
|
-
reviewContext: entry.data.reviewContext ? mapRef(entry.data.reviewContext, ids) : null
|
|
18249
|
-
}
|
|
18250
|
-
}));
|
|
18251
|
-
const decisions = source.decisions.map((entry) => ({
|
|
18252
|
-
...entry,
|
|
18253
|
-
id: fresh(entry.id),
|
|
18254
|
-
recordedAt: timestamp,
|
|
18255
|
-
provenance
|
|
18879
|
+
provenance,
|
|
18880
|
+
data: rewriteRecordRefs(entry.data, evidenceSchema, remap)
|
|
18256
18881
|
}));
|
|
18257
|
-
const
|
|
18882
|
+
const decisions = source.decisions.map((entry) => ({
|
|
18258
18883
|
...entry,
|
|
18259
18884
|
id: fresh(entry.id),
|
|
18260
18885
|
recordedAt: timestamp,
|
|
18261
|
-
provenance
|
|
18262
|
-
data: {
|
|
18263
|
-
...entry.data,
|
|
18264
|
-
refs: entry.data.refs.map((ref) => mapRef(ref, ids)),
|
|
18265
|
-
resolution: entry.data.resolution ? {
|
|
18266
|
-
...entry.data.resolution,
|
|
18267
|
-
evidenceIds: entry.data.resolution.evidenceIds.map((id) => ids.get(id) ?? id),
|
|
18268
|
-
decisionIds: entry.data.resolution.decisionIds.map((id) => ids.get(id) ?? id)
|
|
18269
|
-
} : null
|
|
18270
|
-
}
|
|
18886
|
+
provenance
|
|
18271
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
|
+
});
|
|
18272
18905
|
const workers = source.workers.map((entry) => ({
|
|
18273
18906
|
...entry,
|
|
18274
18907
|
id: fresh(entry.id),
|
|
@@ -18311,19 +18944,21 @@ var importedTask = (source, bundle, destinationWorkspaceId, context, timestamp)
|
|
|
18311
18944
|
closure: null,
|
|
18312
18945
|
assessments,
|
|
18313
18946
|
evidence,
|
|
18314
|
-
decisions: decisions.map((entry) =>
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
...entry
|
|
18318
|
-
|
|
18319
|
-
...
|
|
18320
|
-
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
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
|
+
}),
|
|
18327
18962
|
...actionProgress ? { actionProgress } : {},
|
|
18328
18963
|
findings,
|
|
18329
18964
|
workers,
|
|
@@ -18361,7 +18996,7 @@ class WorkitCore {
|
|
|
18361
18996
|
}
|
|
18362
18997
|
contextRootError() {
|
|
18363
18998
|
try {
|
|
18364
|
-
if (
|
|
18999
|
+
if (realpathSync5(this.context.root) !== this.store.root)
|
|
18365
19000
|
return failure("invalid_input", "operation context root does not match the task store root");
|
|
18366
19001
|
} catch {
|
|
18367
19002
|
return failure("invalid_input", "operation context root cannot be resolved");
|
|
@@ -18406,7 +19041,7 @@ class WorkitCore {
|
|
|
18406
19041
|
activeWorkerBlocker(task, workspace) {
|
|
18407
19042
|
if (workspace.writer)
|
|
18408
19043
|
return failure("recovery_required", "writer ownership must be released first");
|
|
18409
|
-
if (task.workers.some((entry) =>
|
|
19044
|
+
if (task.workers.some((entry) => workerBlocksTransition("close", entry.data.state)))
|
|
18410
19045
|
return failure("recovery_required", "worker state requires reconciliation");
|
|
18411
19046
|
return null;
|
|
18412
19047
|
}
|
|
@@ -18652,37 +19287,33 @@ class WorkitCore {
|
|
|
18652
19287
|
const currentCandidate = captureCandidate(this.store.root, task.data.intent.data.scope, environment());
|
|
18653
19288
|
if (!currentCandidate.ok)
|
|
18654
19289
|
return currentCandidate;
|
|
18655
|
-
|
|
18656
|
-
|
|
18657
|
-
evidence.candidateId ??= currentCandidate.data.id;
|
|
18658
|
-
} else {
|
|
18659
|
-
evidence.beforeCandidateId ??= null;
|
|
18660
|
-
evidence.candidateId ??= null;
|
|
18661
|
-
}
|
|
19290
|
+
const pin = helper && helper.ok ? helper.data.data.assignment.candidateId : null;
|
|
19291
|
+
const bound = resolveBinding(evidence, pin, currentCandidate.data.id);
|
|
18662
19292
|
if (helper?.ok) {
|
|
18663
19293
|
const assignment = helper.data.data.assignment;
|
|
18664
|
-
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))
|
|
18665
19295
|
return failure("permission_denied", "evidence is outside the worker assignment");
|
|
18666
19296
|
}
|
|
18667
19297
|
const knownCandidates = new Set(task.data.candidates.map((candidate) => candidate.id));
|
|
18668
|
-
for (const candidateId of [
|
|
19298
|
+
for (const candidateId of [bound.beforeCandidateId, bound.candidateId]) {
|
|
18669
19299
|
if (candidateId && candidateId !== currentCandidate.data.id && !knownCandidates.has(candidateId))
|
|
18670
19300
|
return failure("invalid_input", "evidence candidate is not a captured candidate");
|
|
18671
19301
|
}
|
|
19302
|
+
const boundEvidence = { ...evidence, ...bound };
|
|
18672
19303
|
const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
|
|
18673
19304
|
const candidates = current.candidates.some((item) => item.id === currentCandidate.data.id) ? current.candidates : [...current.candidates, currentCandidate.data];
|
|
18674
19305
|
const entry = {
|
|
18675
19306
|
id: newId(),
|
|
18676
19307
|
recordedAt: mutation.now,
|
|
18677
19308
|
provenance: provenance(this.context, "agent_reported"),
|
|
18678
|
-
data:
|
|
19309
|
+
data: boundEvidence
|
|
18679
19310
|
};
|
|
18680
19311
|
return success(mutation.revision, null, {
|
|
18681
19312
|
...current,
|
|
18682
19313
|
candidates,
|
|
18683
19314
|
evidence: [...current.evidence, entry],
|
|
18684
19315
|
findings: current.findings.map((finding) => {
|
|
18685
|
-
if (finding.data.disposition === "open" ||
|
|
19316
|
+
if (finding.data.disposition === "open" || boundEvidence.result === "skipped")
|
|
18686
19317
|
return finding;
|
|
18687
19318
|
if (finding.data.disposition !== "fixed")
|
|
18688
19319
|
return finding;
|
|
@@ -18691,8 +19322,12 @@ class WorkitCore {
|
|
|
18691
19322
|
item.evidenceId,
|
|
18692
19323
|
item.status
|
|
18693
19324
|
]));
|
|
18694
|
-
const verified = withEntry.evidence.some((item) =>
|
|
18695
|
-
|
|
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)));
|
|
18696
19331
|
return verified && !contradicted ? finding : { ...finding, data: { ...finding.data, disposition: "open", resolution: null } };
|
|
18697
19332
|
})
|
|
18698
19333
|
});
|
|
@@ -18717,7 +19352,12 @@ class WorkitCore {
|
|
|
18717
19352
|
const input = parsed.data;
|
|
18718
19353
|
if (nativeRequired && input.action !== "record")
|
|
18719
19354
|
return failure("permission_denied", "native observation is only valid for recording decisions");
|
|
18720
|
-
|
|
19355
|
+
const stated = input.action === "record" && input.response === "stated";
|
|
19356
|
+
if (stated && input.purpose === "action")
|
|
19357
|
+
return failure("permission_denied", "stated choices cannot authorize mutating actions");
|
|
19358
|
+
if (stated && !input.binding?.statedChoice)
|
|
19359
|
+
return failure("invalid_input", "stated choices require binding.statedChoice");
|
|
19360
|
+
if (nativeRequired && nativeObservation === undefined && !stated)
|
|
18721
19361
|
return failure("permission_denied", "native decision observation is required");
|
|
18722
19362
|
const task = this.store.readTask(input.taskId);
|
|
18723
19363
|
if (!task.ok)
|
|
@@ -18750,7 +19390,7 @@ class WorkitCore {
|
|
|
18750
19390
|
consumption: null
|
|
18751
19391
|
};
|
|
18752
19392
|
const data = { ...base, digest: decisionDigest(base) };
|
|
18753
|
-
const native = nativeRequired ? verifyNativeDecision(this.context.nativeAuthority, {
|
|
19393
|
+
const native = nativeRequired && !stated ? verifyNativeDecision(this.context.nativeAuthority, {
|
|
18754
19394
|
observation: nativeObservation,
|
|
18755
19395
|
expected: {
|
|
18756
19396
|
taskId: task.data.id,
|
|
@@ -18845,7 +19485,7 @@ class WorkitCore {
|
|
|
18845
19485
|
if (input.action === "record") {
|
|
18846
19486
|
if (helper?.ok) {
|
|
18847
19487
|
const assignment = helper.data.data.assignment;
|
|
18848
|
-
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))
|
|
18849
19489
|
return failure("permission_denied", "finding is outside the worker assignment");
|
|
18850
19490
|
}
|
|
18851
19491
|
if (input.candidateId && !task.data.candidates.some((candidate) => candidate.id === input.candidateId))
|
|
@@ -18892,7 +19532,11 @@ class WorkitCore {
|
|
|
18892
19532
|
const evaluations = evaluateEvidence(task.data, current.data);
|
|
18893
19533
|
const verified = evidence.some((entry) => {
|
|
18894
19534
|
const evaluation = evaluations.find((item) => item.evidenceId === entry.id);
|
|
18895
|
-
return
|
|
19535
|
+
return findingVerificationPasses(finding.data.candidateId, {
|
|
19536
|
+
kind: entry.data.kind,
|
|
19537
|
+
candidateId: entry.data.candidateId,
|
|
19538
|
+
status: evaluation?.status ?? "missing"
|
|
19539
|
+
});
|
|
18896
19540
|
});
|
|
18897
19541
|
if (!verified)
|
|
18898
19542
|
return failure("permission_denied", "fixed findings require passing verification evidence");
|
|
@@ -18904,7 +19548,7 @@ class WorkitCore {
|
|
|
18904
19548
|
if (entry.data.result === "missing" || entry.data.result === "skipped")
|
|
18905
19549
|
return false;
|
|
18906
19550
|
const candidateMatches = finding.data.candidateId === null ? entry.data.candidateId === null : entry.data.candidateId === finding.data.candidateId || entry.data.beforeCandidateId === finding.data.candidateId;
|
|
18907
|
-
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)));
|
|
18908
19552
|
return candidateMatches && (referenceMatches || entry.data.claim === finding.data.claim);
|
|
18909
19553
|
});
|
|
18910
19554
|
if (!relevant)
|
|
@@ -18982,7 +19626,7 @@ class WorkitCore {
|
|
|
18982
19626
|
const workerId = newId();
|
|
18983
19627
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
18984
19628
|
taskId: task.data.id,
|
|
18985
|
-
|
|
19629
|
+
expectedRevision: input.expectedRevision,
|
|
18986
19630
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
18987
19631
|
now: trustedNow(this.context),
|
|
18988
19632
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19020,7 +19664,7 @@ class WorkitCore {
|
|
|
19020
19664
|
return failure("permission_denied", "worker report is outside the worker assignment");
|
|
19021
19665
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19022
19666
|
taskId: task.data.id,
|
|
19023
|
-
|
|
19667
|
+
expectedRevision: input.expectedRevision,
|
|
19024
19668
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19025
19669
|
now: trustedNow(this.context),
|
|
19026
19670
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19044,24 +19688,25 @@ class WorkitCore {
|
|
|
19044
19688
|
return failure("invalid_transition", "closed task cannot cancel workers");
|
|
19045
19689
|
if (entry.data.state === "unknown")
|
|
19046
19690
|
return failure("recovery_required", "worker state requires recovery");
|
|
19047
|
-
if (entry.data.state === "stopped")
|
|
19048
|
-
|
|
19049
|
-
|
|
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
|
+
}
|
|
19050
19695
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19051
19696
|
taskId: task.data.id,
|
|
19052
|
-
|
|
19697
|
+
expectedRevision: input.expectedRevision,
|
|
19053
19698
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19054
19699
|
now: trustedNow(this.context),
|
|
19055
|
-
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
|
+
}),
|
|
19056
19704
|
task: (current, mutation) => success(mutation.revision, null, {
|
|
19057
19705
|
...current,
|
|
19058
19706
|
workers: current.workers.map((candidate) => candidate.id === input.workerId ? {
|
|
19059
19707
|
...candidate,
|
|
19060
19708
|
recordedAt: mutation.now,
|
|
19061
|
-
data: {
|
|
19062
|
-
...candidate.data,
|
|
19063
|
-
state: settles ? "stopped" : "cancelling"
|
|
19064
|
-
}
|
|
19709
|
+
data: { ...candidate.data, state: "stopped" }
|
|
19065
19710
|
} : candidate)
|
|
19066
19711
|
})
|
|
19067
19712
|
});
|
|
@@ -19158,7 +19803,7 @@ class WorkitCore {
|
|
|
19158
19803
|
return attested;
|
|
19159
19804
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19160
19805
|
taskId: task.data.id,
|
|
19161
|
-
|
|
19806
|
+
expectedRevision: input.expectedRevision,
|
|
19162
19807
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19163
19808
|
now: trustedNow(this.context),
|
|
19164
19809
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -19324,6 +19969,12 @@ class WorkitCore {
|
|
|
19324
19969
|
if (!sameSession2(helper.data.data.session, this.context))
|
|
19325
19970
|
return failure("permission_denied", "worker session does not match the caller");
|
|
19326
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
|
+
}
|
|
19327
19978
|
const owner = {
|
|
19328
19979
|
taskId: task.data.id,
|
|
19329
19980
|
workerId: helperId,
|
|
@@ -19335,7 +19986,7 @@ class WorkitCore {
|
|
|
19335
19986
|
};
|
|
19336
19987
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19337
19988
|
taskId: task.data.id,
|
|
19338
|
-
|
|
19989
|
+
expectedRevision: input.expectedRevision,
|
|
19339
19990
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19340
19991
|
now: trustedNow(this.context),
|
|
19341
19992
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -19366,7 +20017,7 @@ class WorkitCore {
|
|
|
19366
20017
|
}
|
|
19367
20018
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19368
20019
|
taskId: task.data.id,
|
|
19369
|
-
|
|
20020
|
+
expectedRevision: input.expectedRevision,
|
|
19370
20021
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19371
20022
|
now: trustedNow(this.context),
|
|
19372
20023
|
workspace: (currentWorkspace, mutation) => success(mutation.revision, mutation.revision, { ...currentWorkspace, writer: null }),
|
|
@@ -19598,7 +20249,7 @@ class WorkitCore {
|
|
|
19598
20249
|
if (view.task.workspaceId !== view.workspace.id)
|
|
19599
20250
|
return failure("invalid_input", "task and workspace bindings are invalid");
|
|
19600
20251
|
try {
|
|
19601
|
-
if (
|
|
20252
|
+
if (realpathSync5(view.workspace.root) !== this.store.root)
|
|
19602
20253
|
return failure("invalid_input", "task view root does not match the task store");
|
|
19603
20254
|
} catch {
|
|
19604
20255
|
return failure("invalid_input", "task view root cannot be resolved");
|
|
@@ -19615,7 +20266,15 @@ class WorkitCore {
|
|
|
19615
20266
|
if (seen.has(observation.workerId))
|
|
19616
20267
|
return failure("invalid_input", "worker observations must be unique");
|
|
19617
20268
|
seen.add(observation.workerId);
|
|
19618
|
-
|
|
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)
|
|
19619
20278
|
return failure("revision_conflict", "worker observation is stale");
|
|
19620
20279
|
if (!view.task.workers.some((entry) => entry.id === observation.workerId))
|
|
19621
20280
|
return failure("permission_denied", "worker observation is not assigned");
|
|
@@ -19701,19 +20360,26 @@ class WorkitCore {
|
|
|
19701
20360
|
return failure("permission_denied", "imported resume requires native destination approval");
|
|
19702
20361
|
resumeCandidate = current.data.candidate;
|
|
19703
20362
|
}
|
|
19704
|
-
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);
|
|
19705
20364
|
if (blocker)
|
|
19706
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
|
+
}
|
|
19707
20373
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19708
20374
|
taskId: task.data.id,
|
|
19709
|
-
|
|
20375
|
+
expectedRevision: input.expectedRevision,
|
|
19710
20376
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19711
20377
|
now: trustedNow(this.context),
|
|
19712
20378
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
19713
20379
|
task: (current, context) => success(context.revision, null, {
|
|
19714
20380
|
...current,
|
|
19715
20381
|
status,
|
|
19716
|
-
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,
|
|
19717
20383
|
progress: current.progress,
|
|
19718
20384
|
pauseReason: status === "paused" ? input.reason ?? null : null
|
|
19719
20385
|
})
|
|
@@ -19751,12 +20417,13 @@ class WorkitCore {
|
|
|
19751
20417
|
return workspace;
|
|
19752
20418
|
if (!workspace.data)
|
|
19753
20419
|
return failure("not_found", "workspace not found");
|
|
19754
|
-
|
|
19755
|
-
|
|
20420
|
+
const revisionBlocker = this.activeWorkerBlocker(task.data, workspace.data);
|
|
20421
|
+
if (revisionBlocker)
|
|
20422
|
+
return revisionBlocker;
|
|
19756
20423
|
this.fillRevisions(input, task.data, workspace.data);
|
|
19757
20424
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19758
20425
|
taskId: task.data.id,
|
|
19759
|
-
|
|
20426
|
+
expectedRevision: input.expectedRevision,
|
|
19760
20427
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19761
20428
|
now: trustedNow(this.context),
|
|
19762
20429
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
@@ -19812,7 +20479,7 @@ class WorkitCore {
|
|
|
19812
20479
|
return closure;
|
|
19813
20480
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
19814
20481
|
taskId: task.data.id,
|
|
19815
|
-
|
|
20482
|
+
expectedRevision: input.expectedRevision,
|
|
19816
20483
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
19817
20484
|
now: trustedNow(this.context),
|
|
19818
20485
|
workspace: (value, context) => success(context.revision, context.revision, value),
|
|
@@ -19849,7 +20516,7 @@ function gitRevisionParts(value) {
|
|
|
19849
20516
|
}
|
|
19850
20517
|
function resolveGitRevision(root, value) {
|
|
19851
20518
|
for (const part of gitRevisionParts(value)) {
|
|
19852
|
-
const result =
|
|
20519
|
+
const result = run2(root, "git", [
|
|
19853
20520
|
"rev-parse",
|
|
19854
20521
|
"--verify",
|
|
19855
20522
|
"--quiet",
|
|
@@ -19861,23 +20528,23 @@ function resolveGitRevision(root, value) {
|
|
|
19861
20528
|
}
|
|
19862
20529
|
}
|
|
19863
20530
|
function resolveInside(root, candidate) {
|
|
19864
|
-
const base =
|
|
19865
|
-
const target =
|
|
19866
|
-
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)) {
|
|
19867
20534
|
throw new Error("path must stay inside repository root");
|
|
19868
20535
|
}
|
|
19869
20536
|
let ancestor = target;
|
|
19870
|
-
while (!
|
|
19871
|
-
ancestor =
|
|
19872
|
-
const canonicalAncestor =
|
|
19873
|
-
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)) {
|
|
19874
20541
|
throw new Error("path must stay inside repository root");
|
|
19875
20542
|
}
|
|
19876
20543
|
return target;
|
|
19877
20544
|
}
|
|
19878
|
-
function
|
|
19879
|
-
const cwd =
|
|
19880
|
-
const result =
|
|
20545
|
+
function run2(root, executable, args, env = {}) {
|
|
20546
|
+
const cwd = realpathSync6(root);
|
|
20547
|
+
const result = spawnSync3(executable, args, {
|
|
19881
20548
|
cwd,
|
|
19882
20549
|
encoding: "utf8",
|
|
19883
20550
|
env: { ...process.env, ...env }
|
|
@@ -24517,1029 +25184,707 @@ class Protocol {
|
|
|
24517
25184
|
this._onrequest(message, extra);
|
|
24518
25185
|
} else if (isJSONRPCNotification(message)) {
|
|
24519
25186
|
this._onnotification(message);
|
|
24520
|
-
} else {
|
|
24521
|
-
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
24522
|
-
}
|
|
24523
|
-
};
|
|
24524
|
-
await this._transport.start();
|
|
24525
|
-
}
|
|
24526
|
-
_onclose() {
|
|
24527
|
-
const responseHandlers = this._responseHandlers;
|
|
24528
|
-
this._responseHandlers = new Map;
|
|
24529
|
-
this._progressHandlers.clear();
|
|
24530
|
-
this._taskProgressTokens.clear();
|
|
24531
|
-
this._pendingDebouncedNotifications.clear();
|
|
24532
|
-
for (const info of this._timeoutInfo.values()) {
|
|
24533
|
-
clearTimeout(info.timeoutId);
|
|
24534
|
-
}
|
|
24535
|
-
this._timeoutInfo.clear();
|
|
24536
|
-
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
24537
|
-
controller.abort();
|
|
24538
|
-
}
|
|
24539
|
-
this._requestHandlerAbortControllers.clear();
|
|
24540
|
-
const error = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
24541
|
-
this._transport = undefined;
|
|
24542
|
-
this.onclose?.();
|
|
24543
|
-
for (const handler of responseHandlers.values()) {
|
|
24544
|
-
handler(error);
|
|
24545
|
-
}
|
|
24546
|
-
}
|
|
24547
|
-
_onerror(error) {
|
|
24548
|
-
this.onerror?.(error);
|
|
24549
|
-
}
|
|
24550
|
-
_onnotification(notification) {
|
|
24551
|
-
const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler;
|
|
24552
|
-
if (handler === undefined) {
|
|
24553
|
-
return;
|
|
24554
|
-
}
|
|
24555
|
-
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
24556
|
-
}
|
|
24557
|
-
_onrequest(request, extra) {
|
|
24558
|
-
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
24559
|
-
const capturedTransport = this._transport;
|
|
24560
|
-
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
24561
|
-
if (handler === undefined) {
|
|
24562
|
-
const errorResponse = {
|
|
24563
|
-
jsonrpc: "2.0",
|
|
24564
|
-
id: request.id,
|
|
24565
|
-
error: {
|
|
24566
|
-
code: ErrorCode.MethodNotFound,
|
|
24567
|
-
message: "Method not found"
|
|
24568
|
-
}
|
|
24569
|
-
};
|
|
24570
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24571
|
-
this._enqueueTaskMessage(relatedTaskId, {
|
|
24572
|
-
type: "error",
|
|
24573
|
-
message: errorResponse,
|
|
24574
|
-
timestamp: Date.now()
|
|
24575
|
-
}, capturedTransport?.sessionId).catch((error) => this._onerror(new Error(`Failed to enqueue error response: ${error}`)));
|
|
24576
|
-
} else {
|
|
24577
|
-
capturedTransport?.send(errorResponse).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
24578
|
-
}
|
|
24579
|
-
return;
|
|
24580
|
-
}
|
|
24581
|
-
const abortController = new AbortController;
|
|
24582
|
-
this._requestHandlerAbortControllers.set(request.id, abortController);
|
|
24583
|
-
const taskCreationParams = isTaskAugmentedRequestParams(request.params) ? request.params.task : undefined;
|
|
24584
|
-
const taskStore = this._taskStore ? this.requestTaskStore(request, capturedTransport?.sessionId) : undefined;
|
|
24585
|
-
const fullExtra = {
|
|
24586
|
-
signal: abortController.signal,
|
|
24587
|
-
sessionId: capturedTransport?.sessionId,
|
|
24588
|
-
_meta: request.params?._meta,
|
|
24589
|
-
sendNotification: async (notification) => {
|
|
24590
|
-
if (abortController.signal.aborted)
|
|
24591
|
-
return;
|
|
24592
|
-
const notificationOptions = { relatedRequestId: request.id };
|
|
24593
|
-
if (relatedTaskId) {
|
|
24594
|
-
notificationOptions.relatedTask = { taskId: relatedTaskId };
|
|
24595
|
-
}
|
|
24596
|
-
await this.notification(notification, notificationOptions);
|
|
24597
|
-
},
|
|
24598
|
-
sendRequest: async (r, resultSchema, options) => {
|
|
24599
|
-
if (abortController.signal.aborted) {
|
|
24600
|
-
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
24601
|
-
}
|
|
24602
|
-
const requestOptions = { ...options, relatedRequestId: request.id };
|
|
24603
|
-
if (relatedTaskId && !requestOptions.relatedTask) {
|
|
24604
|
-
requestOptions.relatedTask = { taskId: relatedTaskId };
|
|
24605
|
-
}
|
|
24606
|
-
const effectiveTaskId = requestOptions.relatedTask?.taskId ?? relatedTaskId;
|
|
24607
|
-
if (effectiveTaskId && taskStore) {
|
|
24608
|
-
await taskStore.updateTaskStatus(effectiveTaskId, "input_required");
|
|
24609
|
-
}
|
|
24610
|
-
return await this.request(r, resultSchema, requestOptions);
|
|
24611
|
-
},
|
|
24612
|
-
authInfo: extra?.authInfo,
|
|
24613
|
-
requestId: request.id,
|
|
24614
|
-
requestInfo: extra?.requestInfo,
|
|
24615
|
-
taskId: relatedTaskId,
|
|
24616
|
-
taskStore,
|
|
24617
|
-
taskRequestedTtl: taskCreationParams?.ttl,
|
|
24618
|
-
closeSSEStream: extra?.closeSSEStream,
|
|
24619
|
-
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
24620
|
-
};
|
|
24621
|
-
Promise.resolve().then(() => {
|
|
24622
|
-
if (taskCreationParams) {
|
|
24623
|
-
this.assertTaskHandlerCapability(request.method);
|
|
24624
|
-
}
|
|
24625
|
-
}).then(() => handler(request, fullExtra)).then(async (result) => {
|
|
24626
|
-
if (abortController.signal.aborted) {
|
|
24627
|
-
return;
|
|
24628
|
-
}
|
|
24629
|
-
const response = {
|
|
24630
|
-
result,
|
|
24631
|
-
jsonrpc: "2.0",
|
|
24632
|
-
id: request.id
|
|
24633
|
-
};
|
|
24634
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24635
|
-
await this._enqueueTaskMessage(relatedTaskId, {
|
|
24636
|
-
type: "response",
|
|
24637
|
-
message: response,
|
|
24638
|
-
timestamp: Date.now()
|
|
24639
|
-
}, capturedTransport?.sessionId);
|
|
24640
|
-
} else {
|
|
24641
|
-
await capturedTransport?.send(response);
|
|
24642
|
-
}
|
|
24643
|
-
}, async (error) => {
|
|
24644
|
-
if (abortController.signal.aborted) {
|
|
24645
|
-
return;
|
|
24646
|
-
}
|
|
24647
|
-
const errorResponse = {
|
|
24648
|
-
jsonrpc: "2.0",
|
|
24649
|
-
id: request.id,
|
|
24650
|
-
error: {
|
|
24651
|
-
code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
|
|
24652
|
-
message: error.message ?? "Internal error",
|
|
24653
|
-
...error["data"] !== undefined && { data: error["data"] }
|
|
24654
|
-
}
|
|
24655
|
-
};
|
|
24656
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24657
|
-
await this._enqueueTaskMessage(relatedTaskId, {
|
|
24658
|
-
type: "error",
|
|
24659
|
-
message: errorResponse,
|
|
24660
|
-
timestamp: Date.now()
|
|
24661
|
-
}, capturedTransport?.sessionId);
|
|
24662
|
-
} else {
|
|
24663
|
-
await capturedTransport?.send(errorResponse);
|
|
24664
|
-
}
|
|
24665
|
-
}).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
|
|
24666
|
-
if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
|
|
24667
|
-
this._requestHandlerAbortControllers.delete(request.id);
|
|
24668
|
-
}
|
|
24669
|
-
});
|
|
24670
|
-
}
|
|
24671
|
-
_onprogress(notification) {
|
|
24672
|
-
const { progressToken, ...params } = notification.params;
|
|
24673
|
-
const messageId = Number(progressToken);
|
|
24674
|
-
const handler = this._progressHandlers.get(messageId);
|
|
24675
|
-
if (!handler) {
|
|
24676
|
-
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
|
24677
|
-
return;
|
|
24678
|
-
}
|
|
24679
|
-
const responseHandler = this._responseHandlers.get(messageId);
|
|
24680
|
-
const timeoutInfo = this._timeoutInfo.get(messageId);
|
|
24681
|
-
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
|
|
24682
|
-
try {
|
|
24683
|
-
this._resetTimeout(messageId);
|
|
24684
|
-
} catch (error) {
|
|
24685
|
-
this._responseHandlers.delete(messageId);
|
|
24686
|
-
this._progressHandlers.delete(messageId);
|
|
24687
|
-
this._cleanupTimeout(messageId);
|
|
24688
|
-
responseHandler(error);
|
|
24689
|
-
return;
|
|
24690
|
-
}
|
|
24691
|
-
}
|
|
24692
|
-
handler(params);
|
|
24693
|
-
}
|
|
24694
|
-
_onresponse(response) {
|
|
24695
|
-
const messageId = Number(response.id);
|
|
24696
|
-
const resolver = this._requestResolvers.get(messageId);
|
|
24697
|
-
if (resolver) {
|
|
24698
|
-
this._requestResolvers.delete(messageId);
|
|
24699
|
-
if (isJSONRPCResultResponse(response)) {
|
|
24700
|
-
resolver(response);
|
|
24701
|
-
} else {
|
|
24702
|
-
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
|
24703
|
-
resolver(error);
|
|
24704
|
-
}
|
|
24705
|
-
return;
|
|
24706
|
-
}
|
|
24707
|
-
const handler = this._responseHandlers.get(messageId);
|
|
24708
|
-
if (handler === undefined) {
|
|
24709
|
-
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
|
24710
|
-
return;
|
|
24711
|
-
}
|
|
24712
|
-
this._responseHandlers.delete(messageId);
|
|
24713
|
-
this._cleanupTimeout(messageId);
|
|
24714
|
-
let isTaskResponse = false;
|
|
24715
|
-
if (isJSONRPCResultResponse(response) && response.result && typeof response.result === "object") {
|
|
24716
|
-
const result = response.result;
|
|
24717
|
-
if (result.task && typeof result.task === "object") {
|
|
24718
|
-
const task = result.task;
|
|
24719
|
-
if (typeof task.taskId === "string") {
|
|
24720
|
-
isTaskResponse = true;
|
|
24721
|
-
this._taskProgressTokens.set(task.taskId, messageId);
|
|
24722
|
-
}
|
|
25187
|
+
} else {
|
|
25188
|
+
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
24723
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);
|
|
24724
25201
|
}
|
|
24725
|
-
|
|
24726
|
-
|
|
25202
|
+
this._timeoutInfo.clear();
|
|
25203
|
+
for (const controller of this._requestHandlerAbortControllers.values()) {
|
|
25204
|
+
controller.abort();
|
|
24727
25205
|
}
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
|
|
24731
|
-
|
|
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()) {
|
|
24732
25211
|
handler(error);
|
|
24733
25212
|
}
|
|
24734
25213
|
}
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
}
|
|
24738
|
-
async close() {
|
|
24739
|
-
await this._transport?.close();
|
|
25214
|
+
_onerror(error) {
|
|
25215
|
+
this.onerror?.(error);
|
|
24740
25216
|
}
|
|
24741
|
-
|
|
24742
|
-
const
|
|
24743
|
-
if (
|
|
24744
|
-
try {
|
|
24745
|
-
const result = await this.request(request, resultSchema, options);
|
|
24746
|
-
yield { type: "result", result };
|
|
24747
|
-
} catch (error) {
|
|
24748
|
-
yield {
|
|
24749
|
-
type: "error",
|
|
24750
|
-
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
24751
|
-
};
|
|
24752
|
-
}
|
|
25217
|
+
_onnotification(notification) {
|
|
25218
|
+
const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler;
|
|
25219
|
+
if (handler === undefined) {
|
|
24753
25220
|
return;
|
|
24754
25221
|
}
|
|
24755
|
-
|
|
24756
|
-
try {
|
|
24757
|
-
const createResult = await this.request(request, CreateTaskResultSchema, options);
|
|
24758
|
-
if (createResult.task) {
|
|
24759
|
-
taskId = createResult.task.taskId;
|
|
24760
|
-
yield { type: "taskCreated", task: createResult.task };
|
|
24761
|
-
} else {
|
|
24762
|
-
throw new McpError(ErrorCode.InternalError, "Task creation did not return a task");
|
|
24763
|
-
}
|
|
24764
|
-
while (true) {
|
|
24765
|
-
const task = await this.getTask({ taskId }, options);
|
|
24766
|
-
yield { type: "taskStatus", task };
|
|
24767
|
-
if (isTerminal(task.status)) {
|
|
24768
|
-
if (task.status === "completed") {
|
|
24769
|
-
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
24770
|
-
yield { type: "result", result };
|
|
24771
|
-
} else if (task.status === "failed") {
|
|
24772
|
-
yield {
|
|
24773
|
-
type: "error",
|
|
24774
|
-
error: new McpError(ErrorCode.InternalError, `Task ${taskId} failed`)
|
|
24775
|
-
};
|
|
24776
|
-
} else if (task.status === "cancelled") {
|
|
24777
|
-
yield {
|
|
24778
|
-
type: "error",
|
|
24779
|
-
error: new McpError(ErrorCode.InternalError, `Task ${taskId} was cancelled`)
|
|
24780
|
-
};
|
|
24781
|
-
}
|
|
24782
|
-
return;
|
|
24783
|
-
}
|
|
24784
|
-
if (task.status === "input_required") {
|
|
24785
|
-
const result = await this.getTaskResult({ taskId }, resultSchema, options);
|
|
24786
|
-
yield { type: "result", result };
|
|
24787
|
-
return;
|
|
24788
|
-
}
|
|
24789
|
-
const pollInterval = task.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
24790
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
24791
|
-
options?.signal?.throwIfAborted();
|
|
24792
|
-
}
|
|
24793
|
-
} catch (error) {
|
|
24794
|
-
yield {
|
|
24795
|
-
type: "error",
|
|
24796
|
-
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
24797
|
-
};
|
|
24798
|
-
}
|
|
25222
|
+
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
24799
25223
|
}
|
|
24800
|
-
|
|
24801
|
-
const
|
|
24802
|
-
|
|
24803
|
-
|
|
24804
|
-
|
|
24805
|
-
|
|
24806
|
-
if (!this._transport) {
|
|
24807
|
-
earlyReject(new Error("Not connected"));
|
|
24808
|
-
return;
|
|
24809
|
-
}
|
|
24810
|
-
if (this._options?.enforceStrictCapabilities === true) {
|
|
24811
|
-
try {
|
|
24812
|
-
this.assertCapabilityForMethod(request.method);
|
|
24813
|
-
if (task) {
|
|
24814
|
-
this.assertTaskCapability(request.method);
|
|
24815
|
-
}
|
|
24816
|
-
} catch (e) {
|
|
24817
|
-
earlyReject(e);
|
|
24818
|
-
return;
|
|
24819
|
-
}
|
|
24820
|
-
}
|
|
24821
|
-
options?.signal?.throwIfAborted();
|
|
24822
|
-
const messageId = this._requestMessageId++;
|
|
24823
|
-
const jsonrpcRequest = {
|
|
24824
|
-
...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 = {
|
|
24825
25230
|
jsonrpc: "2.0",
|
|
24826
|
-
id:
|
|
25231
|
+
id: request.id,
|
|
25232
|
+
error: {
|
|
25233
|
+
code: ErrorCode.MethodNotFound,
|
|
25234
|
+
message: "Method not found"
|
|
25235
|
+
}
|
|
24827
25236
|
};
|
|
24828
|
-
if (
|
|
24829
|
-
this.
|
|
24830
|
-
|
|
24831
|
-
|
|
24832
|
-
|
|
24833
|
-
|
|
24834
|
-
|
|
24835
|
-
|
|
24836
|
-
};
|
|
24837
|
-
}
|
|
24838
|
-
if (task) {
|
|
24839
|
-
jsonrpcRequest.params = {
|
|
24840
|
-
...jsonrpcRequest.params,
|
|
24841
|
-
task
|
|
24842
|
-
};
|
|
24843
|
-
}
|
|
24844
|
-
if (relatedTask) {
|
|
24845
|
-
jsonrpcRequest.params = {
|
|
24846
|
-
...jsonrpcRequest.params,
|
|
24847
|
-
_meta: {
|
|
24848
|
-
...jsonrpcRequest.params?._meta || {},
|
|
24849
|
-
[RELATED_TASK_META_KEY]: relatedTask
|
|
24850
|
-
}
|
|
24851
|
-
};
|
|
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}`)));
|
|
24852
25245
|
}
|
|
24853
|
-
|
|
24854
|
-
|
|
24855
|
-
|
|
24856
|
-
|
|
24857
|
-
|
|
24858
|
-
|
|
24859
|
-
|
|
24860
|
-
|
|
24861
|
-
|
|
24862
|
-
|
|
24863
|
-
|
|
24864
|
-
|
|
24865
|
-
const error = reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason));
|
|
24866
|
-
reject(error);
|
|
24867
|
-
};
|
|
24868
|
-
this._responseHandlers.set(messageId, (response) => {
|
|
24869
|
-
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)
|
|
24870
25258
|
return;
|
|
25259
|
+
const notificationOptions = { relatedRequestId: request.id };
|
|
25260
|
+
if (relatedTaskId) {
|
|
25261
|
+
notificationOptions.relatedTask = { taskId: relatedTaskId };
|
|
24871
25262
|
}
|
|
24872
|
-
|
|
24873
|
-
|
|
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");
|
|
24874
25268
|
}
|
|
24875
|
-
|
|
24876
|
-
|
|
24877
|
-
|
|
24878
|
-
reject(parseResult.error);
|
|
24879
|
-
} else {
|
|
24880
|
-
resolve(parseResult.data);
|
|
24881
|
-
}
|
|
24882
|
-
} catch (error) {
|
|
24883
|
-
reject(error);
|
|
25269
|
+
const requestOptions = { ...options, relatedRequestId: request.id };
|
|
25270
|
+
if (relatedTaskId && !requestOptions.relatedTask) {
|
|
25271
|
+
requestOptions.relatedTask = { taskId: relatedTaskId };
|
|
24884
25272
|
}
|
|
24885
|
-
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
24889
|
-
|
|
24890
|
-
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
this.
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
|
|
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,
|
|
24906
25305
|
timestamp: Date.now()
|
|
24907
|
-
})
|
|
24908
|
-
this._cleanupTimeout(messageId);
|
|
24909
|
-
reject(error);
|
|
24910
|
-
});
|
|
25306
|
+
}, capturedTransport?.sessionId);
|
|
24911
25307
|
} else {
|
|
24912
|
-
|
|
24913
|
-
this._cleanupTimeout(messageId);
|
|
24914
|
-
reject(error);
|
|
24915
|
-
});
|
|
25308
|
+
await capturedTransport?.send(response);
|
|
24916
25309
|
}
|
|
24917
|
-
})
|
|
24918
|
-
|
|
24919
|
-
|
|
24920
|
-
|
|
24921
|
-
|
|
24922
|
-
async getTaskResult(params, resultSchema, options) {
|
|
24923
|
-
return this.request({ method: "tasks/result", params }, resultSchema, options);
|
|
24924
|
-
}
|
|
24925
|
-
async listTasks(params, options) {
|
|
24926
|
-
return this.request({ method: "tasks/list", params }, ListTasksResultSchema, options);
|
|
24927
|
-
}
|
|
24928
|
-
async cancelTask(params, options) {
|
|
24929
|
-
return this.request({ method: "tasks/cancel", params }, CancelTaskResultSchema, options);
|
|
24930
|
-
}
|
|
24931
|
-
async notification(notification, options) {
|
|
24932
|
-
if (!this._transport) {
|
|
24933
|
-
throw new Error("Not connected");
|
|
24934
|
-
}
|
|
24935
|
-
this.assertNotificationCapability(notification.method);
|
|
24936
|
-
const relatedTaskId = options?.relatedTask?.taskId;
|
|
24937
|
-
if (relatedTaskId) {
|
|
24938
|
-
const jsonrpcNotification = {
|
|
24939
|
-
...notification,
|
|
25310
|
+
}, async (error) => {
|
|
25311
|
+
if (abortController.signal.aborted) {
|
|
25312
|
+
return;
|
|
25313
|
+
}
|
|
25314
|
+
const errorResponse = {
|
|
24940
25315
|
jsonrpc: "2.0",
|
|
24941
|
-
|
|
24942
|
-
|
|
24943
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
}
|
|
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"] }
|
|
24947
25321
|
}
|
|
24948
25322
|
};
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
|
|
24953
|
-
|
|
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)}`));
|
|
24954
25344
|
return;
|
|
24955
25345
|
}
|
|
24956
|
-
const
|
|
24957
|
-
const
|
|
24958
|
-
if (
|
|
24959
|
-
|
|
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);
|
|
24960
25356
|
return;
|
|
24961
25357
|
}
|
|
24962
|
-
|
|
24963
|
-
|
|
24964
|
-
|
|
24965
|
-
|
|
24966
|
-
|
|
24967
|
-
|
|
24968
|
-
|
|
24969
|
-
|
|
24970
|
-
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
...jsonrpcNotification.params,
|
|
24977
|
-
_meta: {
|
|
24978
|
-
...jsonrpcNotification.params?._meta || {},
|
|
24979
|
-
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
24980
|
-
}
|
|
24981
|
-
}
|
|
24982
|
-
};
|
|
24983
|
-
}
|
|
24984
|
-
this._transport?.send(jsonrpcNotification, options).catch((error) => this._onerror(error));
|
|
24985
|
-
});
|
|
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
|
+
}
|
|
24986
25372
|
return;
|
|
24987
25373
|
}
|
|
24988
|
-
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
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);
|
|
25001
25389
|
}
|
|
25002
|
-
}
|
|
25390
|
+
}
|
|
25003
25391
|
}
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25009
|
-
|
|
25010
|
-
const
|
|
25011
|
-
|
|
25012
|
-
});
|
|
25013
|
-
}
|
|
25014
|
-
removeRequestHandler(method) {
|
|
25015
|
-
this._requestHandlers.delete(method);
|
|
25016
|
-
}
|
|
25017
|
-
assertCanSetRequestHandler(method) {
|
|
25018
|
-
if (this._requestHandlers.has(method)) {
|
|
25019
|
-
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);
|
|
25020
25400
|
}
|
|
25021
25401
|
}
|
|
25022
|
-
|
|
25023
|
-
|
|
25024
|
-
this._notificationHandlers.set(method, (notification) => {
|
|
25025
|
-
const parsed = parseWithCompat(notificationSchema, notification);
|
|
25026
|
-
return Promise.resolve(handler(parsed));
|
|
25027
|
-
});
|
|
25028
|
-
}
|
|
25029
|
-
removeNotificationHandler(method) {
|
|
25030
|
-
this._notificationHandlers.delete(method);
|
|
25402
|
+
get transport() {
|
|
25403
|
+
return this._transport;
|
|
25031
25404
|
}
|
|
25032
|
-
|
|
25033
|
-
|
|
25034
|
-
if (progressToken !== undefined) {
|
|
25035
|
-
this._progressHandlers.delete(progressToken);
|
|
25036
|
-
this._taskProgressTokens.delete(taskId);
|
|
25037
|
-
}
|
|
25405
|
+
async close() {
|
|
25406
|
+
await this._transport?.close();
|
|
25038
25407
|
}
|
|
25039
|
-
async
|
|
25040
|
-
|
|
25041
|
-
|
|
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;
|
|
25042
25421
|
}
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
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
|
+
};
|
|
25058
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;
|
|
25059
25455
|
}
|
|
25456
|
+
const pollInterval = task.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
25457
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
25458
|
+
options?.signal?.throwIfAborted();
|
|
25060
25459
|
}
|
|
25460
|
+
} catch (error) {
|
|
25461
|
+
yield {
|
|
25462
|
+
type: "error",
|
|
25463
|
+
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
25464
|
+
};
|
|
25061
25465
|
}
|
|
25062
25466
|
}
|
|
25063
|
-
|
|
25064
|
-
|
|
25065
|
-
try {
|
|
25066
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
25067
|
-
if (task?.pollInterval) {
|
|
25068
|
-
interval = task.pollInterval;
|
|
25069
|
-
}
|
|
25070
|
-
} catch {}
|
|
25467
|
+
request(request, resultSchema, options) {
|
|
25468
|
+
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
25071
25469
|
return new Promise((resolve, reject) => {
|
|
25072
|
-
|
|
25073
|
-
reject(
|
|
25470
|
+
const earlyReject = (error) => {
|
|
25471
|
+
reject(error);
|
|
25472
|
+
};
|
|
25473
|
+
if (!this._transport) {
|
|
25474
|
+
earlyReject(new Error("Not connected"));
|
|
25074
25475
|
return;
|
|
25075
25476
|
}
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
});
|
|
25082
|
-
}
|
|
25083
|
-
requestTaskStore(request, sessionId) {
|
|
25084
|
-
const taskStore = this._taskStore;
|
|
25085
|
-
if (!taskStore) {
|
|
25086
|
-
throw new Error("No task store configured");
|
|
25087
|
-
}
|
|
25088
|
-
return {
|
|
25089
|
-
createTask: async (taskParams) => {
|
|
25090
|
-
if (!request) {
|
|
25091
|
-
throw new Error("No request provided");
|
|
25092
|
-
}
|
|
25093
|
-
return await taskStore.createTask(taskParams, request.id, {
|
|
25094
|
-
method: request.method,
|
|
25095
|
-
params: request.params
|
|
25096
|
-
}, sessionId);
|
|
25097
|
-
},
|
|
25098
|
-
getTask: async (taskId) => {
|
|
25099
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25100
|
-
if (!task) {
|
|
25101
|
-
throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
25102
|
-
}
|
|
25103
|
-
return task;
|
|
25104
|
-
},
|
|
25105
|
-
storeTaskResult: async (taskId, status, result) => {
|
|
25106
|
-
await taskStore.storeTaskResult(taskId, status, result, sessionId);
|
|
25107
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25108
|
-
if (task) {
|
|
25109
|
-
const notification = TaskStatusNotificationSchema.parse({
|
|
25110
|
-
method: "notifications/tasks/status",
|
|
25111
|
-
params: task
|
|
25112
|
-
});
|
|
25113
|
-
await this.notification(notification);
|
|
25114
|
-
if (isTerminal(task.status)) {
|
|
25115
|
-
this._cleanupTaskProgressHandler(taskId);
|
|
25116
|
-
}
|
|
25117
|
-
}
|
|
25118
|
-
},
|
|
25119
|
-
getTaskResult: (taskId) => {
|
|
25120
|
-
return taskStore.getTaskResult(taskId, sessionId);
|
|
25121
|
-
},
|
|
25122
|
-
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
25123
|
-
const task = await taskStore.getTask(taskId, sessionId);
|
|
25124
|
-
if (!task) {
|
|
25125
|
-
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
25126
|
-
}
|
|
25127
|
-
if (isTerminal(task.status)) {
|
|
25128
|
-
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.`);
|
|
25129
|
-
}
|
|
25130
|
-
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
|
|
25131
|
-
const updatedTask = await taskStore.getTask(taskId, sessionId);
|
|
25132
|
-
if (updatedTask) {
|
|
25133
|
-
const notification = TaskStatusNotificationSchema.parse({
|
|
25134
|
-
method: "notifications/tasks/status",
|
|
25135
|
-
params: updatedTask
|
|
25136
|
-
});
|
|
25137
|
-
await this.notification(notification);
|
|
25138
|
-
if (isTerminal(updatedTask.status)) {
|
|
25139
|
-
this._cleanupTaskProgressHandler(taskId);
|
|
25477
|
+
if (this._options?.enforceStrictCapabilities === true) {
|
|
25478
|
+
try {
|
|
25479
|
+
this.assertCapabilityForMethod(request.method);
|
|
25480
|
+
if (task) {
|
|
25481
|
+
this.assertTaskCapability(request.method);
|
|
25140
25482
|
}
|
|
25483
|
+
} catch (e) {
|
|
25484
|
+
earlyReject(e);
|
|
25485
|
+
return;
|
|
25141
25486
|
}
|
|
25142
|
-
},
|
|
25143
|
-
listTasks: (cursor) => {
|
|
25144
|
-
return taskStore.listTasks(cursor, sessionId);
|
|
25145
25487
|
}
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
result[k] = { ...baseValue, ...addValue };
|
|
25162
|
-
} else {
|
|
25163
|
-
result[k] = addValue;
|
|
25164
|
-
}
|
|
25165
|
-
}
|
|
25166
|
-
return result;
|
|
25167
|
-
}
|
|
25168
|
-
|
|
25169
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
25170
|
-
var import_ajv = __toESM(require_ajv(), 1);
|
|
25171
|
-
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
25172
|
-
function createDefaultAjvInstance() {
|
|
25173
|
-
const ajv = new import_ajv.default({
|
|
25174
|
-
strict: false,
|
|
25175
|
-
validateFormats: true,
|
|
25176
|
-
validateSchema: false,
|
|
25177
|
-
allErrors: true
|
|
25178
|
-
});
|
|
25179
|
-
const addFormats = import_ajv_formats.default;
|
|
25180
|
-
addFormats(ajv);
|
|
25181
|
-
return ajv;
|
|
25182
|
-
}
|
|
25183
|
-
|
|
25184
|
-
class AjvJsonSchemaValidator {
|
|
25185
|
-
constructor(ajv) {
|
|
25186
|
-
this._ajv = ajv ?? createDefaultAjvInstance();
|
|
25187
|
-
}
|
|
25188
|
-
getValidator(schema) {
|
|
25189
|
-
const ajvValidator = "$id" in schema && typeof schema.$id === "string" ? this._ajv.getSchema(schema.$id) ?? this._ajv.compile(schema) : this._ajv.compile(schema);
|
|
25190
|
-
return (input) => {
|
|
25191
|
-
const valid = ajvValidator(input);
|
|
25192
|
-
if (valid) {
|
|
25193
|
-
return {
|
|
25194
|
-
valid: true,
|
|
25195
|
-
data: input,
|
|
25196
|
-
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
|
+
}
|
|
25197
25503
|
};
|
|
25198
|
-
}
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25504
|
+
}
|
|
25505
|
+
if (task) {
|
|
25506
|
+
jsonrpcRequest.params = {
|
|
25507
|
+
...jsonrpcRequest.params,
|
|
25508
|
+
task
|
|
25203
25509
|
};
|
|
25204
25510
|
}
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
|
|
25212
|
-
|
|
25213
|
-
}
|
|
25214
|
-
requestStream(request, resultSchema, options) {
|
|
25215
|
-
return this._server.requestStream(request, resultSchema, options);
|
|
25216
|
-
}
|
|
25217
|
-
createMessageStream(params, options) {
|
|
25218
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
25219
|
-
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
25220
|
-
throw new Error("Client does not support sampling tools capability.");
|
|
25221
|
-
}
|
|
25222
|
-
if (params.messages.length > 0) {
|
|
25223
|
-
const lastMessage = params.messages[params.messages.length - 1];
|
|
25224
|
-
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
25225
|
-
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
25226
|
-
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
|
|
25227
|
-
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
25228
|
-
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
25229
|
-
if (hasToolResults) {
|
|
25230
|
-
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
25231
|
-
throw new Error("The last message must contain only tool_result content if any is present");
|
|
25232
|
-
}
|
|
25233
|
-
if (!hasPreviousToolUse) {
|
|
25234
|
-
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
25235
|
-
}
|
|
25511
|
+
if (relatedTask) {
|
|
25512
|
+
jsonrpcRequest.params = {
|
|
25513
|
+
...jsonrpcRequest.params,
|
|
25514
|
+
_meta: {
|
|
25515
|
+
...jsonrpcRequest.params?._meta || {},
|
|
25516
|
+
[RELATED_TASK_META_KEY]: relatedTask
|
|
25517
|
+
}
|
|
25518
|
+
};
|
|
25236
25519
|
}
|
|
25237
|
-
|
|
25238
|
-
|
|
25239
|
-
|
|
25240
|
-
|
|
25241
|
-
|
|
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;
|
|
25242
25538
|
}
|
|
25243
|
-
|
|
25244
|
-
|
|
25245
|
-
return this.requestStream({
|
|
25246
|
-
method: "sampling/createMessage",
|
|
25247
|
-
params
|
|
25248
|
-
}, CreateMessageResultSchema, options);
|
|
25249
|
-
}
|
|
25250
|
-
elicitInputStream(params, options) {
|
|
25251
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
25252
|
-
const mode = params.mode ?? "form";
|
|
25253
|
-
switch (mode) {
|
|
25254
|
-
case "url": {
|
|
25255
|
-
if (!clientCapabilities?.elicitation?.url) {
|
|
25256
|
-
throw new Error("Client does not support url elicitation.");
|
|
25539
|
+
if (response instanceof Error) {
|
|
25540
|
+
return reject(response);
|
|
25257
25541
|
}
|
|
25258
|
-
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25262
|
-
|
|
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);
|
|
25263
25551
|
}
|
|
25264
|
-
|
|
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
|
+
});
|
|
25265
25583
|
}
|
|
25266
|
-
}
|
|
25267
|
-
const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
|
|
25268
|
-
return this.requestStream({
|
|
25269
|
-
method: "elicitation/create",
|
|
25270
|
-
params: normalizedParams
|
|
25271
|
-
}, ElicitResultSchema, options);
|
|
25272
|
-
}
|
|
25273
|
-
async getTask(taskId, options) {
|
|
25274
|
-
return this._server.getTask({ taskId }, options);
|
|
25275
|
-
}
|
|
25276
|
-
async getTaskResult(taskId, resultSchema, options) {
|
|
25277
|
-
return this._server.getTaskResult({ taskId }, resultSchema, options);
|
|
25278
|
-
}
|
|
25279
|
-
async listTasks(cursor, options) {
|
|
25280
|
-
return this._server.listTasks(cursor ? { cursor } : undefined, options);
|
|
25281
|
-
}
|
|
25282
|
-
async cancelTask(taskId, options) {
|
|
25283
|
-
return this._server.cancelTask({ taskId }, options);
|
|
25584
|
+
});
|
|
25284
25585
|
}
|
|
25285
|
-
|
|
25286
|
-
|
|
25287
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
25288
|
-
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
25289
|
-
if (!requests) {
|
|
25290
|
-
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);
|
|
25291
25588
|
}
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
if (!requests.tools?.call) {
|
|
25295
|
-
throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
|
|
25296
|
-
}
|
|
25297
|
-
break;
|
|
25298
|
-
default:
|
|
25299
|
-
break;
|
|
25589
|
+
async getTaskResult(params, resultSchema, options) {
|
|
25590
|
+
return this.request({ method: "tasks/result", params }, resultSchema, options);
|
|
25300
25591
|
}
|
|
25301
|
-
|
|
25302
|
-
|
|
25303
|
-
if (!requests) {
|
|
25304
|
-
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);
|
|
25305
25594
|
}
|
|
25306
|
-
|
|
25307
|
-
|
|
25308
|
-
if (!requests.sampling?.createMessage) {
|
|
25309
|
-
throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
|
|
25310
|
-
}
|
|
25311
|
-
break;
|
|
25312
|
-
case "elicitation/create":
|
|
25313
|
-
if (!requests.elicitation?.create) {
|
|
25314
|
-
throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
|
|
25315
|
-
}
|
|
25316
|
-
break;
|
|
25317
|
-
default:
|
|
25318
|
-
break;
|
|
25595
|
+
async cancelTask(params, options) {
|
|
25596
|
+
return this.request({ method: "tasks/cancel", params }, CancelTaskResultSchema, options);
|
|
25319
25597
|
}
|
|
25320
|
-
|
|
25321
|
-
|
|
25322
|
-
|
|
25323
|
-
class Server extends Protocol {
|
|
25324
|
-
constructor(_serverInfo, options) {
|
|
25325
|
-
super(options);
|
|
25326
|
-
this._serverInfo = _serverInfo;
|
|
25327
|
-
this._loggingLevels = new Map;
|
|
25328
|
-
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
25329
|
-
this.isMessageIgnored = (level, sessionId) => {
|
|
25330
|
-
const currentLevel = this._loggingLevels.get(sessionId);
|
|
25331
|
-
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
25332
|
-
};
|
|
25333
|
-
this._capabilities = options?.capabilities ?? {};
|
|
25334
|
-
this._instructions = options?.instructions;
|
|
25335
|
-
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator;
|
|
25336
|
-
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
|
25337
|
-
this.setNotificationHandler(InitializedNotificationSchema, () => this.oninitialized?.());
|
|
25338
|
-
if (this._capabilities.logging) {
|
|
25339
|
-
this.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {
|
|
25340
|
-
const transportSessionId = extra.sessionId || extra.requestInfo?.headers["mcp-session-id"] || undefined;
|
|
25341
|
-
const { level } = request.params;
|
|
25342
|
-
const parseResult = LoggingLevelSchema.safeParse(level);
|
|
25343
|
-
if (parseResult.success) {
|
|
25344
|
-
this._loggingLevels.set(transportSessionId, parseResult.data);
|
|
25345
|
-
}
|
|
25346
|
-
return {};
|
|
25347
|
-
});
|
|
25598
|
+
async notification(notification, options) {
|
|
25599
|
+
if (!this._transport) {
|
|
25600
|
+
throw new Error("Not connected");
|
|
25348
25601
|
}
|
|
25349
|
-
|
|
25350
|
-
|
|
25351
|
-
if (
|
|
25352
|
-
|
|
25353
|
-
|
|
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
|
+
}
|
|
25354
25615
|
};
|
|
25616
|
+
await this._enqueueTaskMessage(relatedTaskId, {
|
|
25617
|
+
type: "notification",
|
|
25618
|
+
message: jsonrpcNotification,
|
|
25619
|
+
timestamp: Date.now()
|
|
25620
|
+
});
|
|
25621
|
+
return;
|
|
25355
25622
|
}
|
|
25356
|
-
|
|
25357
|
-
|
|
25358
|
-
|
|
25359
|
-
|
|
25360
|
-
|
|
25361
|
-
|
|
25362
|
-
|
|
25363
|
-
|
|
25364
|
-
|
|
25365
|
-
|
|
25366
|
-
|
|
25367
|
-
if (!methodSchema) {
|
|
25368
|
-
throw new Error("Schema is missing a method literal");
|
|
25369
|
-
}
|
|
25370
|
-
const methodValue = getLiteralValue(methodSchema);
|
|
25371
|
-
if (typeof methodValue !== "string") {
|
|
25372
|
-
throw new Error("Schema method literal must be a string");
|
|
25373
|
-
}
|
|
25374
|
-
const method = methodValue;
|
|
25375
|
-
if (method === "tools/call") {
|
|
25376
|
-
const wrappedHandler = async (request, extra) => {
|
|
25377
|
-
const validatedRequest = safeParse4(CallToolRequestSchema, request);
|
|
25378
|
-
if (!validatedRequest.success) {
|
|
25379
|
-
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
25380
|
-
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;
|
|
25381
25634
|
}
|
|
25382
|
-
|
|
25383
|
-
|
|
25384
|
-
|
|
25385
|
-
|
|
25386
|
-
|
|
25387
|
-
|
|
25388
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
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
|
+
};
|
|
25391
25650
|
}
|
|
25392
|
-
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
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
|
+
}
|
|
25396
25668
|
}
|
|
25397
|
-
return validationResult.data;
|
|
25398
25669
|
};
|
|
25399
|
-
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
25400
25670
|
}
|
|
25401
|
-
|
|
25671
|
+
await this._transport.send(jsonrpcNotification, options);
|
|
25402
25672
|
}
|
|
25403
|
-
|
|
25404
|
-
|
|
25405
|
-
|
|
25406
|
-
|
|
25407
|
-
|
|
25408
|
-
|
|
25409
|
-
|
|
25410
|
-
|
|
25411
|
-
|
|
25412
|
-
|
|
25413
|
-
|
|
25414
|
-
|
|
25415
|
-
|
|
25416
|
-
|
|
25417
|
-
throw new Error(`Client does not support listing roots (required for ${method})`);
|
|
25418
|
-
}
|
|
25419
|
-
break;
|
|
25420
|
-
case "ping":
|
|
25421
|
-
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`);
|
|
25422
25687
|
}
|
|
25423
25688
|
}
|
|
25424
|
-
|
|
25425
|
-
|
|
25426
|
-
|
|
25427
|
-
|
|
25428
|
-
|
|
25429
|
-
|
|
25430
|
-
|
|
25431
|
-
|
|
25432
|
-
|
|
25433
|
-
|
|
25434
|
-
|
|
25435
|
-
|
|
25436
|
-
|
|
25437
|
-
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25445
|
-
|
|
25446
|
-
|
|
25447
|
-
|
|
25448
|
-
|
|
25449
|
-
|
|
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
|
+
}
|
|
25450
25726
|
}
|
|
25451
|
-
|
|
25452
|
-
case "notifications/cancelled":
|
|
25453
|
-
break;
|
|
25454
|
-
case "notifications/progress":
|
|
25455
|
-
break;
|
|
25727
|
+
}
|
|
25456
25728
|
}
|
|
25457
25729
|
}
|
|
25458
|
-
|
|
25459
|
-
|
|
25460
|
-
|
|
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");
|
|
25461
25754
|
}
|
|
25462
|
-
|
|
25463
|
-
|
|
25464
|
-
if (!
|
|
25465
|
-
throw new Error(
|
|
25755
|
+
return {
|
|
25756
|
+
createTask: async (taskParams) => {
|
|
25757
|
+
if (!request) {
|
|
25758
|
+
throw new Error("No request provided");
|
|
25466
25759
|
}
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
|
|
25470
|
-
|
|
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");
|
|
25471
25769
|
}
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
|
|
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
|
+
}
|
|
25477
25784
|
}
|
|
25478
|
-
|
|
25479
|
-
|
|
25480
|
-
|
|
25481
|
-
|
|
25482
|
-
|
|
25483
|
-
|
|
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`);
|
|
25484
25793
|
}
|
|
25485
|
-
|
|
25486
|
-
|
|
25487
|
-
case "tools/list":
|
|
25488
|
-
if (!this._capabilities.tools) {
|
|
25489
|
-
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.`);
|
|
25490
25796
|
}
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
|
|
25494
|
-
|
|
25495
|
-
|
|
25496
|
-
|
|
25497
|
-
|
|
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
|
+
}
|
|
25498
25808
|
}
|
|
25499
|
-
|
|
25500
|
-
|
|
25501
|
-
|
|
25502
|
-
|
|
25503
|
-
}
|
|
25504
|
-
}
|
|
25505
|
-
assertTaskCapability(method) {
|
|
25506
|
-
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
25507
|
-
}
|
|
25508
|
-
assertTaskHandlerCapability(method) {
|
|
25509
|
-
if (!this._capabilities) {
|
|
25510
|
-
return;
|
|
25511
|
-
}
|
|
25512
|
-
assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
|
|
25513
|
-
}
|
|
25514
|
-
async _oninitialize(request) {
|
|
25515
|
-
const requestedVersion = request.params.protocolVersion;
|
|
25516
|
-
this._clientCapabilities = request.params.capabilities;
|
|
25517
|
-
this._clientVersion = request.params.clientInfo;
|
|
25518
|
-
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : LATEST_PROTOCOL_VERSION;
|
|
25519
|
-
return {
|
|
25520
|
-
protocolVersion,
|
|
25521
|
-
capabilities: this.getCapabilities(),
|
|
25522
|
-
serverInfo: this._serverInfo,
|
|
25523
|
-
...this._instructions && { instructions: this._instructions }
|
|
25809
|
+
},
|
|
25810
|
+
listTasks: (cursor) => {
|
|
25811
|
+
return taskStore.listTasks(cursor, sessionId);
|
|
25812
|
+
}
|
|
25524
25813
|
};
|
|
25525
25814
|
}
|
|
25526
|
-
|
|
25527
|
-
|
|
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();
|
|
25528
25854
|
}
|
|
25529
|
-
|
|
25530
|
-
|
|
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
|
+
};
|
|
25531
25873
|
}
|
|
25532
|
-
|
|
25533
|
-
|
|
25874
|
+
}
|
|
25875
|
+
|
|
25876
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
25877
|
+
class ExperimentalServerTasks {
|
|
25878
|
+
constructor(_server) {
|
|
25879
|
+
this._server = _server;
|
|
25534
25880
|
}
|
|
25535
|
-
|
|
25536
|
-
return this.request
|
|
25881
|
+
requestStream(request, resultSchema, options) {
|
|
25882
|
+
return this._server.requestStream(request, resultSchema, options);
|
|
25537
25883
|
}
|
|
25538
|
-
|
|
25539
|
-
|
|
25540
|
-
|
|
25541
|
-
|
|
25542
|
-
}
|
|
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.");
|
|
25543
25888
|
}
|
|
25544
25889
|
if (params.messages.length > 0) {
|
|
25545
25890
|
const lastMessage = params.messages[params.messages.length - 1];
|
|
@@ -25564,807 +25909,572 @@ class Server extends Protocol {
|
|
|
25564
25909
|
}
|
|
25565
25910
|
}
|
|
25566
25911
|
}
|
|
25567
|
-
|
|
25568
|
-
|
|
25569
|
-
|
|
25570
|
-
|
|
25912
|
+
return this.requestStream({
|
|
25913
|
+
method: "sampling/createMessage",
|
|
25914
|
+
params
|
|
25915
|
+
}, CreateMessageResultSchema, options);
|
|
25571
25916
|
}
|
|
25572
|
-
|
|
25917
|
+
elicitInputStream(params, options) {
|
|
25918
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
25573
25919
|
const mode = params.mode ?? "form";
|
|
25574
25920
|
switch (mode) {
|
|
25575
25921
|
case "url": {
|
|
25576
|
-
if (!
|
|
25922
|
+
if (!clientCapabilities?.elicitation?.url) {
|
|
25577
25923
|
throw new Error("Client does not support url elicitation.");
|
|
25578
25924
|
}
|
|
25579
|
-
|
|
25580
|
-
return this.request({ method: "elicitation/create", params: urlParams }, ElicitResultSchema, options);
|
|
25925
|
+
break;
|
|
25581
25926
|
}
|
|
25582
25927
|
case "form": {
|
|
25583
|
-
if (!
|
|
25928
|
+
if (!clientCapabilities?.elicitation?.form) {
|
|
25584
25929
|
throw new Error("Client does not support form elicitation.");
|
|
25585
25930
|
}
|
|
25586
|
-
|
|
25587
|
-
const result = await this.request({ method: "elicitation/create", params: formParams }, ElicitResultSchema, options);
|
|
25588
|
-
if (result.action === "accept" && result.content && formParams.requestedSchema) {
|
|
25589
|
-
try {
|
|
25590
|
-
const validator = this._jsonSchemaValidator.getValidator(formParams.requestedSchema);
|
|
25591
|
-
const validationResult = validator(result.content);
|
|
25592
|
-
if (!validationResult.valid) {
|
|
25593
|
-
throw new McpError(ErrorCode.InvalidParams, `Elicitation response content does not match requested schema: ${validationResult.errorMessage}`);
|
|
25594
|
-
}
|
|
25595
|
-
} catch (error) {
|
|
25596
|
-
if (error instanceof McpError) {
|
|
25597
|
-
throw error;
|
|
25598
|
-
}
|
|
25599
|
-
throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error instanceof Error ? error.message : String(error)}`);
|
|
25600
|
-
}
|
|
25601
|
-
}
|
|
25602
|
-
return result;
|
|
25603
|
-
}
|
|
25604
|
-
}
|
|
25605
|
-
}
|
|
25606
|
-
createElicitationCompletionNotifier(elicitationId, options) {
|
|
25607
|
-
if (!this._clientCapabilities?.elicitation?.url) {
|
|
25608
|
-
throw new Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");
|
|
25609
|
-
}
|
|
25610
|
-
return () => this.notification({
|
|
25611
|
-
method: "notifications/elicitation/complete",
|
|
25612
|
-
params: {
|
|
25613
|
-
elicitationId
|
|
25614
|
-
}
|
|
25615
|
-
}, options);
|
|
25616
|
-
}
|
|
25617
|
-
async listRoots(params, options) {
|
|
25618
|
-
return this.request({ method: "roots/list", params }, ListRootsResultSchema, options);
|
|
25619
|
-
}
|
|
25620
|
-
async sendLoggingMessage(params, sessionId) {
|
|
25621
|
-
if (this._capabilities.logging) {
|
|
25622
|
-
if (!this.isMessageIgnored(params.level, sessionId)) {
|
|
25623
|
-
return this.notification({ method: "notifications/message", params });
|
|
25931
|
+
break;
|
|
25624
25932
|
}
|
|
25625
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);
|
|
25626
25939
|
}
|
|
25627
|
-
async
|
|
25628
|
-
return this.
|
|
25629
|
-
method: "notifications/resources/updated",
|
|
25630
|
-
params
|
|
25631
|
-
});
|
|
25632
|
-
}
|
|
25633
|
-
async sendResourceListChanged() {
|
|
25634
|
-
return this.notification({
|
|
25635
|
-
method: "notifications/resources/list_changed"
|
|
25636
|
-
});
|
|
25637
|
-
}
|
|
25638
|
-
async sendToolListChanged() {
|
|
25639
|
-
return this.notification({ method: "notifications/tools/list_changed" });
|
|
25640
|
-
}
|
|
25641
|
-
async sendPromptListChanged() {
|
|
25642
|
-
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
25643
|
-
}
|
|
25644
|
-
}
|
|
25645
|
-
|
|
25646
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
25647
|
-
import process3 from "node:process";
|
|
25648
|
-
|
|
25649
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
25650
|
-
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
25651
|
-
|
|
25652
|
-
class ReadBuffer {
|
|
25653
|
-
constructor(options) {
|
|
25654
|
-
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
25940
|
+
async getTask(taskId, options) {
|
|
25941
|
+
return this._server.getTask({ taskId }, options);
|
|
25655
25942
|
}
|
|
25656
|
-
|
|
25657
|
-
|
|
25658
|
-
if (newSize > this._maxBufferSize) {
|
|
25659
|
-
this.clear();
|
|
25660
|
-
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
25661
|
-
}
|
|
25662
|
-
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
25943
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
25944
|
+
return this._server.getTaskResult({ taskId }, resultSchema, options);
|
|
25663
25945
|
}
|
|
25664
|
-
|
|
25665
|
-
|
|
25666
|
-
return null;
|
|
25667
|
-
}
|
|
25668
|
-
const index = this._buffer.indexOf(`
|
|
25669
|
-
`);
|
|
25670
|
-
if (index === -1) {
|
|
25671
|
-
return null;
|
|
25672
|
-
}
|
|
25673
|
-
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
25674
|
-
this._buffer = this._buffer.subarray(index + 1);
|
|
25675
|
-
return deserializeMessage(line);
|
|
25946
|
+
async listTasks(cursor, options) {
|
|
25947
|
+
return this._server.listTasks(cursor ? { cursor } : undefined, options);
|
|
25676
25948
|
}
|
|
25677
|
-
|
|
25678
|
-
this.
|
|
25949
|
+
async cancelTask(taskId, options) {
|
|
25950
|
+
return this._server.cancelTask({ taskId }, options);
|
|
25679
25951
|
}
|
|
25680
25952
|
}
|
|
25681
|
-
function deserializeMessage(line) {
|
|
25682
|
-
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
25683
|
-
}
|
|
25684
|
-
function serializeMessage(message) {
|
|
25685
|
-
return JSON.stringify(message) + `
|
|
25686
|
-
`;
|
|
25687
|
-
}
|
|
25688
25953
|
|
|
25689
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
this._stdout = _stdout;
|
|
25694
|
-
this._started = false;
|
|
25695
|
-
this._ondata = (chunk) => {
|
|
25696
|
-
try {
|
|
25697
|
-
this._readBuffer.append(chunk);
|
|
25698
|
-
this.processReadBuffer();
|
|
25699
|
-
} catch (error) {
|
|
25700
|
-
this.onerror?.(error);
|
|
25701
|
-
this.close().catch(() => {});
|
|
25702
|
-
}
|
|
25703
|
-
};
|
|
25704
|
-
this._onerror = (error) => {
|
|
25705
|
-
this.onerror?.(error);
|
|
25706
|
-
};
|
|
25707
|
-
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
25708
|
-
}
|
|
25709
|
-
async start() {
|
|
25710
|
-
if (this._started) {
|
|
25711
|
-
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
25712
|
-
}
|
|
25713
|
-
this._started = true;
|
|
25714
|
-
this._stdin.on("data", this._ondata);
|
|
25715
|
-
this._stdin.on("error", this._onerror);
|
|
25716
|
-
}
|
|
25717
|
-
processReadBuffer() {
|
|
25718
|
-
while (true) {
|
|
25719
|
-
try {
|
|
25720
|
-
const message = this._readBuffer.readMessage();
|
|
25721
|
-
if (message === null) {
|
|
25722
|
-
break;
|
|
25723
|
-
}
|
|
25724
|
-
this.onmessage?.(message);
|
|
25725
|
-
} catch (error) {
|
|
25726
|
-
this.onerror?.(error);
|
|
25727
|
-
}
|
|
25728
|
-
}
|
|
25729
|
-
}
|
|
25730
|
-
async close() {
|
|
25731
|
-
this._stdin.off("data", this._ondata);
|
|
25732
|
-
this._stdin.off("error", this._onerror);
|
|
25733
|
-
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
25734
|
-
if (remainingDataListeners === 0) {
|
|
25735
|
-
this._stdin.pause();
|
|
25736
|
-
}
|
|
25737
|
-
this._readBuffer.clear();
|
|
25738
|
-
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})`);
|
|
25739
25958
|
}
|
|
25740
|
-
|
|
25741
|
-
|
|
25742
|
-
|
|
25743
|
-
|
|
25744
|
-
resolve();
|
|
25745
|
-
} else {
|
|
25746
|
-
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})`);
|
|
25747
25963
|
}
|
|
25748
|
-
|
|
25964
|
+
break;
|
|
25965
|
+
default:
|
|
25966
|
+
break;
|
|
25749
25967
|
}
|
|
25750
25968
|
}
|
|
25751
|
-
|
|
25752
|
-
|
|
25753
|
-
|
|
25754
|
-
|
|
25755
|
-
// packages/workit-core/src/core/boundary.ts
|
|
25756
|
-
import { statSync } from "node:fs";
|
|
25757
|
-
var EVENT = {
|
|
25758
|
-
initialization: "initialization",
|
|
25759
|
-
provenance: "provenance",
|
|
25760
|
-
assets: "assets",
|
|
25761
|
-
configurationSource: "configuration_source",
|
|
25762
|
-
hooks: "hooks",
|
|
25763
|
-
mcpConnection: "mcp_connection",
|
|
25764
|
-
migration: "migration",
|
|
25765
|
-
installSteps: "install_steps",
|
|
25766
|
-
uncaughtFailure: "uncaught_failure",
|
|
25767
|
-
toolsFailed: "tools_failed",
|
|
25768
|
-
doctor: "doctor"
|
|
25769
|
-
};
|
|
25770
|
-
var errorDetail = (err) => {
|
|
25771
|
-
if (err instanceof Error) {
|
|
25772
|
-
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})`);
|
|
25773
25972
|
}
|
|
25774
|
-
|
|
25775
|
-
|
|
25776
|
-
|
|
25777
|
-
|
|
25778
|
-
|
|
25779
|
-
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
|
|
25786
|
-
|
|
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;
|
|
25787
25986
|
}
|
|
25788
|
-
|
|
25789
|
-
};
|
|
25790
|
-
|
|
25791
|
-
// packages/workit-core/src/core/logger.ts
|
|
25792
|
-
import os from "node:os";
|
|
25793
|
-
var REDACTED = "[REDACTED]";
|
|
25794
|
-
var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
|
|
25795
|
-
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;
|
|
25796
|
-
var URL_QUERY = /(https?:\/\/[^?#\s]+)\?[^#\s]*/g;
|
|
25797
|
-
var SENSITIVE_WORDS = new Set([
|
|
25798
|
-
"token",
|
|
25799
|
-
"secret",
|
|
25800
|
-
"password",
|
|
25801
|
-
"passwd",
|
|
25802
|
-
"authorization",
|
|
25803
|
-
"credential",
|
|
25804
|
-
"credentials",
|
|
25805
|
-
"cookie",
|
|
25806
|
-
"api",
|
|
25807
|
-
"apikey",
|
|
25808
|
-
"apitoken",
|
|
25809
|
-
"accesstoken",
|
|
25810
|
-
"clientsecret",
|
|
25811
|
-
"refreshtoken",
|
|
25812
|
-
"key",
|
|
25813
|
-
"bearer",
|
|
25814
|
-
"prompt",
|
|
25815
|
-
"message",
|
|
25816
|
-
"messages",
|
|
25817
|
-
"content",
|
|
25818
|
-
"body",
|
|
25819
|
-
"args",
|
|
25820
|
-
"argument",
|
|
25821
|
-
"result",
|
|
25822
|
-
"results",
|
|
25823
|
-
"output",
|
|
25824
|
-
"issue",
|
|
25825
|
-
"description",
|
|
25826
|
-
"summary",
|
|
25827
|
-
"payload",
|
|
25828
|
-
"script",
|
|
25829
|
-
"command",
|
|
25830
|
-
"text",
|
|
25831
|
-
"query"
|
|
25832
|
-
]);
|
|
25833
|
-
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
25834
|
-
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25835
|
-
var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
25836
|
-
var applyPatterns = (value) => {
|
|
25837
|
-
let out = value;
|
|
25838
|
-
out = out.replace(SECRET_VALUE, REDACTED);
|
|
25839
|
-
out = out.replace(KEY_EQ_VALUE, "$1$2[REDACTED]");
|
|
25840
|
-
out = out.replace(URL_QUERY, "$1?[REDACTED]");
|
|
25841
|
-
out = out.replace(homePattern, "~");
|
|
25842
|
-
if (process.platform === "win32")
|
|
25843
|
-
out = out.replace(/\\/g, "/");
|
|
25844
|
-
return out;
|
|
25845
|
-
};
|
|
25846
|
-
var redactSecrets = (value) => applyPatterns(value);
|
|
25987
|
+
}
|
|
25847
25988
|
|
|
25848
|
-
//
|
|
25849
|
-
|
|
25850
|
-
|
|
25851
|
-
|
|
25852
|
-
|
|
25853
|
-
|
|
25854
|
-
|
|
25855
|
-
|
|
25856
|
-
|
|
25857
|
-
|
|
25858
|
-
} catch (error) {
|
|
25859
|
-
const e = error;
|
|
25860
|
-
return {
|
|
25861
|
-
stdout: (e.stdout ?? "").trimEnd(),
|
|
25862
|
-
stderr: (e.stderr ?? "").trimEnd(),
|
|
25863
|
-
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;
|
|
25864
25999
|
};
|
|
25865
|
-
|
|
25866
|
-
|
|
25867
|
-
|
|
25868
|
-
|
|
25869
|
-
|
|
25870
|
-
|
|
25871
|
-
|
|
25872
|
-
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
const unstaged = [];
|
|
25881
|
-
const untracked = [];
|
|
25882
|
-
for (const line of status_short.split(`
|
|
25883
|
-
`).filter(Boolean)) {
|
|
25884
|
-
const code = line.slice(0, 2);
|
|
25885
|
-
const file = line.slice(3);
|
|
25886
|
-
if (code === "??") {
|
|
25887
|
-
untracked.push(file);
|
|
25888
|
-
} else {
|
|
25889
|
-
if (code[0] !== " " && code[0] !== "?")
|
|
25890
|
-
staged.push(file);
|
|
25891
|
-
if (code[1] !== " " && code[1] !== "?")
|
|
25892
|
-
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
|
+
});
|
|
25893
26015
|
}
|
|
25894
26016
|
}
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
|
|
25900
|
-
|
|
25901
|
-
|
|
25902
|
-
workspace_root: cwd,
|
|
25903
|
-
branch,
|
|
25904
|
-
status_short,
|
|
25905
|
-
staged,
|
|
25906
|
-
unstaged,
|
|
25907
|
-
untracked,
|
|
25908
|
-
diff_stat: [diff_stat, cached_stat].filter(Boolean).join(`
|
|
25909
|
-
`),
|
|
25910
|
-
partial_staged: partial_staged.length > 0,
|
|
25911
|
-
partial_staged_files: partial_staged,
|
|
25912
|
-
...failure ? { stderr: failure.stderr, exitCode: failure.exitCode } : {}
|
|
25913
|
-
};
|
|
25914
|
-
};
|
|
25915
|
-
|
|
25916
|
-
// packages/workit-core/src/core/config.ts
|
|
25917
|
-
import {
|
|
25918
|
-
copyFileSync,
|
|
25919
|
-
cpSync,
|
|
25920
|
-
existsSync as existsSync5,
|
|
25921
|
-
mkdirSync as mkdirSync2,
|
|
25922
|
-
readFileSync as readFileSync4,
|
|
25923
|
-
readdirSync as readdirSync3,
|
|
25924
|
-
writeFileSync as writeFileSync2
|
|
25925
|
-
} from "node:fs";
|
|
25926
|
-
import os2 from "node:os";
|
|
25927
|
-
import path8 from "node:path";
|
|
25928
|
-
var diagnosticLogger;
|
|
25929
|
-
var PRESETS = {
|
|
25930
|
-
gitflow: {
|
|
25931
|
-
allowed: ["feature/*", "bugfix/*", "hotfix/*", "release/*"],
|
|
25932
|
-
protected: ["main", "develop", "master", "prod", "production"]
|
|
25933
|
-
},
|
|
25934
|
-
"github-flow": { allowed: ["*"], protected: ["main"] },
|
|
25935
|
-
"trunk-based": { allowed: ["*"], protected: ["main"] },
|
|
25936
|
-
custom: { allowed: [], protected: [] }
|
|
25937
|
-
};
|
|
25938
|
-
var mergePreset = (preset, input = {}, current = {
|
|
25939
|
-
branchPolicy: { preset, allowed: [], protected: [] }
|
|
25940
|
-
}) => {
|
|
25941
|
-
const defs = PRESETS[preset];
|
|
25942
|
-
return {
|
|
25943
|
-
preset,
|
|
25944
|
-
allowed: preset === "custom" ? input.allowed ?? current.branchPolicy.allowed : [...defs.allowed],
|
|
25945
|
-
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
25946
|
-
};
|
|
25947
|
-
};
|
|
25948
|
-
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");
|
|
25949
|
-
var migratedDir = null;
|
|
25950
|
-
var migrationFailed = false;
|
|
25951
|
-
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
25952
|
-
if (migratedDir === dir)
|
|
25953
|
-
return dir;
|
|
25954
|
-
if (process.env.WORKFLOW_TOOLKIT_CONFIG || process.env.WORKFLOW_TOOLKIT_CONFIG_DIR) {
|
|
25955
|
-
migratedDir = dir;
|
|
25956
|
-
return dir;
|
|
26017
|
+
get experimental() {
|
|
26018
|
+
if (!this._experimental) {
|
|
26019
|
+
this._experimental = {
|
|
26020
|
+
tasks: new ExperimentalServerTasks(this)
|
|
26021
|
+
};
|
|
26022
|
+
}
|
|
26023
|
+
return this._experimental;
|
|
25957
26024
|
}
|
|
25958
|
-
|
|
25959
|
-
|
|
25960
|
-
|
|
25961
|
-
|
|
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);
|
|
25962
26030
|
}
|
|
25963
|
-
|
|
25964
|
-
|
|
25965
|
-
|
|
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);
|
|
25966
26069
|
}
|
|
25967
|
-
|
|
25968
|
-
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
25976
|
-
|
|
25977
|
-
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
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;
|
|
25984
26089
|
}
|
|
25985
26090
|
}
|
|
25986
|
-
|
|
25987
|
-
|
|
25988
|
-
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
}
|
|
26003
|
-
|
|
26004
|
-
|
|
26005
|
-
|
|
26006
|
-
|
|
26007
|
-
|
|
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
|
+
}
|
|
26008
26124
|
}
|
|
26009
|
-
|
|
26010
|
-
|
|
26011
|
-
|
|
26012
|
-
|
|
26013
|
-
|
|
26014
|
-
|
|
26015
|
-
|
|
26016
|
-
|
|
26017
|
-
|
|
26018
|
-
|
|
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
|
+
}
|
|
26019
26171
|
}
|
|
26020
|
-
|
|
26021
|
-
|
|
26172
|
+
assertTaskCapability(method) {
|
|
26173
|
+
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
26022
26174
|
}
|
|
26023
|
-
|
|
26024
|
-
|
|
26025
|
-
|
|
26026
|
-
|
|
26027
|
-
|
|
26028
|
-
status: "valid",
|
|
26029
|
-
path: file,
|
|
26030
|
-
config: {
|
|
26031
|
-
locale,
|
|
26032
|
-
localeOptions: Array.isArray(input.localeOptions) ? input.localeOptions : DEFAULTS.localeOptions,
|
|
26033
|
-
timezone: input.timezone ?? DEFAULTS.timezone,
|
|
26034
|
-
branchPolicy: mergePreset(preset, {
|
|
26035
|
-
allowed: Array.isArray(input.branchPolicy?.allowed) ? input.branchPolicy.allowed : undefined,
|
|
26036
|
-
protectedNames: Array.isArray(input.branchPolicy?.protected) ? input.branchPolicy.protected : undefined
|
|
26037
|
-
}, DEFAULTS),
|
|
26038
|
-
commitPolicy: {
|
|
26039
|
-
preset: commitPreset,
|
|
26040
|
-
...typeof input.commitPolicy?.pattern === "string" ? { pattern: input.commitPolicy.pattern } : {}
|
|
26041
|
-
}
|
|
26042
|
-
}
|
|
26043
|
-
};
|
|
26044
|
-
};
|
|
26045
|
-
var readConfigTyped = (dir) => {
|
|
26046
|
-
const file = path8.join(dir ?? configDir(), "config.json");
|
|
26047
|
-
return parseConfigResult(readSafe(file), file);
|
|
26048
|
-
};
|
|
26049
|
-
var readConfig = () => {
|
|
26050
|
-
const result = readConfigTyped();
|
|
26051
|
-
if (result.status === "malformed")
|
|
26052
|
-
throw new Error(result.error);
|
|
26053
|
-
return result.config ?? DEFAULTS;
|
|
26054
|
-
};
|
|
26055
|
-
var resolveBranchPolicy = (config, workspace) => {
|
|
26056
|
-
const wp = workspace?.branchPolicy ?? {};
|
|
26057
|
-
const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
|
|
26058
|
-
const merged = mergePreset(preset, {
|
|
26059
|
-
allowed: wp.allowed,
|
|
26060
|
-
protectedNames: wp.protected
|
|
26061
|
-
}, config);
|
|
26062
|
-
const allowed = merged.allowed.map((p) => new RegExp(`^${p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"));
|
|
26063
|
-
return {
|
|
26064
|
-
preset,
|
|
26065
|
-
allowed,
|
|
26066
|
-
protected: new Set(merged.protected.map((p) => p.toLowerCase())),
|
|
26067
|
-
integration: wp.integration === "merge" ? "merge" : "pr",
|
|
26068
|
-
defaultTargetBranch: preset === "github-flow" ? "main" : preset === "trunk-based" ? "master" : "develop"
|
|
26069
|
-
};
|
|
26070
|
-
};
|
|
26071
|
-
var COMMIT_PRESETS = [
|
|
26072
|
-
"conventional",
|
|
26073
|
-
"gitmoji",
|
|
26074
|
-
"ticket-prefix",
|
|
26075
|
-
"freeform",
|
|
26076
|
-
"custom",
|
|
26077
|
-
"auto"
|
|
26078
|
-
];
|
|
26079
|
-
|
|
26080
|
-
// packages/workit-core/src/core/workspaces.ts
|
|
26081
|
-
import { readFileSync as readFileSync5, realpathSync as realpathSync6 } from "node:fs";
|
|
26082
|
-
import path9 from "node:path";
|
|
26083
|
-
var readWorkspacesResult = (dir = configDir()) => {
|
|
26084
|
-
const file = path9.join(dir, "workspaces.json");
|
|
26085
|
-
let raw;
|
|
26086
|
-
try {
|
|
26087
|
-
raw = readFileSync5(file, "utf8");
|
|
26088
|
-
} catch {
|
|
26089
|
-
return { status: "missing", path: file, entries: [] };
|
|
26175
|
+
assertTaskHandlerCapability(method) {
|
|
26176
|
+
if (!this._capabilities) {
|
|
26177
|
+
return;
|
|
26178
|
+
}
|
|
26179
|
+
assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
|
|
26090
26180
|
}
|
|
26091
|
-
|
|
26092
|
-
|
|
26093
|
-
|
|
26094
|
-
|
|
26095
|
-
|
|
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
|
+
};
|
|
26096
26192
|
}
|
|
26097
|
-
|
|
26098
|
-
return
|
|
26193
|
+
getClientCapabilities() {
|
|
26194
|
+
return this._clientCapabilities;
|
|
26099
26195
|
}
|
|
26100
|
-
|
|
26101
|
-
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
}
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
26118
|
-
|
|
26119
|
-
|
|
26120
|
-
|
|
26121
|
-
|
|
26122
|
-
|
|
26123
|
-
|
|
26124
|
-
|
|
26125
|
-
|
|
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}`);
|
|
26126
26261
|
}
|
|
26127
|
-
}
|
|
26128
|
-
|
|
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)}`);
|
|
26129
26267
|
}
|
|
26130
|
-
i++;
|
|
26131
26268
|
}
|
|
26132
|
-
|
|
26133
|
-
out += "[^/]*";
|
|
26269
|
+
return result;
|
|
26134
26270
|
}
|
|
26135
|
-
} else {
|
|
26136
|
-
out += c.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
26137
26271
|
}
|
|
26138
26272
|
}
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
var realpathOf = (p) => {
|
|
26143
|
-
const real = realpathSync6.native ?? realpathSync6;
|
|
26144
|
-
try {
|
|
26145
|
-
return real(p);
|
|
26146
|
-
} catch {
|
|
26147
|
-
return p;
|
|
26148
|
-
}
|
|
26149
|
-
};
|
|
26150
|
-
var canonicalGlob = (glob) => {
|
|
26151
|
-
const m = /[*?[\]{]/.exec(glob);
|
|
26152
|
-
const prefix = m ? glob.slice(0, m.index) : glob;
|
|
26153
|
-
const rest = m ? glob.slice(m.index) : "";
|
|
26154
|
-
if (!prefix)
|
|
26155
|
-
return glob;
|
|
26156
|
-
const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
|
|
26157
|
-
return real + (prefix.endsWith("/") ? "/" : "") + rest;
|
|
26158
|
-
};
|
|
26159
|
-
var resolveWorkspaceFrom = (cwd, dir) => {
|
|
26160
|
-
const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
|
|
26161
|
-
for (const entry of loadWorkspacesFrom(dir)) {
|
|
26162
|
-
if (!entry || typeof entry !== "object")
|
|
26163
|
-
continue;
|
|
26164
|
-
const ws = entry;
|
|
26165
|
-
if (typeof ws.glob !== "string" || !ws.glob)
|
|
26166
|
-
continue;
|
|
26167
|
-
const glob = ws.glob.replaceAll("\\", "/");
|
|
26168
|
-
const canonical = canonicalGlob(glob);
|
|
26169
|
-
for (const target of targets) {
|
|
26170
|
-
if (matchWorkspace(glob, target))
|
|
26171
|
-
return ws;
|
|
26172
|
-
if (canonical !== glob && matchWorkspace(canonical, target))
|
|
26173
|
-
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)");
|
|
26174
26276
|
}
|
|
26277
|
+
return () => this.notification({
|
|
26278
|
+
method: "notifications/elicitation/complete",
|
|
26279
|
+
params: {
|
|
26280
|
+
elicitationId
|
|
26281
|
+
}
|
|
26282
|
+
}, options);
|
|
26175
26283
|
}
|
|
26176
|
-
|
|
26177
|
-
};
|
|
26178
|
-
var resolveWorkspace = (cwd) => resolveWorkspaceFrom(cwd, configDir());
|
|
26179
|
-
|
|
26180
|
-
// packages/workit-core/src/core/vcs-config.ts
|
|
26181
|
-
import fs7 from "node:fs";
|
|
26182
|
-
import path10 from "node:path";
|
|
26183
|
-
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
26184
|
-
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
26185
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
|
|
26186
|
-
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
26187
|
-
var remoteProvider = (cwd) => {
|
|
26188
|
-
const r = spawnSync3("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
26189
|
-
if (r.status !== 0)
|
|
26190
|
-
return null;
|
|
26191
|
-
const url = (r.stdout ?? "").trim();
|
|
26192
|
-
if (/github\.com[:/]/.test(url))
|
|
26193
|
-
return "github";
|
|
26194
|
-
if (/gitlab\.com[:/]/.test(url))
|
|
26195
|
-
return "gitlab";
|
|
26196
|
-
return null;
|
|
26197
|
-
};
|
|
26198
|
-
var readVcsConfig = () => {
|
|
26199
|
-
const file = vcsConfigPath();
|
|
26200
|
-
let raw;
|
|
26201
|
-
try {
|
|
26202
|
-
raw = fs7.readFileSync(file, "utf8");
|
|
26203
|
-
} catch {
|
|
26204
|
-
return { status: "missing", path: file, config: {} };
|
|
26284
|
+
async listRoots(params, options) {
|
|
26285
|
+
return this.request({ method: "roots/list", params }, ListRootsResultSchema, options);
|
|
26205
26286
|
}
|
|
26206
|
-
|
|
26207
|
-
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
|
|
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
|
+
}
|
|
26211
26293
|
}
|
|
26212
|
-
|
|
26213
|
-
return {
|
|
26294
|
+
async sendResourceUpdated(params) {
|
|
26295
|
+
return this.notification({
|
|
26296
|
+
method: "notifications/resources/updated",
|
|
26297
|
+
params
|
|
26298
|
+
});
|
|
26214
26299
|
}
|
|
26215
|
-
|
|
26216
|
-
|
|
26217
|
-
|
|
26218
|
-
|
|
26219
|
-
const wsVcs = ws?.vcs ?? {};
|
|
26220
|
-
const wsYt = ws?.youtrack ?? {};
|
|
26221
|
-
const wsIssues = ws?.issues ?? {};
|
|
26222
|
-
const { status: cfgStatus, path: cfgPath, config: cfg, error: cfgError } = readVcsConfig();
|
|
26223
|
-
const root = vcsCwd(cwd);
|
|
26224
|
-
const determinateRoot = cwd !== undefined || process.env.WORKFLOW_WORKSPACE_ROOT !== undefined;
|
|
26225
|
-
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
26226
|
-
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
26227
|
-
const wp = ws?.branchPolicy ?? {};
|
|
26228
|
-
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
26229
|
-
const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
|
|
26230
|
-
const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
|
|
26231
|
-
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
26232
|
-
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
26233
|
-
let issuesProvider = null;
|
|
26234
|
-
let linkOnPr = null;
|
|
26235
|
-
if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
|
|
26236
|
-
issuesProvider = "github";
|
|
26237
|
-
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
|
+
});
|
|
26238
26304
|
}
|
|
26239
|
-
|
|
26240
|
-
|
|
26241
|
-
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
26242
|
-
return {
|
|
26243
|
-
ok: true,
|
|
26244
|
-
workspace_name: ws?.name ?? null,
|
|
26245
|
-
provider,
|
|
26246
|
-
defaultTargetBranch: defaultTarget,
|
|
26247
|
-
link_issues: linkIssues,
|
|
26248
|
-
youtrack_base_url: youtrackBaseUrl,
|
|
26249
|
-
issues_provider: issuesProvider,
|
|
26250
|
-
link_on_pr: linkOnPr
|
|
26251
|
-
};
|
|
26305
|
+
async sendToolListChanged() {
|
|
26306
|
+
return this.notification({ method: "notifications/tools/list_changed" });
|
|
26252
26307
|
}
|
|
26253
|
-
|
|
26254
|
-
return {
|
|
26308
|
+
async sendPromptListChanged() {
|
|
26309
|
+
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
26255
26310
|
}
|
|
26256
|
-
|
|
26257
|
-
|
|
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;
|
|
26258
26322
|
}
|
|
26259
|
-
|
|
26260
|
-
|
|
26261
|
-
|
|
26262
|
-
|
|
26263
|
-
|
|
26264
|
-
}
|
|
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;
|
|
26265
26330
|
}
|
|
26266
|
-
|
|
26267
|
-
|
|
26268
|
-
|
|
26269
|
-
|
|
26270
|
-
|
|
26271
|
-
|
|
26272
|
-
|
|
26273
|
-
|
|
26274
|
-
|
|
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);
|
|
26275
26343
|
}
|
|
26276
|
-
|
|
26277
|
-
|
|
26278
|
-
configPath: path10.resolve(cfgPath),
|
|
26279
|
-
provider,
|
|
26280
|
-
defaultTargetBranch: defaultTarget,
|
|
26281
|
-
pr: cfg.pr ?? {},
|
|
26282
|
-
tokenPath,
|
|
26283
|
-
tokenPresent: fs7.existsSync(tokenPath),
|
|
26284
|
-
tokenReady: tokenOk,
|
|
26285
|
-
workspace_name: ws?.name ?? null,
|
|
26286
|
-
link_issues: linkIssues,
|
|
26287
|
-
youtrack_base_url: youtrackBaseUrl,
|
|
26288
|
-
issues_provider: issuesProvider,
|
|
26289
|
-
link_on_pr: linkOnPr
|
|
26290
|
-
};
|
|
26291
|
-
if (provider === "gitlab") {
|
|
26292
|
-
out.gitlab = {
|
|
26293
|
-
host: prov.host ?? "gitlab.com",
|
|
26294
|
-
apiUrl: prov.apiUrl ?? "https://gitlab.com/api/v4"
|
|
26295
|
-
};
|
|
26296
|
-
} else if (provider === "github") {
|
|
26297
|
-
out.github = { host: prov.host ?? "github.com" };
|
|
26344
|
+
clear() {
|
|
26345
|
+
this._buffer = undefined;
|
|
26298
26346
|
}
|
|
26299
|
-
if (mode === "summary")
|
|
26300
|
-
delete out.tokenPath;
|
|
26301
|
-
return out;
|
|
26302
26347
|
}
|
|
26303
|
-
function
|
|
26304
|
-
|
|
26305
|
-
|
|
26306
|
-
|
|
26307
|
-
|
|
26308
|
-
|
|
26309
|
-
|
|
26310
|
-
|
|
26311
|
-
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26322
|
-
|
|
26323
|
-
|
|
26324
|
-
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26331
|
-
|
|
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.");
|
|
26332
26379
|
}
|
|
26333
|
-
|
|
26334
|
-
|
|
26335
|
-
|
|
26336
|
-
|
|
26337
|
-
|
|
26338
|
-
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
|
|
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
|
+
}
|
|
26343
26395
|
}
|
|
26344
|
-
}
|
|
26345
|
-
|
|
26346
|
-
|
|
26347
|
-
|
|
26348
|
-
|
|
26349
|
-
|
|
26350
|
-
|
|
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();
|
|
26351
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
|
+
});
|
|
26352
26416
|
}
|
|
26353
|
-
return {
|
|
26354
|
-
ok: true,
|
|
26355
|
-
provider,
|
|
26356
|
-
count: examples.length,
|
|
26357
|
-
styleHints: [
|
|
26358
|
-
"Prefer ## Summary bullets + ## Validation or ## Test plan only",
|
|
26359
|
-
"Do not add ## Notes with branch names, commit counts, or diff stats",
|
|
26360
|
-
"Do not paste commit log or diff stat into the body"
|
|
26361
|
-
],
|
|
26362
|
-
examples
|
|
26363
|
-
};
|
|
26364
26417
|
}
|
|
26365
26418
|
|
|
26366
|
-
// packages/workit-
|
|
26367
|
-
|
|
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);
|
|
26368
26478
|
|
|
26369
26479
|
// packages/workit-core/src/core/pr-create.ts
|
|
26370
26480
|
import fs8 from "node:fs";
|