@brainervirus/workit-cli 0.8.8 → 0.8.10
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/README.md
CHANGED
|
@@ -25,6 +25,7 @@ workit flow pause --plan docs/<slug>/plan.md [--confirm] # active -> paused
|
|
|
25
25
|
workit flow resume --plan docs/<slug>/plan.md [--confirm] # paused -> active
|
|
26
26
|
workit flow complete --plan docs/<slug>/plan.md [--confirm] # complete (ledger + verification gated)
|
|
27
27
|
workit flow review-package --plan docs/<slug>/plan.md --base <sha> --head <sha> [--confirm] # write a review diff
|
|
28
|
+
workit flow append-advisory --plan docs/<slug>/plan.md --task <id> --text <text> [--confirm] # record an advisory review finding
|
|
28
29
|
workit handoff --message "docs/<slug>/plan.md" # print the destination handoff prompt
|
|
29
30
|
workit # help
|
|
30
31
|
```
|
|
@@ -7,59 +7,61 @@ Load `using-superpowers`, `subagent-driven-development`, `test-driven-developmen
|
|
|
7
7
|
|
|
8
8
|
## Handoff destination
|
|
9
9
|
|
|
10
|
-
This session is a handoff destination for a continued plan. The originating session already recorded the post-plan menu choice; present exactly these four choices and never re-offer the originating handoff option:
|
|
10
|
+
This session is a handoff destination for a continued plan. The originating session already recorded the post-plan menu choice; present exactly these four choices plus model deferral and never re-offer the originating handoff option:
|
|
11
11
|
|
|
12
12
|
- Subagent-driven
|
|
13
13
|
- Inline
|
|
14
14
|
- Review spec first
|
|
15
15
|
- Review plan first
|
|
16
|
+
- Change model first
|
|
16
17
|
|
|
17
18
|
<workflow-handoff-destination>true</workflow-handoff-destination>
|
|
18
19
|
|
|
19
20
|
## Hard gates
|
|
20
21
|
|
|
21
22
|
- The parent is coordinator-only: it does not edit product code or perform delegated exploration.
|
|
22
|
-
- Never use a worktree. Branch changes are in-place through `
|
|
23
|
-
- Working state, briefs, ledgers, and review diffs live only under gitignored `<SDD_DIR>` in `docs/<slug>/sdd/` and use `
|
|
23
|
+
- Never use a worktree. Branch changes are in-place through `workit_branch_setup` on `feature/*` or `bugfix/*`; never commit on protected branches.
|
|
24
|
+
- Working state, briefs, ledgers, and review diffs live only under gitignored `<SDD_DIR>` in `docs/<slug>/sdd/` and use `workit_sdd_*` tools.
|
|
24
25
|
- Use native `todowrite` for visible task state as well as the gitignored ledger.
|
|
25
26
|
- Use native `question` for branch/stash choices and guarded external mutations; call mutation tools only after approval with `confirmed: true` (grounded in the recorded NativeChoiceEvidence).
|
|
26
|
-
- Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `
|
|
27
|
-
-
|
|
27
|
+
- Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`) and subagent-driven execution is rejected as unsupported.
|
|
28
|
+
- Delegated authority is direct-child-only: a worker is the session whose host `parentID` exactly equals the activating coordinator's recorded `coordinator_session_id`; missing, mismatched, or multi-owner lineage fails closed with `delegation_lineage_denied`, and nested `opencode` launches are denied during active delegated work. An authorized child receives only the compact worker contract (execute the supplied brief, follow TDD, land one contiguous non-empty commit range, report results) — never coordinator guidance, `wk-implement`, or ledger management; coordinator bookkeeping via `workit_sdd_*` stays with the coordinator session.
|
|
29
|
+
- On Cursor, for every repository-scoped `workit_*` call, pass the active Cursor workspace as `workspace_root`; never rely on the MCP process default.
|
|
28
30
|
- Use native `task` with only the built-in `explore` and `general` agents.
|
|
29
31
|
|
|
30
32
|
## Flow gates (HARD)
|
|
31
33
|
|
|
32
34
|
- `wk-implement` refuses to run unless the plan is `approved` (flow.json) and the post-plan menu was presented.
|
|
33
35
|
- `wk-handoff` refuses to run unless both spec and plan are `approved`.
|
|
34
|
-
- Sequence is enforced by tools: `
|
|
36
|
+
- Sequence is enforced by tools: `workit_spec_approve`, `workit_plan_approve`, `workit_plan_menu` — never skip a step (the spec/plan self-review runs automatically inside the transition; only the final approval asks for your confirmation).
|
|
35
37
|
|
|
36
38
|
## Setup
|
|
37
39
|
|
|
38
|
-
0. Call `
|
|
39
|
-
1. Call `
|
|
40
|
-
2. Call `
|
|
40
|
+
0. Call `workit_docs_validate` with the linked spec/plan paths. Hard-fail on any error before todos or branch setup.
|
|
41
|
+
1. Call `workit_sdd_context` with `<PLAN_PATH>` and initialize `todowrite` from returned tasks.
|
|
42
|
+
2. Call `workit_plan_tasks`; cache each top-level task's `section_text`.
|
|
41
43
|
3. Mark IDs in `completed_task_ids` completed and never redispatch them.
|
|
42
|
-
4. Call `
|
|
44
|
+
4. Call `workit_resolve_branch`, then show the current branch, target branch, and stash behavior before any in-place checkout/setup mutation.
|
|
43
45
|
5. Always use `question`: for a clean tree ask whether to proceed or cancel; for a dirty tree add the stash choice and describe what will be stashed.
|
|
44
|
-
6. Call `
|
|
46
|
+
6. Call `workit_branch_setup` with `confirmed: true` only after approval.
|
|
45
47
|
|
|
46
48
|
## Remaining-task loop
|
|
47
49
|
|
|
48
50
|
For each top-level task absent from `completed_task_ids`:
|
|
49
51
|
|
|
50
52
|
1. Mark it `in_progress` with `todowrite`.
|
|
51
|
-
2. Create a working-state brief with `
|
|
53
|
+
2. Create a working-state brief with `workit_sdd_task_brief` and `confirmed: true`.
|
|
52
54
|
3. Delegate read-only discovery, when needed, to an `explore` agent. Delegate implementation to a fresh `general` agent. Product changes follow TDD.
|
|
53
|
-
4. Create a working-state diff with `
|
|
55
|
+
4. Create a working-state diff with `workit_sdd_review_package` and `confirmed: true`.
|
|
54
56
|
5. Delegate spec-compliance review and code-quality review to separate `general` agents.
|
|
55
|
-
6. **Blocking** findings (Critical, Important, or spec-compliance) may trigger at most **two** fix+re-review rounds per task. **Advisory** findings (Minor, style, YAGNI, taste) never pause the loop — append them
|
|
56
|
-
7. Append the validated ledger entry with `
|
|
57
|
+
6. **Blocking** findings (Critical, Important, or spec-compliance) may trigger at most **two** fix+re-review rounds per task. **Advisory** findings (Minor, style, YAGNI, taste) never pause the loop — append them with `workit_sdd_append_advisory` (`--task <id> --text <text>`, `confirmed: true`) instead of an unrestricted file edit.
|
|
58
|
+
7. Append the validated ledger entry with `workit_sdd_append_progress` and `confirmed: true`; mark the todo completed.
|
|
57
59
|
|
|
58
60
|
## Final gate
|
|
59
61
|
|
|
60
|
-
Run a separate full-branch code review, then `
|
|
62
|
+
Run a separate full-branch code review, then `workit_verify`. Present the full `<SDD_DIR>/advisories.md` roll-up once, then use native `question` so the user can choose which advisory items to fix, discuss, or discard. Report exact check results and never infer success. Use `workit_git_context` for a commit preview and load `wk-commit` through `skill` for an approved commit. If working state contains a stash reference, preview reapplication through `question`, then call `workit_branch_setup` with `confirmed: true` after approval.
|
|
61
63
|
|
|
62
|
-
**Mandatory:** end the run by calling `
|
|
64
|
+
**Mandatory:** end the run by calling `workit_plan_complete` (OpenCode/Cursor) or the CLI `workit flow complete` (CLI host) after the final task once the SDD ledger is complete (all task IDs appended) and `workit_verify` passes — a complete ledger and green verification are the tool's gates. Never finish the run while the plan is still `active`.
|
|
63
65
|
|
|
64
66
|
## Task order
|
|
65
67
|
|
|
@@ -68,4 +70,4 @@ Run a separate full-branch code review, then `workflow_verify`. Present the full
|
|
|
68
70
|
## Quality gate (HARD)
|
|
69
71
|
|
|
70
72
|
- Specs/plans are written from `templates/spec-template.md` / `templates/plan-template.md`.
|
|
71
|
-
- After `
|
|
73
|
+
- After `workit_docs_validate`, surface `quality` findings (spec scan). Hard findings (missing required section, missing CA-XX) block task start unless the user explicitly waives them. Warnings are advisory.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
## Global Constraints
|
|
11
11
|
|
|
12
12
|
- Each task lands exactly one contiguous non-empty commit range (`base..head`): fix rounds append commits to that range and never rewrite/amend an active review range; each progress line records the task's real base..head shas.
|
|
13
|
-
- The final task ends execution with `
|
|
13
|
+
- The final task ends execution with `workit_plan_complete` (or the CLI `workit flow complete`) once the SDD ledger is complete and repository verification passes — a run never finishes while the plan is still `active`.
|
|
14
14
|
- <project-wide requirements, one line each>
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
## Architecture
|
|
18
18
|
|
|
19
|
-
<!-- REQUIRED if this spec has flows or architecture: render a mermaid diagram (
|
|
19
|
+
<!-- REQUIRED if this spec has flows or architecture: render a mermaid diagram (workit_present_flow). -->
|
|
20
20
|
```mermaid
|
|
21
21
|
flowchart TD
|
|
22
22
|
A[Start] --> B[Step]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
<!-- REQUIRED if this spec touches UI: render an ASCII wireframe (
|
|
25
|
+
<!-- REQUIRED if this spec touches UI: render an ASCII wireframe (workit_present_ascii). -->
|
|
26
26
|
```text
|
|
27
27
|
┌──────────────┐
|
|
28
28
|
│ Header │
|
|
@@ -27,31 +27,31 @@ Plans require:
|
|
|
27
27
|
|
|
28
28
|
`bugfix/<slug>` is also valid. Never use `main`, `develop`, `master`, or `prod`. Use plain backtick paths. Top-level headings are exactly `### Task N: Title`; steps use `- [ ] **Step N:** ...`; task headings never appear inside fences.
|
|
29
29
|
|
|
30
|
-
Before writing **Branch:** into a new spec or plan, call `
|
|
30
|
+
Before writing **Branch:** into a new spec or plan, call `workit_docs_branch` and write the returned `branch` verbatim. When `action` is `keep`, use the current feature/bugfix branch. When `action` is `create_from_develop` or `create_from_base`, create the branch only through `workit_branch_setup`; it uses the configured workspace/global target branch.
|
|
31
31
|
|
|
32
32
|
## Execution and handoff
|
|
33
33
|
|
|
34
34
|
- Implementation uses `wk-implement` and subagent-driven development, with native `todowrite` and `task`.
|
|
35
35
|
- Commits use `wk-commit` after its native `question` confirmation.
|
|
36
|
-
- Continuation uses `wk-handoff`, whose `
|
|
37
|
-
- Never use worktrees. Resolve the declared branch with `
|
|
38
|
-
- Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `
|
|
39
|
-
- Keep all SDD state under the gitignored `docs/<slug>/sdd/`; use `
|
|
40
|
-
- After implementation, use `question` before an approved stash reapply through `
|
|
36
|
+
- Continuation uses `wk-handoff`, whose `workit_handoff_session` creates and seeds the OpenCode session automatically.
|
|
37
|
+
- Never use worktrees. Resolve the declared branch with `workit_resolve_branch`, preview dirty-tree stash choices with `question`, and apply an approved in-place checkout through `workit_branch_setup` with `confirmed: true` (grounded in the recorded NativeChoiceEvidence).
|
|
38
|
+
- Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`) and subagent-driven execution is rejected as unsupported.
|
|
39
|
+
- Keep all SDD state under the gitignored `docs/<slug>/sdd/`; use `workit_sdd_context` and the registered `workit_sdd_*` tools.
|
|
40
|
+
- After implementation, use `question` before an approved stash reapply through `workit_branch_setup` with `confirmed: true`.
|
|
41
41
|
|
|
42
42
|
## YouTrack content
|
|
43
43
|
|
|
44
|
-
Chat follows the user's language. YouTrack task comments are Spanish (`es-CL`) and use `
|
|
44
|
+
Chat follows the user's language. YouTrack task comments are Spanish (`es-CL`) and use `workit_youtrack_draft` followed by reviewed `workit_youtrack_post` with `confirmed: true`. Preserve the user's paragraph voice; do not inject commits, file paths, or robotic bullet reports.
|
|
45
45
|
|
|
46
46
|
## Final self-check
|
|
47
47
|
|
|
48
|
-
Before handoff, call `
|
|
48
|
+
Before handoff, call `workit_docs_validate` on the linked spec/plan pair. Hard-fail on any error; never offer execution when validation fails.
|
|
49
49
|
|
|
50
50
|
Before handoff, verify the saved spec path, plan path, declared branch, top-level task numbering, and workflow-managed SDD directory through the registered read-only workflow tools. Report structured failures; never infer success.
|
|
51
51
|
|
|
52
52
|
## Post-plan execution choice
|
|
53
53
|
|
|
54
|
-
After saving a plan, call `
|
|
54
|
+
After saving a plan, call `workit_docs_validate` on the spec/plan pair. On failure, stop and fix docs — do not offer execution.
|
|
55
55
|
|
|
56
56
|
On success, use native `question` / Cursor `AskQuestion` with exactly these options (no stay, no A/B/C prose duplicate):
|
|
57
57
|
|
|
@@ -60,10 +60,13 @@ On success, use native `question` / Cursor `AskQuestion` with exactly these opti
|
|
|
60
60
|
3. Handoff → load `wk-handoff` (new session only)
|
|
61
61
|
4. Review spec first
|
|
62
62
|
5. Review plan first
|
|
63
|
+
6. Change model first
|
|
64
|
+
|
|
65
|
+
`Change model first` is display-only deferral: it ends the turn without calling `workit_plan_menu` and re-presents the menu on the next turn. Every other choice must call `workit_plan_menu` immediately after the answer and before any skill, branch question, mutation, or handoff.
|
|
63
66
|
|
|
64
67
|
Never emit Superpowers text beginning “Two execution options”.
|
|
65
68
|
|
|
66
|
-
A handoff destination session (the seeded contract carries `<workflow-handoff-destination>true</workflow-handoff-destination>`) presents exactly
|
|
69
|
+
A handoff destination session (the seeded contract carries `<workflow-handoff-destination>true</workflow-handoff-destination>`) presents exactly five choices — Subagent-driven, Inline, Review spec first, Review plan first, Change model first — and never re-offers the originating handoff option.
|
|
67
70
|
|
|
68
71
|
- Specs/plans must follow `templates/spec-template.md` / `templates/plan-template.md` (mandated diagrams, tables, CA-XX).
|
|
69
72
|
|
package/dist/index.js
CHANGED
|
@@ -46436,6 +46436,7 @@ import {
|
|
|
46436
46436
|
fsyncSync,
|
|
46437
46437
|
mkdirSync as mkdirSync8,
|
|
46438
46438
|
openSync,
|
|
46439
|
+
readdirSync as readdirSync5,
|
|
46439
46440
|
readFileSync as readFileSync13,
|
|
46440
46441
|
renameSync as renameSync2,
|
|
46441
46442
|
rmSync as rmSync2,
|
|
@@ -46982,6 +46983,58 @@ function sddReviewPackage({
|
|
|
46982
46983
|
return { error: error instanceof Error ? error.message : "git diff failed" };
|
|
46983
46984
|
}
|
|
46984
46985
|
}
|
|
46986
|
+
function sddAppendAdvisory({
|
|
46987
|
+
advisories_path,
|
|
46988
|
+
task_id,
|
|
46989
|
+
text,
|
|
46990
|
+
workspace_root
|
|
46991
|
+
}) {
|
|
46992
|
+
if (typeof task_id !== "number" || !Number.isSafeInteger(task_id) || task_id <= 0) {
|
|
46993
|
+
return { error: "task_id must be a positive safe integer", code: "advisory_task_invalid" };
|
|
46994
|
+
}
|
|
46995
|
+
if (typeof text !== "string") {
|
|
46996
|
+
return {
|
|
46997
|
+
error: "advisory text must be a string of 1-1000 characters after normalization",
|
|
46998
|
+
code: "advisory_text_invalid"
|
|
46999
|
+
};
|
|
47000
|
+
}
|
|
47001
|
+
if (text.includes("\r") || text.includes(`
|
|
47002
|
+
`)) {
|
|
47003
|
+
return {
|
|
47004
|
+
error: "advisory text must be a single line (no CR/LF)",
|
|
47005
|
+
code: "advisory_text_invalid"
|
|
47006
|
+
};
|
|
47007
|
+
}
|
|
47008
|
+
const collapsed = text.trim().replace(/[ \t]+/g, " ");
|
|
47009
|
+
if (collapsed.length === 0 || collapsed.length > 1000) {
|
|
47010
|
+
return {
|
|
47011
|
+
error: "advisory text must be 1-1000 characters after trim and horizontal-space collapse",
|
|
47012
|
+
code: "advisory_text_invalid"
|
|
47013
|
+
};
|
|
47014
|
+
}
|
|
47015
|
+
if (!/^docs\/[^/]+\/sdd\/advisories\.md$/.test(advisories_path)) {
|
|
47016
|
+
return {
|
|
47017
|
+
error: `advisories_path must be docs/<slug>/sdd/advisories.md: ${advisories_path}`,
|
|
47018
|
+
code: "advisory_path_invalid"
|
|
47019
|
+
};
|
|
47020
|
+
}
|
|
47021
|
+
const contained = resolveDocsPath({ workspace_root, path: advisories_path });
|
|
47022
|
+
if (!contained.ok)
|
|
47023
|
+
return { error: contained.error, code: "advisory_path_invalid" };
|
|
47024
|
+
const abs = contained.path;
|
|
47025
|
+
if (existsSync12(abs) && statSync5(abs).isDirectory()) {
|
|
47026
|
+
return {
|
|
47027
|
+
error: `advisory target is a directory: ${advisories_path}`,
|
|
47028
|
+
code: "advisory_target_invalid"
|
|
47029
|
+
};
|
|
47030
|
+
}
|
|
47031
|
+
mkdirSync6(path15.dirname(abs), { recursive: true });
|
|
47032
|
+
const line = `- Task ${task_id}: ${collapsed}
|
|
47033
|
+
`;
|
|
47034
|
+
appendFileSync2(abs, line, "utf8");
|
|
47035
|
+
const rel = posix2(path15.relative(contained.base, abs));
|
|
47036
|
+
return { ok: true, advisory: collapsed, advisories_path: rel };
|
|
47037
|
+
}
|
|
46985
47038
|
|
|
46986
47039
|
// packages/workit-core/src/core/verify-project.ts
|
|
46987
47040
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
@@ -47370,7 +47423,7 @@ root: ${cwd2}
|
|
|
47370
47423
|
}
|
|
47371
47424
|
|
|
47372
47425
|
// packages/workit-core/src/core/flow-state.ts
|
|
47373
|
-
var COORDINATOR_RECOVERY_TEXT = "A subagent-driven plan is active: coordinator product edits are blocked. " + "Delegate product mutations
|
|
47426
|
+
var COORDINATOR_RECOVERY_TEXT = "A subagent-driven plan is active: coordinator product edits are blocked. " + "Delegate product mutations to an authenticated delegated worker via `task` / `wk-implement` instead of " + "editing in the coordinator session.";
|
|
47374
47427
|
var CURSOR_SUBAGENT_UNSUPPORTED_TEXT = "Cursor cannot execute subagent-driven plans: the MCP has no child-session " + "support. Choose Inline, Handoff, or a review option in this session, or " + "run the plan in OpenCode with `wk-implement`.";
|
|
47375
47428
|
var MENU_CHOICES = [
|
|
47376
47429
|
"subagent-driven",
|
|
@@ -47503,6 +47556,12 @@ var validateState = (parsed, slug) => {
|
|
|
47503
47556
|
if (execRaw?.evidence !== undefined && !validateEvidenceValue(execRaw.evidence, true)) {
|
|
47504
47557
|
return { ok: false, error: "flow state execution.evidence has an unsupported shape" };
|
|
47505
47558
|
}
|
|
47559
|
+
if (execRaw?.coordinator_session_id !== undefined && execRaw.coordinator_session_id !== null && typeof execRaw.coordinator_session_id !== "string") {
|
|
47560
|
+
return {
|
|
47561
|
+
ok: false,
|
|
47562
|
+
error: "flow state execution.coordinator_session_id must be a string or null"
|
|
47563
|
+
};
|
|
47564
|
+
}
|
|
47506
47565
|
return {
|
|
47507
47566
|
ok: true,
|
|
47508
47567
|
state: {
|
|
@@ -47518,7 +47577,8 @@ var validateState = (parsed, slug) => {
|
|
|
47518
47577
|
execution: {
|
|
47519
47578
|
status: execRaw?.status ?? "pending",
|
|
47520
47579
|
mode: execRaw?.mode ?? null,
|
|
47521
|
-
evidence: execRaw?.evidence ?? null
|
|
47580
|
+
evidence: execRaw?.evidence ?? null,
|
|
47581
|
+
coordinator_session_id: execRaw?.coordinator_session_id ?? null
|
|
47522
47582
|
},
|
|
47523
47583
|
handoff_destination: parsed.handoff_destination ?? false,
|
|
47524
47584
|
updated_at: parsed.updated_at ?? Date.now()
|
|
@@ -47529,7 +47589,7 @@ var readFlowStrict = (root, slug) => {
|
|
|
47529
47589
|
const file = flowPath(root, slug);
|
|
47530
47590
|
const rel = path18.posix.join("docs", slug, "sdd", "flow.json");
|
|
47531
47591
|
if (!existsSync14(file)) {
|
|
47532
|
-
return err2("flow_not_activated", `flow not activated for ${slug} — run
|
|
47592
|
+
return err2("flow_not_activated", `flow not activated for ${slug} — run workit_flow_status first`);
|
|
47533
47593
|
}
|
|
47534
47594
|
let text;
|
|
47535
47595
|
try {
|
|
@@ -47655,7 +47715,7 @@ var resetForSpecDrift = (state) => ({
|
|
|
47655
47715
|
spec: { ...state.spec, status: "draft", evidence: null, approved_digest: null },
|
|
47656
47716
|
plan: { ...state.plan, status: "draft", evidence: null, approved_digest: null },
|
|
47657
47717
|
menu: { presented: false, chosen: "", evidence: null },
|
|
47658
|
-
execution: { status: "pending", mode: null, evidence: null },
|
|
47718
|
+
execution: { status: "pending", mode: null, evidence: null, coordinator_session_id: null },
|
|
47659
47719
|
handoff_destination: false,
|
|
47660
47720
|
updated_at: Date.now()
|
|
47661
47721
|
});
|
|
@@ -47698,9 +47758,14 @@ var reconcileState = (root, slug, state) => {
|
|
|
47698
47758
|
var deriveLegacyExecution = (root, slug, state) => {
|
|
47699
47759
|
const ledger = ledgerCompletion(root, slug);
|
|
47700
47760
|
if (state.plan.status === "approved" && state.menu.chosen === "subagent-driven" && ledger.started && !ledger.complete) {
|
|
47701
|
-
return {
|
|
47761
|
+
return {
|
|
47762
|
+
status: "active",
|
|
47763
|
+
mode: "subagent-driven",
|
|
47764
|
+
evidence: null,
|
|
47765
|
+
coordinator_session_id: null
|
|
47766
|
+
};
|
|
47702
47767
|
}
|
|
47703
|
-
return { status: "pending", mode: null, evidence: null };
|
|
47768
|
+
return { status: "pending", mode: null, evidence: null, coordinator_session_id: null };
|
|
47704
47769
|
};
|
|
47705
47770
|
var normalizeCompatibility = (root, slug, parsed, state) => {
|
|
47706
47771
|
if (!isRecord3(parsed) || !("execution" in parsed)) {
|
|
@@ -47709,6 +47774,11 @@ var normalizeCompatibility = (root, slug, parsed, state) => {
|
|
|
47709
47774
|
if (derived.status !== current.status || derived.mode !== current.mode) {
|
|
47710
47775
|
return { state: { ...state, execution: derived, updated_at: Date.now() }, changed: true };
|
|
47711
47776
|
}
|
|
47777
|
+
return { state, changed: false };
|
|
47778
|
+
}
|
|
47779
|
+
const execRaw = isRecord3(parsed.execution) ? parsed.execution : undefined;
|
|
47780
|
+
if (execRaw && !("coordinator_session_id" in execRaw)) {
|
|
47781
|
+
return { state: { ...state, updated_at: Date.now() }, changed: true };
|
|
47712
47782
|
}
|
|
47713
47783
|
return { state, changed: false };
|
|
47714
47784
|
};
|
|
@@ -47871,19 +47941,49 @@ var isNegativeLabel = (label) => {
|
|
|
47871
47941
|
return firstWord.replace(/[^a-z]/g, "") === entry;
|
|
47872
47942
|
});
|
|
47873
47943
|
};
|
|
47944
|
+
var receiptPurposeForLabel = (label) => {
|
|
47945
|
+
const n = normalizeLabel(label);
|
|
47946
|
+
if (n === "approve spec" || n === "approve spec recommended")
|
|
47947
|
+
return "spec-approval";
|
|
47948
|
+
if (n === "approve plan" || n === "approve plan recommended")
|
|
47949
|
+
return "plan-approval";
|
|
47950
|
+
if (n === "approve")
|
|
47951
|
+
return;
|
|
47952
|
+
if (n === "pause plan")
|
|
47953
|
+
return "plan-pause";
|
|
47954
|
+
if (n === "resume plan")
|
|
47955
|
+
return "plan-resume";
|
|
47956
|
+
if (n === "complete plan")
|
|
47957
|
+
return "plan-complete";
|
|
47958
|
+
const exec3 = new Set([
|
|
47959
|
+
"subagent driven",
|
|
47960
|
+
"inline",
|
|
47961
|
+
"handoff",
|
|
47962
|
+
"review spec",
|
|
47963
|
+
"review plan",
|
|
47964
|
+
"change model"
|
|
47965
|
+
]);
|
|
47966
|
+
if (exec3.has(n))
|
|
47967
|
+
return "execution-menu";
|
|
47968
|
+
return;
|
|
47969
|
+
};
|
|
47874
47970
|
|
|
47875
47971
|
class HostReceiptStore {
|
|
47876
47972
|
#bySession = new Map;
|
|
47877
|
-
record(sessionId, callID, selectedLabel, recordedAt = Date.now(), question) {
|
|
47878
|
-
const
|
|
47879
|
-
if (!
|
|
47973
|
+
record(sessionId, callID, selectedLabel, recordedAt = Date.now(), question = "", purpose) {
|
|
47974
|
+
const trimmed = selectedLabel.trim();
|
|
47975
|
+
if (!trimmed)
|
|
47880
47976
|
return;
|
|
47881
47977
|
if (recordedAt > Date.now() + MAX_CLOCK_SKEW_MS)
|
|
47882
47978
|
return;
|
|
47979
|
+
const derived = purpose ?? receiptPurposeForLabel(selectedLabel);
|
|
47980
|
+
if (derived === undefined)
|
|
47981
|
+
return;
|
|
47982
|
+
const q = question ?? "";
|
|
47883
47983
|
const queue = this.#bySession.get(sessionId) ?? [];
|
|
47884
47984
|
if (queue.length >= MAX_RECEIPTS_PER_SESSION)
|
|
47885
47985
|
queue.shift();
|
|
47886
|
-
queue.push({ sessionId, callID, selectedLabel
|
|
47986
|
+
queue.push({ sessionId, callID, selectedLabel, recordedAt, question: q, purpose: derived });
|
|
47887
47987
|
this.#bySession.set(sessionId, queue);
|
|
47888
47988
|
}
|
|
47889
47989
|
count(sessionId) {
|
|
@@ -47900,10 +48000,40 @@ class HostReceiptStore {
|
|
|
47900
48000
|
if (!queue || queue.length === 0) {
|
|
47901
48001
|
return err2("receipt_missing", "no host-observed native-question receipt for this session — ask the native " + "`question` tool and have the user answer before calling this tool");
|
|
47902
48002
|
}
|
|
47903
|
-
|
|
48003
|
+
let index = -1;
|
|
48004
|
+
if (opts.purpose !== undefined) {
|
|
48005
|
+
const top = queue[queue.length - 1];
|
|
48006
|
+
if (top && top.purpose === opts.purpose && isNegativeLabel(top.selectedLabel)) {
|
|
48007
|
+
const filtered = queue.filter((r) => r.purpose !== opts.purpose);
|
|
48008
|
+
if (filtered.length === 0)
|
|
48009
|
+
this.#bySession.delete(sessionId);
|
|
48010
|
+
else
|
|
48011
|
+
this.#bySession.set(sessionId, filtered);
|
|
48012
|
+
return err2("receipt_rejected", `the user's most recent answer (${JSON.stringify(top.selectedLabel)}) is a ` + "negative answer — it cannot authorize an approval; ask the native question again");
|
|
48013
|
+
}
|
|
48014
|
+
for (let i = queue.length - 1;i >= 0; i--) {
|
|
48015
|
+
if (queue[i].purpose === opts.purpose) {
|
|
48016
|
+
index = i;
|
|
48017
|
+
break;
|
|
48018
|
+
}
|
|
48019
|
+
}
|
|
48020
|
+
if (index === -1) {
|
|
48021
|
+
return err2("receipt_missing", `no host-observed receipt for purpose ${JSON.stringify(opts.purpose)} — ask the native question for that purpose`);
|
|
48022
|
+
}
|
|
48023
|
+
} else {
|
|
48024
|
+
index = queue.length - 1;
|
|
48025
|
+
}
|
|
47904
48026
|
const receipt = queue[index];
|
|
47905
48027
|
if (isNegativeLabel(receipt.selectedLabel)) {
|
|
47906
|
-
|
|
48028
|
+
if (opts.purpose !== undefined) {
|
|
48029
|
+
const filtered = queue.filter((r) => r.purpose !== opts.purpose);
|
|
48030
|
+
if (filtered.length === 0)
|
|
48031
|
+
this.#bySession.delete(sessionId);
|
|
48032
|
+
else
|
|
48033
|
+
this.#bySession.set(sessionId, filtered);
|
|
48034
|
+
} else {
|
|
48035
|
+
this.#bySession.delete(sessionId);
|
|
48036
|
+
}
|
|
47907
48037
|
return err2("receipt_rejected", `the user's most recent answer (${JSON.stringify(receipt.selectedLabel)}) is a ` + "negative answer — it cannot authorize an approval; ask the native question again");
|
|
47908
48038
|
}
|
|
47909
48039
|
if (opts.label !== undefined && !sameChoiceLabel(receipt.selectedLabel, opts.label)) {
|
|
@@ -48095,7 +48225,7 @@ var completeExecution = (root, slug, deps) => {
|
|
|
48095
48225
|
}
|
|
48096
48226
|
const next = {
|
|
48097
48227
|
...reconciled.state,
|
|
48098
|
-
execution: { ...exec3, status: "completed" },
|
|
48228
|
+
execution: { ...exec3, status: "completed", coordinator_session_id: null },
|
|
48099
48229
|
handoff_destination: false,
|
|
48100
48230
|
updated_at: Date.now()
|
|
48101
48231
|
};
|
|
@@ -48155,6 +48285,38 @@ var slugFromPath = (p) => {
|
|
|
48155
48285
|
const dirName = path18.basename(path18.dirname(p));
|
|
48156
48286
|
return dirName === "." || dirName === "/" || dirName === "" ? "" : dirName;
|
|
48157
48287
|
};
|
|
48288
|
+
var assertSddControlGates = (root, slug, opts = {}, ctx) => {
|
|
48289
|
+
const bound = assertMutationWorkspace(root, ctx);
|
|
48290
|
+
if (!bound.ok)
|
|
48291
|
+
return bound;
|
|
48292
|
+
const effective = readEffectiveFlowState(root, slug);
|
|
48293
|
+
if (!effective.ok)
|
|
48294
|
+
return effective;
|
|
48295
|
+
const state = effective.state;
|
|
48296
|
+
if (state.spec.status !== "approved") {
|
|
48297
|
+
return err2("spec_not_approved", `spec not approved (status: ${state.spec.status}). Run workit_spec_approve after the user's approval.`);
|
|
48298
|
+
}
|
|
48299
|
+
if (state.plan.status !== "approved") {
|
|
48300
|
+
return err2("plan_not_approved", `plan not approved (status: ${state.plan.status}). Run workit_plan_approve after the user's approval.`);
|
|
48301
|
+
}
|
|
48302
|
+
if (opts.requireMenu && !state.menu.presented) {
|
|
48303
|
+
return err2("menu_not_presented", "post-plan menu not presented. Record the native question answer with workit_plan_menu.");
|
|
48304
|
+
}
|
|
48305
|
+
if (opts.requireDocs) {
|
|
48306
|
+
const validated = docsValidate({
|
|
48307
|
+
spec_path: path18.posix.join("docs", slug, "spec.md"),
|
|
48308
|
+
plan_path: path18.posix.join("docs", slug, "plan.md"),
|
|
48309
|
+
workspace_root: root
|
|
48310
|
+
});
|
|
48311
|
+
if (validated.ok === false)
|
|
48312
|
+
return err2("docs_invalid", validated.error);
|
|
48313
|
+
}
|
|
48314
|
+
if (state.execution.status === "active" && state.execution.mode === "subagent-driven" && roleFromParentage(ctx?.parentSessionId, state.execution.coordinator_session_id) === "delegated") {
|
|
48315
|
+
return err2("sdd_control_denied", "SDD control metadata is coordinator-owned while a subagent-driven plan is active — delegated workers cannot mutate task briefs, review packages, progress, or advisories");
|
|
48316
|
+
}
|
|
48317
|
+
return { ok: true };
|
|
48318
|
+
};
|
|
48319
|
+
var roleFromParentage = (parentID, coordinatorSessionId) => typeof parentID === "string" && parentID !== "" && parentID === coordinatorSessionId ? "delegated" : "coordinator";
|
|
48158
48320
|
var BASH_READ_TOKENS = new Set([
|
|
48159
48321
|
"cat",
|
|
48160
48322
|
"head",
|
|
@@ -48282,12 +48444,12 @@ var COORDINATOR_SHELL_DENIED_TEXT = "Coordinator shell commands are restricted w
|
|
|
48282
48444
|
import path20 from "node:path";
|
|
48283
48445
|
|
|
48284
48446
|
// packages/workit-core/src/core/handoff-context.ts
|
|
48285
|
-
import { existsSync as existsSync15, readFileSync as readFileSync14, readdirSync as
|
|
48447
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
48286
48448
|
import path19 from "node:path";
|
|
48287
48449
|
var DOC_RE = /docs\/([A-Za-z0-9][A-Za-z0-9._-]*)\/(spec|plan)\.md/g;
|
|
48288
48450
|
var listMd = (dir) => {
|
|
48289
48451
|
try {
|
|
48290
|
-
return
|
|
48452
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".md")).sort();
|
|
48291
48453
|
} catch {
|
|
48292
48454
|
return [];
|
|
48293
48455
|
}
|
|
@@ -48313,7 +48475,7 @@ var resolveActivePair = (root) => {
|
|
|
48313
48475
|
let best = null;
|
|
48314
48476
|
let entries = [];
|
|
48315
48477
|
try {
|
|
48316
|
-
entries =
|
|
48478
|
+
entries = readdirSync6(docsDir);
|
|
48317
48479
|
} catch {
|
|
48318
48480
|
return { error: "no pair" };
|
|
48319
48481
|
}
|
|
@@ -48405,13 +48567,21 @@ var buildHandoffPrompt = (root, message) => {
|
|
|
48405
48567
|
};
|
|
48406
48568
|
|
|
48407
48569
|
// packages/workit-cli/src/flow.ts
|
|
48408
|
-
var FLOW_ACTIONS = [
|
|
48570
|
+
var FLOW_ACTIONS = [
|
|
48571
|
+
"status",
|
|
48572
|
+
"pause",
|
|
48573
|
+
"resume",
|
|
48574
|
+
"complete",
|
|
48575
|
+
"review-package",
|
|
48576
|
+
"append-advisory"
|
|
48577
|
+
];
|
|
48409
48578
|
var COMMANDS = {
|
|
48410
48579
|
status: "workit flow status --plan <path>",
|
|
48411
48580
|
pause: "workit flow pause --plan <path> [--confirm]",
|
|
48412
48581
|
resume: "workit flow resume --plan <path> [--confirm]",
|
|
48413
48582
|
complete: "workit flow complete --plan <path> [--confirm]",
|
|
48414
48583
|
"review-package": "workit flow review-package --plan <path> --base <sha> --head <sha> [--confirm]",
|
|
48584
|
+
"append-advisory": "workit flow append-advisory --plan <path> --task <id> --text <text> [--confirm]",
|
|
48415
48585
|
handoff: "workit handoff --message <text>"
|
|
48416
48586
|
};
|
|
48417
48587
|
var FLOW_COMMANDS = {
|
|
@@ -48419,7 +48589,8 @@ var FLOW_COMMANDS = {
|
|
|
48419
48589
|
pause: COMMANDS.pause,
|
|
48420
48590
|
resume: COMMANDS.resume,
|
|
48421
48591
|
complete: COMMANDS.complete,
|
|
48422
|
-
"review-package": COMMANDS["review-package"]
|
|
48592
|
+
"review-package": COMMANDS["review-package"],
|
|
48593
|
+
"append-advisory": COMMANDS["append-advisory"]
|
|
48423
48594
|
};
|
|
48424
48595
|
var CLI_FLAG_EVIDENCE = { host: "cli", attested: false, confirmation: "flag" };
|
|
48425
48596
|
var CLI_TTY_EVIDENCE = { host: "cli", attested: false, confirmation: "tty" };
|
|
@@ -48452,14 +48623,22 @@ var usage = (err3, text) => {
|
|
|
48452
48623
|
write(err3, text);
|
|
48453
48624
|
return 2;
|
|
48454
48625
|
};
|
|
48455
|
-
var VALUE_FLAGS = ["--plan", "--base", "--head"];
|
|
48626
|
+
var VALUE_FLAGS = ["--plan", "--base", "--head", "--task", "--text"];
|
|
48456
48627
|
function parseFlowFlags(action, argv, err3) {
|
|
48457
48628
|
const parsed = {};
|
|
48458
48629
|
let confirm = false;
|
|
48459
48630
|
for (let i = 0;i < argv.length; i++) {
|
|
48460
48631
|
const token = argv[i];
|
|
48461
48632
|
if (VALUE_FLAGS.includes(token)) {
|
|
48462
|
-
if (token !== "--plan" && action !== "review-package") {
|
|
48633
|
+
if (token !== "--plan" && action !== "review-package" && action !== "append-advisory") {
|
|
48634
|
+
usage(err3, `usage: ${FLOW_COMMANDS[action]} — unknown flag: ${token}`);
|
|
48635
|
+
return { ok: false };
|
|
48636
|
+
}
|
|
48637
|
+
if ((token === "--base" || token === "--head") && action !== "review-package") {
|
|
48638
|
+
usage(err3, `usage: ${FLOW_COMMANDS[action]} — unknown flag: ${token}`);
|
|
48639
|
+
return { ok: false };
|
|
48640
|
+
}
|
|
48641
|
+
if ((token === "--task" || token === "--text") && action !== "append-advisory") {
|
|
48463
48642
|
usage(err3, `usage: ${FLOW_COMMANDS[action]} — unknown flag: ${token}`);
|
|
48464
48643
|
return { ok: false };
|
|
48465
48644
|
}
|
|
@@ -48473,7 +48652,7 @@ function parseFlowFlags(action, argv, err3) {
|
|
|
48473
48652
|
usage(err3, `usage: ${FLOW_COMMANDS[action]} — unknown flag: ${value}`);
|
|
48474
48653
|
return { ok: false };
|
|
48475
48654
|
}
|
|
48476
|
-
const existing = token === "--plan" ? parsed.plan : token === "--base" ? parsed.base : parsed.head;
|
|
48655
|
+
const existing = token === "--plan" ? parsed.plan : token === "--base" ? parsed.base : token === "--head" ? parsed.head : token === "--task" ? parsed.task : parsed.text;
|
|
48477
48656
|
if (existing !== undefined) {
|
|
48478
48657
|
usage(err3, `usage: ${FLOW_COMMANDS[action]} — duplicate ${token} flag`);
|
|
48479
48658
|
return { ok: false };
|
|
@@ -48482,8 +48661,12 @@ function parseFlowFlags(action, argv, err3) {
|
|
|
48482
48661
|
parsed.plan = value;
|
|
48483
48662
|
else if (token === "--base")
|
|
48484
48663
|
parsed.base = value;
|
|
48485
|
-
else
|
|
48664
|
+
else if (token === "--head")
|
|
48486
48665
|
parsed.head = value;
|
|
48666
|
+
else if (token === "--task")
|
|
48667
|
+
parsed.task = value;
|
|
48668
|
+
else
|
|
48669
|
+
parsed.text = value;
|
|
48487
48670
|
i += 1;
|
|
48488
48671
|
} else if (token === "--confirm") {
|
|
48489
48672
|
if (action === "status") {
|
|
@@ -48514,7 +48697,27 @@ function parseFlowFlags(action, argv, err3) {
|
|
|
48514
48697
|
return { ok: false };
|
|
48515
48698
|
}
|
|
48516
48699
|
}
|
|
48517
|
-
|
|
48700
|
+
if (action === "append-advisory") {
|
|
48701
|
+
if (parsed.task === undefined) {
|
|
48702
|
+
usage(err3, `usage: ${FLOW_COMMANDS[action]} — --task <id> required`);
|
|
48703
|
+
return { ok: false };
|
|
48704
|
+
}
|
|
48705
|
+
if (parsed.text === undefined) {
|
|
48706
|
+
usage(err3, `usage: ${FLOW_COMMANDS[action]} — --text <text> required`);
|
|
48707
|
+
return { ok: false };
|
|
48708
|
+
}
|
|
48709
|
+
}
|
|
48710
|
+
return {
|
|
48711
|
+
ok: true,
|
|
48712
|
+
parsed: {
|
|
48713
|
+
plan: parsed.plan,
|
|
48714
|
+
confirm,
|
|
48715
|
+
base: parsed.base,
|
|
48716
|
+
head: parsed.head,
|
|
48717
|
+
task: parsed.task,
|
|
48718
|
+
text: parsed.text
|
|
48719
|
+
}
|
|
48720
|
+
};
|
|
48518
48721
|
}
|
|
48519
48722
|
async function resolveConfirmation(deps, confirmFlag, out, err3) {
|
|
48520
48723
|
if (confirmFlag)
|
|
@@ -48590,12 +48793,34 @@ function reviewPackageCommand(root, parsed, out, err3) {
|
|
|
48590
48793
|
}
|
|
48591
48794
|
return domainFail(err3, result2.code ?? "review_package_failed", result2.error);
|
|
48592
48795
|
}
|
|
48796
|
+
function appendAdvisoryCommand(root, parsed, out, err3) {
|
|
48797
|
+
const resolved = resolveCanonicalLayout({ workspace_root: root, plan_path: parsed.plan });
|
|
48798
|
+
if (!resolved.ok)
|
|
48799
|
+
return domainFail(err3, "path_invalid", resolved.error);
|
|
48800
|
+
const slug = resolved.layout.slug;
|
|
48801
|
+
const controlGate = assertSddControlGates(root, slug, { requireMenu: true, requireDocs: true });
|
|
48802
|
+
if (!controlGate.ok)
|
|
48803
|
+
return domainFail(err3, controlGate.code, controlGate.error);
|
|
48804
|
+
const trimmed = parsed.task.trim();
|
|
48805
|
+
const taskId = /^-?\d+(\.\d+)?$/.test(trimmed) ? Number(trimmed) : trimmed;
|
|
48806
|
+
const result2 = sddAppendAdvisory({
|
|
48807
|
+
advisories_path: path21.posix.join("docs", slug, "sdd", "advisories.md"),
|
|
48808
|
+
task_id: taskId,
|
|
48809
|
+
text: parsed.text,
|
|
48810
|
+
workspace_root: root
|
|
48811
|
+
});
|
|
48812
|
+
if ("error" in result2) {
|
|
48813
|
+
return domainFail(err3, result2.code ?? "advisory_failed", result2.error);
|
|
48814
|
+
}
|
|
48815
|
+
writeJSON(out, { ok: true, advisories_path: result2.advisories_path, advisory: result2.advisory });
|
|
48816
|
+
return 0;
|
|
48817
|
+
}
|
|
48593
48818
|
async function runFlowCommand(argv, deps = {}) {
|
|
48594
48819
|
const out = outStream(deps);
|
|
48595
48820
|
const err3 = errStream(deps);
|
|
48596
48821
|
const [action, ...rest2] = argv;
|
|
48597
48822
|
if (!action || !FLOW_ACTIONS.includes(action)) {
|
|
48598
|
-
return usage(err3, "usage: workit flow <status|pause|resume|complete|review-package> --plan <path> [--confirm]");
|
|
48823
|
+
return usage(err3, "usage: workit flow <status|pause|resume|complete|review-package|append-advisory> --plan <path> [--confirm]");
|
|
48599
48824
|
}
|
|
48600
48825
|
const flowAction = action;
|
|
48601
48826
|
const parsed = parseFlowFlags(flowAction, rest2, err3);
|
|
@@ -48611,6 +48836,9 @@ async function runFlowCommand(argv, deps = {}) {
|
|
|
48611
48836
|
if (flowAction === "review-package") {
|
|
48612
48837
|
return reviewPackageCommand(root, parsed.parsed, out, err3);
|
|
48613
48838
|
}
|
|
48839
|
+
if (flowAction === "append-advisory") {
|
|
48840
|
+
return appendAdvisoryCommand(root, parsed.parsed, out, err3);
|
|
48841
|
+
}
|
|
48614
48842
|
return mutateCommand(root, parsed.parsed.plan, flowAction, evidence, deps, out, err3);
|
|
48615
48843
|
}
|
|
48616
48844
|
async function runHandoffCommand(argv, deps = {}) {
|
|
@@ -48649,6 +48877,7 @@ var COMMAND_DESCRIPTIONS = [
|
|
|
48649
48877
|
[COMMANDS.resume, "Resume a paused plan"],
|
|
48650
48878
|
[COMMANDS.complete, "Complete a plan (ledger and verification gated)"],
|
|
48651
48879
|
[COMMANDS["review-package"], "Write a review diff for a base..head range"],
|
|
48880
|
+
[COMMANDS["append-advisory"], "Append an advisory line to docs/<slug>/sdd/advisories.md"],
|
|
48652
48881
|
[COMMANDS.handoff, "Emit the destination handoff prompt for a plan"]
|
|
48653
48882
|
];
|
|
48654
48883
|
var helpColumn = Math.max(...COMMAND_DESCRIPTIONS.map(([cmd]) => cmd.length)) + 2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.10",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit interactive setup wizard (Ink TUI)",
|
|
6
6
|
"keywords": [
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"typecheck": "tsc --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@brainervirus/workit-core": "^0.8.
|
|
38
|
-
"@brainervirus/workit-cursor": "^0.8.
|
|
39
|
-
"@brainervirus/workit-opencode": "^0.8.
|
|
37
|
+
"@brainervirus/workit-core": "^0.8.10",
|
|
38
|
+
"@brainervirus/workit-cursor": "^0.8.10",
|
|
39
|
+
"@brainervirus/workit-opencode": "^0.8.10",
|
|
40
40
|
"@inkjs/ui": "2.0.0",
|
|
41
41
|
"ink": "7.1.1",
|
|
42
42
|
"react": "19.2.8"
|