@brainervirus/workit-codex 8.14.0 → 8.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/launch-mcp.js
CHANGED
|
@@ -14236,6 +14236,8 @@ var text = string2().check((ctx) => {
|
|
|
14236
14236
|
ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
|
|
14237
14237
|
});
|
|
14238
14238
|
var id = text.regex(uuidPattern, "expected lowercase UUID");
|
|
14239
|
+
var idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
|
|
14240
|
+
var idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
|
|
14239
14241
|
var digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
|
|
14240
14242
|
var revision = text.regex(uuidPattern, "expected UUID revision");
|
|
14241
14243
|
var validUtc = (value) => {
|
|
@@ -14613,7 +14615,7 @@ var workerReportSchema = object({
|
|
|
14613
14615
|
outcome: _enum(["completed", "failed", "cancelled"]),
|
|
14614
14616
|
summary: text,
|
|
14615
14617
|
evidenceIds: array(id),
|
|
14616
|
-
findingIds: array(
|
|
14618
|
+
findingIds: array(idRef)
|
|
14617
14619
|
}).strict();
|
|
14618
14620
|
var workerSchema = object({
|
|
14619
14621
|
assignment: assignmentSchema,
|
|
@@ -14859,7 +14861,7 @@ var findingOperations = {
|
|
|
14859
14861
|
action: literal("resolve"),
|
|
14860
14862
|
...taskId,
|
|
14861
14863
|
expectedRevision: revision.optional(),
|
|
14862
|
-
findingId:
|
|
14864
|
+
findingId: idRef,
|
|
14863
14865
|
disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
|
|
14864
14866
|
reason: text,
|
|
14865
14867
|
evidenceIds: array(id),
|
|
@@ -14900,7 +14902,7 @@ var workerOperations = {
|
|
|
14900
14902
|
...taskId,
|
|
14901
14903
|
expectedRevision: revision.optional(),
|
|
14902
14904
|
expectedWorkspaceRevision: revision.optional(),
|
|
14903
|
-
workerId:
|
|
14905
|
+
workerId: idRef,
|
|
14904
14906
|
report: workerReportSchema
|
|
14905
14907
|
}),
|
|
14906
14908
|
cancel: operation({
|
|
@@ -14908,7 +14910,7 @@ var workerOperations = {
|
|
|
14908
14910
|
...taskId,
|
|
14909
14911
|
...revisions,
|
|
14910
14912
|
expectedWorkspaceRevision: revision.optional(),
|
|
14911
|
-
workerId:
|
|
14913
|
+
workerId: idRef,
|
|
14912
14914
|
reason: text
|
|
14913
14915
|
})
|
|
14914
14916
|
};
|
|
@@ -14958,6 +14960,16 @@ var success = (revisionValue, workspaceRevisionValue, data) => ({
|
|
|
14958
14960
|
data
|
|
14959
14961
|
});
|
|
14960
14962
|
var failure2 = (code, error, details = {}) => ({ ok: false, schemaVersion: 1, code, error, details });
|
|
14963
|
+
function resolveIdRef(kind, ref, ids) {
|
|
14964
|
+
if (ids.includes(ref))
|
|
14965
|
+
return success(null, null, ref);
|
|
14966
|
+
const matches = ids.filter((candidate) => candidate.startsWith(ref));
|
|
14967
|
+
if (matches.length === 1)
|
|
14968
|
+
return success(null, null, matches[0]);
|
|
14969
|
+
if (matches.length === 0)
|
|
14970
|
+
return failure2("not_found", `${kind} not found`);
|
|
14971
|
+
return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
|
|
14972
|
+
}
|
|
14961
14973
|
function parseOperation(family, input) {
|
|
14962
14974
|
if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
|
|
14963
14975
|
return failure2("unsupported_version", "unsupported schema version", { operation: family });
|
|
@@ -17476,20 +17488,26 @@ class TaskStore {
|
|
|
17476
17488
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
17477
17489
|
}
|
|
17478
17490
|
taskForWorker(workerId) {
|
|
17479
|
-
if (typeof workerId !== "string" || !
|
|
17491
|
+
if (typeof workerId !== "string" || !idRefPattern.test(workerId))
|
|
17480
17492
|
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
17481
17493
|
const listed = this.listTaskIndex();
|
|
17482
17494
|
if (!listed.ok)
|
|
17483
17495
|
return listed;
|
|
17496
|
+
const owners = new Map;
|
|
17484
17497
|
for (const entry of listed.data) {
|
|
17485
17498
|
if (entry.status === "closed")
|
|
17486
17499
|
continue;
|
|
17487
17500
|
const loaded = this.load(entry.id);
|
|
17488
17501
|
if (!loaded.ok)
|
|
17489
17502
|
return loaded;
|
|
17490
|
-
|
|
17491
|
-
|
|
17503
|
+
for (const worker of loaded.data?.record.workers ?? [])
|
|
17504
|
+
owners.set(worker.id, entry.id);
|
|
17492
17505
|
}
|
|
17506
|
+
const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
|
|
17507
|
+
if (resolved.ok)
|
|
17508
|
+
return success(null, null, owners.get(resolved.data) ?? null);
|
|
17509
|
+
if (resolved.code !== "not_found")
|
|
17510
|
+
return resolved;
|
|
17493
17511
|
return success(null, null, null);
|
|
17494
17512
|
}
|
|
17495
17513
|
originTaskEntry() {
|
|
@@ -19609,20 +19627,19 @@ var workspaceConfigSchema = object({
|
|
|
19609
19627
|
union([boolean2(), literal("verified")]).optional()
|
|
19610
19628
|
]))).passthrough().optional(),
|
|
19611
19629
|
youtrack: object({ baseUrl: nonBlank.optional(), link_issues: boolean2().optional() }).passthrough().optional(),
|
|
19612
|
-
issues: object({
|
|
19630
|
+
issues: object({
|
|
19631
|
+
provider: _enum(["github", "gitlab", "youtrack"]).optional(),
|
|
19632
|
+
link: boolean2().optional(),
|
|
19633
|
+
relation: unknown().optional(),
|
|
19634
|
+
backlink: boolean2().optional(),
|
|
19635
|
+
link_on_pr: boolean2().optional()
|
|
19636
|
+
}).passthrough().optional(),
|
|
19613
19637
|
branchPolicy: workspaceBranchPolicySchema.optional(),
|
|
19614
19638
|
commitPolicy: workspaceCommitPolicySchema.optional(),
|
|
19615
19639
|
defaultProfile: nonBlank.optional(),
|
|
19616
19640
|
profiles: record(nonBlank, workspaceProfileSchema).optional(),
|
|
19617
19641
|
releaseTracks: record(nonBlank, releaseTrackSchema).optional()
|
|
19618
19642
|
}).passthrough().superRefine((workspace, context) => {
|
|
19619
|
-
if (workspace.issues && workspace.vcs?.provider !== "github") {
|
|
19620
|
-
context.addIssue({
|
|
19621
|
-
code: "custom",
|
|
19622
|
-
path: ["issues"],
|
|
19623
|
-
message: `GitHub issue linking requires the github provider, got ${workspace.vcs?.provider ?? "unset"}`
|
|
19624
|
-
});
|
|
19625
|
-
}
|
|
19626
19643
|
if (workspace.defaultProfile !== undefined && !Object.hasOwn(workspace.profiles ?? {}, workspace.defaultProfile)) {
|
|
19627
19644
|
context.addIssue({
|
|
19628
19645
|
code: "custom",
|
|
@@ -20462,6 +20479,44 @@ var readVcsConfig = () => {
|
|
|
20462
20479
|
}
|
|
20463
20480
|
return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
|
|
20464
20481
|
};
|
|
20482
|
+
var TRACKERS = new Set(["github", "gitlab", "youtrack"]);
|
|
20483
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
20484
|
+
var flag = (value) => typeof value === "boolean" ? value : null;
|
|
20485
|
+
var text2 = (value) => typeof value === "string" && value.trim() ? value.trim() : null;
|
|
20486
|
+
function issueTrackerOf(issues, youtrack) {
|
|
20487
|
+
const iss = asRecord(issues);
|
|
20488
|
+
const yt = asRecord(youtrack);
|
|
20489
|
+
const warnings = [];
|
|
20490
|
+
const named = typeof iss.provider === "string" && TRACKERS.has(iss.provider.toLowerCase()) ? iss.provider.toLowerCase() : null;
|
|
20491
|
+
if (iss.relation !== undefined && iss.relation !== "closes" && iss.relation !== "refs")
|
|
20492
|
+
warnings.push(`issues.relation ${JSON.stringify(iss.relation)} is not closes or refs; read as closes`);
|
|
20493
|
+
for (const key of ["repo", "host"])
|
|
20494
|
+
if (iss[key] !== undefined && text2(iss[key]) === null)
|
|
20495
|
+
warnings.push(`issues.${key} is not a non-empty string; ignored`);
|
|
20496
|
+
const common = {
|
|
20497
|
+
relation: iss.relation === "refs" ? "refs" : "closes",
|
|
20498
|
+
backlink: iss.backlink === true,
|
|
20499
|
+
baseUrl: text2(yt.baseUrl),
|
|
20500
|
+
repo: text2(iss.repo)?.replace(/^\/+|\/+$/gu, "") ?? null,
|
|
20501
|
+
host: text2(iss.host)?.toLowerCase() ?? null,
|
|
20502
|
+
warnings
|
|
20503
|
+
};
|
|
20504
|
+
const legacyGithub = named === "github" && flag(iss.link) === null;
|
|
20505
|
+
if (flag(yt.link_issues) === true && (named === null || legacyGithub))
|
|
20506
|
+
return { provider: "youtrack", link: true, ...common, source: "youtrack.link_issues" };
|
|
20507
|
+
if (named) {
|
|
20508
|
+
const link = flag(iss.link) ?? flag(iss.link_on_pr) ?? (named === "youtrack" ? flag(yt.link_issues) : null) ?? false;
|
|
20509
|
+
return {
|
|
20510
|
+
provider: named,
|
|
20511
|
+
link,
|
|
20512
|
+
...common,
|
|
20513
|
+
source: flag(iss.link) === null && flag(iss.link_on_pr) !== null ? "issues.link_on_pr" : "issues"
|
|
20514
|
+
};
|
|
20515
|
+
}
|
|
20516
|
+
if (common.baseUrl)
|
|
20517
|
+
return { provider: "youtrack", link: false, ...common, source: "youtrack.baseUrl" };
|
|
20518
|
+
return null;
|
|
20519
|
+
}
|
|
20465
20520
|
var trackSummary = (resolution) => resolution.status === "resolved" ? {
|
|
20466
20521
|
name: resolution.track?.name ?? null,
|
|
20467
20522
|
source: resolution.source,
|
|
@@ -20482,6 +20537,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
20482
20537
|
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
20483
20538
|
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
20484
20539
|
const workspaceDefault = workspaceDefaultTarget(root, cfg.defaultTargetBranch);
|
|
20540
|
+
const issueTracker = issueTrackerOf(wsIssues, wsYt);
|
|
20485
20541
|
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
20486
20542
|
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
20487
20543
|
let issuesProvider = null;
|
|
@@ -20514,7 +20570,8 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
20514
20570
|
link_issues: linkIssues,
|
|
20515
20571
|
youtrack_base_url: youtrackBaseUrl,
|
|
20516
20572
|
issues_provider: issuesProvider,
|
|
20517
|
-
link_on_pr: linkOnPr
|
|
20573
|
+
link_on_pr: linkOnPr,
|
|
20574
|
+
issue_tracker: issueTracker
|
|
20518
20575
|
};
|
|
20519
20576
|
}
|
|
20520
20577
|
if (cfgStatus === "malformed") {
|
|
@@ -20540,7 +20597,8 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
20540
20597
|
link_issues: linkIssues,
|
|
20541
20598
|
youtrack_base_url: youtrackBaseUrl,
|
|
20542
20599
|
issues_provider: issuesProvider,
|
|
20543
|
-
link_on_pr: linkOnPr
|
|
20600
|
+
link_on_pr: linkOnPr,
|
|
20601
|
+
issue_tracker: issueTracker
|
|
20544
20602
|
};
|
|
20545
20603
|
if (provider === "gitlab") {
|
|
20546
20604
|
out.gitlab = {
|
|
@@ -20644,7 +20702,12 @@ var MAX_LINE_BYTES = 4096;
|
|
|
20644
20702
|
var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
|
|
20645
20703
|
var FAILING = new Set(["failed", "blocked"]);
|
|
20646
20704
|
var STRONG_RESULTS = new Set(["verified", "tests-verified"]);
|
|
20647
|
-
var PR_ROW_TYPES = new Set([
|
|
20705
|
+
var PR_ROW_TYPES = new Set([
|
|
20706
|
+
"pr.created",
|
|
20707
|
+
"pr.status",
|
|
20708
|
+
"pr.merged",
|
|
20709
|
+
"pr.linked"
|
|
20710
|
+
]);
|
|
20648
20711
|
var err = (code, error, unblock) => ({
|
|
20649
20712
|
ok: false,
|
|
20650
20713
|
code,
|
|
@@ -22781,7 +22844,7 @@ var RISK = {
|
|
|
22781
22844
|
};
|
|
22782
22845
|
var YES = new Set(["true", "yes", "y", "1", "on"]);
|
|
22783
22846
|
var NO = new Set(["false", "no", "n", "0", "off", "none"]);
|
|
22784
|
-
var
|
|
22847
|
+
var flag2 = (value, unknownAs) => {
|
|
22785
22848
|
if (typeof value === "boolean")
|
|
22786
22849
|
return { ok: true, value };
|
|
22787
22850
|
if (typeof value === "number" && (value === 0 || value === 1))
|
|
@@ -22847,12 +22910,12 @@ function normalizeJudgment(raw, previous) {
|
|
|
22847
22910
|
const items = Array.isArray(value) ? value : [value];
|
|
22848
22911
|
judgment.refs.push(...items.filter((item) => item !== null && item !== "").map(refOf));
|
|
22849
22912
|
} else {
|
|
22850
|
-
if (name === "needsPlan" && typeof value === "string" && !
|
|
22913
|
+
if (name === "needsPlan" && typeof value === "string" && !flag2(value, false).ok && value.trim()) {
|
|
22851
22914
|
judgment.needsPlan = true;
|
|
22852
22915
|
judgment.refs.push(refOf(value.trim()));
|
|
22853
22916
|
continue;
|
|
22854
22917
|
}
|
|
22855
|
-
const parsed =
|
|
22918
|
+
const parsed = flag2(value, name === "behaviorChange");
|
|
22856
22919
|
if (parsed.ok)
|
|
22857
22920
|
judgment[name] = parsed.value;
|
|
22858
22921
|
else
|
|
@@ -23207,6 +23270,8 @@ var TASK_SCOPED_ACTIONS = new Set([
|
|
|
23207
23270
|
"worker.cancel",
|
|
23208
23271
|
"state.export"
|
|
23209
23272
|
]);
|
|
23273
|
+
var ONLY_OWN_REPORT = "workers can submit only their own report";
|
|
23274
|
+
var NO_HELPER_CONTROL = "helpers cannot cancel or control workers";
|
|
23210
23275
|
var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
|
|
23211
23276
|
var workerCommand = (taskId, request) => {
|
|
23212
23277
|
const { action, workerId, reason, report } = request;
|
|
@@ -24104,6 +24169,10 @@ class WorkitCore {
|
|
|
24104
24169
|
}
|
|
24105
24170
|
if (helper?.ok)
|
|
24106
24171
|
return failure2("permission_denied", "helpers cannot resolve findings");
|
|
24172
|
+
const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
|
|
24173
|
+
if (!findingRef.ok)
|
|
24174
|
+
return findingRef;
|
|
24175
|
+
input.findingId = findingRef.data;
|
|
24107
24176
|
const finding = task.data.findings.find((entry) => entry.id === input.findingId);
|
|
24108
24177
|
if (!finding)
|
|
24109
24178
|
return failure2("not_found", "finding not found");
|
|
@@ -24255,15 +24324,31 @@ class WorkitCore {
|
|
|
24255
24324
|
return changed;
|
|
24256
24325
|
return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
|
|
24257
24326
|
}
|
|
24327
|
+
const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
|
|
24328
|
+
if (!workerRef.ok)
|
|
24329
|
+
return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
|
|
24330
|
+
input.workerId = workerRef.data;
|
|
24258
24331
|
const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
24259
24332
|
if (!entry)
|
|
24260
24333
|
return failure2("not_found", "worker not found");
|
|
24261
24334
|
if (input.action === "report") {
|
|
24262
24335
|
if (helperId === null || helperId !== input.workerId)
|
|
24263
|
-
return failure2("permission_denied",
|
|
24336
|
+
return failure2("permission_denied", ONLY_OWN_REPORT);
|
|
24264
24337
|
const helper = this.helperEntry(task.data, true, true);
|
|
24265
24338
|
if (!helper.ok)
|
|
24266
24339
|
return helper;
|
|
24340
|
+
const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
|
|
24341
|
+
const reported = [];
|
|
24342
|
+
for (const findingRef of input.report.findingIds) {
|
|
24343
|
+
const found = resolveIdRef("finding", findingRef, ownFindings);
|
|
24344
|
+
if (found.ok)
|
|
24345
|
+
reported.push(found.data);
|
|
24346
|
+
else if (found.code === "not_found")
|
|
24347
|
+
reported.push(findingRef);
|
|
24348
|
+
else
|
|
24349
|
+
return found;
|
|
24350
|
+
}
|
|
24351
|
+
input.report.findingIds = reported;
|
|
24267
24352
|
const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
|
|
24268
24353
|
const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
|
|
24269
24354
|
if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
|
|
@@ -24291,7 +24376,7 @@ class WorkitCore {
|
|
|
24291
24376
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
|
|
24292
24377
|
}
|
|
24293
24378
|
if (helperId !== null)
|
|
24294
|
-
return failure2("permission_denied",
|
|
24379
|
+
return failure2("permission_denied", NO_HELPER_CONTROL);
|
|
24295
24380
|
if (task.data.status === "closed")
|
|
24296
24381
|
return failure2("invalid_transition", "closed task cannot cancel workers");
|
|
24297
24382
|
if (entry.data.state === "stopped") {
|
|
@@ -7966,6 +7966,8 @@ var text = string2().check((ctx) => {
|
|
|
7966
7966
|
ctx.issues.push({ code: "custom", input: ctx.value, message: "invalid Unicode", path: [] });
|
|
7967
7967
|
});
|
|
7968
7968
|
var id = text.regex(uuidPattern, "expected lowercase UUID");
|
|
7969
|
+
var idRefPattern = /^[0-9a-f][0-9a-f-]{7,35}$/;
|
|
7970
|
+
var idRef = text.regex(idRefPattern, "expected a UUID or an id prefix of 8+ characters");
|
|
7969
7971
|
var digest = text.regex(digestPattern, "expected lowercase SHA-256 digest");
|
|
7970
7972
|
var revision = text.regex(uuidPattern, "expected UUID revision");
|
|
7971
7973
|
var validUtc = (value) => {
|
|
@@ -8343,7 +8345,7 @@ var workerReportSchema = object({
|
|
|
8343
8345
|
outcome: _enum(["completed", "failed", "cancelled"]),
|
|
8344
8346
|
summary: text,
|
|
8345
8347
|
evidenceIds: array(id),
|
|
8346
|
-
findingIds: array(
|
|
8348
|
+
findingIds: array(idRef)
|
|
8347
8349
|
}).strict();
|
|
8348
8350
|
var workerSchema = object({
|
|
8349
8351
|
assignment: assignmentSchema,
|
|
@@ -8589,7 +8591,7 @@ var findingOperations = {
|
|
|
8589
8591
|
action: literal("resolve"),
|
|
8590
8592
|
...taskId,
|
|
8591
8593
|
expectedRevision: revision.optional(),
|
|
8592
|
-
findingId:
|
|
8594
|
+
findingId: idRef,
|
|
8593
8595
|
disposition: _enum(["open", "fixed", "dismissed", "deferred"]),
|
|
8594
8596
|
reason: text,
|
|
8595
8597
|
evidenceIds: array(id),
|
|
@@ -8630,7 +8632,7 @@ var workerOperations = {
|
|
|
8630
8632
|
...taskId,
|
|
8631
8633
|
expectedRevision: revision.optional(),
|
|
8632
8634
|
expectedWorkspaceRevision: revision.optional(),
|
|
8633
|
-
workerId:
|
|
8635
|
+
workerId: idRef,
|
|
8634
8636
|
report: workerReportSchema
|
|
8635
8637
|
}),
|
|
8636
8638
|
cancel: operation({
|
|
@@ -8638,7 +8640,7 @@ var workerOperations = {
|
|
|
8638
8640
|
...taskId,
|
|
8639
8641
|
...revisions,
|
|
8640
8642
|
expectedWorkspaceRevision: revision.optional(),
|
|
8641
|
-
workerId:
|
|
8643
|
+
workerId: idRef,
|
|
8642
8644
|
reason: text
|
|
8643
8645
|
})
|
|
8644
8646
|
};
|
|
@@ -8688,6 +8690,16 @@ var success = (revisionValue, workspaceRevisionValue, data) => ({
|
|
|
8688
8690
|
data
|
|
8689
8691
|
});
|
|
8690
8692
|
var failure2 = (code, error, details = {}) => ({ ok: false, schemaVersion: 1, code, error, details });
|
|
8693
|
+
function resolveIdRef(kind, ref, ids) {
|
|
8694
|
+
if (ids.includes(ref))
|
|
8695
|
+
return success(null, null, ref);
|
|
8696
|
+
const matches = ids.filter((candidate) => candidate.startsWith(ref));
|
|
8697
|
+
if (matches.length === 1)
|
|
8698
|
+
return success(null, null, matches[0]);
|
|
8699
|
+
if (matches.length === 0)
|
|
8700
|
+
return failure2("not_found", `${kind} not found`);
|
|
8701
|
+
return failure2("invalid_input", `${kind} prefix ${ref} is ambiguous; candidates: ${matches.join(", ")}`);
|
|
8702
|
+
}
|
|
8691
8703
|
function parseOperation(family, input) {
|
|
8692
8704
|
if (typeof input === "object" && input !== null && "schemaVersion" in input && input.schemaVersion !== SCHEMA_VERSION)
|
|
8693
8705
|
return failure2("unsupported_version", "unsupported schema version", { operation: family });
|
|
@@ -9934,7 +9946,7 @@ var removeIfEmpty = (dir) => {
|
|
|
9934
9946
|
};
|
|
9935
9947
|
var tokenHash = (token) => createHash4("sha256").update(token).digest("hex");
|
|
9936
9948
|
function recordIssuedSession(cwd, lead, issued) {
|
|
9937
|
-
const token = randomBytes2(18).toString("
|
|
9949
|
+
const token = randomBytes2(18).toString("hex");
|
|
9938
9950
|
try {
|
|
9939
9951
|
migrateRepoIssued(cwd);
|
|
9940
9952
|
const own = hash(issued);
|
|
@@ -10937,20 +10949,26 @@ class TaskStore {
|
|
|
10937
10949
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
10938
10950
|
}
|
|
10939
10951
|
taskForWorker(workerId) {
|
|
10940
|
-
if (typeof workerId !== "string" || !
|
|
10952
|
+
if (typeof workerId !== "string" || !idRefPattern.test(workerId))
|
|
10941
10953
|
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
10942
10954
|
const listed = this.listTaskIndex();
|
|
10943
10955
|
if (!listed.ok)
|
|
10944
10956
|
return listed;
|
|
10957
|
+
const owners = new Map;
|
|
10945
10958
|
for (const entry of listed.data) {
|
|
10946
10959
|
if (entry.status === "closed")
|
|
10947
10960
|
continue;
|
|
10948
10961
|
const loaded = this.load(entry.id);
|
|
10949
10962
|
if (!loaded.ok)
|
|
10950
10963
|
return loaded;
|
|
10951
|
-
|
|
10952
|
-
|
|
10964
|
+
for (const worker of loaded.data?.record.workers ?? [])
|
|
10965
|
+
owners.set(worker.id, entry.id);
|
|
10953
10966
|
}
|
|
10967
|
+
const resolved = resolveIdRef("worker", workerId, [...owners.keys()]);
|
|
10968
|
+
if (resolved.ok)
|
|
10969
|
+
return success(null, null, owners.get(resolved.data) ?? null);
|
|
10970
|
+
if (resolved.code !== "not_found")
|
|
10971
|
+
return resolved;
|
|
10954
10972
|
return success(null, null, null);
|
|
10955
10973
|
}
|
|
10956
10974
|
originTaskEntry() {
|
|
@@ -12679,20 +12697,19 @@ var workspaceConfigSchema = object({
|
|
|
12679
12697
|
union([boolean2(), literal("verified")]).optional()
|
|
12680
12698
|
]))).passthrough().optional(),
|
|
12681
12699
|
youtrack: object({ baseUrl: nonBlank.optional(), link_issues: boolean2().optional() }).passthrough().optional(),
|
|
12682
|
-
issues: object({
|
|
12700
|
+
issues: object({
|
|
12701
|
+
provider: _enum(["github", "gitlab", "youtrack"]).optional(),
|
|
12702
|
+
link: boolean2().optional(),
|
|
12703
|
+
relation: unknown().optional(),
|
|
12704
|
+
backlink: boolean2().optional(),
|
|
12705
|
+
link_on_pr: boolean2().optional()
|
|
12706
|
+
}).passthrough().optional(),
|
|
12683
12707
|
branchPolicy: workspaceBranchPolicySchema.optional(),
|
|
12684
12708
|
commitPolicy: workspaceCommitPolicySchema.optional(),
|
|
12685
12709
|
defaultProfile: nonBlank.optional(),
|
|
12686
12710
|
profiles: record(nonBlank, workspaceProfileSchema).optional(),
|
|
12687
12711
|
releaseTracks: record(nonBlank, releaseTrackSchema).optional()
|
|
12688
12712
|
}).passthrough().superRefine((workspace, context) => {
|
|
12689
|
-
if (workspace.issues && workspace.vcs?.provider !== "github") {
|
|
12690
|
-
context.addIssue({
|
|
12691
|
-
code: "custom",
|
|
12692
|
-
path: ["issues"],
|
|
12693
|
-
message: `GitHub issue linking requires the github provider, got ${workspace.vcs?.provider ?? "unset"}`
|
|
12694
|
-
});
|
|
12695
|
-
}
|
|
12696
12713
|
if (workspace.defaultProfile !== undefined && !Object.hasOwn(workspace.profiles ?? {}, workspace.defaultProfile)) {
|
|
12697
12714
|
context.addIssue({
|
|
12698
12715
|
code: "custom",
|
|
@@ -13494,6 +13511,44 @@ var readVcsConfig = () => {
|
|
|
13494
13511
|
}
|
|
13495
13512
|
return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
|
|
13496
13513
|
};
|
|
13514
|
+
var TRACKERS = new Set(["github", "gitlab", "youtrack"]);
|
|
13515
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
13516
|
+
var flag = (value) => typeof value === "boolean" ? value : null;
|
|
13517
|
+
var text2 = (value) => typeof value === "string" && value.trim() ? value.trim() : null;
|
|
13518
|
+
function issueTrackerOf(issues, youtrack) {
|
|
13519
|
+
const iss = asRecord(issues);
|
|
13520
|
+
const yt = asRecord(youtrack);
|
|
13521
|
+
const warnings = [];
|
|
13522
|
+
const named = typeof iss.provider === "string" && TRACKERS.has(iss.provider.toLowerCase()) ? iss.provider.toLowerCase() : null;
|
|
13523
|
+
if (iss.relation !== undefined && iss.relation !== "closes" && iss.relation !== "refs")
|
|
13524
|
+
warnings.push(`issues.relation ${JSON.stringify(iss.relation)} is not closes or refs; read as closes`);
|
|
13525
|
+
for (const key of ["repo", "host"])
|
|
13526
|
+
if (iss[key] !== undefined && text2(iss[key]) === null)
|
|
13527
|
+
warnings.push(`issues.${key} is not a non-empty string; ignored`);
|
|
13528
|
+
const common = {
|
|
13529
|
+
relation: iss.relation === "refs" ? "refs" : "closes",
|
|
13530
|
+
backlink: iss.backlink === true,
|
|
13531
|
+
baseUrl: text2(yt.baseUrl),
|
|
13532
|
+
repo: text2(iss.repo)?.replace(/^\/+|\/+$/gu, "") ?? null,
|
|
13533
|
+
host: text2(iss.host)?.toLowerCase() ?? null,
|
|
13534
|
+
warnings
|
|
13535
|
+
};
|
|
13536
|
+
const legacyGithub = named === "github" && flag(iss.link) === null;
|
|
13537
|
+
if (flag(yt.link_issues) === true && (named === null || legacyGithub))
|
|
13538
|
+
return { provider: "youtrack", link: true, ...common, source: "youtrack.link_issues" };
|
|
13539
|
+
if (named) {
|
|
13540
|
+
const link = flag(iss.link) ?? flag(iss.link_on_pr) ?? (named === "youtrack" ? flag(yt.link_issues) : null) ?? false;
|
|
13541
|
+
return {
|
|
13542
|
+
provider: named,
|
|
13543
|
+
link,
|
|
13544
|
+
...common,
|
|
13545
|
+
source: flag(iss.link) === null && flag(iss.link_on_pr) !== null ? "issues.link_on_pr" : "issues"
|
|
13546
|
+
};
|
|
13547
|
+
}
|
|
13548
|
+
if (common.baseUrl)
|
|
13549
|
+
return { provider: "youtrack", link: false, ...common, source: "youtrack.baseUrl" };
|
|
13550
|
+
return null;
|
|
13551
|
+
}
|
|
13497
13552
|
var trackSummary = (resolution) => resolution.status === "resolved" ? {
|
|
13498
13553
|
name: resolution.track?.name ?? null,
|
|
13499
13554
|
source: resolution.source,
|
|
@@ -13514,6 +13569,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13514
13569
|
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
13515
13570
|
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
13516
13571
|
const workspaceDefault = workspaceDefaultTarget(root, cfg.defaultTargetBranch);
|
|
13572
|
+
const issueTracker = issueTrackerOf(wsIssues, wsYt);
|
|
13517
13573
|
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
13518
13574
|
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
13519
13575
|
let issuesProvider = null;
|
|
@@ -13546,7 +13602,8 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13546
13602
|
link_issues: linkIssues,
|
|
13547
13603
|
youtrack_base_url: youtrackBaseUrl,
|
|
13548
13604
|
issues_provider: issuesProvider,
|
|
13549
|
-
link_on_pr: linkOnPr
|
|
13605
|
+
link_on_pr: linkOnPr,
|
|
13606
|
+
issue_tracker: issueTracker
|
|
13550
13607
|
};
|
|
13551
13608
|
}
|
|
13552
13609
|
if (cfgStatus === "malformed") {
|
|
@@ -13572,7 +13629,8 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13572
13629
|
link_issues: linkIssues,
|
|
13573
13630
|
youtrack_base_url: youtrackBaseUrl,
|
|
13574
13631
|
issues_provider: issuesProvider,
|
|
13575
|
-
link_on_pr: linkOnPr
|
|
13632
|
+
link_on_pr: linkOnPr,
|
|
13633
|
+
issue_tracker: issueTracker
|
|
13576
13634
|
};
|
|
13577
13635
|
if (provider === "gitlab") {
|
|
13578
13636
|
out.gitlab = {
|
|
@@ -13591,7 +13649,12 @@ var MAX_LINE_BYTES = 4096;
|
|
|
13591
13649
|
var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
|
|
13592
13650
|
var FAILING = new Set(["failed", "blocked"]);
|
|
13593
13651
|
var STRONG_RESULTS = new Set(["verified", "tests-verified"]);
|
|
13594
|
-
var PR_ROW_TYPES = new Set([
|
|
13652
|
+
var PR_ROW_TYPES = new Set([
|
|
13653
|
+
"pr.created",
|
|
13654
|
+
"pr.status",
|
|
13655
|
+
"pr.merged",
|
|
13656
|
+
"pr.linked"
|
|
13657
|
+
]);
|
|
13595
13658
|
var err = (code, error, unblock) => ({
|
|
13596
13659
|
ok: false,
|
|
13597
13660
|
code,
|
|
@@ -15741,7 +15804,7 @@ var RISK = {
|
|
|
15741
15804
|
};
|
|
15742
15805
|
var YES = new Set(["true", "yes", "y", "1", "on"]);
|
|
15743
15806
|
var NO = new Set(["false", "no", "n", "0", "off", "none"]);
|
|
15744
|
-
var
|
|
15807
|
+
var flag2 = (value, unknownAs) => {
|
|
15745
15808
|
if (typeof value === "boolean")
|
|
15746
15809
|
return { ok: true, value };
|
|
15747
15810
|
if (typeof value === "number" && (value === 0 || value === 1))
|
|
@@ -15807,12 +15870,12 @@ function normalizeJudgment(raw, previous) {
|
|
|
15807
15870
|
const items = Array.isArray(value) ? value : [value];
|
|
15808
15871
|
judgment.refs.push(...items.filter((item) => item !== null && item !== "").map(refOf));
|
|
15809
15872
|
} else {
|
|
15810
|
-
if (name === "needsPlan" && typeof value === "string" && !
|
|
15873
|
+
if (name === "needsPlan" && typeof value === "string" && !flag2(value, false).ok && value.trim()) {
|
|
15811
15874
|
judgment.needsPlan = true;
|
|
15812
15875
|
judgment.refs.push(refOf(value.trim()));
|
|
15813
15876
|
continue;
|
|
15814
15877
|
}
|
|
15815
|
-
const parsed =
|
|
15878
|
+
const parsed = flag2(value, name === "behaviorChange");
|
|
15816
15879
|
if (parsed.ok)
|
|
15817
15880
|
judgment[name] = parsed.value;
|
|
15818
15881
|
else
|
|
@@ -16294,6 +16357,8 @@ var TASK_SCOPED_ACTIONS = new Set([
|
|
|
16294
16357
|
"worker.cancel",
|
|
16295
16358
|
"state.export"
|
|
16296
16359
|
]);
|
|
16360
|
+
var ONLY_OWN_REPORT = "workers can submit only their own report";
|
|
16361
|
+
var NO_HELPER_CONTROL = "helpers cannot cancel or control workers";
|
|
16297
16362
|
var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
|
|
16298
16363
|
var workerCommand = (taskId, request) => {
|
|
16299
16364
|
const { action, workerId, reason, report } = request;
|
|
@@ -17191,6 +17256,10 @@ class WorkitCore {
|
|
|
17191
17256
|
}
|
|
17192
17257
|
if (helper?.ok)
|
|
17193
17258
|
return failure2("permission_denied", "helpers cannot resolve findings");
|
|
17259
|
+
const findingRef = resolveIdRef("finding", input.findingId, task.data.findings.map((entry) => entry.id));
|
|
17260
|
+
if (!findingRef.ok)
|
|
17261
|
+
return findingRef;
|
|
17262
|
+
input.findingId = findingRef.data;
|
|
17194
17263
|
const finding = task.data.findings.find((entry) => entry.id === input.findingId);
|
|
17195
17264
|
if (!finding)
|
|
17196
17265
|
return failure2("not_found", "finding not found");
|
|
@@ -17342,15 +17411,31 @@ class WorkitCore {
|
|
|
17342
17411
|
return changed;
|
|
17343
17412
|
return success(changed.data.task.revision, changed.data.workspace.revision, changed.data.task.workers.at(-1));
|
|
17344
17413
|
}
|
|
17414
|
+
const workerRef = resolveIdRef("worker", input.workerId, helperId === null ? task.data.workers.map((candidate) => candidate.id) : [helperId]);
|
|
17415
|
+
if (!workerRef.ok)
|
|
17416
|
+
return helperId === null ? workerRef : failure2("permission_denied", input.action === "report" ? ONLY_OWN_REPORT : NO_HELPER_CONTROL);
|
|
17417
|
+
input.workerId = workerRef.data;
|
|
17345
17418
|
const entry = task.data.workers.find((candidate) => candidate.id === input.workerId);
|
|
17346
17419
|
if (!entry)
|
|
17347
17420
|
return failure2("not_found", "worker not found");
|
|
17348
17421
|
if (input.action === "report") {
|
|
17349
17422
|
if (helperId === null || helperId !== input.workerId)
|
|
17350
|
-
return failure2("permission_denied",
|
|
17423
|
+
return failure2("permission_denied", ONLY_OWN_REPORT);
|
|
17351
17424
|
const helper = this.helperEntry(task.data, true, true);
|
|
17352
17425
|
if (!helper.ok)
|
|
17353
17426
|
return helper;
|
|
17427
|
+
const ownFindings = task.data.findings.filter((candidate) => candidate.provenance.workerId === helperId).map((candidate) => candidate.id);
|
|
17428
|
+
const reported = [];
|
|
17429
|
+
for (const findingRef of input.report.findingIds) {
|
|
17430
|
+
const found = resolveIdRef("finding", findingRef, ownFindings);
|
|
17431
|
+
if (found.ok)
|
|
17432
|
+
reported.push(found.data);
|
|
17433
|
+
else if (found.code === "not_found")
|
|
17434
|
+
reported.push(findingRef);
|
|
17435
|
+
else
|
|
17436
|
+
return found;
|
|
17437
|
+
}
|
|
17438
|
+
input.report.findingIds = reported;
|
|
17354
17439
|
const evidence = task.data.evidence.filter((candidate) => input.report.evidenceIds.includes(candidate.id));
|
|
17355
17440
|
const findings = task.data.findings.filter((candidate) => input.report.findingIds.includes(candidate.id));
|
|
17356
17441
|
if (evidence.length !== input.report.evidenceIds.length || findings.length !== input.report.findingIds.length)
|
|
@@ -17378,7 +17463,7 @@ class WorkitCore {
|
|
|
17378
17463
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during report");
|
|
17379
17464
|
}
|
|
17380
17465
|
if (helperId !== null)
|
|
17381
|
-
return failure2("permission_denied",
|
|
17466
|
+
return failure2("permission_denied", NO_HELPER_CONTROL);
|
|
17382
17467
|
if (task.data.status === "closed")
|
|
17383
17468
|
return failure2("invalid_transition", "closed task cannot cancel workers");
|
|
17384
17469
|
if (entry.data.state === "stopped") {
|
package/dist/workit-hook.js
CHANGED
|
@@ -37,6 +37,6 @@ if (quiet)
|
|
|
37
37
|
process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: quiet } })}
|
|
38
38
|
`);
|
|
39
39
|
else {
|
|
40
|
-
const { runCodexHook } = await import("./workit-hook-
|
|
40
|
+
const { runCodexHook } = await import("./workit-hook-v4a1y79w.js");
|
|
41
41
|
await runCodexHook([payload]);
|
|
42
42
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-codex",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.15.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
|
|
6
6
|
"keywords": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"build": "bun scripts/build.ts"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@brainervirus/workit-core": "^8.
|
|
43
|
-
"@brainervirus/workit-mcp": "^8.
|
|
42
|
+
"@brainervirus/workit-core": "^8.15.0",
|
|
43
|
+
"@brainervirus/workit-mcp": "^8.15.0"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=24"
|
|
@@ -33,8 +33,8 @@ that repeats because the base keeps moving, or after 3 failed fix attempts on
|
|
|
33
33
|
the same check.
|
|
34
34
|
|
|
35
35
|
1. **Open.** `workit git push`, then `workit pr create --title "<title>"
|
|
36
|
-
--body-file <f|->` (
|
|
37
|
-
`workit pr edit`). A stack: `workit stack plan <bottom> ... <top>`, one
|
|
36
|
+
--body-file <f|->` plus `--issue <#n|ID>` per issue (`--refs`: no close; idempotent;
|
|
37
|
+
body: `references/pr-body.md`; edits: `workit pr edit`). A stack: `workit stack plan <bottom> ... <top>`, one
|
|
38
38
|
`workit pr create --base <parent> --fill` per branch, then
|
|
39
39
|
`workit stack sync`. Finish the whole stack before babysitting any PR.
|
|
40
40
|
2. **Read state** with `workit pr status --json`. `REVIEW` alone is a pending
|