@deniscodp/skills 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +89 -2
- package/bin/deniscodp-skills.mjs +4 -0
- package/package.json +23 -4
- package/scripts/catalog.mjs +68 -0
- package/scripts/cli.mjs +264 -0
- package/scripts/install.mjs +184 -0
- package/scripts/recommended.mjs +102 -0
- package/skills/denisco-handoff-implementation/SKILL.md +254 -0
- package/skills/denisco-handoff-implementation/references/blocker-checklist.md +71 -0
- package/skills/denisco-handoff-implementation/references/delegated-implementation.md +168 -0
- package/skills/denisco-handoff-implementation/references/ownership.md +105 -0
- package/skills/denisco-handoff-implementation/references/session-plan.md +195 -0
- package/skills/denisco-handoff-implementation/scripts/ownership.mjs +153 -0
- package/skills/denisco-implementation-coordinator/SKILL.md +237 -0
- package/skills/denisco-implementation-coordinator/agents/openai.yaml +2 -0
- package/skills/denisco-implementation-coordinator/references/documents.md +175 -0
- package/skills/denisco-implementation-coordinator/references/runtimes.md +105 -0
- package/skills/denisco-interactive-spec-definition/SKILL.md +126 -0
- package/skills/denisco-interactive-spec-definition/references/blocker-checklist.md +71 -0
- package/skills/denisco-interactive-spec-definition/references/handoff-template.md +124 -0
- package/skills/denisco-project-context/SKILL.md +60 -0
- package/skills/denisco-project-context/references/project-documents.md +70 -0
- package/skills/denisco-visual-check/SKILL.md +136 -0
- package/skills/denisco-visual-check/references/judge-prompt.md +55 -0
- package/skills/denisco-visual-check/references/project-config.md +118 -0
- package/skills/denisco-workflow-benchmark/SKILL.md +113 -0
- package/skills/denisco-workflow-benchmark/agents/openai.yaml +2 -0
- package/skills/denisco-workflow-benchmark/references/measurement.md +166 -0
- package/skills/denisco-workflow-benchmark/references/workflow-contract.md +371 -0
- package/skills/denisco-workflow-benchmark/scripts/bench.mjs +156 -0
- package/skills/denisco-workflow-benchmark/scripts/cases.mjs +46 -0
- package/skills/denisco-workflow-benchmark/scripts/configuration.mjs +71 -0
- package/skills/denisco-workflow-benchmark/scripts/discover.mjs +88 -0
- package/skills/denisco-workflow-benchmark/scripts/eval-worker.mjs +58 -0
- package/skills/denisco-workflow-benchmark/scripts/io.mjs +82 -0
- package/skills/denisco-workflow-benchmark/scripts/prepare.mjs +69 -0
- package/skills/denisco-workflow-benchmark/scripts/runs.mjs +235 -0
- package/skills/denisco-workflow-benchmark/scripts/state-prompt.mjs +96 -0
- package/skills/denisco-workflow-benchmark/scripts/tracking.mjs +91 -0
- package/skills/denisco-workflow-benchmark/scripts/usage.mjs +175 -0
- package/skills/denisco-workflow-benchmark/scripts/workflow.mjs +334 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Bounded implementation assignments
|
|
2
|
+
|
|
3
|
+
Read this contract for an explicit bounded request or an assignment from an authorized
|
|
4
|
+
`denisco-implementation-coordinator`. Direct "continue from B1" still continues through ready blocks.
|
|
5
|
+
"Only B1 and B2, then return" stops after those blocks. A saved starting-block prompt does not
|
|
6
|
+
override an explicit assignment boundary. This is a procedural boundary, not a filesystem sandbox.
|
|
7
|
+
|
|
8
|
+
For a direct bounded user request, resolve the named blocks and stop at that boundary using the
|
|
9
|
+
ordinary human-entry, question and persistence rules. Coordinator contact, coordination state and
|
|
10
|
+
worker parentage below apply only when an authorized coordinator actually dispatched the work.
|
|
11
|
+
|
|
12
|
+
## Assignment packet
|
|
13
|
+
|
|
14
|
+
The coordinator supplies concrete values for:
|
|
15
|
+
|
|
16
|
+
- Task and paths: worktree, handoff, PLAN, STATE, operational JSON, COORDINATOR and its history,
|
|
17
|
+
installed implementation skill. Coordination documents are read-only inputs for the worker.
|
|
18
|
+
The packet cites the history entries the worker needs; read those, not the whole history.
|
|
19
|
+
- Authorization: user's coordination request, date/scope, current restrictions and permission list
|
|
20
|
+
location. Forward actual known answers and external changes; do not imply unanswered actions are done.
|
|
21
|
+
- Assignment ID, attempt ID and kind: `implementation` or `integration`; ordered explicit block IDs, dependencies,
|
|
22
|
+
required criteria and any narrowed residual work. Expand ranges against PLAN, not numeric guesses.
|
|
23
|
+
- Stop boundary: return after this assignment; checkpoint early for context pressure or a real blocker.
|
|
24
|
+
Implementation cannot move into unassigned blocks. Integration names checks and allowed corrections
|
|
25
|
+
across listed blocks; it does not authorize new product goals.
|
|
26
|
+
- Profile and reading scope: requested effort; the HANDOFF points to read (the assigned points plus
|
|
27
|
+
the sections they cite); targeted checks, meaning browser checks of the assigned criteria and test
|
|
28
|
+
or build output read as summary and failures only; extra skills from the
|
|
29
|
+
operating guide's coordinated-workers section, or none.
|
|
30
|
+
- Coordinator contact and question route; observable limits; measurement state preserved from the
|
|
31
|
+
sidecar. With enabled measurement include actual parent-attribution evidence when available,
|
|
32
|
+
never another session's registration ticket or ownership token.
|
|
33
|
+
|
|
34
|
+
Example dispatch (substitute actual paths and recorded evidence):
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Use denisco-handoff-implementation at <installed-skill-path> and its bounded-assignment contract.
|
|
38
|
+
Worktree: <absolute-project-path>. Task: <task-id>. Handoff: <absolute-HANDOFF>.
|
|
39
|
+
Read <STATE>, <PLAN>, <operational-JSON>, <COORDINATOR> and the COORDINATOR-HISTORY entries
|
|
40
|
+
<entry headings>; follow applicable project instructions.
|
|
41
|
+
Authorization: <recorded user request/date and approved scope>; restrictions: <current limits>.
|
|
42
|
+
Coordinator: <contact>. Assignment A2, attempt A2-1, kind implementation. Execute ONLY B3, B4, B5, B6 in
|
|
43
|
+
dependency order. Required criteria and dependencies are in PLAN. Return after B6; do not start B7.
|
|
44
|
+
Profile: light, effort medium. Read only HANDOFF points <P3-P6> and the sections they cite.
|
|
45
|
+
Browser: targeted checks of the assigned criteria. Tests and builds: full output to a log file;
|
|
46
|
+
read only the summary and the failures. Extra skills: <from the operating guide, or none>.
|
|
47
|
+
Known user answers/changes: <recorded answers or none reported; pending actions stay pending>.
|
|
48
|
+
Measurement: disabled. Acquire your own worktree claim; the coordinator has released its claim.
|
|
49
|
+
If context pressure or a blocker prevents completion, checkpoint the residual work and return.
|
|
50
|
+
Route questions to the coordinator. Update technical documents only through denisco-handoff-implementation;
|
|
51
|
+
leave the coordination documents and packet files unchanged. Update STATE/STATE-HISTORY, save continuation,
|
|
52
|
+
clean up owned resources, hand over any service that stays up with port and PID, release the claim
|
|
53
|
+
and return the delivery defined by the bounded-assignment contract.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For integration replace the assignment line with the actual block IDs, cross-block checks,
|
|
57
|
+
outstanding criteria and correction scope. Attach a saved prompt as background only when useful;
|
|
58
|
+
the explicit bounded packet is the execution assignment, not the generic "continue from" text.
|
|
59
|
+
|
|
60
|
+
## Worker entry and authority
|
|
61
|
+
|
|
62
|
+
Read the applicable skills and assigned requirements in full, inspect repository evidence and
|
|
63
|
+
acquire a new claim under [ownership](ownership.md). Record assignment/attempt IDs, actual observed
|
|
64
|
+
worker identity and a link to COORDINATOR in STATE before application edits. If the prepared
|
|
65
|
+
coordination assignment, technical documents and incoming packet conflict, ask the
|
|
66
|
+
coordinator to reconcile before writing code. A prepared assignment without an active launch is
|
|
67
|
+
not permission for an unrelated process to take it. Resumed by message after an external
|
|
68
|
+
interruption, such as a usage limit or network error, recheck your claim with the ownership helper and continue from
|
|
69
|
+
your last checkpoint within the same assignment.
|
|
70
|
+
|
|
71
|
+
The programmer is the sole implementation owner: code, tests, HANDOFF, PLAN, STATE, STATE-HISTORY,
|
|
72
|
+
sidecar and enabled measurement are its responsibility under the existing standard workflow.
|
|
73
|
+
It updates STATE and appends its session entry to STATE-HISTORY, including when it is the final
|
|
74
|
+
integration worker. HANDOFF/PLAN/map changes follow the existing split, new-point, new-goal and
|
|
75
|
+
permission procedures; neither actor invents an alternative editing or approval path.
|
|
76
|
+
The coordinator reads these documents but never edits them, even between workers. Conversely,
|
|
77
|
+
the programmer never edits COORDINATOR or COORDINATOR-HISTORY, including for lifecycle bookkeeping.
|
|
78
|
+
A visual-only child has a narrower artifact scope;
|
|
79
|
+
do not confuse the two roles. The coordinator remains read-only while the programmer owns the worktree.
|
|
80
|
+
Delegation does not expand the handoff permission list or bypass any always-ask action.
|
|
81
|
+
|
|
82
|
+
Use the coordinator's recorded user updates instead of repeating human-entry questions. Send new
|
|
83
|
+
questions to the coordinator, work on independent assigned portions and record returned answers.
|
|
84
|
+
If communication is unavailable, save the question as a blocker and return rather than guess.
|
|
85
|
+
A plan split may clarify work within this assignment; new block IDs or changes extending its scope
|
|
86
|
+
require a revised coordinator assignment before execution. The worker does not dispatch its successor.
|
|
87
|
+
|
|
88
|
+
## Verification roles and measurement
|
|
89
|
+
|
|
90
|
+
The programmer performs ordinary denisco-visual-check captures and measurements as the implementation owner.
|
|
91
|
+
It follows denisco-visual-check's principal responsibilities for source stability, index updates and cleanup;
|
|
92
|
+
the restricted visual-child role applies only to a separately delegated visual-only checker.
|
|
93
|
+
Use the runtime's available independent judge, or relay its blind packet through the coordinator
|
|
94
|
+
when nested delegation is unavailable. The coordinator remains read-only during that relay.
|
|
95
|
+
A relay is a pause, not a delivery: checkpoint STATE, keep the claim and owned services, and hand
|
|
96
|
+
the coordinator the packet path marked as a relay request. It resumes this same worker with the
|
|
97
|
+
verbatim observations; the worker saves them as evidence and applies the predeclared condition.
|
|
98
|
+
Only when the runtime cannot resume the worker does the judgment become residual work in the
|
|
99
|
+
ordinary delivery.
|
|
100
|
+
|
|
101
|
+
With measurement enabled, native parentage remains factual: register the coordinator first, then
|
|
102
|
+
the programmer as its actual child, and judges under their actual parent. A programmer's visual
|
|
103
|
+
attempt uses `executor: subagent` with the coordinator as principal session when that is the native
|
|
104
|
+
relationship; a genuinely top-level executor uses `principal`. The explicit coordination request
|
|
105
|
+
includes the programmer's required checks. Reconcile future sidecar executor entries, preserving
|
|
106
|
+
historical attempts. The owning programmer records its own results; the coordinator must not write
|
|
107
|
+
the run concurrently. Missing native attribution/loading evidence stays pending, never relabeled
|
|
108
|
+
to satisfy the checker. With measurement disabled none of this activates benchmark tooling.
|
|
109
|
+
|
|
110
|
+
## Checkpoint and delivery
|
|
111
|
+
|
|
112
|
+
After each block update evidence and STATE normally. Within a long block or residual, also refresh
|
|
113
|
+
STATE after each verified correction or completed evidence run, so an interrupted attempt leaves a
|
|
114
|
+
resumable record. At the assignment boundary, or an early return,
|
|
115
|
+
finish applicable checks, preserve verification gaps, append a dated HISTORY entry and save the
|
|
116
|
+
ordinary implementation continuation for remaining task work. Even after the last implementation
|
|
117
|
+
block, retain a continuation anchored to that block while final integration remains; STATE names
|
|
118
|
+
the integration work so a direct manual resume does not redo finished implementation.
|
|
119
|
+
The coordinator owns group selection; a worker can propose the next step but cannot launch it.
|
|
120
|
+
Clean up or explicitly hand over retained resources, drain children, finish state/measurement writes
|
|
121
|
+
and release the claim before returning. A service that must stay up runs detached from you and is
|
|
122
|
+
handed over with port and PID, because the coordinator closes you after delivery. A final message
|
|
123
|
+
alone does not prove safe transfer.
|
|
124
|
+
|
|
125
|
+
Return the delivery in the user's language with these headings, every time, in this order; write
|
|
126
|
+
"unknown" or "none" rather than dropping a heading:
|
|
127
|
+
|
|
128
|
+
1. **Outcome:** one line with assignment and attempt IDs, blocks, implementation/verification status
|
|
129
|
+
and whether useful progress occurred.
|
|
130
|
+
2. **Blocks and criteria:** criterion results per block with evidence paths; verification gaps named.
|
|
131
|
+
3. **Commits and changes:** commits, changed areas, relevant dirty files/user changes and any
|
|
132
|
+
invalidated earlier evidence.
|
|
133
|
+
4. **Findings:** facts the coordinator or user should know, such as pre-existing defects or
|
|
134
|
+
technical choices recorded in PLAN.
|
|
135
|
+
5. **Residual work and questions:** exact unfinished work, blockers/questions and dependency
|
|
136
|
+
readiness, including context-driven stops; the supported next step.
|
|
137
|
+
6. **Your checks:** user verifications this work added to Your actions, with where and how.
|
|
138
|
+
7. **Cleanup, services and claim:** resource/child cleanup, services handed over with port and PID,
|
|
139
|
+
ownership-release result, STATE/HISTORY paths and the saved continuation location.
|
|
140
|
+
8. **Identity and configuration:** observed native worker identity; requested/observed model and
|
|
141
|
+
effort with sources or unknown values; fresh-context invocation evidence when available, never
|
|
142
|
+
an invented clear/reset.
|
|
143
|
+
|
|
144
|
+
## Technical persistence and coordinator references
|
|
145
|
+
|
|
146
|
+
Follow the existing session-plan contract for technical state and history. In STATE's Status keep
|
|
147
|
+
only the coordination link, assignment/attempt reference, actual worker identity and scoped execution
|
|
148
|
+
authorization alongside normal technical status. Put the programmer's work and evidence in its dated
|
|
149
|
+
STATE-HISTORY entry. The session grouping, recovery allowance, lifecycle history and coordination
|
|
150
|
+
launch/resume prompt belong in the coordinator-owned documents, never a second plan inside STATE.
|
|
151
|
+
|
|
152
|
+
The coordinator writes its prepared attempt before launching, then stays read-only until return
|
|
153
|
+
and verified handover. Its files may therefore lag a running worker. Persist the attempt identity
|
|
154
|
+
in the technical record so recovery can correlate it with native invocation/peer evidence and the
|
|
155
|
+
ownership claim. A prepared record or missing handle alone does not prove that no worker started.
|
|
156
|
+
Return the actual evidence; the coordinator records it after reacquiring, with the recording time.
|
|
157
|
+
|
|
158
|
+
For legacy Coordination notes in STATE, the coordinator imports supported facts into its own files
|
|
159
|
+
without touching technical documents. During the next ordinary authorized worker update, archive
|
|
160
|
+
the replaced notes unchanged in STATE-HISTORY and replace them with the short reference above.
|
|
161
|
+
Preserve technical results, outstanding user actions, authorization, retry facts and source history;
|
|
162
|
+
report conflicts to the coordinator before treating an old note as current. Do not erase old HISTORY
|
|
163
|
+
entries or restart a worker because of a migration. If migration cannot run yet, keep it pending.
|
|
164
|
+
|
|
165
|
+
The ordinary generated STATE prompt remains the direct implementation continuation. The separate
|
|
166
|
+
coordinator prompt lives in COORDINATOR. Its presence never activates delegation on a direct request.
|
|
167
|
+
The programmer clears only obsolete technical continuation prompts under the standard completion/stop
|
|
168
|
+
rules; the coordinator clears its own prompts. Neither clears the other's document or pending evidence.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# One writer per worktree
|
|
2
|
+
|
|
3
|
+
An assignment, native conversation ID, tracking ticket or saved continuation is not an execution
|
|
4
|
+
claim. Two interactive processes can resume the same conversation. Treat each new CLI/process
|
|
5
|
+
entry as a new execution instance even when its transcript contains an earlier claim token.
|
|
6
|
+
Compaction within a demonstrably continuous instance does not require reacquiring; if continuity
|
|
7
|
+
is uncertain, remain read-only and inspect the owner rather than adopting the transcript's token.
|
|
8
|
+
|
|
9
|
+
## Enter and claim
|
|
10
|
+
|
|
11
|
+
Before task writes (including PLAN/STATE, COORDINATOR and its history, sidecar, measurement registration, probes or builds),
|
|
12
|
+
inspect the actual Git worktree, current task documents and available peer/process metadata.
|
|
13
|
+
Distinguish top-level processes from explicitly delegated children using actual parent evidence;
|
|
14
|
+
sharing a native session ID proves neither that they are one process nor that one is a child.
|
|
15
|
+
Do not launch/resume a second implementation CLI to delegate a visual check.
|
|
16
|
+
|
|
17
|
+
Use the installed [ownership helper](../scripts/ownership.mjs), with Node 20+ in an initialized
|
|
18
|
+
Git worktree. It reads the `.git` directory/file directly and launches no subprocesses:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
node <denisco-handoff-implementation>/scripts/ownership.mjs status --worktree <directory>
|
|
22
|
+
node <denisco-handoff-implementation>/scripts/ownership.mjs acquire --worktree <directory> --handoff <file> --block <B1-or-planning> --session <diagnostic-label>
|
|
23
|
+
node <denisco-handoff-implementation>/scripts/ownership.mjs check --worktree <directory> --claim <returned-claimId>
|
|
24
|
+
node <denisco-handoff-implementation>/scripts/ownership.mjs release --worktree <directory> --claim <returned-claimId>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The agent runs these commands and keeps tokens internal; never ask the user to assemble them.
|
|
28
|
+
Acquisition creates `.agent/workflow-writer.json` at the real Git worktree root, independently of
|
|
29
|
+
measurement. It claims the whole worktree, including shared task state and tooling, not just B1.
|
|
30
|
+
Nested invocation paths resolve to the same root; separate Git worktrees have separate claims.
|
|
31
|
+
When task documents and code live in different worktrees of one repository, claim each worktree
|
|
32
|
+
you write and pass the same real HANDOFF to both acquisitions: the helper accepts a handoff in any
|
|
33
|
+
worktree of the same repository and rejects one from another repository.
|
|
34
|
+
Do not commit the local record. Existing task authorization permits this bookkeeping in writable
|
|
35
|
+
mode; read-only/Plan Mode uses `status` and leaves acquisition pending.
|
|
36
|
+
|
|
37
|
+
Acquire once on entry; only `acquired` permits writing. An existing claim always conflicts,
|
|
38
|
+
including one with the same session label. `--session` is diagnostic, not an ownership key.
|
|
39
|
+
Retain the newly returned claim ID only in the instance that acquired it; do not copy tokens from
|
|
40
|
+
the owner file, inherited conversation, another instance or a continuation prompt to pass `check`.
|
|
41
|
+
Recheck before each editing/verification phase and before shared state/register updates. Only
|
|
42
|
+
`owned-by-caller` permits continued writes; missing/replaced claims stop them.
|
|
43
|
+
|
|
44
|
+
This is a cooperative guard: it serializes claims, but cannot intercept arbitrary editor/shell
|
|
45
|
+
writes or prove which process supplied a token. Peer inspection and adherence remain necessary,
|
|
46
|
+
especially with older sessions that do not use the guard. A free claim does not make an observed
|
|
47
|
+
active legacy writer safe. If the helper is unavailable or cannot establish the worktree, report
|
|
48
|
+
that narrow blocker and continue read-only inspection, not unguarded implementation.
|
|
49
|
+
|
|
50
|
+
## Conflict and transfer
|
|
51
|
+
|
|
52
|
+
With another owner, keep this instance read-only: no probes/build outputs, `track`, `open`,
|
|
53
|
+
`collect`, `result`, `close`, STATE updates or shared index edits. `open` is not read-only when
|
|
54
|
+
measurement is enabled. Read existing documents, logs, artifacts and `checkpoint` output instead.
|
|
55
|
+
Report the owner and evidence of activity without claiming an unknown process is a subagent.
|
|
56
|
+
Do not kill/message peers without authorization, race their writes, or launch repeated watchers.
|
|
57
|
+
|
|
58
|
+
Quiet files, elapsed time, an idle status, a final response, a shared session ID or a stale claim
|
|
59
|
+
do not authorize takeover. The owner retains the claim until its writes and children have stopped,
|
|
60
|
+
validation and state/report updates are finished, and it explicitly releases it. Release also on
|
|
61
|
+
a deliberate pause after recording pending work and stopping/draining delegated tasks. A fresh
|
|
62
|
+
entry then acquires a new claim, rereads current evidence and continues only unfinished authorized
|
|
63
|
+
work. Parallel implementation belongs in separate worktrees with explicitly coordinated scope.
|
|
64
|
+
|
|
65
|
+
After a crash, inspect the claim and establish that the previous writer and its children cannot
|
|
66
|
+
continue (for example, verified process exit or an explicit coordinated stop). If uncertain, ask
|
|
67
|
+
for that concrete coordination decision; do not expire a claim automatically. Only after that
|
|
68
|
+
evidence may recovery release the observed claim using its exact ID, then acquire afresh. An old
|
|
69
|
+
ID cannot release a replacement claim. A corrupt record or leftover short-lived `.lock` requires
|
|
70
|
+
manual inspection under the same stopped-writer condition; never blindly delete either.
|
|
71
|
+
|
|
72
|
+
## Sequential programming workers
|
|
73
|
+
|
|
74
|
+
An explicitly authorized denisco-implementation-coordinator follows
|
|
75
|
+
[bounded implementation](delegated-implementation.md). The coordinator may claim the worktree for
|
|
76
|
+
preparation or bookkeeping between workers, then releases before launch. Its document writes are
|
|
77
|
+
limited to COORDINATOR and COORDINATOR-HISTORY; holding the claim never permits technical-document
|
|
78
|
+
edits. Ownership records and explicitly enabled measurement registration/reporting remain governed
|
|
79
|
+
by their existing helpers. The programmer acquires its own new claim
|
|
80
|
+
and owns code, verification, task documents and enabled measurement. During that assignment the
|
|
81
|
+
coordinator remains read-only, including its own documents. The programmer also leaves the
|
|
82
|
+
coordination documents unchanged: document authority does not transfer with the worktree claim.
|
|
83
|
+
Neither actor passes a claim token to the other. After releasing to launch, the coordinator may not
|
|
84
|
+
reacquire during the worker's startup window just to save its handle; defer recording until safe return.
|
|
85
|
+
|
|
86
|
+
After a worker's final writes, cleanup and explicit release, verify its children and outstanding
|
|
87
|
+
commands cannot continue writing before the coordinator or successor acquires. A missing claim
|
|
88
|
+
alone does not prove all old processes stopped. Recovery after a crash uses the same verified
|
|
89
|
+
stopped-writer rule above. A prepared assignment or an old worker handle never replaces this check.
|
|
90
|
+
|
|
91
|
+
## Visual children and evidence
|
|
92
|
+
|
|
93
|
+
The implementation owner retains ownership while delegating a visual-only check. A visual child receives criterion IDs, a
|
|
94
|
+
baseline/post-edit role and an exclusive artifact directory; it never acquires/releases the
|
|
95
|
+
principal claim, edits source/task documents/registers, or starts a second implementation CLI.
|
|
96
|
+
The child returns exact artifacts, proposed index rows and skill-loading evidence. The principal
|
|
97
|
+
merges the index and registers the child/results serially. Do not edit the measured source or
|
|
98
|
+
shared capture tooling while a visual attempt is running; finish a baseline before source edits.
|
|
99
|
+
|
|
100
|
+
On resume or transfer, read current STATE, the bound run's attempts/results, referenced artifacts
|
|
101
|
+
and attributable child logs before declaring a check absent or scheduling a replacement. Match
|
|
102
|
+
criterion, attempt, parent/child identity, explicit skill loading and the tested code/fixture.
|
|
103
|
+
Distinguish absent evidence from evidence that exists but is unregistered, stale, failed or
|
|
104
|
+
inconsistent. Reconcile a registration gap using existing evidence; rerun only when the evidence
|
|
105
|
+
does not cover the current requirement/code. Preserve prior failures and explain any invalidation.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Session plan and persistent state
|
|
2
|
+
|
|
3
|
+
Default: PLAN.md, STATE.md and STATE-HISTORY.md alongside the handoff. Honor project conventions
|
|
4
|
+
and explicit paths. Create documents only in a mode that permits writing.
|
|
5
|
+
|
|
6
|
+
## Group by coherence before difficulty
|
|
7
|
+
|
|
8
|
+
1. Build the dependency graph. Resolve cycles as one coherent change or an explicit staged contract.
|
|
9
|
+
2. Keep duplicated instances of the same rule together when intermediate divergence would be wrong.
|
|
10
|
+
This takes precedence over difficulty or file-count heuristics.
|
|
11
|
+
3. Put shared contracts, pure rules and persistence before consumers; use verifiable blocks.
|
|
12
|
+
4. Estimate context and verification effort. Colors explain difficulty, not fixed session counts.
|
|
13
|
+
Allow a small task in one session or multiple tightly related points.
|
|
14
|
+
5. Work through the approved plan in dependency order. Work outside it follows the skill's split,
|
|
15
|
+
new-point and new-goal rules; finishing early does not authorize unrelated work.
|
|
16
|
+
|
|
17
|
+
Record the split once; revisit when evidence changes dependencies, scope or feasibility. A revision
|
|
18
|
+
rewrites PLAN and moves the replaced version to STATE-HISTORY.md.
|
|
19
|
+
Parallel execution requires an explicit coordination decision: independent dependencies do not
|
|
20
|
+
guarantee safe concurrent edits, fixtures or shared environments.
|
|
21
|
+
Apply [worktree ownership](ownership.md) before any task write, including planning and accounting.
|
|
22
|
+
A block assignment is not a claim; two processes can share a conversation ID. The worktree claim
|
|
23
|
+
is separate from PLAN/STATE and measurement so disabled accounting cannot bypass coordination.
|
|
24
|
+
|
|
25
|
+
## Operational JSON
|
|
26
|
+
|
|
27
|
+
Append `.workflow.json` to the full handoff filename, including its `.md` extension.
|
|
28
|
+
This file carries structure and links, not a second copy of criterion outcomes:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"schemaVersion": 1,
|
|
33
|
+
"taskId": "feature-example",
|
|
34
|
+
"handoff": "HANDOFF.md",
|
|
35
|
+
"plan": "PLAN.md",
|
|
36
|
+
"state": "STATE.md",
|
|
37
|
+
"measurement": { "status": "disabled" },
|
|
38
|
+
"blocks": [
|
|
39
|
+
{ "id": "B1", "points": ["P1"], "dependsOn": [], "criteria": ["P1-A1", "P1-A2"] },
|
|
40
|
+
{ "id": "B2", "points": ["P2"], "dependsOn": ["B1"], "criteria": ["P2-A1"] }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Resolve document paths relative to the JSON. During specification `blocks` may be empty.
|
|
46
|
+
Before executing a block, reconcile the complete planned map with the handoff, including blocked
|
|
47
|
+
criteria and those the user verifies. A script cannot detect a criterion never supplied or assigned
|
|
48
|
+
to the wrong block. Blockers, permissions and Your actions live in the Markdown documents, not here.
|
|
49
|
+
|
|
50
|
+
Measurement is `unknown`, `disabled`, or `enabled`. Default to `disabled` unless the current user
|
|
51
|
+
request or applicable project instructions explicitly activate workflow measurement for this task.
|
|
52
|
+
Recover legacy context only from referenced documents. Disabled is authoritative across sessions:
|
|
53
|
+
do not load, install or invoke denisco-workflow-benchmark, search for a run, or rewrite it to unknown/enabled.
|
|
54
|
+
Unknown is inert legacy or interrupted explicit setup, never an active default; preserve it or resolve
|
|
55
|
+
it to disabled unless explicit activation evidence exists. Do not invent another run. In Plan Mode
|
|
56
|
+
propose the JSON for the writable phase. Missing helpers are not a product-evidence limitation when
|
|
57
|
+
measurement is inactive.
|
|
58
|
+
|
|
59
|
+
When enabled, denisco-workflow-benchmark `bind --run <file> --handoff <file>` populates measurement with
|
|
60
|
+
`status`, absolute `run`, `runId`, benchmark `taskId`, and `criteriaHash`. Use the command rather
|
|
61
|
+
than inventing the hash. Project and benchmark task IDs may differ: preserve both explicitly.
|
|
62
|
+
Stale/moved bindings require review, not guessing. The detailed CLI belongs to denisco-workflow-benchmark.
|
|
63
|
+
|
|
64
|
+
Measured criterion outcomes/history belong in the run; STATE.md explains them. Without measurement,
|
|
65
|
+
STATE.md is the evidence record and automated checks cover only structure and links.
|
|
66
|
+
|
|
67
|
+
## PLAN.md
|
|
68
|
+
|
|
69
|
+
First entry may have only HANDOFF and an empty operational map. Register the planning conversation
|
|
70
|
+
through track after setup. A handoff-only request is planning-only: create/reconcile PLAN, STATE,
|
|
71
|
+
the complete planned block map and a saved/checked first execution prompt, then choose the
|
|
72
|
+
coordinated or direct execution path and reach its start question. Preserve an existing split and
|
|
73
|
+
observed progress when repairing partial documents.
|
|
74
|
+
|
|
75
|
+
PLAN is the block map, rewritten when the plan changes:
|
|
76
|
+
|
|
77
|
+
- Task ID, handoff link, **Done when** from the handoff and the plan date.
|
|
78
|
+
- Table: block ID, point IDs, purpose, dependencies (blocks and your-action items) and verification.
|
|
79
|
+
- Final integration checks and excluded points with reasons.
|
|
80
|
+
- Operational JSON link and complete planned block/criterion map. The map describes the plan,
|
|
81
|
+
not permission to execute it.
|
|
82
|
+
|
|
83
|
+
Resolve every unresolved blocker before delivering a runnable assignment. Choose the first
|
|
84
|
+
dependency-ready block; if every block waits on a your-action item or a third party, say so in
|
|
85
|
+
STATE, fill Your actions and stop without the start question. In Plan Mode present all planning
|
|
86
|
+
deliverables, including the first execution prompt. Once writing is allowed, persist them and ask.
|
|
87
|
+
A private CLI plan does not substitute for these documents or change this phase boundary.
|
|
88
|
+
|
|
89
|
+
## STATE.md
|
|
90
|
+
|
|
91
|
+
STATE is the current picture, rewritten each session and readable in about two minutes (about
|
|
92
|
+
100-150 lines). Its sections, in this order:
|
|
93
|
+
|
|
94
|
+
1. **Your actions:** each item says what to do, where, which point it unblocks and how the agent
|
|
95
|
+
will check it. Done items leave the list. An empty list reads "Nothing needed from you."
|
|
96
|
+
2. **Status:** task ID, links to HANDOFF, PLAN and STATE-HISTORY, last update; branch, commit and
|
|
97
|
+
relevant uncommitted files, distinguishing user changes; the current phase and the user
|
|
98
|
+
instruction that started it, with date and scope. Tool permissions and document existence alone
|
|
99
|
+
never establish that instruction.
|
|
100
|
+
3. **Points and criteria:** point status (planned, in-progress, implemented-unverified, verified or
|
|
101
|
+
blocked); per criterion pass/fail/not-run, observation, evidence path and verifier.
|
|
102
|
+
4. **Blockers:** each pending question or wait, and what it stops.
|
|
103
|
+
5. **Next step:** the next block, or why the session stopped.
|
|
104
|
+
6. The saved next-session prompt in its generated section, while task work remains.
|
|
105
|
+
|
|
106
|
+
For coordinated execution the programmer adds a link to COORDINATOR and the current assignment/attempt
|
|
107
|
+
reference in Status, following [bounded implementation](delegated-implementation.md). The session
|
|
108
|
+
plan, coordination history and coordinator resume prompt live in COORDINATOR.md and
|
|
109
|
+
COORDINATOR-HISTORY.md beside STATE by default. Only the coordinator writes those files; only the
|
|
110
|
+
programmer updates the technical documents through this existing workflow. No sidecar schema change.
|
|
111
|
+
|
|
112
|
+
Mention worktree ownership only for a conflict or a handover between runtimes; the live ownership
|
|
113
|
+
record arbitrates writers, and claim tokens never go into STATE or the next prompt. Mention
|
|
114
|
+
measurement only while it is enabled.
|
|
115
|
+
|
|
116
|
+
## STATE-HISTORY.md
|
|
117
|
+
|
|
118
|
+
Append-only, beside STATE. Each session adds one dated entry: work done, answers and decisions
|
|
119
|
+
received, evidence paths, reopenings, and any text replaced in HANDOFF, PLAN or STATE. Nothing is
|
|
120
|
+
deleted from it. In coordinated mode each programmer, including final integration, writes its own
|
|
121
|
+
technical session entry; the coordinator writes only COORDINATOR-HISTORY. Read it when the current picture is not enough: an audit, a reopening or a
|
|
122
|
+
disputed result.
|
|
123
|
+
|
|
124
|
+
A STATE written before this format: move it unchanged into STATE-HISTORY.md as the first entry,
|
|
125
|
+
then write a new STATE from it. Carry every open criterion, blocker and pending user action into
|
|
126
|
+
the new STATE.
|
|
127
|
+
|
|
128
|
+
Never erase previous results: a result replaced in STATE moves to STATE-HISTORY.md. Never mark a
|
|
129
|
+
point verified because code exists or an agent said done. Reconcile stale state with the repository
|
|
130
|
+
on resume and before delivery. Replace obsolete current claims such as execution pending or no
|
|
131
|
+
checks run after the user has launched implementation. Read current run attempts, result artifacts
|
|
132
|
+
and attributable child logs before declaring delegated verification absent. Existing but
|
|
133
|
+
unregistered evidence needs attribution/registration repair, not an automatic new model run.
|
|
134
|
+
With finished code and required verification gaps use `implemented-unverified`, never
|
|
135
|
+
`verified except A5`. Keep implementation, verification, accounting and user acceptance distinct.
|
|
136
|
+
|
|
137
|
+
Only when measurement is explicitly enabled, register through `track` and its returned nextCall,
|
|
138
|
+
then use `open --handoff <file> --block <B1>` after the block map exists. Keep session keys and
|
|
139
|
+
tickets internal. After each block's final validation, record measured evidence with `result`,
|
|
140
|
+
update STATE and run the read-only `checkpoint` for that block. When the session stops, close with
|
|
141
|
+
`close --handoff <file> --block <last-block> --implementation <state>
|
|
142
|
+
(--next-block <B2> | --final) --claim <proposed-status>`, which saves or clears the continuation
|
|
143
|
+
and runs the checkpoint. The equivalent separate commands remain available:
|
|
144
|
+
`next-prompt --handoff <file> --block <B2> --save` followed by
|
|
145
|
+
`checkpoint --handoff <file> --block <B1> --implementation complete --claim <proposed-status>
|
|
146
|
+
--next-block <B2>`. A contradicting claim or missing/stale saved prompt returns code 2 and
|
|
147
|
+
the computed status. Add `--session-key provider:id` only when identified and `--session-state active`
|
|
148
|
+
while work is live. Missing registration is reported separately from technical verification.
|
|
149
|
+
Reconcile STATE.md and the final response with the output; technical status and continuation
|
|
150
|
+
delivery are separate. The checker verifies the generated section, not claims in free prose.
|
|
151
|
+
If code or evidence changes after this check, refresh evidence/results and repeat the checkpoint.
|
|
152
|
+
Review evidence relevance yourself: a matching hash is not semantic proof of an acceptance criterion.
|
|
153
|
+
|
|
154
|
+
## Next-session prompt
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Use denisco-handoff-implementation to continue task <task-id> (<HANDOFF.md>) from block <B2>.
|
|
158
|
+
Read <STATE.md> first: Your actions, pending blockers and the next step are there.
|
|
159
|
+
Plan: <PLAN.md>. Operational context: <absolute handoff-path.workflow.json>.
|
|
160
|
+
Measurement: disabled.
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Everything else the next session needs lives in STATE and in this skill: ownership, evidence
|
|
164
|
+
reconciliation, permissions and authorization rules are not repeated in the prompt. If those files
|
|
165
|
+
cannot be located, supply actual content instead of pretending they exist. Only an explicit
|
|
166
|
+
measurement activation replaces the inactive measurement line with the denisco-workflow-benchmark
|
|
167
|
+
registration, open, close and internal ticket instructions from this skill and the benchmark
|
|
168
|
+
contract.
|
|
169
|
+
|
|
170
|
+
When measurement is explicitly enabled and the helper is available, use denisco-workflow-benchmark
|
|
171
|
+
`next-prompt --handoff <file> --block <B2> --save` for the
|
|
172
|
+
proposed next assignment; the helper resolves STATE from the operational JSON and verifies its write.
|
|
173
|
+
`--check` checks the saved prompt without writing. Without either option the command only prints:
|
|
174
|
+
printing does not satisfy persistence. `--save`, `--check` and `--clear` are mutually exclusive.
|
|
175
|
+
|
|
176
|
+
The helper owns only the section between `<!-- workflow:next-prompt:start -->` and
|
|
177
|
+
`<!-- workflow:next-prompt:end -->`. Keep everything else outside it; do not manually customize
|
|
178
|
+
the generated text. A first save adds the section without removing legacy prose: reconcile any
|
|
179
|
+
obsolete manual prompt yourself, moving it to STATE-HISTORY.md. Duplicate or damaged markers
|
|
180
|
+
require repair, not a second generated section.
|
|
181
|
+
|
|
182
|
+
The next block is explicit, never picked by the generator. Use the same block for unfinished
|
|
183
|
+
implementation or verification. A subsequent user request launches that prompt. An explicitly
|
|
184
|
+
authorized denisco-implementation-coordinator instead dispatches a bounded packet; its block list and stop
|
|
185
|
+
boundary take precedence over the generic starting-block prompt. Keep the coordinator launch/resume
|
|
186
|
+
prompt in COORDINATOR; STATE keeps its technical continuation and short coordination reference.
|
|
187
|
+
No generator change or manual alteration of generated text is needed.
|
|
188
|
+
Clear it only when no task work remains, or the user ends the task or asks for no prompt; a user
|
|
189
|
+
stop with work remaining keeps it. Preserve pending acceptance/accounting.
|
|
190
|
+
Measurement disabled uses the template directly. For legacy `unknown`, replace only the status and
|
|
191
|
+
say that it remains inactive without a current explicit activation. Save and reread the prompt
|
|
192
|
+
manually without loading or installing denisco-workflow-benchmark. Automated benchmark acceptance and prompt
|
|
193
|
+
checking are intentionally inactive. In Plan Mode
|
|
194
|
+
propose changes and identify the pending write. Link STATE in the final response and copy only
|
|
195
|
+
its actual saved prompt if also displaying it in chat.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
// Cooperative worktree ownership, independent of conversation IDs and measurement.
|
|
7
|
+
// This guards claims, not arbitrary editor/shell writes. Never expire claims by age.
|
|
8
|
+
function noSymlinks(file) {
|
|
9
|
+
let current = path.resolve(file);
|
|
10
|
+
for (;;) {
|
|
11
|
+
try {
|
|
12
|
+
if (fs.lstatSync(current).isSymbolicLink()) throw new Error(`Symlink ownership path: ${current}`);
|
|
13
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
14
|
+
const parent = path.dirname(current);
|
|
15
|
+
if (parent === current) break;
|
|
16
|
+
current = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function gitRoot(directory) {
|
|
21
|
+
// Read standard Git markers directly: the guard must also work where subprocesses are denied.
|
|
22
|
+
// Native realpath expands Windows 8.3 aliases before comparing root and handoff paths.
|
|
23
|
+
let root = fs.realpathSync.native(path.resolve(directory));
|
|
24
|
+
if (!fs.statSync(root).isDirectory()) throw new Error('Worktree must be a directory');
|
|
25
|
+
for (;;) {
|
|
26
|
+
const marker = path.join(root, '.git');
|
|
27
|
+
let stat;
|
|
28
|
+
try { stat = fs.statSync(marker); }
|
|
29
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
30
|
+
if (stat) {
|
|
31
|
+
let gitDir = marker;
|
|
32
|
+
if (stat.isFile()) {
|
|
33
|
+
const match = /^gitdir: (.+)\r?\n?$/.exec(fs.readFileSync(marker, 'utf8').trimEnd());
|
|
34
|
+
if (!match) throw new Error('Invalid Git worktree marker; inspect before claiming');
|
|
35
|
+
gitDir = path.resolve(root, match[1]);
|
|
36
|
+
} else if (!stat.isDirectory()) throw new Error('Invalid Git worktree marker');
|
|
37
|
+
if (!fs.statSync(path.join(gitDir, 'HEAD')).isFile()) throw new Error('Invalid Git worktree HEAD');
|
|
38
|
+
return { root, gitDir };
|
|
39
|
+
}
|
|
40
|
+
const parent = path.dirname(root);
|
|
41
|
+
if (parent === root) throw new Error('Ownership requires an initialized Git worktree; verify its root before writing');
|
|
42
|
+
root = parent;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Linked worktrees of one repository share its common Git directory. Task documents can then live
|
|
47
|
+
// in one checkout (often the main one) while the code is written in another.
|
|
48
|
+
function commonDir(gitDir) {
|
|
49
|
+
const pointer = path.join(gitDir, 'commondir');
|
|
50
|
+
const common = fs.existsSync(pointer) ? path.resolve(gitDir, fs.readFileSync(pointer, 'utf8').trim()) : gitDir;
|
|
51
|
+
return fs.realpathSync.native(common);
|
|
52
|
+
}
|
|
53
|
+
const samePath = (a, b) => process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
54
|
+
function sameRepository(loc, file) {
|
|
55
|
+
let other;
|
|
56
|
+
try { other = gitRoot(path.dirname(file)); } catch { return false; }
|
|
57
|
+
return samePath(commonDir(loc.gitDir), commonDir(other.gitDir));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function location(worktree) {
|
|
61
|
+
if (!worktree) throw new Error('Provide --worktree DIR');
|
|
62
|
+
const { root, gitDir } = gitRoot(worktree);
|
|
63
|
+
const dir = path.join(root, '.agent');
|
|
64
|
+
const file = path.join(dir, 'workflow-writer.json');
|
|
65
|
+
const lock = `${file}.lock`;
|
|
66
|
+
noSymlinks(file); noSymlinks(lock);
|
|
67
|
+
return { root, gitDir, dir, file, lock };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readOwner(file, root) {
|
|
71
|
+
let data;
|
|
72
|
+
try { data = JSON.parse(fs.readFileSync(file, 'utf8')); }
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error.code === 'ENOENT') return null;
|
|
75
|
+
throw new Error('Unreadable ownership record; inspect without replacing it');
|
|
76
|
+
}
|
|
77
|
+
const sameRoot = typeof data?.worktree === 'string' && samePath(data.worktree, root);
|
|
78
|
+
if (data?.schemaVersion !== 1 || !sameRoot || typeof data.claimId !== 'string'
|
|
79
|
+
|| !/^[a-f0-9-]{36}$/.test(data.claimId) || typeof data.handoff !== 'string') {
|
|
80
|
+
throw new Error('Invalid ownership record; inspect without replacing it');
|
|
81
|
+
}
|
|
82
|
+
return data;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function ownership({ action, worktree, handoff, block = 'planning', session, claim } = {}) {
|
|
86
|
+
if (!['status', 'acquire', 'check', 'release'].includes(action)) throw new Error('Use status|acquire|check|release');
|
|
87
|
+
if (action === 'acquire' && claim) throw new Error('Acquire always creates a new claim; never reuse an old token');
|
|
88
|
+
if (['check', 'release'].includes(action) && !claim) throw new Error('Provide the current execution instance\'s --claim TOKEN');
|
|
89
|
+
const loc = location(worktree);
|
|
90
|
+
let target;
|
|
91
|
+
if (action === 'acquire') {
|
|
92
|
+
if (!handoff) throw new Error('Provide --handoff FILE');
|
|
93
|
+
target = fs.realpathSync.native(path.resolve(handoff));
|
|
94
|
+
const relative = path.relative(loc.root, target);
|
|
95
|
+
const inside = relative && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
96
|
+
if (!fs.statSync(target).isFile() || (!inside && !sameRepository(loc, target))) {
|
|
97
|
+
throw new Error('Handoff must be a file inside this worktree or another worktree of the same repository');
|
|
98
|
+
}
|
|
99
|
+
if (typeof block !== 'string' || !block.trim()) throw new Error('Provide a block or planning label');
|
|
100
|
+
}
|
|
101
|
+
const inspect = () => {
|
|
102
|
+
const owner = readOwner(loc.file, loc.root);
|
|
103
|
+
if (action === 'status') return { status: owner ? 'owned' : 'unclaimed', owner, file: loc.file };
|
|
104
|
+
if (action === 'check') return { status: owner?.claimId === claim ? 'owned-by-caller' : 'conflict', owner, file: loc.file };
|
|
105
|
+
if (action === 'acquire') {
|
|
106
|
+
// Deliberately non-reentrant: a duplicate resume can share session metadata.
|
|
107
|
+
if (owner) return { status: 'conflict', owner, file: loc.file };
|
|
108
|
+
const next = { schemaVersion: 1, claimId: crypto.randomUUID(), worktree: loc.root,
|
|
109
|
+
handoff: target, block, session: session ?? null, acquiredAt: new Date().toISOString() };
|
|
110
|
+
fs.writeFileSync(loc.file, `${JSON.stringify(next, null, 2)}\n`, { flag: 'wx' });
|
|
111
|
+
return { status: 'acquired', owner: next, file: loc.file };
|
|
112
|
+
}
|
|
113
|
+
if (owner?.claimId !== claim) return { status: 'conflict', owner, file: loc.file };
|
|
114
|
+
fs.unlinkSync(loc.file);
|
|
115
|
+
return { status: 'released', claimId: claim, file: loc.file };
|
|
116
|
+
};
|
|
117
|
+
if (['status', 'check'].includes(action)) {
|
|
118
|
+
if (fs.existsSync(loc.lock)) return { status: 'busy', file: loc.file };
|
|
119
|
+
const result = inspect();
|
|
120
|
+
if (fs.existsSync(loc.lock)) return { status: 'busy', file: loc.file };
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
fs.mkdirSync(loc.dir, { recursive: true });
|
|
124
|
+
noSymlinks(loc.file); noSymlinks(loc.lock);
|
|
125
|
+
let fd;
|
|
126
|
+
try { fd = fs.openSync(loc.lock, 'wx'); }
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error.code === 'EEXIST') return { status: 'busy', file: loc.file };
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
try { return inspect(); }
|
|
132
|
+
finally { fs.closeSync(fd); fs.unlinkSync(loc.lock); }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const usage = 'node ownership.mjs status|acquire|check|release --worktree DIR [--handoff FILE --block ID --session LABEL] [--claim TOKEN]';
|
|
136
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
137
|
+
try {
|
|
138
|
+
const [action, ...args] = process.argv.slice(2);
|
|
139
|
+
if (action === 'help' || !action) { console.log(usage); }
|
|
140
|
+
else {
|
|
141
|
+
const options = { action };
|
|
142
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
143
|
+
const key = args[i].slice(2);
|
|
144
|
+
if (!args[i].startsWith('--') || !['worktree', 'handoff', 'block', 'session', 'claim'].includes(key)
|
|
145
|
+
|| !args[i + 1] || args[i + 1].startsWith('--') || Object.hasOwn(options, key)) throw new Error(usage);
|
|
146
|
+
options[key] = args[i + 1];
|
|
147
|
+
}
|
|
148
|
+
const result = ownership(options);
|
|
149
|
+
console.log(JSON.stringify(result, null, 2));
|
|
150
|
+
if (['conflict', 'busy'].includes(result.status)) process.exitCode = 2;
|
|
151
|
+
}
|
|
152
|
+
} catch (error) { console.error(error.message); process.exitCode = 1; }
|
|
153
|
+
}
|