@brainervirus/workit-codex 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/dist/launch-mcp.js +13 -8
- package/dist/workit-hook.js +159 -54
- package/package.json +3 -3
- package/skills/workit-babysit/SKILL.md +9 -4
package/dist/launch-mcp.js
CHANGED
|
@@ -14457,7 +14457,7 @@ var workerReportSchema = object({
|
|
|
14457
14457
|
}).strict();
|
|
14458
14458
|
var workerSchema = object({
|
|
14459
14459
|
assignment: assignmentSchema,
|
|
14460
|
-
state: _enum(["assigned", "running", "cancelling", "stopped", "unknown"]),
|
|
14460
|
+
state: _enum(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
|
|
14461
14461
|
session: refSchema.nullable(),
|
|
14462
14462
|
report: workerReportSchema.nullable()
|
|
14463
14463
|
}).strict();
|
|
@@ -17291,7 +17291,7 @@ function reconcileResume(view, observations = []) {
|
|
|
17291
17291
|
return candidate;
|
|
17292
17292
|
const staleEvidenceIds = evaluateEvidence(view.task, candidate.data).filter((entry) => entry.status === "stale").map((entry) => entry.evidenceId);
|
|
17293
17293
|
const blockers = [...view.task.progress.blockers];
|
|
17294
|
-
if (view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
17294
|
+
if (view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
17295
17295
|
blockers.push({
|
|
17296
17296
|
reason: "worker state requires reconciliation",
|
|
17297
17297
|
dependentAction: "resume",
|
|
@@ -17899,10 +17899,10 @@ var applyWorkerLifecycle = (input) => {
|
|
|
17899
17899
|
const notStarted = input.dispatch === true;
|
|
17900
17900
|
if (notStarted && (input.state !== "stopped" || input.session !== null))
|
|
17901
17901
|
return failure("invalid_input", "a never-dispatched worker stops with no session");
|
|
17902
|
-
if (notStarted &&
|
|
17903
|
-
return failure("invalid_transition", "worker is no longer awaiting dispatch");
|
|
17904
|
-
if (notStarted && (entry.data.session !== null || entry.data.state === "running"))
|
|
17902
|
+
if (notStarted && entry.data.session !== null)
|
|
17905
17903
|
return failure("invalid_transition", "worker already has an observed session");
|
|
17904
|
+
if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
|
|
17905
|
+
return failure("invalid_transition", "worker launch was not claimed");
|
|
17906
17906
|
if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
|
|
17907
17907
|
return failure("invalid_input", "running worker observations require a session");
|
|
17908
17908
|
if (entry.data.session && !sameValue(entry.data.session, input.session))
|
|
@@ -18289,7 +18289,7 @@ class WorkitCore {
|
|
|
18289
18289
|
activeWorkerBlocker(task, workspace) {
|
|
18290
18290
|
if (workspace.writer)
|
|
18291
18291
|
return failure("recovery_required", "writer ownership must be released first");
|
|
18292
|
-
if (task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
18292
|
+
if (task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
18293
18293
|
return failure("recovery_required", "worker state requires reconciliation");
|
|
18294
18294
|
return null;
|
|
18295
18295
|
}
|
|
@@ -19053,7 +19053,12 @@ class WorkitCore {
|
|
|
19053
19053
|
return failure("invalid_transition", "worker is not awaiting dispatch");
|
|
19054
19054
|
return success(mutation.revision, null, {
|
|
19055
19055
|
...current,
|
|
19056
|
-
workers: current.workers.map((item) => item.id === input.workerId ? {
|
|
19056
|
+
workers: current.workers.map((item) => item.id === input.workerId ? {
|
|
19057
|
+
...item,
|
|
19058
|
+
recordedAt: mutation.now,
|
|
19059
|
+
provenance: attested.data,
|
|
19060
|
+
data: { ...item.data, state: "dispatching" }
|
|
19061
|
+
} : item)
|
|
19057
19062
|
});
|
|
19058
19063
|
}
|
|
19059
19064
|
});
|
|
@@ -19522,7 +19527,7 @@ class WorkitCore {
|
|
|
19522
19527
|
const base = reconcileResume(effectiveView);
|
|
19523
19528
|
if (!base.ok)
|
|
19524
19529
|
return base;
|
|
19525
|
-
const needsReconciliation = view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
|
|
19530
|
+
const needsReconciliation = view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
|
|
19526
19531
|
const blockers = [...base.data.blockers];
|
|
19527
19532
|
if (needsReconciliation && !blockers.some((entry) => entry.reason === "worker state requires reconciliation"))
|
|
19528
19533
|
blockers.push({
|
package/dist/workit-hook.js
CHANGED
|
@@ -7611,7 +7611,7 @@ var workerReportSchema = object({
|
|
|
7611
7611
|
}).strict();
|
|
7612
7612
|
var workerSchema = object({
|
|
7613
7613
|
assignment: assignmentSchema,
|
|
7614
|
-
state: _enum(["assigned", "running", "cancelling", "stopped", "unknown"]),
|
|
7614
|
+
state: _enum(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
|
|
7615
7615
|
session: refSchema.nullable(),
|
|
7616
7616
|
report: workerReportSchema.nullable()
|
|
7617
7617
|
}).strict();
|
|
@@ -10380,6 +10380,95 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
10380
10380
|
});
|
|
10381
10381
|
}
|
|
10382
10382
|
|
|
10383
|
+
// packages/workit-core/src/core/methods.ts
|
|
10384
|
+
var METHODS = {
|
|
10385
|
+
"workit-challenge": { dimensions: ["challenge", "decisions"] },
|
|
10386
|
+
"workit-behavioral-tdd": { dimensions: ["testing"] },
|
|
10387
|
+
"workit-review": { dimensions: ["review"] },
|
|
10388
|
+
"workit-plan": { dimensions: ["artifacts", "continuity"] },
|
|
10389
|
+
"workit-implement": { dimensions: ["delegation"] },
|
|
10390
|
+
"workit-debug": { ruleIds: ["root-cause-investigation"] },
|
|
10391
|
+
"workit-handoff": { ruleIds: ["durable-handoff"] },
|
|
10392
|
+
"workit-deslop": { ruleIds: ["pre-pr-cleanup"] }
|
|
10393
|
+
};
|
|
10394
|
+
var methodMatches = (id, definition, requirement) => definition.dimensions?.includes(requirement.dimension) === true && !(id === "workit-review" && requirement.ruleId === "self-review") || definition.ruleIds?.includes(requirement.ruleId) === true;
|
|
10395
|
+
var assuranceFor = (id, definition, capabilities) => {
|
|
10396
|
+
const keys = new Set([
|
|
10397
|
+
id,
|
|
10398
|
+
...definition.dimensions ?? [],
|
|
10399
|
+
...definition.ruleIds ?? []
|
|
10400
|
+
]);
|
|
10401
|
+
const matches = capabilities.filter((capability) => keys.has(capability.name) || keys.has(capability.surface));
|
|
10402
|
+
if (id === "workit-review" && matches.length === 0)
|
|
10403
|
+
return { assurance: "unavailable", reasons: ["independent review capability is unavailable"] };
|
|
10404
|
+
if (matches.some((capability) => capability.assurance === "unavailable"))
|
|
10405
|
+
return {
|
|
10406
|
+
assurance: "unavailable",
|
|
10407
|
+
reasons: matches.filter((capability) => capability.assurance === "unavailable").map((capability) => capability.reason)
|
|
10408
|
+
};
|
|
10409
|
+
if (matches.some((capability) => capability.assurance === "enforced"))
|
|
10410
|
+
return { assurance: "enforced", reasons: matches.map((capability) => capability.reason) };
|
|
10411
|
+
return { assurance: "agent_guided", reasons: matches.map((capability) => capability.reason) };
|
|
10412
|
+
};
|
|
10413
|
+
function selectMethods(policy, capabilities) {
|
|
10414
|
+
return Object.entries(METHODS).flatMap(([id, definition]) => {
|
|
10415
|
+
const requirements = policy.requirements.filter((requirement) => methodMatches(id, definition, requirement));
|
|
10416
|
+
if (requirements.length === 0)
|
|
10417
|
+
return [];
|
|
10418
|
+
const capability = assuranceFor(id, definition, capabilities);
|
|
10419
|
+
const reasons = [
|
|
10420
|
+
...new Set(requirements.map((requirement) => requirement.reason)),
|
|
10421
|
+
...capability.reasons
|
|
10422
|
+
];
|
|
10423
|
+
if (capability.assurance === "unavailable")
|
|
10424
|
+
reasons.unshift("required capability is unavailable");
|
|
10425
|
+
return [{ id, reason: reasons.join("; "), assurance: capability.assurance }];
|
|
10426
|
+
});
|
|
10427
|
+
}
|
|
10428
|
+
var invariantBootstrap = () => `
|
|
10429
|
+
Workit keeps one accountable lead and one shared task state. Inspect current task
|
|
10430
|
+
state before acting. An empty task.list means no session yet, not permission to
|
|
10431
|
+
skip Workit; for user-requested product, debug, or behavior work with no active
|
|
10432
|
+
or paused task, run task.start then policy.assess before other product mutations.
|
|
10433
|
+
Omitted expectedRevision, expectedWorkspaceRevision, and writer workerId default
|
|
10434
|
+
to the current records; explicit values are still concurrency-checked, so never
|
|
10435
|
+
copy revisions between calls. Happy path: task.list, task.start {intent} with no
|
|
10436
|
+
revisions, policy.assess {assessment: {facts, signals, consequences,
|
|
10437
|
+
verification}} where facts are inferred or observed with file refs,
|
|
10438
|
+
writer.acquire {taskId} before product writes, evidence.record {evidence} where
|
|
10439
|
+
check and review kinds auto-bind the current tree and need no digests. Record
|
|
10440
|
+
self-review requirements with kind review and reviewContext matching your own
|
|
10441
|
+
host session; the lead may also record checks. Fresh-context review requires a
|
|
10442
|
+
session distinct from the task creator and every other evidence recorder. Record
|
|
10443
|
+
verification evidence last: later evidence or commits can reopen fixed findings
|
|
10444
|
+
for re-verification, so verify, resolve, then close with nothing in between.
|
|
10445
|
+
decision.record {binding with taskId/workspaceId from inspect plus presented and
|
|
10446
|
+
approvedContent} only through a native approval question asked receipt-shaped:
|
|
10447
|
+
header Workit decision: <purpose>, the same label repeated in the question
|
|
10448
|
+
text (some host UIs do not render headers), exactly two options approved and
|
|
10449
|
+
rejected; ask once, never re-ask to mint a receipt. task.close {outcome,
|
|
10450
|
+
summary, decisionIds}. A completed native subagent run stops its bound worker
|
|
10451
|
+
by itself; if a worker strands in cancelling with its run verifiably over,
|
|
10452
|
+
repeat worker.cancel {reason} to confirm the stop. Check and review evidence
|
|
10453
|
+
without a bound candidate goes stale; findings close only as fixed with passing
|
|
10454
|
+
verification, dismissed with supporting evidence, or deferred under an approved
|
|
10455
|
+
limitation. Use only the
|
|
10456
|
+
shared operations for task, policy, evidence, finding, decision, worker, writer,
|
|
10457
|
+
and state changes. Authority is bounded by the requested scope, current
|
|
10458
|
+
revision, caller/session provenance, and observed capabilities. Never claim host
|
|
10459
|
+
enforcement or evidence that the host cannot provide. Shell-executed writes are
|
|
10460
|
+
unattested agent-guided work even when a writer is held. Preserve unresolved
|
|
10461
|
+
requirements, gaps, and uncertain workers. Skill routing: slash aliases /wk-*
|
|
10462
|
+
always load on demand. Model-invoked: new instructions, interruptions, or
|
|
10463
|
+
forgotten items mid-task → load workit-steer before responding; about to open
|
|
10464
|
+
a PR or fresh from implementing → load workit-deslop; CI red → load
|
|
10465
|
+
workit-green-run; small-looking change before close or merge → load
|
|
10466
|
+
workit-blast-radius; ambiguous, consequential, or disputed proposal before
|
|
10467
|
+
recommending → load workit-challenge; spec or plan needs a flow diagram →
|
|
10468
|
+
load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
|
|
10469
|
+
act from memory of it.
|
|
10470
|
+
`.trim();
|
|
10471
|
+
|
|
10383
10472
|
// packages/workit-core/src/core/task-context.ts
|
|
10384
10473
|
function reconcileResume(view, observations = []) {
|
|
10385
10474
|
if (observations.length > 0)
|
|
@@ -10389,7 +10478,7 @@ function reconcileResume(view, observations = []) {
|
|
|
10389
10478
|
return candidate;
|
|
10390
10479
|
const staleEvidenceIds = evaluateEvidence(view.task, candidate.data).filter((entry) => entry.status === "stale").map((entry) => entry.evidenceId);
|
|
10391
10480
|
const blockers = [...view.task.progress.blockers];
|
|
10392
|
-
if (view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
10481
|
+
if (view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
10393
10482
|
blockers.push({
|
|
10394
10483
|
reason: "worker state requires reconciliation",
|
|
10395
10484
|
dependentAction: "resume",
|
|
@@ -10439,6 +10528,11 @@ function compactTaskContext(view) {
|
|
|
10439
10528
|
digest: entry.data.digest,
|
|
10440
10529
|
references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
|
|
10441
10530
|
}));
|
|
10531
|
+
const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
|
|
10532
|
+
id: method.id,
|
|
10533
|
+
assurance: method.assurance,
|
|
10534
|
+
reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
|
|
10535
|
+
})) : [];
|
|
10442
10536
|
const gaps = Array.from(new Set([
|
|
10443
10537
|
...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
|
|
10444
10538
|
...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
|
|
@@ -10448,15 +10542,18 @@ function compactTaskContext(view) {
|
|
|
10448
10542
|
objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
|
|
10449
10543
|
status: view.task.status,
|
|
10450
10544
|
decisions,
|
|
10545
|
+
methods,
|
|
10451
10546
|
gaps,
|
|
10452
10547
|
nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
|
|
10453
10548
|
};
|
|
10454
10549
|
let encoded = JSON.stringify(context);
|
|
10455
|
-
while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.gaps.length)) {
|
|
10550
|
+
while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
|
|
10456
10551
|
if (context.gaps.length)
|
|
10457
10552
|
context.gaps.pop();
|
|
10458
|
-
else
|
|
10553
|
+
else if (context.decisions.length)
|
|
10459
10554
|
context.decisions.pop();
|
|
10555
|
+
else
|
|
10556
|
+
context.methods.pop();
|
|
10460
10557
|
encoded = JSON.stringify(context);
|
|
10461
10558
|
}
|
|
10462
10559
|
if (compactBytes(encoded) > COMPACT_MAX_BYTES) {
|
|
@@ -10472,50 +10569,47 @@ var exportDigest = (bundle) => sha256({
|
|
|
10472
10569
|
sourceWorkspaceId: bundle.sourceWorkspaceId,
|
|
10473
10570
|
task: bundle.task
|
|
10474
10571
|
});
|
|
10475
|
-
// packages/workit-core/src/core/
|
|
10476
|
-
var
|
|
10477
|
-
Workit
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
load workit-diagram, a UI sketch → load workit-mockup. Load the skill; never
|
|
10517
|
-
act from memory of it.
|
|
10518
|
-
`.trim();
|
|
10572
|
+
// packages/workit-core/src/core/route-intent.ts
|
|
10573
|
+
var GUIDANCE = {
|
|
10574
|
+
"git.branch_setup": "use the Workit git.branch_setup action (workit_external_action in hosts, or `workit action git.branch_setup --payload '{}' --confirm --json` in the CLI)",
|
|
10575
|
+
"hosting.pull_request": "use the Workit hosting.pull_request action (workit_external_action in hosts, or `workit action hosting.pull_request --payload '{...}' --confirm --json` in the CLI), then drive the created PR through workit-babysit"
|
|
10576
|
+
};
|
|
10577
|
+
var unbalancedQuotes = (segment) => {
|
|
10578
|
+
const text = segment.replace(/\\./gu, "");
|
|
10579
|
+
return (text.match(/"/gu)?.length ?? 0) % 2 !== 0 || (text.match(/'/gu)?.length ?? 0) % 2 !== 0;
|
|
10580
|
+
};
|
|
10581
|
+
var segmentTokens = (segment) => {
|
|
10582
|
+
if (segment.includes("`") || segment.includes("$("))
|
|
10583
|
+
return null;
|
|
10584
|
+
if (unbalancedQuotes(segment))
|
|
10585
|
+
return null;
|
|
10586
|
+
const parts = segment.trim().split(/\s+/u);
|
|
10587
|
+
while (parts.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/u.test(parts[0]))
|
|
10588
|
+
parts.shift();
|
|
10589
|
+
return parts.length > 0 ? parts : null;
|
|
10590
|
+
};
|
|
10591
|
+
var unquote = (token) => token.replace(/^['"]|['"]$/gu, "");
|
|
10592
|
+
function shellRouteIntent(command) {
|
|
10593
|
+
if (typeof command !== "string" || command.trim() === "")
|
|
10594
|
+
return null;
|
|
10595
|
+
for (const raw of command.split(/&&|\|\||;|\n/u)) {
|
|
10596
|
+
const parts = segmentTokens(raw);
|
|
10597
|
+
if (!parts)
|
|
10598
|
+
continue;
|
|
10599
|
+
const head = unquote(parts[0]);
|
|
10600
|
+
const second = unquote(parts[1] ?? "");
|
|
10601
|
+
const third = unquote(parts[2] ?? "");
|
|
10602
|
+
if (head === "git" && second === "switch" && (third === "-c" || third === "--create"))
|
|
10603
|
+
return { route: "git.branch_setup", guidance: GUIDANCE["git.branch_setup"] };
|
|
10604
|
+
if (head === "git" && second === "checkout" && (third === "-b" || third === "-B"))
|
|
10605
|
+
return { route: "git.branch_setup", guidance: GUIDANCE["git.branch_setup"] };
|
|
10606
|
+
if (head === "gh" && second === "pr" && third === "create")
|
|
10607
|
+
return { route: "hosting.pull_request", guidance: GUIDANCE["hosting.pull_request"] };
|
|
10608
|
+
if (head === "glab" && second === "mr" && third === "create")
|
|
10609
|
+
return { route: "hosting.pull_request", guidance: GUIDANCE["hosting.pull_request"] };
|
|
10610
|
+
}
|
|
10611
|
+
return null;
|
|
10612
|
+
}
|
|
10519
10613
|
// packages/workit-core/src/core/external-action.ts
|
|
10520
10614
|
var externalActionSchema = discriminatedUnion("operation", [
|
|
10521
10615
|
object({
|
|
@@ -11104,10 +11198,10 @@ var applyWorkerLifecycle = (input) => {
|
|
|
11104
11198
|
const notStarted = input.dispatch === true;
|
|
11105
11199
|
if (notStarted && (input.state !== "stopped" || input.session !== null))
|
|
11106
11200
|
return failure("invalid_input", "a never-dispatched worker stops with no session");
|
|
11107
|
-
if (notStarted &&
|
|
11108
|
-
return failure("invalid_transition", "worker is no longer awaiting dispatch");
|
|
11109
|
-
if (notStarted && (entry.data.session !== null || entry.data.state === "running"))
|
|
11201
|
+
if (notStarted && entry.data.session !== null)
|
|
11110
11202
|
return failure("invalid_transition", "worker already has an observed session");
|
|
11203
|
+
if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
|
|
11204
|
+
return failure("invalid_transition", "worker launch was not claimed");
|
|
11111
11205
|
if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
|
|
11112
11206
|
return failure("invalid_input", "running worker observations require a session");
|
|
11113
11207
|
if (entry.data.session && !sameValue(entry.data.session, input.session))
|
|
@@ -11494,7 +11588,7 @@ class WorkitCore {
|
|
|
11494
11588
|
activeWorkerBlocker(task, workspace) {
|
|
11495
11589
|
if (workspace.writer)
|
|
11496
11590
|
return failure("recovery_required", "writer ownership must be released first");
|
|
11497
|
-
if (task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
11591
|
+
if (task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(entry.data.state)))
|
|
11498
11592
|
return failure("recovery_required", "worker state requires reconciliation");
|
|
11499
11593
|
return null;
|
|
11500
11594
|
}
|
|
@@ -12258,7 +12352,12 @@ class WorkitCore {
|
|
|
12258
12352
|
return failure("invalid_transition", "worker is not awaiting dispatch");
|
|
12259
12353
|
return success(mutation.revision, null, {
|
|
12260
12354
|
...current,
|
|
12261
|
-
workers: current.workers.map((item) => item.id === input.workerId ? {
|
|
12355
|
+
workers: current.workers.map((item) => item.id === input.workerId ? {
|
|
12356
|
+
...item,
|
|
12357
|
+
recordedAt: mutation.now,
|
|
12358
|
+
provenance: attested.data,
|
|
12359
|
+
data: { ...item.data, state: "dispatching" }
|
|
12360
|
+
} : item)
|
|
12262
12361
|
});
|
|
12263
12362
|
}
|
|
12264
12363
|
});
|
|
@@ -12727,7 +12826,7 @@ class WorkitCore {
|
|
|
12727
12826
|
const base = reconcileResume(effectiveView);
|
|
12728
12827
|
if (!base.ok)
|
|
12729
12828
|
return base;
|
|
12730
|
-
const needsReconciliation = view.task.workers.some((entry) => ["running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
|
|
12829
|
+
const needsReconciliation = view.task.workers.some((entry) => ["dispatching", "running", "cancelling", "unknown"].includes(observedStates.get(entry.id) ?? entry.data.state));
|
|
12731
12830
|
const blockers = [...base.data.blockers];
|
|
12732
12831
|
if (needsReconciliation && !blockers.some((entry) => entry.reason === "worker state requires reconciliation"))
|
|
12733
12832
|
blockers.push({
|
|
@@ -13151,6 +13250,12 @@ var handleCodexHook = (raw) => {
|
|
|
13151
13250
|
return output("SessionStart", { additionalContext: sessionContext(input) });
|
|
13152
13251
|
}
|
|
13153
13252
|
if (input.hook_event_name === "PreToolUse") {
|
|
13253
|
+
if (["bash", "unified-exec"].includes(String(input.tool_name).toLowerCase())) {
|
|
13254
|
+
const command = record2(input.tool_input) ? input.tool_input.command : undefined;
|
|
13255
|
+
const route = typeof command === "string" ? shellRouteIntent(command) : null;
|
|
13256
|
+
if (route)
|
|
13257
|
+
return denied("PreToolUse", `direct branch or PR creation bypasses the Workit route; ${route.guidance}`);
|
|
13258
|
+
}
|
|
13154
13259
|
return output("PreToolUse", { permissionDecision: "allow" });
|
|
13155
13260
|
}
|
|
13156
13261
|
if (input.hook_event_name === "SubagentStart")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-codex",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, and fourteen method skills",
|
|
6
6
|
"keywords": [
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"build": "bun scripts/build.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@brainervirus/workit-core": "^1.0.
|
|
42
|
-
"@brainervirus/workit-mcp": "^1.0.
|
|
41
|
+
"@brainervirus/workit-core": "^1.0.9",
|
|
42
|
+
"@brainervirus/workit-mcp": "^1.0.9"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=24"
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: workit-babysit
|
|
3
|
-
description: Use when a PR needs driving to merge-ready, CI is red, or the user says babysit
|
|
3
|
+
description: Use after creating a PR (auto-starts, drive default), when a PR needs driving to merge-ready, CI is red, or the user says babysit
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Babysit a PR to merge-ready
|
|
7
7
|
|
|
8
|
-
Babysit starts automatically on PR creation unless declined (
|
|
8
|
+
Babysit starts automatically on PR creation unless declined (`babysit:false`).
|
|
9
9
|
One babysitter per PR; never mutate PR topology (no rebase strategy changes,
|
|
10
|
-
no force-push).
|
|
10
|
+
no force-push). When a PR URL is observed from a route Workit did not enforce
|
|
11
|
+
(for example a raw `gh pr create` the host allowed), load this skill and drive
|
|
12
|
+
that PR anyway; do not claim the Workit route was enforced.
|
|
11
13
|
|
|
12
14
|
## Before method work
|
|
13
15
|
|
|
@@ -17,8 +19,11 @@ selects requirements; do not wait for a rule that can only exist after assess.
|
|
|
17
19
|
|
|
18
20
|
## Method
|
|
19
21
|
|
|
20
|
-
1. Declare mode: drive (fix + merge
|
|
22
|
+
1. Declare mode in the same turn as the PR URL: drive (fix + merge, the
|
|
23
|
+
default), watch (report only), or threads-only.
|
|
21
24
|
2. Work the merge frontier in order: conflicts → review threads → CI.
|
|
25
|
+
Record a frontier brief (frontier state, next action) in task progress
|
|
26
|
+
per pass so the steps stay visible.
|
|
22
27
|
3. Classify CI before retry: flake (rerun once) vs stale base (verify with
|
|
23
28
|
`git merge-base --is-ancestor` before updating) vs real failure (fix).
|
|
24
29
|
4. Triage bot findings skeptically: reproduce or quote code before acting;
|