@brainervirus/workit-cursor 8.14.0 → 8.14.1
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 +49 -11
- package/dist/mcp-server.js +49 -9
- package/dist/workit-hook.js +49 -9
- package/package.json +3 -3
|
@@ -7624,6 +7624,16 @@ var init_zod = __esm(() => {
|
|
|
7624
7624
|
|
|
7625
7625
|
// packages/workit-core/src/core/task-contract.ts
|
|
7626
7626
|
import { createHash, randomUUID } from "node:crypto";
|
|
7627
|
+
function resolveIdRef(kind, ref, ids) {
|
|
7628
|
+
if (ids.includes(ref))
|
|
7629
|
+
return success(null, null, ref);
|
|
7630
|
+
const matches = ids.filter((candidate) => candidate.startsWith(ref));
|
|
7631
|
+
if (matches.length === 1)
|
|
7632
|
+
return success(null, null, matches[0]);
|
|
7633
|
+
if (matches.length === 0)
|
|
7634
|
+
return failure2("not_found", `${kind} not found`);
|
|
7635
|
+
return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
|
|
7636
|
+
}
|
|
7627
7637
|
function parseOperation(family, input) {
|
|
7628
7638
|
if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
|
|
7629
7639
|
return failure2("unsupported_version", "unsupported schema version", { operation: family });
|
|
@@ -7726,7 +7736,7 @@ var SCHEMA_VERSION = 1, POLICY_VERSION = "1.0.0", OPERATION_FAMILIES, uuidPatter
|
|
|
7726
7736
|
return true;
|
|
7727
7737
|
}
|
|
7728
7738
|
return false;
|
|
7729
|
-
}, text, id, digest, revision, validUtc = (value) => {
|
|
7739
|
+
}, text, id, idRefPattern, idRef, digest, revision, validUtc = (value) => {
|
|
7730
7740
|
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?Z$/.exec(value);
|
|
7731
7741
|
if (!match)
|
|
7732
7742
|
return false;
|
|
@@ -7909,6 +7919,8 @@ var init_task_contract = __esm(() => {
|
|
|
7909
7919
|
ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
|
|
7910
7920
|
});
|
|
7911
7921
|
id = text.regex(uuidPattern, "expected lowercase UUID");
|
|
7922
|
+
idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
|
|
7923
|
+
idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
|
|
7912
7924
|
digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
|
|
7913
7925
|
revision = text.regex(uuidPattern, "expected UUID revision");
|
|
7914
7926
|
utcSchema = text.check((ctx) => {
|
|
@@ -8177,7 +8189,7 @@ var init_task_contract = __esm(() => {
|
|
|
8177
8189
|
outcome: _enum(["completed", "failed", "cancelled"]),
|
|
8178
8190
|
summary: text,
|
|
8179
8191
|
evidenceIds: array(id),
|
|
8180
|
-
findingIds: array(
|
|
8192
|
+
findingIds: array(idRef)
|
|
8181
8193
|
}).strict();
|
|
8182
8194
|
workerSchema = object({
|
|
8183
8195
|
assignment: assignmentSchema,
|
|
@@ -8369,7 +8381,7 @@ var init_task_contract = __esm(() => {
|
|
|
8369
8381
|
action: literal("resolve"),
|
|
8370
8382
|
...taskId,
|
|
8371
8383
|
expectedRevision: revision.optional(),
|
|
8372
|
-
findingId:
|
|
8384
|
+
findingId: idRef,
|
|
8373
8385
|
disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
|
|
8374
8386
|
reason: text,
|
|
8375
8387
|
evidenceIds: array(id),
|
|
@@ -8410,7 +8422,7 @@ var init_task_contract = __esm(() => {
|
|
|
8410
8422
|
...taskId,
|
|
8411
8423
|
expectedRevision: revision.optional(),
|
|
8412
8424
|
expectedWorkspaceRevision: revision.optional(),
|
|
8413
|
-
workerId:
|
|
8425
|
+
workerId: idRef,
|
|
8414
8426
|
report: workerReportSchema
|
|
8415
8427
|
}),
|
|
8416
8428
|
cancel: operation({
|
|
@@ -8418,7 +8430,7 @@ var init_task_contract = __esm(() => {
|
|
|
8418
8430
|
...taskId,
|
|
8419
8431
|
...revisions,
|
|
8420
8432
|
expectedWorkspaceRevision: revision.optional(),
|
|
8421
|
-
workerId:
|
|
8433
|
+
workerId: idRef,
|
|
8422
8434
|
reason: text
|
|
8423
8435
|
})
|
|
8424
8436
|
};
|
|
@@ -13462,20 +13474,26 @@ class TaskStore {
|
|
|
13462
13474
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
13463
13475
|
}
|
|
13464
13476
|
taskForWorker(workerId) {
|
|
13465
|
-
if (typeof workerId !== "string" || !
|
|
13477
|
+
if (typeof workerId !== "string" || !idRefPattern.test(workerId))
|
|
13466
13478
|
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
13467
13479
|
const listed = this.listTaskIndex();
|
|
13468
13480
|
if (!listed.ok)
|
|
13469
13481
|
return listed;
|
|
13482
|
+
const owners = new Map;
|
|
13470
13483
|
for (const entry of listed.data) {
|
|
13471
13484
|
if (entry.status === "closed")
|
|
13472
13485
|
continue;
|
|
13473
13486
|
const loaded = this.load(entry.id);
|
|
13474
13487
|
if (!loaded.ok)
|
|
13475
13488
|
return loaded;
|
|
13476
|
-
|
|
13477
|
-
|
|
13489
|
+
for (const worker of loaded.data?.record.workers ?? [])
|
|
13490
|
+
owners.set(worker.id, entry.id);
|
|
13478
13491
|
}
|
|
13492
|
+
const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
|
|
13493
|
+
if (resolved.ok)
|
|
13494
|
+
return success(null, null, owners.get(resolved.data) ?? null);
|
|
13495
|
+
if (resolved.code !== "not_found")
|
|
13496
|
+
return resolved;
|
|
13479
13497
|
return success(null, null, null);
|
|
13480
13498
|
}
|
|
13481
13499
|
originTaskEntry() {
|
|
@@ -16734,6 +16752,10 @@ class WorkitCore {
|
|
|
16734
16752
|
}
|
|
16735
16753
|
if (helper?.ok)
|
|
16736
16754
|
return failure2("permission_denied", "helpers cannot resolve findings");
|
|
16755
|
+
const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
|
|
16756
|
+
if (!findingRef.ok)
|
|
16757
|
+
return findingRef;
|
|
16758
|
+
input.findingId = findingRef.data;
|
|
16737
16759
|
const finding = task.data.findings.find((entry) => entry.id === input.findingId);
|
|
16738
16760
|
if (!finding)
|
|
16739
16761
|
return failure2("not_found", "finding not found");
|
|
@@ -16885,15 +16907,31 @@ class WorkitCore {
|
|
|
16885
16907
|
return changed;
|
|
16886
16908
|
return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
|
|
16887
16909
|
}
|
|
16910
|
+
const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
|
|
16911
|
+
if (!workerRef.ok)
|
|
16912
|
+
return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
|
|
16913
|
+
input.workerId = workerRef.data;
|
|
16888
16914
|
const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
16889
16915
|
if (!entry)
|
|
16890
16916
|
return failure2("not_found", "worker not found");
|
|
16891
16917
|
if (input.action === "report") {
|
|
16892
16918
|
if (helperId === null || helperId !== input.workerId)
|
|
16893
|
-
return failure2("permission_denied",
|
|
16919
|
+
return failure2("permission_denied", ONLY_OWN_REPORT);
|
|
16894
16920
|
const helper = this.helperEntry(task.data, true, true);
|
|
16895
16921
|
if (!helper.ok)
|
|
16896
16922
|
return helper;
|
|
16923
|
+
const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
|
|
16924
|
+
const reported = [];
|
|
16925
|
+
for (const findingRef of input.report.findingIds) {
|
|
16926
|
+
const found = resolveIdRef("finding", findingRef, ownFindings);
|
|
16927
|
+
if (found.ok)
|
|
16928
|
+
reported.push(found.data);
|
|
16929
|
+
else if (found.code === "not_found")
|
|
16930
|
+
reported.push(findingRef);
|
|
16931
|
+
else
|
|
16932
|
+
return found;
|
|
16933
|
+
}
|
|
16934
|
+
input.report.findingIds = reported;
|
|
16897
16935
|
const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
|
|
16898
16936
|
const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
|
|
16899
16937
|
if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
|
|
@@ -16921,7 +16959,7 @@ class WorkitCore {
|
|
|
16921
16959
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
|
|
16922
16960
|
}
|
|
16923
16961
|
if (helperId !== null)
|
|
16924
|
-
return failure2("permission_denied",
|
|
16962
|
+
return failure2("permission_denied", NO_HELPER_CONTROL);
|
|
16925
16963
|
if (task.data.status === "closed")
|
|
16926
16964
|
return failure2("invalid_transition", "closed task cannot cancel workers");
|
|
16927
16965
|
if (entry.data.state === "stopped") {
|
|
@@ -17450,7 +17488,7 @@ var MAX_JUDGED_REFS = 5, workspaceVerification = (root) => {
|
|
|
17450
17488
|
return changed;
|
|
17451
17489
|
const updated = changed.data.task.workers.find((candidate) => candidate.id === input.workerId);
|
|
17452
17490
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
|
|
17453
|
-
}, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS, WORKER_ADDRESSED_ACTIONS, workerCommand = (taskId, request) => {
|
|
17491
|
+
}, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS, ONLY_OWN_REPORT = "workers can submit only their own report", NO_HELPER_CONTROL = "helpers cannot cancel or control workers", WORKER_ADDRESSED_ACTIONS, workerCommand = (taskId, request) => {
|
|
17454
17492
|
const { action, workerId, reason, report } = request;
|
|
17455
17493
|
const rest = JSON.stringify({ reason, report });
|
|
17456
17494
|
const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
|
package/dist/mcp-server.js
CHANGED
|
@@ -16617,6 +16617,8 @@ var text = string2().check((ctx) => {
|
|
|
16617
16617
|
ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
|
|
16618
16618
|
});
|
|
16619
16619
|
var id = text.regex(uuidPattern, "expected lowercase UUID");
|
|
16620
|
+
var idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
|
|
16621
|
+
var idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
|
|
16620
16622
|
var digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
|
|
16621
16623
|
var revision = text.regex(uuidPattern, "expected UUID revision");
|
|
16622
16624
|
var validUtc = (value) => {
|
|
@@ -16994,7 +16996,7 @@ var workerReportSchema = object2({
|
|
|
16994
16996
|
outcome: _enum(["completed", "failed", "cancelled"]),
|
|
16995
16997
|
summary: text,
|
|
16996
16998
|
evidenceIds: array(id),
|
|
16997
|
-
findingIds: array(
|
|
16999
|
+
findingIds: array(idRef)
|
|
16998
17000
|
}).strict();
|
|
16999
17001
|
var workerSchema = object2({
|
|
17000
17002
|
assignment: assignmentSchema,
|
|
@@ -17240,7 +17242,7 @@ var findingOperations = {
|
|
|
17240
17242
|
action: literal("resolve"),
|
|
17241
17243
|
...taskId,
|
|
17242
17244
|
expectedRevision: revision.optional(),
|
|
17243
|
-
findingId:
|
|
17245
|
+
findingId: idRef,
|
|
17244
17246
|
disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
|
|
17245
17247
|
reason: text,
|
|
17246
17248
|
evidenceIds: array(id),
|
|
@@ -17281,7 +17283,7 @@ var workerOperations = {
|
|
|
17281
17283
|
...taskId,
|
|
17282
17284
|
expectedRevision: revision.optional(),
|
|
17283
17285
|
expectedWorkspaceRevision: revision.optional(),
|
|
17284
|
-
workerId:
|
|
17286
|
+
workerId: idRef,
|
|
17285
17287
|
report: workerReportSchema
|
|
17286
17288
|
}),
|
|
17287
17289
|
cancel: operation({
|
|
@@ -17289,7 +17291,7 @@ var workerOperations = {
|
|
|
17289
17291
|
...taskId,
|
|
17290
17292
|
...revisions,
|
|
17291
17293
|
expectedWorkspaceRevision: revision.optional(),
|
|
17292
|
-
workerId:
|
|
17294
|
+
workerId: idRef,
|
|
17293
17295
|
reason: text
|
|
17294
17296
|
})
|
|
17295
17297
|
};
|
|
@@ -17339,6 +17341,16 @@ var success = (revisionValue, workspaceRevisionValue, data) => ({
|
|
|
17339
17341
|
data
|
|
17340
17342
|
});
|
|
17341
17343
|
var failure2 = (code, error, details = {}) => ({ ok: false, schemaVersion: 1, code, error, details });
|
|
17344
|
+
function resolveIdRef(kind, ref, ids) {
|
|
17345
|
+
if (ids.includes(ref))
|
|
17346
|
+
return success(null, null, ref);
|
|
17347
|
+
const matches = ids.filter((candidate) => candidate.startsWith(ref));
|
|
17348
|
+
if (matches.length === 1)
|
|
17349
|
+
return success(null, null, matches[0]);
|
|
17350
|
+
if (matches.length === 0)
|
|
17351
|
+
return failure2("not_found", `${kind} not found`);
|
|
17352
|
+
return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
|
|
17353
|
+
}
|
|
17342
17354
|
function parseOperation(family, input) {
|
|
17343
17355
|
if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
|
|
17344
17356
|
return failure2("unsupported_version", "unsupported schema version", { operation: family });
|
|
@@ -19857,20 +19869,26 @@ class TaskStore {
|
|
|
19857
19869
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
19858
19870
|
}
|
|
19859
19871
|
taskForWorker(workerId) {
|
|
19860
|
-
if (typeof workerId !== "string" || !
|
|
19872
|
+
if (typeof workerId !== "string" || !idRefPattern.test(workerId))
|
|
19861
19873
|
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
19862
19874
|
const listed = this.listTaskIndex();
|
|
19863
19875
|
if (!listed.ok)
|
|
19864
19876
|
return listed;
|
|
19877
|
+
const owners = new Map;
|
|
19865
19878
|
for (const entry of listed.data) {
|
|
19866
19879
|
if (entry.status === "closed")
|
|
19867
19880
|
continue;
|
|
19868
19881
|
const loaded = this.load(entry.id);
|
|
19869
19882
|
if (!loaded.ok)
|
|
19870
19883
|
return loaded;
|
|
19871
|
-
|
|
19872
|
-
|
|
19884
|
+
for (const worker of loaded.data?.record.workers ?? [])
|
|
19885
|
+
owners.set(worker.id, entry.id);
|
|
19873
19886
|
}
|
|
19887
|
+
const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
|
|
19888
|
+
if (resolved.ok)
|
|
19889
|
+
return success(null, null, owners.get(resolved.data) ?? null);
|
|
19890
|
+
if (resolved.code !== "not_found")
|
|
19891
|
+
return resolved;
|
|
19874
19892
|
return success(null, null, null);
|
|
19875
19893
|
}
|
|
19876
19894
|
originTaskEntry() {
|
|
@@ -25588,6 +25606,8 @@ var TASK_SCOPED_ACTIONS = new Set([
|
|
|
25588
25606
|
"worker.cancel",
|
|
25589
25607
|
"state.export"
|
|
25590
25608
|
]);
|
|
25609
|
+
var ONLY_OWN_REPORT = "workers can submit only their own report";
|
|
25610
|
+
var NO_HELPER_CONTROL = "helpers cannot cancel or control workers";
|
|
25591
25611
|
var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
|
|
25592
25612
|
var workerCommand = (taskId, request) => {
|
|
25593
25613
|
const { action, workerId, reason, report } = request;
|
|
@@ -26485,6 +26505,10 @@ class WorkitCore {
|
|
|
26485
26505
|
}
|
|
26486
26506
|
if (helper?.ok)
|
|
26487
26507
|
return failure2("permission_denied", "helpers cannot resolve findings");
|
|
26508
|
+
const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
|
|
26509
|
+
if (!findingRef.ok)
|
|
26510
|
+
return findingRef;
|
|
26511
|
+
input.findingId = findingRef.data;
|
|
26488
26512
|
const finding = task.data.findings.find((entry) => entry.id === input.findingId);
|
|
26489
26513
|
if (!finding)
|
|
26490
26514
|
return failure2("not_found", "finding not found");
|
|
@@ -26636,15 +26660,31 @@ class WorkitCore {
|
|
|
26636
26660
|
return changed;
|
|
26637
26661
|
return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
|
|
26638
26662
|
}
|
|
26663
|
+
const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
|
|
26664
|
+
if (!workerRef.ok)
|
|
26665
|
+
return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
|
|
26666
|
+
input.workerId = workerRef.data;
|
|
26639
26667
|
const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
26640
26668
|
if (!entry)
|
|
26641
26669
|
return failure2("not_found", "worker not found");
|
|
26642
26670
|
if (input.action === "report") {
|
|
26643
26671
|
if (helperId === null || helperId !== input.workerId)
|
|
26644
|
-
return failure2("permission_denied",
|
|
26672
|
+
return failure2("permission_denied", ONLY_OWN_REPORT);
|
|
26645
26673
|
const helper = this.helperEntry(task.data, true, true);
|
|
26646
26674
|
if (!helper.ok)
|
|
26647
26675
|
return helper;
|
|
26676
|
+
const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
|
|
26677
|
+
const reported = [];
|
|
26678
|
+
for (const findingRef of input.report.findingIds) {
|
|
26679
|
+
const found = resolveIdRef("finding", findingRef, ownFindings);
|
|
26680
|
+
if (found.ok)
|
|
26681
|
+
reported.push(found.data);
|
|
26682
|
+
else if (found.code === "not_found")
|
|
26683
|
+
reported.push(findingRef);
|
|
26684
|
+
else
|
|
26685
|
+
return found;
|
|
26686
|
+
}
|
|
26687
|
+
input.report.findingIds = reported;
|
|
26648
26688
|
const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
|
|
26649
26689
|
const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
|
|
26650
26690
|
if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
|
|
@@ -26672,7 +26712,7 @@ class WorkitCore {
|
|
|
26672
26712
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
|
|
26673
26713
|
}
|
|
26674
26714
|
if (helperId !== null)
|
|
26675
|
-
return failure2("permission_denied",
|
|
26715
|
+
return failure2("permission_denied", NO_HELPER_CONTROL);
|
|
26676
26716
|
if (task.data.status === "closed")
|
|
26677
26717
|
return failure2("invalid_transition", "closed task cannot cancel workers");
|
|
26678
26718
|
if (entry.data.state === "stopped") {
|
package/dist/workit-hook.js
CHANGED
|
@@ -7548,6 +7548,8 @@ var text = string2().check((ctx) => {
|
|
|
7548
7548
|
ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
|
|
7549
7549
|
});
|
|
7550
7550
|
var id = text.regex(uuidPattern, "expected lowercase UUID");
|
|
7551
|
+
var idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
|
|
7552
|
+
var idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
|
|
7551
7553
|
var digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
|
|
7552
7554
|
var revision = text.regex(uuidPattern, "expected UUID revision");
|
|
7553
7555
|
var validUtc = (value) => {
|
|
@@ -7925,7 +7927,7 @@ var workerReportSchema = object({
|
|
|
7925
7927
|
outcome: _enum(["completed", "failed", "cancelled"]),
|
|
7926
7928
|
summary: text,
|
|
7927
7929
|
evidenceIds: array(id),
|
|
7928
|
-
findingIds: array(
|
|
7930
|
+
findingIds: array(idRef)
|
|
7929
7931
|
}).strict();
|
|
7930
7932
|
var workerSchema = object({
|
|
7931
7933
|
assignment: assignmentSchema,
|
|
@@ -8171,7 +8173,7 @@ var findingOperations = {
|
|
|
8171
8173
|
action: literal("resolve"),
|
|
8172
8174
|
...taskId,
|
|
8173
8175
|
expectedRevision: revision.optional(),
|
|
8174
|
-
findingId:
|
|
8176
|
+
findingId: idRef,
|
|
8175
8177
|
disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
|
|
8176
8178
|
reason: text,
|
|
8177
8179
|
evidenceIds: array(id),
|
|
@@ -8212,7 +8214,7 @@ var workerOperations = {
|
|
|
8212
8214
|
...taskId,
|
|
8213
8215
|
expectedRevision: revision.optional(),
|
|
8214
8216
|
expectedWorkspaceRevision: revision.optional(),
|
|
8215
|
-
workerId:
|
|
8217
|
+
workerId: idRef,
|
|
8216
8218
|
report: workerReportSchema
|
|
8217
8219
|
}),
|
|
8218
8220
|
cancel: operation({
|
|
@@ -8220,7 +8222,7 @@ var workerOperations = {
|
|
|
8220
8222
|
...taskId,
|
|
8221
8223
|
...revisions,
|
|
8222
8224
|
expectedWorkspaceRevision: revision.optional(),
|
|
8223
|
-
workerId:
|
|
8225
|
+
workerId: idRef,
|
|
8224
8226
|
reason: text
|
|
8225
8227
|
})
|
|
8226
8228
|
};
|
|
@@ -8270,6 +8272,16 @@ var success = (revisionValue, workspaceRevisionValue, data) => ({
|
|
|
8270
8272
|
data
|
|
8271
8273
|
});
|
|
8272
8274
|
var failure2 = (code, error, details = {}) => ({ ok: false, schemaVersion: 1, code, error, details });
|
|
8275
|
+
function resolveIdRef(kind, ref, ids) {
|
|
8276
|
+
if (ids.includes(ref))
|
|
8277
|
+
return success(null, null, ref);
|
|
8278
|
+
const matches = ids.filter((candidate) => candidate.startsWith(ref));
|
|
8279
|
+
if (matches.length === 1)
|
|
8280
|
+
return success(null, null, matches[0]);
|
|
8281
|
+
if (matches.length === 0)
|
|
8282
|
+
return failure2("not_found", `${kind} not found`);
|
|
8283
|
+
return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
|
|
8284
|
+
}
|
|
8273
8285
|
function parseOperation(family, input) {
|
|
8274
8286
|
if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
|
|
8275
8287
|
return failure2("unsupported_version", "unsupported schema version", { operation: family });
|
|
@@ -13631,20 +13643,26 @@ class TaskStore {
|
|
|
13631
13643
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
13632
13644
|
}
|
|
13633
13645
|
taskForWorker(workerId) {
|
|
13634
|
-
if (typeof workerId !== "string" || !
|
|
13646
|
+
if (typeof workerId !== "string" || !idRefPattern.test(workerId))
|
|
13635
13647
|
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
13636
13648
|
const listed = this.listTaskIndex();
|
|
13637
13649
|
if (!listed.ok)
|
|
13638
13650
|
return listed;
|
|
13651
|
+
const owners = new Map;
|
|
13639
13652
|
for (const entry of listed.data) {
|
|
13640
13653
|
if (entry.status === "closed")
|
|
13641
13654
|
continue;
|
|
13642
13655
|
const loaded = this.load(entry.id);
|
|
13643
13656
|
if (!loaded.ok)
|
|
13644
13657
|
return loaded;
|
|
13645
|
-
|
|
13646
|
-
|
|
13658
|
+
for (const worker of loaded.data?.record.workers ?? [])
|
|
13659
|
+
owners.set(worker.id, entry.id);
|
|
13647
13660
|
}
|
|
13661
|
+
const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
|
|
13662
|
+
if (resolved.ok)
|
|
13663
|
+
return success(null, null, owners.get(resolved.data) ?? null);
|
|
13664
|
+
if (resolved.code !== "not_found")
|
|
13665
|
+
return resolved;
|
|
13648
13666
|
return success(null, null, null);
|
|
13649
13667
|
}
|
|
13650
13668
|
originTaskEntry() {
|
|
@@ -16270,6 +16288,8 @@ var TASK_SCOPED_ACTIONS = new Set([
|
|
|
16270
16288
|
"worker.cancel",
|
|
16271
16289
|
"state.export"
|
|
16272
16290
|
]);
|
|
16291
|
+
var ONLY_OWN_REPORT = "workers can submit only their own report";
|
|
16292
|
+
var NO_HELPER_CONTROL = "helpers cannot cancel or control workers";
|
|
16273
16293
|
var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
|
|
16274
16294
|
var workerCommand = (taskId, request) => {
|
|
16275
16295
|
const { action, workerId, reason, report } = request;
|
|
@@ -17167,6 +17187,10 @@ class WorkitCore {
|
|
|
17167
17187
|
}
|
|
17168
17188
|
if (helper?.ok)
|
|
17169
17189
|
return failure2("permission_denied", "helpers cannot resolve findings");
|
|
17190
|
+
const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
|
|
17191
|
+
if (!findingRef.ok)
|
|
17192
|
+
return findingRef;
|
|
17193
|
+
input.findingId = findingRef.data;
|
|
17170
17194
|
const finding = task.data.findings.find((entry) => entry.id === input.findingId);
|
|
17171
17195
|
if (!finding)
|
|
17172
17196
|
return failure2("not_found", "finding not found");
|
|
@@ -17318,15 +17342,31 @@ class WorkitCore {
|
|
|
17318
17342
|
return changed;
|
|
17319
17343
|
return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
|
|
17320
17344
|
}
|
|
17345
|
+
const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
|
|
17346
|
+
if (!workerRef.ok)
|
|
17347
|
+
return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
|
|
17348
|
+
input.workerId = workerRef.data;
|
|
17321
17349
|
const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
17322
17350
|
if (!entry)
|
|
17323
17351
|
return failure2("not_found", "worker not found");
|
|
17324
17352
|
if (input.action === "report") {
|
|
17325
17353
|
if (helperId === null || helperId !== input.workerId)
|
|
17326
|
-
return failure2("permission_denied",
|
|
17354
|
+
return failure2("permission_denied", ONLY_OWN_REPORT);
|
|
17327
17355
|
const helper = this.helperEntry(task.data, true, true);
|
|
17328
17356
|
if (!helper.ok)
|
|
17329
17357
|
return helper;
|
|
17358
|
+
const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
|
|
17359
|
+
const reported = [];
|
|
17360
|
+
for (const findingRef of input.report.findingIds) {
|
|
17361
|
+
const found = resolveIdRef("finding", findingRef, ownFindings);
|
|
17362
|
+
if (found.ok)
|
|
17363
|
+
reported.push(found.data);
|
|
17364
|
+
else if (found.code === "not_found")
|
|
17365
|
+
reported.push(findingRef);
|
|
17366
|
+
else
|
|
17367
|
+
return found;
|
|
17368
|
+
}
|
|
17369
|
+
input.report.findingIds = reported;
|
|
17330
17370
|
const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
|
|
17331
17371
|
const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
|
|
17332
17372
|
if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
|
|
@@ -17354,7 +17394,7 @@ class WorkitCore {
|
|
|
17354
17394
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
|
|
17355
17395
|
}
|
|
17356
17396
|
if (helperId !== null)
|
|
17357
|
-
return failure2("permission_denied",
|
|
17397
|
+
return failure2("permission_denied", NO_HELPER_CONTROL);
|
|
17358
17398
|
if (task.data.status === "closed")
|
|
17359
17399
|
return failure2("invalid_transition", "closed task cannot cancel workers");
|
|
17360
17400
|
if (entry.data.state === "stopped") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cursor",
|
|
3
|
-
"version": "8.14.
|
|
3
|
+
"version": "8.14.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit Cursor plugin — shared MCP transport, native hooks, and sixteen method skills",
|
|
6
6
|
"keywords": [
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"build": "bun scripts/build.ts"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@brainervirus/workit-core": "^8.14.
|
|
50
|
-
"@brainervirus/workit-mcp": "^8.14.
|
|
49
|
+
"@brainervirus/workit-core": "^8.14.1",
|
|
50
|
+
"@brainervirus/workit-mcp": "^8.14.1"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=24"
|