@brainervirus/workit-cursor 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/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +377 -218
- package/dist/mcp-server.js +2980 -2870
- package/dist/workit-hook.js +346 -216
- package/package.json +3 -3
|
@@ -7492,7 +7492,87 @@ var SCHEMA_VERSION = 1, POLICY_VERSION = "1.0.0", OPERATION_FAMILIES, uuidPatter
|
|
|
7492
7492
|
const covers = (path) => normOuter.paths.some((base) => base === "." || path === base || path.startsWith(`${base}/`)) && !excluded(path, normOuter);
|
|
7493
7493
|
const innerExcludes = (path) => innerExclusions.some((excludedPath) => excludedPath === path || path.startsWith(`${excludedPath}/`));
|
|
7494
7494
|
return innerPaths.every(covers) && !normOuter.exclusions.some((excludedPath) => innerPaths.some((base) => (base === "." || excludedPath === base || excludedPath.startsWith(`${base}/`)) && !innerExcludes(excludedPath)));
|
|
7495
|
-
}, refSchema,
|
|
7495
|
+
}, refSchema, rewriteUnknown = (value, map) => {
|
|
7496
|
+
if (Array.isArray(value)) {
|
|
7497
|
+
const out = [];
|
|
7498
|
+
for (const item of value) {
|
|
7499
|
+
const rewritten = rewriteUnknown(item, map);
|
|
7500
|
+
if (!rewritten.drop)
|
|
7501
|
+
out.push(rewritten.value);
|
|
7502
|
+
}
|
|
7503
|
+
return { drop: false, value: out };
|
|
7504
|
+
}
|
|
7505
|
+
if (typeof value === "object" && value !== null) {
|
|
7506
|
+
if (refSchema.safeParse(value).success) {
|
|
7507
|
+
const mapped = map(value);
|
|
7508
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
7509
|
+
}
|
|
7510
|
+
const out = {};
|
|
7511
|
+
for (const [key, item] of Object.entries(value)) {
|
|
7512
|
+
const rewritten = rewriteUnknown(item, map);
|
|
7513
|
+
out[key] = rewritten.drop ? null : rewritten.value;
|
|
7514
|
+
}
|
|
7515
|
+
return { drop: false, value: out };
|
|
7516
|
+
}
|
|
7517
|
+
return { drop: false, value };
|
|
7518
|
+
}, rewriteNode = (value, schema, map) => {
|
|
7519
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && refSchema.safeParse(value).success) {
|
|
7520
|
+
const mapped = map(value);
|
|
7521
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
7522
|
+
}
|
|
7523
|
+
let node = schema;
|
|
7524
|
+
while (node instanceof ZodNullable || node instanceof ZodOptional || node instanceof ZodDefault) {
|
|
7525
|
+
node = node.unwrap();
|
|
7526
|
+
}
|
|
7527
|
+
if (node === refSchema) {
|
|
7528
|
+
if (!refSchema.safeParse(value).success)
|
|
7529
|
+
return { drop: false, value };
|
|
7530
|
+
const mapped = map(value);
|
|
7531
|
+
return mapped === null ? { drop: true } : { drop: false, value: mapped };
|
|
7532
|
+
}
|
|
7533
|
+
if (node instanceof ZodArray) {
|
|
7534
|
+
if (!Array.isArray(value))
|
|
7535
|
+
return { drop: false, value };
|
|
7536
|
+
const out = [];
|
|
7537
|
+
for (const item of value) {
|
|
7538
|
+
const rewritten = rewriteNode(item, node.element, map);
|
|
7539
|
+
if (!rewritten.drop)
|
|
7540
|
+
out.push(rewritten.value);
|
|
7541
|
+
}
|
|
7542
|
+
return { drop: false, value: out };
|
|
7543
|
+
}
|
|
7544
|
+
if (node instanceof ZodObject) {
|
|
7545
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
7546
|
+
return { drop: false, value };
|
|
7547
|
+
const shape = node.shape;
|
|
7548
|
+
const record = value;
|
|
7549
|
+
const out = {};
|
|
7550
|
+
for (const [key, item] of Object.entries(record)) {
|
|
7551
|
+
if (!(key in shape)) {
|
|
7552
|
+
const scrubbed = rewriteUnknown(item, map);
|
|
7553
|
+
out[key] = scrubbed.drop ? null : scrubbed.value;
|
|
7554
|
+
continue;
|
|
7555
|
+
}
|
|
7556
|
+
const child = shape[key];
|
|
7557
|
+
const rewritten = rewriteNode(item, child, map);
|
|
7558
|
+
if (rewritten.drop) {
|
|
7559
|
+
if (child instanceof ZodOptional || child instanceof ZodDefault)
|
|
7560
|
+
continue;
|
|
7561
|
+
if (child instanceof ZodNullable) {
|
|
7562
|
+
out[key] = null;
|
|
7563
|
+
continue;
|
|
7564
|
+
}
|
|
7565
|
+
return { drop: true };
|
|
7566
|
+
}
|
|
7567
|
+
out[key] = rewritten.value;
|
|
7568
|
+
}
|
|
7569
|
+
return { drop: false, value: out };
|
|
7570
|
+
}
|
|
7571
|
+
return { drop: false, value };
|
|
7572
|
+
}, rewriteRecordRefs = (value, schema, map) => {
|
|
7573
|
+
const rewritten = rewriteNode(value, schema, map);
|
|
7574
|
+
return rewritten.drop ? null : rewritten.value;
|
|
7575
|
+
}, provenanceSchema, entrySchema = (data) => object({ id, recordedAt: utc, provenance: provenanceSchema, data }).strict(), factSchema, signalSchema, signalSet, consequenceSchema, verificationSchema, assessmentSchema, constraintSchema, intentSchema, progressSchema, dimensionSchema, policySchema, requirementSchema, policyChangeSchema, candidateSchema, evidenceSchema, evidenceEvaluationSchema, decisionSchema, findingSchema, assignmentSchema, workerReportSchema, workerSchema, ownerSchema, closureSchema, actionProgressSchema, actionProgressListSchema, runtimeSchema, taskRecordSchema, workspaceRecordSchema, capabilitySchema, requirementEvaluationSchema, taskViewSchema, taskSummarySchema, exportBundleSchema, callerSchema, base, revisions, taskId, operation = (shape) => object({ ...base, ...shape }).strict(), taskOperations, policyOperations, evidenceOperations, findingOperations, decisionOperations, workerOperations, writerOperations, stateOperations, operationSchemas, compiledOperationSchemas, success = (revisionValue, workspaceRevisionValue, data) => ({
|
|
7496
7576
|
ok: true,
|
|
7497
7577
|
schemaVersion: 1,
|
|
7498
7578
|
revision: revisionValue,
|
|
@@ -7795,10 +7875,11 @@ var init_task_contract = __esm(() => {
|
|
|
7795
7875
|
presented: text,
|
|
7796
7876
|
approvedContent: text,
|
|
7797
7877
|
displayed: text.optional(),
|
|
7798
|
-
contentRefs: array(refSchema)
|
|
7878
|
+
contentRefs: array(refSchema),
|
|
7879
|
+
statedChoice: object({ ref: text, text }).strict().optional()
|
|
7799
7880
|
}).strict(),
|
|
7800
7881
|
digest,
|
|
7801
|
-
response: _enum(["approved", "rejected"]),
|
|
7882
|
+
response: _enum(["approved", "rejected", "stated"]),
|
|
7802
7883
|
requirementIds: array(digest),
|
|
7803
7884
|
revoked: object({ at: utc, reason: text }).strict().nullable(),
|
|
7804
7885
|
consumption: object({
|
|
@@ -9074,11 +9155,11 @@ class TaskStore {
|
|
|
9074
9155
|
return workspace;
|
|
9075
9156
|
if (!workspace.data)
|
|
9076
9157
|
return failure("not_found", "workspace not found");
|
|
9077
|
-
const
|
|
9078
|
-
if (!
|
|
9158
|
+
const expected = input.expectedRevision;
|
|
9159
|
+
if (!expected)
|
|
9079
9160
|
return failure("invalid_input", "task revision is required");
|
|
9080
|
-
if (task.data.revision !==
|
|
9081
|
-
return this.conflict(
|
|
9161
|
+
if (task.data.revision !== expected)
|
|
9162
|
+
return this.conflict(expected, task.data.revision);
|
|
9082
9163
|
if (workspace.data.revision !== input.expectedWorkspaceRevision)
|
|
9083
9164
|
return this.conflict(input.expectedWorkspaceRevision, workspace.data.revision);
|
|
9084
9165
|
const previousWorkspaceBytes = this.snapshotBytes(this.workspacePath);
|
|
@@ -9704,7 +9785,7 @@ var same = (left, right) => {
|
|
|
9704
9785
|
} catch {
|
|
9705
9786
|
return false;
|
|
9706
9787
|
}
|
|
9707
|
-
}, UNCERTAIN_WORKER_STATES, isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state), callerSession = (caller) => caller.session ?? { kind: "host", host: caller.host, handle: caller.actor }, validPath = (value) => typeof value === "string" && value.length > 0 && ![...value].some((char) => {
|
|
9788
|
+
}, UNCERTAIN_WORKER_STATES, isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state), workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state), callerSession = (caller) => caller.session ?? { kind: "host", host: caller.host, handle: caller.actor }, validPath = (value) => typeof value === "string" && value.length > 0 && ![...value].some((char) => {
|
|
9708
9789
|
const code = char.charCodeAt(0);
|
|
9709
9790
|
return code < 32 || code === 127;
|
|
9710
9791
|
}) && !value.split(/[\\/]/).includes(".."), callerValue = (value) => ({ host: value.host, actor: value.actor }), workerIdOf = (value) => value.workerId ?? null;
|
|
@@ -9999,6 +10080,33 @@ var verifiedAuthorities, trustedAuthority = (kind, provenance, expected, binding
|
|
|
9999
10080
|
const token = {};
|
|
10000
10081
|
verifiedAuthorities.set(token, { kind, provenance, ...expected, ...binding, caller });
|
|
10001
10082
|
return token;
|
|
10083
|
+
}, chainStepKey = (step) => step.kind === "commit" ? step.message : step.kind === "branch" ? `branch:${step.target}` : "pr", isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeChainSteps = (steps) => {
|
|
10084
|
+
if (!Array.isArray(steps) || steps.length === 0 || steps.length > 32)
|
|
10085
|
+
return null;
|
|
10086
|
+
const normalized = [];
|
|
10087
|
+
for (const step of steps) {
|
|
10088
|
+
if (typeof step === "string") {
|
|
10089
|
+
if (!step.trim())
|
|
10090
|
+
return null;
|
|
10091
|
+
normalized.push({ kind: "commit", message: step });
|
|
10092
|
+
continue;
|
|
10093
|
+
}
|
|
10094
|
+
if (!isRecord(step))
|
|
10095
|
+
return null;
|
|
10096
|
+
if (typeof step.branch === "string" && step.branch.trim() && Object.keys(step).length === 1) {
|
|
10097
|
+
normalized.push({ kind: "branch", target: step.branch });
|
|
10098
|
+
continue;
|
|
10099
|
+
}
|
|
10100
|
+
if (step.pr === true && Object.keys(step).length === 1) {
|
|
10101
|
+
normalized.push({ kind: "pr" });
|
|
10102
|
+
continue;
|
|
10103
|
+
}
|
|
10104
|
+
return null;
|
|
10105
|
+
}
|
|
10106
|
+
const keys = normalized.map(chainStepKey);
|
|
10107
|
+
if (new Set(keys).size !== keys.length)
|
|
10108
|
+
return null;
|
|
10109
|
+
return normalized;
|
|
10002
10110
|
}, scopeEqual = (left, right) => canonicalJson(left) === canonicalJson(right), parseSteps = (content) => {
|
|
10003
10111
|
let value;
|
|
10004
10112
|
try {
|
|
@@ -10009,7 +10117,10 @@ var verifiedAuthorities, trustedAuthority = (kind, provenance, expected, binding
|
|
|
10009
10117
|
if (typeof value !== "object" || value === null || !("steps" in value))
|
|
10010
10118
|
return [];
|
|
10011
10119
|
const steps = value.steps;
|
|
10012
|
-
|
|
10120
|
+
if (!Array.isArray(steps))
|
|
10121
|
+
return null;
|
|
10122
|
+
const normalized = normalizeChainSteps(steps);
|
|
10123
|
+
return normalized;
|
|
10013
10124
|
}, decisionMatches = (entry, purpose, binding) => {
|
|
10014
10125
|
const decision = entry.data;
|
|
10015
10126
|
return binding.taskId === decision.binding.taskId && binding.workspaceId === decision.binding.workspaceId && decision.purpose === purpose && decision.response === "approved" && decision.revoked === null && (purpose !== "action" || decision.consumption === null) && decision.digest === decisionDigest(decision) && scopeEqual(decision.binding.scope, binding.scope) && canonicalJson(decision.binding) === canonicalJson(binding);
|
|
@@ -10179,14 +10290,12 @@ var verifiedAuthorities, trustedAuthority = (kind, provenance, expected, binding
|
|
|
10179
10290
|
return content;
|
|
10180
10291
|
const requestedSteps = parseSteps(decision.binding.approvedContent);
|
|
10181
10292
|
if (requestedSteps === null)
|
|
10182
|
-
return failure("invalid_input", "bounded action steps must be a
|
|
10183
|
-
if (input.steps && canonicalJson(input.steps) !== canonicalJson(requestedSteps))
|
|
10293
|
+
return failure("invalid_input", "bounded action steps must be a unique non-empty array");
|
|
10294
|
+
if (input.steps && canonicalJson(input.steps) !== canonicalJson(requestedSteps.map(chainStepKey)))
|
|
10184
10295
|
return failure("permission_denied", "bounded action steps do not match approved content");
|
|
10185
|
-
if (requestedSteps.some((step) => !step || typeof step !== "string") || new Set(requestedSteps).size !== requestedSteps.length)
|
|
10186
|
-
return failure("invalid_input", "bounded action steps must be unique and non-empty");
|
|
10187
10296
|
const stored = task.actionProgress?.find((item) => item.decisionId === input.decisionId);
|
|
10188
|
-
const workflow = stored ? { steps: stored.steps, completed: stored.completedSteps } : { steps: requestedSteps, completed: [] };
|
|
10189
|
-
if (workflow.steps.length && requestedSteps.length && canonicalJson(workflow.steps) !== canonicalJson(requestedSteps))
|
|
10297
|
+
const workflow = stored ? { steps: stored.steps, completed: stored.completedSteps } : { steps: requestedSteps.map(chainStepKey), completed: [] };
|
|
10298
|
+
if (workflow.steps.length && requestedSteps.length && canonicalJson(workflow.steps) !== canonicalJson(requestedSteps.map(chainStepKey)))
|
|
10190
10299
|
return failure("permission_denied", "bounded action scope changed");
|
|
10191
10300
|
return success(null, null, { entry, workflow });
|
|
10192
10301
|
}, bindingCovers, verifyDecisionContent;
|
|
@@ -10354,7 +10463,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
10354
10463
|
return (task.policy?.requirements ?? []).map((requirement) => {
|
|
10355
10464
|
const related = task.evidence.map((entry, index) => ({ entry, evaluation: evidence[index] })).filter(({ entry }) => entry.data.requirementIds.includes(requirement.id));
|
|
10356
10465
|
const passed = related.filter(({ entry, evaluation }) => {
|
|
10357
|
-
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension))
|
|
10466
|
+
if (!evidenceMatchesRequirement(evaluation.status, entry.data.kind, requirement.dimension, requirement.ruleId))
|
|
10358
10467
|
return false;
|
|
10359
10468
|
if ((entry.data.kind === "check" || entry.data.kind === "review") && (!entry.data.beforeCandidateId || !entry.data.candidateId || entry.data.beforeCandidateId !== entry.data.candidateId))
|
|
10360
10469
|
return false;
|
|
@@ -10362,11 +10471,12 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
10362
10471
|
return true;
|
|
10363
10472
|
const reviewSession = sessionFromRef(entry.data.reviewContext);
|
|
10364
10473
|
const sameImplementation = sameSession(reviewSession, task.intent.provenance.session);
|
|
10365
|
-
const sameEvidenceSession =
|
|
10474
|
+
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));
|
|
10366
10475
|
return entry.data.kind === "review" && reviewSession !== null && sameSession(reviewSession, entry.provenance.session) && (requirement.ruleId === "self-review" || !sameImplementation && !sameEvidenceSession);
|
|
10367
10476
|
});
|
|
10368
10477
|
if (passed.length) {
|
|
10369
|
-
const
|
|
10478
|
+
const currentId = candidate?.id ?? null;
|
|
10479
|
+
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;
|
|
10370
10480
|
if (withRed.length)
|
|
10371
10481
|
return {
|
|
10372
10482
|
requirementId: requirement.id,
|
|
@@ -10403,7 +10513,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
10403
10513
|
status: "satisfied",
|
|
10404
10514
|
evidenceIds: [],
|
|
10405
10515
|
decisionIds: decisions.map((decision) => decision.id),
|
|
10406
|
-
reason: "an applicable approved decision satisfies the requirement"
|
|
10516
|
+
reason: "an applicable approved or stated decision satisfies the requirement"
|
|
10407
10517
|
};
|
|
10408
10518
|
const limitations = requirement.acceptanceAllowed ? applicableDecision2(task, workspace, requirement, checkoutRoot) : [];
|
|
10409
10519
|
if (limitations.length)
|
|
@@ -10415,6 +10525,14 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
|
|
|
10415
10525
|
reason: "an applicable approved limitation permits the missing evidence"
|
|
10416
10526
|
};
|
|
10417
10527
|
const unavailable = capabilities.some((capability) => capability.assurance === "unavailable" && (capability.name === requirement.dimension || capability.surface === requirement.dimension));
|
|
10528
|
+
if (!unavailable && related.length > 0 && !passed.length)
|
|
10529
|
+
return {
|
|
10530
|
+
requirementId: requirement.id,
|
|
10531
|
+
status: "unsatisfied",
|
|
10532
|
+
evidenceIds: related.map(({ entry }) => entry.id),
|
|
10533
|
+
decisionIds: [],
|
|
10534
|
+
reason: `no passing evidence (needs kind:${expectedKinds(requirement.dimension, requirement.ruleId)})`
|
|
10535
|
+
};
|
|
10418
10536
|
return {
|
|
10419
10537
|
requirementId: requirement.id,
|
|
10420
10538
|
status: unavailable ? "unavailable" : "unsatisfied",
|
|
@@ -10439,7 +10557,13 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
10439
10557
|
if (entry.data.disposition === "fixed") {
|
|
10440
10558
|
const verified = entry.data.resolution?.evidenceIds.some((id) => {
|
|
10441
10559
|
const evidence = view.task.evidence.find((item) => item.id === id);
|
|
10442
|
-
|
|
10560
|
+
if (!evidence)
|
|
10561
|
+
return false;
|
|
10562
|
+
return findingVerificationPasses(entry.data.candidateId, {
|
|
10563
|
+
kind: evidence.data.kind,
|
|
10564
|
+
candidateId: evidence.data.candidateId,
|
|
10565
|
+
status: evidenceById.get(id) ?? "missing"
|
|
10566
|
+
});
|
|
10443
10567
|
});
|
|
10444
10568
|
if (!verified)
|
|
10445
10569
|
return failure("requirements_unsatisfied", "fixed findings require current verification");
|
|
@@ -10455,7 +10579,12 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
10455
10579
|
}
|
|
10456
10580
|
}
|
|
10457
10581
|
}
|
|
10458
|
-
const blocking = evaluations.filter((item) =>
|
|
10582
|
+
const blocking = evaluations.filter((item) => {
|
|
10583
|
+
if (item.status !== "unsatisfied" && item.status !== "unavailable")
|
|
10584
|
+
return false;
|
|
10585
|
+
const requirement = view.task.policy?.requirements.find((candidate) => candidate.id === item.requirementId);
|
|
10586
|
+
return !requirement || requirement.before === "close";
|
|
10587
|
+
});
|
|
10459
10588
|
if (requestedOutcome !== "stopped" && blocking.length)
|
|
10460
10589
|
return failure("requirements_unsatisfied", "applicable requirements are unsatisfied", {
|
|
10461
10590
|
requirementIds: blocking.map((item) => item.requirementId),
|
|
@@ -10611,11 +10740,23 @@ var digestBytes3 = (value) => createHash4("sha256").update(value).digest("hex"),
|
|
|
10611
10740
|
}, sameSession = (left, right) => {
|
|
10612
10741
|
const other = sessionFromRef(right);
|
|
10613
10742
|
return left !== null && other !== null && left.host === other.host && left.handle === other.handle;
|
|
10614
|
-
}, evidenceScopes = (task, ids) => (task.policy?.requirements ?? []).filter((requirement) => ids.includes(requirement.id)).map((requirement) => requirement.scope), scopeCovers2,
|
|
10743
|
+
}, evidenceScopes = (task, ids) => (task.policy?.requirements ?? []).filter((requirement) => ids.includes(requirement.id)).map((requirement) => requirement.scope), scopeCovers2, checkPin = (assignment, beforeCandidateId, candidateId) => {
|
|
10744
|
+
const pin = assignment.candidateId ?? null;
|
|
10745
|
+
if (pin === null)
|
|
10746
|
+
return true;
|
|
10747
|
+
return (beforeCandidateId ?? null) === pin || (candidateId ?? null) === pin;
|
|
10748
|
+
}, resolveBinding = (evidence, pin, currentCandidateId) => {
|
|
10749
|
+
const bound = evidence.kind === "check" || evidence.kind === "review";
|
|
10750
|
+
const fallback = bound ? pin ?? currentCandidateId : null;
|
|
10751
|
+
return {
|
|
10752
|
+
beforeCandidateId: evidence.beforeCandidateId ?? fallback,
|
|
10753
|
+
candidateId: evidence.candidateId ?? fallback
|
|
10754
|
+
};
|
|
10755
|
+
}, findingVerificationPasses = (findingCandidateId, evidence) => evidence.status === "passed" && (evidence.kind === "check" || evidence.kind === "review") && ((findingCandidateId ?? null) === null || evidence.candidateId === findingCandidateId), 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"))), 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 })), evidenceMatchesRequirement = (kind, evidenceKind, dimension, ruleId) => {
|
|
10615
10756
|
if (kind !== "passed")
|
|
10616
10757
|
return false;
|
|
10617
10758
|
if (dimension === "testing" || dimension === "verification")
|
|
10618
|
-
return evidenceKind === "check";
|
|
10759
|
+
return evidenceKind === "check" || ruleId === "pre-pr-cleanup" && evidenceKind === "artifact";
|
|
10619
10760
|
if (dimension === "review")
|
|
10620
10761
|
return evidenceKind === "review";
|
|
10621
10762
|
if (dimension === "investigation" || dimension === "challenge")
|
|
@@ -10623,6 +10764,20 @@ var digestBytes3 = (value) => createHash4("sha256").update(value).digest("hex"),
|
|
|
10623
10764
|
if (dimension === "artifacts" || dimension === "continuity")
|
|
10624
10765
|
return evidenceKind === "artifact";
|
|
10625
10766
|
return false;
|
|
10767
|
+
}, expectedKinds = (dimension, ruleId) => {
|
|
10768
|
+
if (dimension === "testing")
|
|
10769
|
+
return "check";
|
|
10770
|
+
if (dimension === "verification")
|
|
10771
|
+
return ruleId === "pre-pr-cleanup" ? "check or artifact" : "check";
|
|
10772
|
+
if (dimension === "review")
|
|
10773
|
+
return "review";
|
|
10774
|
+
if (dimension === "investigation" || dimension === "challenge")
|
|
10775
|
+
return "investigation";
|
|
10776
|
+
if (dimension === "artifacts" || dimension === "continuity")
|
|
10777
|
+
return "artifact";
|
|
10778
|
+
if (dimension === "decisions")
|
|
10779
|
+
return "decision";
|
|
10780
|
+
return "worker report";
|
|
10626
10781
|
};
|
|
10627
10782
|
var init_task_evaluation = __esm(() => {
|
|
10628
10783
|
init_task_contract();
|
|
@@ -10633,7 +10788,7 @@ var init_task_evaluation = __esm(() => {
|
|
|
10633
10788
|
// packages/workit-core/src/core/methods.ts
|
|
10634
10789
|
function selectMethods(policy, capabilities) {
|
|
10635
10790
|
return Object.entries(METHODS).flatMap(([id, definition]) => {
|
|
10636
|
-
const requirements = policy.requirements.filter((requirement) => methodMatches(
|
|
10791
|
+
const requirements = policy.requirements.filter((requirement) => methodMatches(definition, requirement));
|
|
10637
10792
|
if (requirements.length === 0)
|
|
10638
10793
|
return [];
|
|
10639
10794
|
const capability = assuranceFor(id, definition, capabilities);
|
|
@@ -10646,7 +10801,7 @@ function selectMethods(policy, capabilities) {
|
|
|
10646
10801
|
return [{ id, reason: reasons.join("; "), assurance: capability.assurance }];
|
|
10647
10802
|
});
|
|
10648
10803
|
}
|
|
10649
|
-
var METHODS, methodMatches = (
|
|
10804
|
+
var METHODS, methodMatches = (definition, requirement) => definition.dimensions?.includes(requirement.dimension) === true || definition.ruleIds?.includes(requirement.ruleId) === true, assuranceFor = (id, definition, capabilities) => {
|
|
10650
10805
|
const keys = new Set([
|
|
10651
10806
|
id,
|
|
10652
10807
|
...definition.dimensions ?? [],
|
|
@@ -10720,12 +10875,12 @@ act from memory of it.
|
|
|
10720
10875
|
var init_methods = __esm(() => {
|
|
10721
10876
|
METHODS = {
|
|
10722
10877
|
"workit-challenge": { dimensions: ["challenge", "decisions"] },
|
|
10723
|
-
"workit-behavioral-tdd": { dimensions: ["testing"] },
|
|
10724
|
-
"workit-review": { dimensions: ["review"], ruleIds: ["fresh-context-review"] },
|
|
10878
|
+
"workit-behavioral-tdd": { dimensions: ["testing"], ruleIds: ["mechanical-existing-checks"] },
|
|
10879
|
+
"workit-review": { dimensions: ["review"], ruleIds: ["fresh-context-review", "self-review"] },
|
|
10725
10880
|
"workit-plan": { dimensions: ["artifacts", "continuity"] },
|
|
10726
10881
|
"workit-implement": { dimensions: ["delegation"] },
|
|
10727
|
-
"workit-debug": {
|
|
10728
|
-
"workit-handoff": {
|
|
10882
|
+
"workit-debug": {},
|
|
10883
|
+
"workit-handoff": {},
|
|
10729
10884
|
"workit-deslop": { ruleIds: ["pre-pr-cleanup"] }
|
|
10730
10885
|
};
|
|
10731
10886
|
});
|
|
@@ -10832,12 +10987,70 @@ var init_task_context = __esm(() => {
|
|
|
10832
10987
|
});
|
|
10833
10988
|
|
|
10834
10989
|
// packages/workit-core/src/core/route-intent.ts
|
|
10835
|
-
var init_route_intent = () => {
|
|
10990
|
+
var init_route_intent = __esm(() => {
|
|
10991
|
+
init_task_store();
|
|
10992
|
+
});
|
|
10993
|
+
|
|
10994
|
+
// packages/workit-core/src/core/git.ts
|
|
10995
|
+
var init_git = () => {};
|
|
10996
|
+
|
|
10997
|
+
// packages/workit-core/src/core/boundary.ts
|
|
10998
|
+
var init_boundary = () => {};
|
|
10999
|
+
|
|
11000
|
+
// packages/workit-core/src/core/config.ts
|
|
11001
|
+
var PRESETS, DEFAULTS;
|
|
11002
|
+
var init_config = __esm(() => {
|
|
11003
|
+
init_boundary();
|
|
11004
|
+
PRESETS = {
|
|
11005
|
+
gitflow: {
|
|
11006
|
+
allowed: ["feature/*", "bugfix/*", "hotfix/*", "release/*"],
|
|
11007
|
+
protected: ["main", "develop", "master", "prod", "production"]
|
|
11008
|
+
},
|
|
11009
|
+
"github-flow": { allowed: ["*"], protected: ["main"] },
|
|
11010
|
+
"trunk-based": { allowed: ["*"], protected: ["main"] },
|
|
11011
|
+
custom: { allowed: [], protected: [] }
|
|
11012
|
+
};
|
|
11013
|
+
DEFAULTS = {
|
|
11014
|
+
locale: "en",
|
|
11015
|
+
localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
|
|
11016
|
+
timezone: "America/Santiago",
|
|
11017
|
+
branchPolicy: {
|
|
11018
|
+
preset: "gitflow",
|
|
11019
|
+
allowed: [...PRESETS.gitflow.allowed],
|
|
11020
|
+
protected: [...PRESETS.gitflow.protected]
|
|
11021
|
+
},
|
|
11022
|
+
commitPolicy: { preset: "conventional" }
|
|
11023
|
+
};
|
|
11024
|
+
});
|
|
11025
|
+
|
|
11026
|
+
// packages/workit-core/src/core/workspaces.ts
|
|
11027
|
+
var init_workspaces = __esm(() => {
|
|
11028
|
+
init_config();
|
|
11029
|
+
});
|
|
11030
|
+
|
|
11031
|
+
// packages/workit-core/src/core/vcs-config.ts
|
|
11032
|
+
var init_vcs_config = __esm(() => {
|
|
11033
|
+
init_config();
|
|
11034
|
+
init_workspaces();
|
|
11035
|
+
init_branch();
|
|
11036
|
+
});
|
|
11037
|
+
|
|
11038
|
+
// packages/workit-core/src/core/branch.ts
|
|
11039
|
+
var init_branch = __esm(() => {
|
|
11040
|
+
init_git();
|
|
11041
|
+
init_config();
|
|
11042
|
+
init_workspaces();
|
|
11043
|
+
init_vcs_config();
|
|
11044
|
+
});
|
|
11045
|
+
|
|
11046
|
+
// packages/workit-core/src/core/runtime-identity.ts
|
|
11047
|
+
var init_runtime_identity = () => {};
|
|
10836
11048
|
|
|
10837
11049
|
// packages/workit-core/src/core/external-action.ts
|
|
10838
11050
|
var externalActionSchema;
|
|
10839
11051
|
var init_external_action = __esm(() => {
|
|
10840
11052
|
init_task_contract();
|
|
11053
|
+
init_authority();
|
|
10841
11054
|
init_zod();
|
|
10842
11055
|
externalActionSchema = discriminatedUnion("operation", [
|
|
10843
11056
|
object({
|
|
@@ -11311,7 +11524,7 @@ class WorkitCore {
|
|
|
11311
11524
|
activeWorkerBlocker(task, workspace) {
|
|
11312
11525
|
if (workspace.writer)
|
|
11313
11526
|
return failure("recovery_required", "writer ownership must be released first");
|
|
11314
|
-
if (task.workers.some((entry) =>
|
|
11527
|
+
if (task.workers.some((entry) => workerBlocksTransition("close", entry.data.state)))
|
|
11315
11528
|
return failure("recovery_required", "worker state requires reconciliation");
|
|
11316
11529
|
return null;
|
|
11317
11530
|
}
|
|
@@ -11557,37 +11770,33 @@ class WorkitCore {
|
|
|
11557
11770
|
const currentCandidate = captureCandidate(this.store.root, task.data.intent.data.scope, environment());
|
|
11558
11771
|
if (!currentCandidate.ok)
|
|
11559
11772
|
return currentCandidate;
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
evidence.candidateId ??= currentCandidate.data.id;
|
|
11563
|
-
} else {
|
|
11564
|
-
evidence.beforeCandidateId ??= null;
|
|
11565
|
-
evidence.candidateId ??= null;
|
|
11566
|
-
}
|
|
11773
|
+
const pin = helper && helper.ok ? helper.data.data.assignment.candidateId : null;
|
|
11774
|
+
const bound = resolveBinding(evidence, pin, currentCandidate.data.id);
|
|
11567
11775
|
if (helper?.ok) {
|
|
11568
11776
|
const assignment = helper.data.data.assignment;
|
|
11569
|
-
if (evidence.requirementIds.some((id) => !assignment.requirementIds.includes(id)) || assignment
|
|
11777
|
+
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))
|
|
11570
11778
|
return failure("permission_denied", "evidence is outside the worker assignment");
|
|
11571
11779
|
}
|
|
11572
11780
|
const knownCandidates = new Set(task.data.candidates.map((candidate) => candidate.id));
|
|
11573
|
-
for (const candidateId of [
|
|
11781
|
+
for (const candidateId of [bound.beforeCandidateId, bound.candidateId]) {
|
|
11574
11782
|
if (candidateId && candidateId !== currentCandidate.data.id && !knownCandidates.has(candidateId))
|
|
11575
11783
|
return failure("invalid_input", "evidence candidate is not a captured candidate");
|
|
11576
11784
|
}
|
|
11785
|
+
const boundEvidence = { ...evidence, ...bound };
|
|
11577
11786
|
const changed = this.store.mutateTask(task.data.id, input.expectedRevision, (current, mutation) => {
|
|
11578
11787
|
const candidates = current.candidates.some((item) => item.id === currentCandidate.data.id) ? current.candidates : [...current.candidates, currentCandidate.data];
|
|
11579
11788
|
const entry = {
|
|
11580
11789
|
id: newId(),
|
|
11581
11790
|
recordedAt: mutation.now,
|
|
11582
11791
|
provenance: provenance(this.context, "agent_reported"),
|
|
11583
|
-
data:
|
|
11792
|
+
data: boundEvidence
|
|
11584
11793
|
};
|
|
11585
11794
|
return success(mutation.revision, null, {
|
|
11586
11795
|
...current,
|
|
11587
11796
|
candidates,
|
|
11588
11797
|
evidence: [...current.evidence, entry],
|
|
11589
11798
|
findings: current.findings.map((finding) => {
|
|
11590
|
-
if (finding.data.disposition === "open" ||
|
|
11799
|
+
if (finding.data.disposition === "open" || boundEvidence.result === "skipped")
|
|
11591
11800
|
return finding;
|
|
11592
11801
|
if (finding.data.disposition !== "fixed")
|
|
11593
11802
|
return finding;
|
|
@@ -11596,8 +11805,12 @@ class WorkitCore {
|
|
|
11596
11805
|
item.evidenceId,
|
|
11597
11806
|
item.status
|
|
11598
11807
|
]));
|
|
11599
|
-
const verified = withEntry.evidence.some((item) =>
|
|
11600
|
-
|
|
11808
|
+
const verified = withEntry.evidence.some((item) => findingVerificationPasses(finding.data.candidateId, {
|
|
11809
|
+
kind: item.data.kind,
|
|
11810
|
+
candidateId: item.data.candidateId,
|
|
11811
|
+
status: statuses.get(item.id) ?? "missing"
|
|
11812
|
+
}));
|
|
11813
|
+
const contradicted = boundEvidence.result === "failed" && finding.data.refs.some((left) => boundEvidence.refs.some((right) => sameValue(left, right)));
|
|
11601
11814
|
return verified && !contradicted ? finding : { ...finding, data: { ...finding.data, disposition: "open", resolution: null } };
|
|
11602
11815
|
})
|
|
11603
11816
|
});
|
|
@@ -11622,7 +11835,12 @@ class WorkitCore {
|
|
|
11622
11835
|
const input = parsed.data;
|
|
11623
11836
|
if (nativeRequired && input.action !== "record")
|
|
11624
11837
|
return failure("permission_denied", "native observation is only valid for recording decisions");
|
|
11625
|
-
|
|
11838
|
+
const stated = input.action === "record" && input.response === "stated";
|
|
11839
|
+
if (stated && input.purpose === "action")
|
|
11840
|
+
return failure("permission_denied", "stated choices cannot authorize mutating actions");
|
|
11841
|
+
if (stated && !input.binding?.statedChoice)
|
|
11842
|
+
return failure("invalid_input", "stated choices require binding.statedChoice");
|
|
11843
|
+
if (nativeRequired && nativeObservation === undefined && !stated)
|
|
11626
11844
|
return failure("permission_denied", "native decision observation is required");
|
|
11627
11845
|
const task = this.store.readTask(input.taskId);
|
|
11628
11846
|
if (!task.ok)
|
|
@@ -11655,7 +11873,7 @@ class WorkitCore {
|
|
|
11655
11873
|
consumption: null
|
|
11656
11874
|
};
|
|
11657
11875
|
const data = { ...base, digest: decisionDigest(base) };
|
|
11658
|
-
const native = nativeRequired ? verifyNativeDecision(this.context.nativeAuthority, {
|
|
11876
|
+
const native = nativeRequired && !stated ? verifyNativeDecision(this.context.nativeAuthority, {
|
|
11659
11877
|
observation: nativeObservation,
|
|
11660
11878
|
expected: {
|
|
11661
11879
|
taskId: task.data.id,
|
|
@@ -11750,7 +11968,7 @@ class WorkitCore {
|
|
|
11750
11968
|
if (input.action === "record") {
|
|
11751
11969
|
if (helper?.ok) {
|
|
11752
11970
|
const assignment = helper.data.data.assignment;
|
|
11753
|
-
if (!bindingCovers(assignment.scope, input.scope) || !bindingCovers(task.data.intent.data.scope, input.scope) || assignment
|
|
11971
|
+
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))
|
|
11754
11972
|
return failure("permission_denied", "finding is outside the worker assignment");
|
|
11755
11973
|
}
|
|
11756
11974
|
if (input.candidateId && !task.data.candidates.some((candidate) => candidate.id === input.candidateId))
|
|
@@ -11797,7 +12015,11 @@ class WorkitCore {
|
|
|
11797
12015
|
const evaluations = evaluateEvidence(task.data, current.data);
|
|
11798
12016
|
const verified = evidence.some((entry) => {
|
|
11799
12017
|
const evaluation = evaluations.find((item) => item.evidenceId === entry.id);
|
|
11800
|
-
return
|
|
12018
|
+
return findingVerificationPasses(finding.data.candidateId, {
|
|
12019
|
+
kind: entry.data.kind,
|
|
12020
|
+
candidateId: entry.data.candidateId,
|
|
12021
|
+
status: evaluation?.status ?? "missing"
|
|
12022
|
+
});
|
|
11801
12023
|
});
|
|
11802
12024
|
if (!verified)
|
|
11803
12025
|
return failure("permission_denied", "fixed findings require passing verification evidence");
|
|
@@ -11809,7 +12031,7 @@ class WorkitCore {
|
|
|
11809
12031
|
if (entry.data.result === "missing" || entry.data.result === "skipped")
|
|
11810
12032
|
return false;
|
|
11811
12033
|
const candidateMatches = finding.data.candidateId === null ? entry.data.candidateId === null : entry.data.candidateId === finding.data.candidateId || entry.data.beforeCandidateId === finding.data.candidateId;
|
|
11812
|
-
const referenceMatches = finding.data.refs.some((left) => entry.data.refs.some((right) =>
|
|
12034
|
+
const referenceMatches = finding.data.refs.some((left) => entry.data.refs.some((right) => sameValue(left, right)));
|
|
11813
12035
|
return candidateMatches && (referenceMatches || entry.data.claim === finding.data.claim);
|
|
11814
12036
|
});
|
|
11815
12037
|
if (!relevant)
|
|
@@ -11887,7 +12109,7 @@ class WorkitCore {
|
|
|
11887
12109
|
const workerId = newId();
|
|
11888
12110
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
11889
12111
|
taskId: task.data.id,
|
|
11890
|
-
|
|
12112
|
+
expectedRevision: input.expectedRevision,
|
|
11891
12113
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
11892
12114
|
now: trustedNow(this.context),
|
|
11893
12115
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -11925,7 +12147,7 @@ class WorkitCore {
|
|
|
11925
12147
|
return failure("permission_denied", "worker report is outside the worker assignment");
|
|
11926
12148
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
11927
12149
|
taskId: task.data.id,
|
|
11928
|
-
|
|
12150
|
+
expectedRevision: input.expectedRevision,
|
|
11929
12151
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
11930
12152
|
now: trustedNow(this.context),
|
|
11931
12153
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -11949,24 +12171,25 @@ class WorkitCore {
|
|
|
11949
12171
|
return failure("invalid_transition", "closed task cannot cancel workers");
|
|
11950
12172
|
if (entry.data.state === "unknown")
|
|
11951
12173
|
return failure("recovery_required", "worker state requires recovery");
|
|
11952
|
-
if (entry.data.state === "stopped")
|
|
11953
|
-
|
|
11954
|
-
|
|
12174
|
+
if (entry.data.state === "stopped") {
|
|
12175
|
+
const stopped = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
12176
|
+
return success(task.data.revision, workspace.data.revision, stopped);
|
|
12177
|
+
}
|
|
11955
12178
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
11956
12179
|
taskId: task.data.id,
|
|
11957
|
-
|
|
12180
|
+
expectedRevision: input.expectedRevision,
|
|
11958
12181
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
11959
12182
|
now: trustedNow(this.context),
|
|
11960
|
-
workspace: (current, mutation) => success(mutation.revision, mutation.revision,
|
|
12183
|
+
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
12184
|
+
...current,
|
|
12185
|
+
writer: current.writer?.owner.workerId === input.workerId ? null : current.writer
|
|
12186
|
+
}),
|
|
11961
12187
|
task: (current, mutation) => success(mutation.revision, null, {
|
|
11962
12188
|
...current,
|
|
11963
12189
|
workers: current.workers.map((candidate) => candidate.id === input.workerId ? {
|
|
11964
12190
|
...candidate,
|
|
11965
12191
|
recordedAt: mutation.now,
|
|
11966
|
-
data: {
|
|
11967
|
-
...candidate.data,
|
|
11968
|
-
state: settles ? "stopped" : "cancelling"
|
|
11969
|
-
}
|
|
12192
|
+
data: { ...candidate.data, state: "stopped" }
|
|
11970
12193
|
} : candidate)
|
|
11971
12194
|
})
|
|
11972
12195
|
});
|
|
@@ -12063,7 +12286,7 @@ class WorkitCore {
|
|
|
12063
12286
|
return attested;
|
|
12064
12287
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12065
12288
|
taskId: task.data.id,
|
|
12066
|
-
|
|
12289
|
+
expectedRevision: input.expectedRevision,
|
|
12067
12290
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12068
12291
|
now: trustedNow(this.context),
|
|
12069
12292
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, current),
|
|
@@ -12229,6 +12452,12 @@ class WorkitCore {
|
|
|
12229
12452
|
if (!sameSession2(helper.data.data.session, this.context))
|
|
12230
12453
|
return failure("permission_denied", "worker session does not match the caller");
|
|
12231
12454
|
}
|
|
12455
|
+
const gate = this.view(task.data);
|
|
12456
|
+
if (gate.ok) {
|
|
12457
|
+
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")));
|
|
12458
|
+
if (writeGates.length)
|
|
12459
|
+
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) });
|
|
12460
|
+
}
|
|
12232
12461
|
const owner = {
|
|
12233
12462
|
taskId: task.data.id,
|
|
12234
12463
|
workerId: helperId,
|
|
@@ -12240,7 +12469,7 @@ class WorkitCore {
|
|
|
12240
12469
|
};
|
|
12241
12470
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12242
12471
|
taskId: task.data.id,
|
|
12243
|
-
|
|
12472
|
+
expectedRevision: input.expectedRevision,
|
|
12244
12473
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12245
12474
|
now: trustedNow(this.context),
|
|
12246
12475
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -12271,7 +12500,7 @@ class WorkitCore {
|
|
|
12271
12500
|
}
|
|
12272
12501
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12273
12502
|
taskId: task.data.id,
|
|
12274
|
-
|
|
12503
|
+
expectedRevision: input.expectedRevision,
|
|
12275
12504
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12276
12505
|
now: trustedNow(this.context),
|
|
12277
12506
|
workspace: (currentWorkspace, mutation) => success(mutation.revision, mutation.revision, { ...currentWorkspace, writer: null }),
|
|
@@ -12520,7 +12749,15 @@ class WorkitCore {
|
|
|
12520
12749
|
if (seen.has(observation.workerId))
|
|
12521
12750
|
return failure("invalid_input", "worker observations must be unique");
|
|
12522
12751
|
seen.add(observation.workerId);
|
|
12523
|
-
|
|
12752
|
+
const freshTask = this.store.readTask(view.task.id);
|
|
12753
|
+
const freshWorkspace = this.store.readWorkspace();
|
|
12754
|
+
if (!freshTask.ok)
|
|
12755
|
+
return freshTask;
|
|
12756
|
+
if (!freshWorkspace.ok)
|
|
12757
|
+
return freshWorkspace;
|
|
12758
|
+
if (!freshWorkspace.data)
|
|
12759
|
+
return failure("not_found", "workspace not found");
|
|
12760
|
+
if (observation.taskId !== view.task.id || observation.expectedRevision !== freshTask.data.revision || observation.expectedWorkspaceRevision !== freshWorkspace.data.revision)
|
|
12524
12761
|
return failure("revision_conflict", "worker observation is stale");
|
|
12525
12762
|
if (!view.task.workers.some((entry) => entry.id === observation.workerId))
|
|
12526
12763
|
return failure("permission_denied", "worker observation is not assigned");
|
|
@@ -12606,19 +12843,26 @@ class WorkitCore {
|
|
|
12606
12843
|
return failure("permission_denied", "imported resume requires native destination approval");
|
|
12607
12844
|
resumeCandidate = current.data.candidate;
|
|
12608
12845
|
}
|
|
12609
|
-
const blocker = this.activeWorkerBlocker(task.data, workspace.data);
|
|
12846
|
+
const blocker = status === "paused" ? workspace.data.writer ? failure("recovery_required", "writer ownership must be released first") : null : this.activeWorkerBlocker(task.data, workspace.data);
|
|
12610
12847
|
if (blocker)
|
|
12611
12848
|
return blocker;
|
|
12849
|
+
let pauseCandidate = null;
|
|
12850
|
+
if (status === "paused") {
|
|
12851
|
+
const captured = captureCandidate(this.store.root, task.data.intent.data.scope, environment());
|
|
12852
|
+
if (!captured.ok)
|
|
12853
|
+
return captured;
|
|
12854
|
+
pauseCandidate = captured.data;
|
|
12855
|
+
}
|
|
12612
12856
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12613
12857
|
taskId: task.data.id,
|
|
12614
|
-
|
|
12858
|
+
expectedRevision: input.expectedRevision,
|
|
12615
12859
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12616
12860
|
now: trustedNow(this.context),
|
|
12617
12861
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
12618
12862
|
task: (current, context) => success(context.revision, null, {
|
|
12619
12863
|
...current,
|
|
12620
12864
|
status,
|
|
12621
|
-
candidates: resumeCandidate && !current.candidates.some((candidate) => candidate.id === resumeCandidate.id) ? [...current.candidates, resumeCandidate] : current.candidates,
|
|
12865
|
+
candidates: (resumeCandidate ?? pauseCandidate) && !current.candidates.some((candidate) => candidate.id === (resumeCandidate ?? pauseCandidate).id) ? [...current.candidates, resumeCandidate ?? pauseCandidate] : current.candidates,
|
|
12622
12866
|
progress: current.progress,
|
|
12623
12867
|
pauseReason: status === "paused" ? input.reason ?? null : null
|
|
12624
12868
|
})
|
|
@@ -12656,12 +12900,13 @@ class WorkitCore {
|
|
|
12656
12900
|
return workspace;
|
|
12657
12901
|
if (!workspace.data)
|
|
12658
12902
|
return failure("not_found", "workspace not found");
|
|
12659
|
-
|
|
12660
|
-
|
|
12903
|
+
const revisionBlocker = this.activeWorkerBlocker(task.data, workspace.data);
|
|
12904
|
+
if (revisionBlocker)
|
|
12905
|
+
return revisionBlocker;
|
|
12661
12906
|
this.fillRevisions(input, task.data, workspace.data);
|
|
12662
12907
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12663
12908
|
taskId: task.data.id,
|
|
12664
|
-
|
|
12909
|
+
expectedRevision: input.expectedRevision,
|
|
12665
12910
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12666
12911
|
now: trustedNow(this.context),
|
|
12667
12912
|
workspace: (workspace, context) => success(context.revision, context.revision, workspace),
|
|
@@ -12717,7 +12962,7 @@ class WorkitCore {
|
|
|
12717
12962
|
return closure;
|
|
12718
12963
|
const changed = this.store.mutateTaskAndWorkspace({
|
|
12719
12964
|
taskId: task.data.id,
|
|
12720
|
-
|
|
12965
|
+
expectedRevision: input.expectedRevision,
|
|
12721
12966
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12722
12967
|
now: trustedNow(this.context),
|
|
12723
12968
|
workspace: (value, context) => success(context.revision, context.revision, value),
|
|
@@ -12842,6 +13087,8 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
12842
13087
|
if (task.data.status === "paused" && (input.state === "running" || input.state === "cancelling"))
|
|
12843
13088
|
return failure("invalid_transition", "paused task cannot run a worker");
|
|
12844
13089
|
const notStarted = input.dispatch === true;
|
|
13090
|
+
if (notStarted && entry.data.state === "stopped" && input.session === null)
|
|
13091
|
+
return success(task.data.revision, workspace.data.revision, entry);
|
|
12845
13092
|
if (notStarted && (input.state !== "stopped" || input.session !== null))
|
|
12846
13093
|
return failure("invalid_input", "a never-dispatched worker stops with no session");
|
|
12847
13094
|
if (notStarted && entry.data.session !== null)
|
|
@@ -12873,7 +13120,7 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
12873
13120
|
return success(task.data.revision, workspace.data.revision, entry);
|
|
12874
13121
|
const changed = input.store.mutateTaskAndWorkspace({
|
|
12875
13122
|
taskId: task.data.id,
|
|
12876
|
-
|
|
13123
|
+
expectedRevision: input.expectedRevision,
|
|
12877
13124
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
12878
13125
|
now: input.now,
|
|
12879
13126
|
workspace: (current, mutation) => success(mutation.revision, mutation.revision, {
|
|
@@ -12912,90 +13159,22 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
12912
13159
|
workerId: null,
|
|
12913
13160
|
receipts: []
|
|
12914
13161
|
}), portableTask = (task) => {
|
|
12915
|
-
const
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
|
|
12928
|
-
];
|
|
12929
|
-
for (const entry of entries)
|
|
12930
|
-
entry.provenance = portableProvenance(entry.provenance);
|
|
12931
|
-
for (const worker of clone.workers)
|
|
12932
|
-
worker.data.session = null;
|
|
12933
|
-
clone.intent = {
|
|
12934
|
-
...clone.intent,
|
|
12935
|
-
data: { ...clone.intent.data, authorityRefs: portableRefs(clone.intent.data.authorityRefs) }
|
|
12936
|
-
};
|
|
12937
|
-
clone.constraints = clone.constraints.flatMap((constraint) => {
|
|
12938
|
-
const source = portableRef(constraint.source);
|
|
12939
|
-
return source ? [
|
|
12940
|
-
{
|
|
12941
|
-
...constraint,
|
|
12942
|
-
source,
|
|
12943
|
-
requires: constraint.requires.map((requirement) => ({
|
|
12944
|
-
...requirement,
|
|
12945
|
-
refs: portableRefs(requirement.refs)
|
|
12946
|
-
}))
|
|
12947
|
-
}
|
|
12948
|
-
] : [];
|
|
12949
|
-
});
|
|
12950
|
-
clone.assessments = clone.assessments.map((entry) => ({
|
|
12951
|
-
...entry,
|
|
12952
|
-
data: {
|
|
12953
|
-
...entry.data,
|
|
12954
|
-
facts: entry.data.facts.map(portableFact),
|
|
12955
|
-
signals: Object.fromEntries(Object.entries(entry.data.signals).map(([name, signal]) => [name, portableSignal(signal)])),
|
|
12956
|
-
consequences: entry.data.consequences.map((consequence) => ({
|
|
12957
|
-
...consequence,
|
|
12958
|
-
fact: portableFact(consequence.fact)
|
|
12959
|
-
})),
|
|
12960
|
-
verification: entry.data.verification.map((verification) => ({
|
|
12961
|
-
...verification,
|
|
12962
|
-
availableChecks: portableRefs(verification.availableChecks)
|
|
12963
|
-
}))
|
|
12964
|
-
}
|
|
12965
|
-
}));
|
|
12966
|
-
clone.progress = {
|
|
12967
|
-
...clone.progress,
|
|
12968
|
-
blockers: clone.progress.blockers.map((blocker) => ({
|
|
12969
|
-
...blocker,
|
|
12970
|
-
refs: portableRefs(blocker.refs)
|
|
12971
|
-
}))
|
|
13162
|
+
const stripped = rewriteRecordRefs(task, taskRecordSchema, portableRef);
|
|
13163
|
+
if (typeof stripped !== "object" || stripped === null || Array.isArray(stripped))
|
|
13164
|
+
throw new TypeError("portable task rewrite produced a non-record");
|
|
13165
|
+
const clone = structuredClone(stripped);
|
|
13166
|
+
const demote = (facts, signals, consequences) => {
|
|
13167
|
+
for (const fact of facts)
|
|
13168
|
+
Object.assign(fact, portableFact(fact));
|
|
13169
|
+
for (const name of Object.keys(signals)) {
|
|
13170
|
+
const signal = signals[name];
|
|
13171
|
+
Object.assign(signal, portableSignal(signal));
|
|
13172
|
+
}
|
|
13173
|
+
for (const consequence of consequences)
|
|
13174
|
+
Object.assign(consequence.fact, portableFact(consequence.fact));
|
|
12972
13175
|
};
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
data: {
|
|
12976
|
-
...entry.data,
|
|
12977
|
-
refs: portableRefs(entry.data.refs),
|
|
12978
|
-
reviewContext: portableRef(entry.data.reviewContext)
|
|
12979
|
-
}
|
|
12980
|
-
}));
|
|
12981
|
-
clone.decisions = clone.decisions.map((entry) => ({
|
|
12982
|
-
...entry,
|
|
12983
|
-
data: {
|
|
12984
|
-
...entry.data,
|
|
12985
|
-
consumption: entry.data.consumption ? portableRef(entry.data.consumption.actionRef) ? {
|
|
12986
|
-
...entry.data.consumption,
|
|
12987
|
-
actionRef: portableRef(entry.data.consumption.actionRef)
|
|
12988
|
-
} : null : null,
|
|
12989
|
-
binding: {
|
|
12990
|
-
...entry.data.binding,
|
|
12991
|
-
contentRefs: portableRefs(entry.data.binding.contentRefs)
|
|
12992
|
-
}
|
|
12993
|
-
}
|
|
12994
|
-
}));
|
|
12995
|
-
clone.findings = clone.findings.map((entry) => ({
|
|
12996
|
-
...entry,
|
|
12997
|
-
data: { ...entry.data, refs: portableRefs(entry.data.refs) }
|
|
12998
|
-
}));
|
|
13176
|
+
for (const entry of clone.assessments)
|
|
13177
|
+
demote(entry.data.facts, entry.data.signals, entry.data.consequences);
|
|
12999
13178
|
clone.candidates = [];
|
|
13000
13179
|
return clone;
|
|
13001
13180
|
}, importedTask = (source, bundle, destinationWorkspaceId, context, timestamp) => {
|
|
@@ -13019,15 +13198,13 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
13019
13198
|
allocate(entry.id);
|
|
13020
13199
|
const fresh = (id) => allocate(id);
|
|
13021
13200
|
const provenance = importedProvenance(context);
|
|
13201
|
+
const remap = (ref) => mapRef(ref, ids);
|
|
13022
13202
|
const intent = {
|
|
13023
13203
|
...source.intent,
|
|
13024
13204
|
id: fresh(source.intent.id),
|
|
13025
13205
|
recordedAt: timestamp,
|
|
13026
13206
|
provenance,
|
|
13027
|
-
data:
|
|
13028
|
-
...source.intent.data,
|
|
13029
|
-
authorityRefs: source.intent.data.authorityRefs.map((ref) => mapRef(ref, ids))
|
|
13030
|
-
}
|
|
13207
|
+
data: rewriteRecordRefs(source.intent.data, intentSchema, remap)
|
|
13031
13208
|
};
|
|
13032
13209
|
const assessments = source.assessments.map((entry) => {
|
|
13033
13210
|
const data = entry.data;
|
|
@@ -13036,28 +13213,7 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
13036
13213
|
id: fresh(entry.id),
|
|
13037
13214
|
recordedAt: timestamp,
|
|
13038
13215
|
provenance,
|
|
13039
|
-
data:
|
|
13040
|
-
...data,
|
|
13041
|
-
facts: data.facts.map((fact) => ({
|
|
13042
|
-
...fact,
|
|
13043
|
-
refs: fact.refs.map((ref) => mapRef(ref, ids))
|
|
13044
|
-
})),
|
|
13045
|
-
signals: Object.fromEntries(Object.entries(data.signals).map(([name, signal]) => [
|
|
13046
|
-
name,
|
|
13047
|
-
{ ...signal, refs: signal.refs.map((ref) => mapRef(ref, ids)) }
|
|
13048
|
-
])),
|
|
13049
|
-
consequences: data.consequences.map((consequence) => ({
|
|
13050
|
-
...consequence,
|
|
13051
|
-
fact: {
|
|
13052
|
-
...consequence.fact,
|
|
13053
|
-
refs: consequence.fact.refs.map((ref) => mapRef(ref, ids))
|
|
13054
|
-
}
|
|
13055
|
-
})),
|
|
13056
|
-
verification: data.verification.map((verification) => ({
|
|
13057
|
-
...verification,
|
|
13058
|
-
availableChecks: verification.availableChecks.map((ref) => mapRef(ref, ids))
|
|
13059
|
-
}))
|
|
13060
|
-
}
|
|
13216
|
+
data: rewriteRecordRefs(data, assessmentSchema, remap)
|
|
13061
13217
|
};
|
|
13062
13218
|
});
|
|
13063
13219
|
const evidence = source.evidence.map((entry) => ({
|
|
@@ -13065,11 +13221,7 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
13065
13221
|
id: fresh(entry.id),
|
|
13066
13222
|
recordedAt: timestamp,
|
|
13067
13223
|
provenance,
|
|
13068
|
-
data:
|
|
13069
|
-
...entry.data,
|
|
13070
|
-
refs: entry.data.refs.map((ref) => mapRef(ref, ids)),
|
|
13071
|
-
reviewContext: entry.data.reviewContext ? mapRef(entry.data.reviewContext, ids) : null
|
|
13072
|
-
}
|
|
13224
|
+
data: rewriteRecordRefs(entry.data, evidenceSchema, remap)
|
|
13073
13225
|
}));
|
|
13074
13226
|
const decisions = source.decisions.map((entry) => ({
|
|
13075
13227
|
...entry,
|
|
@@ -13077,21 +13229,23 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
13077
13229
|
recordedAt: timestamp,
|
|
13078
13230
|
provenance
|
|
13079
13231
|
}));
|
|
13080
|
-
const findings = source.findings.map((entry) =>
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13232
|
+
const findings = source.findings.map((entry) => {
|
|
13233
|
+
const data = rewriteRecordRefs(entry.data, findingSchema, remap);
|
|
13234
|
+
return {
|
|
13235
|
+
...entry,
|
|
13236
|
+
id: fresh(entry.id),
|
|
13237
|
+
recordedAt: timestamp,
|
|
13238
|
+
provenance,
|
|
13239
|
+
data: {
|
|
13240
|
+
...data,
|
|
13241
|
+
resolution: data.resolution ? {
|
|
13242
|
+
...data.resolution,
|
|
13243
|
+
evidenceIds: data.resolution.evidenceIds.map((id) => ids.get(id) ?? id),
|
|
13244
|
+
decisionIds: data.resolution.decisionIds.map((id) => ids.get(id) ?? id)
|
|
13245
|
+
} : null
|
|
13246
|
+
}
|
|
13247
|
+
};
|
|
13248
|
+
});
|
|
13095
13249
|
const workers = source.workers.map((entry) => ({
|
|
13096
13250
|
...entry,
|
|
13097
13251
|
id: fresh(entry.id),
|
|
@@ -13134,19 +13288,21 @@ var provenance = (context, kind = context.provenanceKind ?? "host_observed") =>
|
|
|
13134
13288
|
closure: null,
|
|
13135
13289
|
assessments,
|
|
13136
13290
|
evidence,
|
|
13137
|
-
decisions: decisions.map((entry) =>
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
...entry
|
|
13141
|
-
|
|
13142
|
-
...
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13291
|
+
decisions: decisions.map((entry) => {
|
|
13292
|
+
const data = rewriteRecordRefs(entry.data, decisionSchema, remap);
|
|
13293
|
+
return {
|
|
13294
|
+
...entry,
|
|
13295
|
+
data: {
|
|
13296
|
+
...data,
|
|
13297
|
+
binding: {
|
|
13298
|
+
...data.binding,
|
|
13299
|
+
taskId: "",
|
|
13300
|
+
workspaceId: destinationWorkspaceId
|
|
13301
|
+
},
|
|
13302
|
+
consumption: null
|
|
13303
|
+
}
|
|
13304
|
+
};
|
|
13305
|
+
}),
|
|
13150
13306
|
...actionProgress ? { actionProgress } : {},
|
|
13151
13307
|
findings,
|
|
13152
13308
|
workers,
|
|
@@ -13188,6 +13344,9 @@ var init_core3 = __esm(() => {
|
|
|
13188
13344
|
init_task_context();
|
|
13189
13345
|
init_methods();
|
|
13190
13346
|
init_route_intent();
|
|
13347
|
+
init_branch();
|
|
13348
|
+
init_runtime_identity();
|
|
13349
|
+
init_authority();
|
|
13191
13350
|
init_authority();
|
|
13192
13351
|
init_external_action();
|
|
13193
13352
|
init_external_action();
|
|
@@ -13252,8 +13411,8 @@ var hostRef = (handle) => ({ kind: "host", host: "cursor", handle }), cursorCapa
|
|
|
13252
13411
|
refs: [hostRef("sessionStart"), hostRef("preCompact")]
|
|
13253
13412
|
}
|
|
13254
13413
|
];
|
|
13255
|
-
},
|
|
13256
|
-
if (!
|
|
13414
|
+
}, isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), eventNames, nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "", parseCursorHookInput = (value) => {
|
|
13415
|
+
if (!isRecord2(value) || !eventNames.has(value.hook_event_name))
|
|
13257
13416
|
return { ok: false, error: "hook_event_name is required" };
|
|
13258
13417
|
const roots = value.workspace_roots;
|
|
13259
13418
|
if (!Array.isArray(roots) || roots.length !== 1 || !roots.every(nonEmpty2))
|
|
@@ -13391,7 +13550,7 @@ var hostRef = (handle) => ({ kind: "host", host: "cursor", handle }), cursorCapa
|
|
|
13391
13550
|
}, handleSubagentStop = () => ({}), handleCursorHook = (raw) => {
|
|
13392
13551
|
const parsed = parseCursorHookInput(raw);
|
|
13393
13552
|
if (!parsed.ok) {
|
|
13394
|
-
return
|
|
13553
|
+
return isRecord2(raw) && raw.hook_event_name === "sessionStart" ? {} : deny(parsed.error);
|
|
13395
13554
|
}
|
|
13396
13555
|
const input = parsed.data;
|
|
13397
13556
|
const root = realpathSync5(input.workspace_roots[0]);
|
|
@@ -13435,7 +13594,7 @@ ${invariantBootstrap()}${compact}
|
|
|
13435
13594
|
const output = handleCursorHook(input);
|
|
13436
13595
|
process.stdout.write(`${JSON.stringify(output)}
|
|
13437
13596
|
`);
|
|
13438
|
-
const event =
|
|
13597
|
+
const event = isRecord2(input) ? input.hook_event_name : undefined;
|
|
13439
13598
|
if (output.permission === "deny" && ["preToolUse", "beforeShellExecution", "subagentStart"].includes(String(event)))
|
|
13440
13599
|
process.exitCode = 2;
|
|
13441
13600
|
} catch {
|