@pennixrv/trellis 0.6.19 → 0.6.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/channel/index.d.ts.map +1 -1
- package/dist/commands/channel/index.js +17 -1
- package/dist/commands/channel/index.js.map +1 -1
- package/dist/commands/channel/wait.d.ts +4 -0
- package/dist/commands/channel/wait.d.ts.map +1 -1
- package/dist/commands/channel/wait.js +8 -1
- package/dist/commands/channel/wait.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +21 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +6 -45
- package/dist/commands/update.js.map +1 -1
- package/dist/migrations/manifests/0.6.19.json +9 -0
- package/dist/migrations/manifests/0.6.20.json +9 -0
- package/dist/migrations/manifests/0.6.21.json +9 -0
- package/dist/templates/common/bundled-skills/trellis-channel/references/command-reference.md +35 -5
- package/dist/templates/common/bundled-skills/trellis-channel/references/progress-debugging.md +24 -13
- package/dist/templates/common/bundled-skills/trellis-channel/references/subnode-work.md +32 -14
- package/dist/templates/common/bundled-skills/trellis-channel/references/workflows.md +6 -3
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +5 -5
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +1 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-research-record/SKILL.md +14 -0
- package/dist/templates/markdown/agents.md +3 -14
- package/dist/templates/trellis/agents/subnode.md +1 -2
- package/dist/templates/trellis/scripts/subnode_artifact.py +45 -10
- package/dist/utils/file-writer.d.ts +2 -3
- package/dist/utils/file-writer.d.ts.map +1 -1
- package/dist/utils/file-writer.js +2 -3
- package/dist/utils/file-writer.js.map +1 -1
- package/dist/utils/managed-paths.d.ts +7 -0
- package/dist/utils/managed-paths.d.ts.map +1 -1
- package/dist/utils/managed-paths.js +40 -0
- package/dist/utils/managed-paths.js.map +1 -1
- package/package.json +2 -2
|
@@ -16,9 +16,11 @@ Before spawning, the coordinator must use an active task (`planning` or
|
|
|
16
16
|
`in_progress`), define one stable `work_id` and
|
|
17
17
|
`subnode_id`, then prepare a brief-draft JSON with the question, independence
|
|
18
18
|
reason, scope, protected targets, lens, evidence method, source snapshot,
|
|
19
|
-
dependencies, stop conditions, deadline, `channel_ref`, `retry_of
|
|
20
|
-
`counter_of` (null unless this is
|
|
21
|
-
|
|
19
|
+
dependencies, stop conditions, deadline, `channel_ref`, `retry_of` (null unless
|
|
20
|
+
this is an explicit manual retry), and `counter_of` (null unless this is
|
|
21
|
+
intentional counterwork). A retry names an existing, different subnode in the
|
|
22
|
+
same task and `work_id`; counterwork may be initialized independently. The
|
|
23
|
+
helper supplies the immutable task identity and report path.
|
|
22
24
|
|
|
23
25
|
```bash
|
|
24
26
|
TASK=.trellis/tasks/09-07-example
|
|
@@ -45,8 +47,8 @@ Do not use a terminal Channel message as the report transport. The short final
|
|
|
45
47
|
message names the already-written `report.json` and its status; the durable
|
|
46
48
|
JSON file carries the reviewable result.
|
|
47
49
|
|
|
48
|
-
The subnode copies identity, scope, and lens from `brief.json
|
|
49
|
-
|
|
50
|
+
The subnode copies identity, scope, and lens from `brief.json`. The minimal
|
|
51
|
+
complete report is:
|
|
50
52
|
|
|
51
53
|
```json
|
|
52
54
|
{
|
|
@@ -55,7 +57,6 @@ SHA-256 digest of the exact `brief.json` bytes. The minimal complete report is:
|
|
|
55
57
|
"work_id": "work-id-from-brief",
|
|
56
58
|
"subnode_id": "subnode-id-from-brief",
|
|
57
59
|
"role_id": "subnode",
|
|
58
|
-
"brief_digest": "sha256-of-brief-json-bytes",
|
|
59
60
|
"status": "complete",
|
|
60
61
|
"scope": ["exact scope copied from brief"],
|
|
61
62
|
"lens": "exact lens copied from brief",
|
|
@@ -78,10 +79,13 @@ non-empty `completed_scope` list and a non-empty `blocker` string. Never use
|
|
|
78
79
|
|
|
79
80
|
## Dispatch And Wait
|
|
80
81
|
|
|
81
|
-
Inspect the installed role first, then
|
|
82
|
+
Inspect the installed role first, then capture a durable event barrier before
|
|
83
|
+
the worker can emit a terminal event. The CLI waits once and replays matching
|
|
84
|
+
events committed after that barrier:
|
|
82
85
|
|
|
83
86
|
```bash
|
|
84
87
|
trellis channel create subnode-example --by main --cwd "$PWD"
|
|
88
|
+
BARRIER="$(trellis channel barrier subnode-example)"
|
|
85
89
|
trellis channel spawn subnode-example --agent subnode --provider codex \
|
|
86
90
|
--as "$SUBNODE_ID" --cwd "$PWD" --timeout 30m
|
|
87
91
|
|
|
@@ -90,13 +94,17 @@ printf '%s\n' "Read $TASK/subnodes/$WORK_ID/$SUBNODE_ID/brief.json and perform o
|
|
|
90
94
|
--stdin --delivery-mode requireRunningWorker
|
|
91
95
|
|
|
92
96
|
trellis channel wait subnode-example --as main --from "$SUBNODE_ID" \
|
|
93
|
-
--kind done,error --timeout 30m
|
|
97
|
+
--kind done,error --after-seq "$BARRIER" --timeout 30m
|
|
94
98
|
```
|
|
95
99
|
|
|
96
|
-
Where the host exposes a live wait continuation,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
Where the host exposes a live wait continuation, capture the same barrier,
|
|
101
|
+
establish one event waiter before triggering the worker, and continue that same
|
|
102
|
+
waiter until terminal state. Until it resolves, times out, or errors, the next
|
|
103
|
+
host operation is only that continuation: do not create another waiter or run
|
|
104
|
+
shell/CLI diagnostics, including `channel messages`, worker inspection, or
|
|
105
|
+
status/list commands. Do not treat an empty transport slice as completion.
|
|
106
|
+
After the waiter returns, use those commands only for an on-demand diagnosis,
|
|
107
|
+
not as a high-frequency supervision loop.
|
|
100
108
|
|
|
101
109
|
## Coordinator Review
|
|
102
110
|
|
|
@@ -139,5 +147,15 @@ python3 .trellis/scripts/subnode_artifact.py validate-counter \
|
|
|
139
147
|
```
|
|
140
148
|
|
|
141
149
|
The coordinator compares the two reports and retains the comparison as part of
|
|
142
|
-
its own disposition.
|
|
143
|
-
|
|
150
|
+
its own disposition.
|
|
151
|
+
|
|
152
|
+
## Manual Retry
|
|
153
|
+
|
|
154
|
+
A retry is a fresh, explicitly approved subnode after a recorded failed or
|
|
155
|
+
incomplete attempt. It uses a new `subnode_id`, preserves the old artifacts,
|
|
156
|
+
and sets `retry_of` to that prior subnode ID in its brief. The coordinator must
|
|
157
|
+
record why it is retrying and check the new report independently; neither the
|
|
158
|
+
helper nor Channel decides when to retry.
|
|
159
|
+
|
|
160
|
+
No scheduler, high-frequency polling loop, automatic retry, worktree, global
|
|
161
|
+
ledger, or provider-specific transport is introduced by this workflow.
|
|
@@ -11,6 +11,7 @@ Use when the user says "和 codex/claude 讨论一下", "brainstorm", or "拉一
|
|
|
11
11
|
```bash
|
|
12
12
|
trellis channel create brainstorm-storage-layer --by main \
|
|
13
13
|
--task .trellis/tasks/05-XX-storage-adapter
|
|
14
|
+
BARRIER="$(trellis channel barrier brainstorm-storage-layer)"
|
|
14
15
|
|
|
15
16
|
trellis channel spawn brainstorm-storage-layer \
|
|
16
17
|
--agent architect --provider codex \
|
|
@@ -22,7 +23,7 @@ trellis channel send brainstorm-storage-layer \
|
|
|
22
23
|
--as main --to cx-arch --text-file /tmp/brainstorm-r1.md
|
|
23
24
|
|
|
24
25
|
trellis channel wait brainstorm-storage-layer \
|
|
25
|
-
--as main --kind done --from cx-arch --timeout 10m
|
|
26
|
+
--as main --kind done --from cx-arch --after-seq "$BARRIER" --timeout 10m
|
|
26
27
|
```
|
|
27
28
|
|
|
28
29
|
Do not stop after one answer. Read the answer, identify vague areas, send a
|
|
@@ -53,6 +54,7 @@ Use when the user asks to dispatch implementation or review work.
|
|
|
53
54
|
```bash
|
|
54
55
|
TASK=.trellis/tasks/05-12-foo
|
|
55
56
|
trellis channel create cr-foo --task "$TASK" --by main
|
|
57
|
+
BARRIER="$(trellis channel barrier cr-foo)"
|
|
56
58
|
|
|
57
59
|
trellis channel spawn cr-foo \
|
|
58
60
|
--agent check \
|
|
@@ -63,7 +65,7 @@ trellis channel spawn cr-foo \
|
|
|
63
65
|
--cwd "$PWD" --timeout 15m
|
|
64
66
|
|
|
65
67
|
trellis channel send cr-foo --as main --to check --text-file /tmp/cr-brief.md
|
|
66
|
-
trellis channel wait cr-foo --as main --kind done --from check --timeout 15m
|
|
68
|
+
trellis channel wait cr-foo --as main --kind done --from check --after-seq "$BARRIER" --timeout 15m
|
|
67
69
|
trellis channel messages cr-foo --kind message --from check --tag final_answer
|
|
68
70
|
```
|
|
69
71
|
|
|
@@ -77,6 +79,7 @@ Use one channel and distinct worker names.
|
|
|
77
79
|
|
|
78
80
|
```bash
|
|
79
81
|
trellis channel create cr-feature --by main --ephemeral
|
|
82
|
+
BARRIER="$(trellis channel barrier cr-feature)"
|
|
80
83
|
|
|
81
84
|
trellis channel spawn cr-feature --agent check \
|
|
82
85
|
--jsonl "$TASK/check.jsonl" --file "$TASK/prd.md" --file "$TASK/design.md" \
|
|
@@ -88,7 +91,7 @@ trellis channel spawn cr-feature --agent check --provider codex --as check-cx \
|
|
|
88
91
|
|
|
89
92
|
trellis channel send cr-feature --as main --to check --text-file /tmp/cr-brief.md
|
|
90
93
|
trellis channel send cr-feature --as main --to check-cx --text-file /tmp/cr-brief.md
|
|
91
|
-
trellis channel wait cr-feature --as main --kind done --from check,check-cx --all --timeout 15m
|
|
94
|
+
trellis channel wait cr-feature --as main --kind done --from check,check-cx --all --after-seq "$BARRIER" --timeout 15m
|
|
92
95
|
```
|
|
93
96
|
|
|
94
97
|
`--all` means every listed worker must emit a matching event.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: trellis-meta
|
|
3
|
-
description: "Understand and customize the local Trellis architecture inside a user project. Use when modifying .trellis plus platform hooks, settings, agents, skills, commands, prompts, workflows, the channel runtime (trellis channel), bundled runtime agents under .trellis/agents/, selectable workflow templates, registry-backed spec refresh, cross-session memory (trellis mem) generated by trellis init, or AI-facing bundled skills
|
|
3
|
+
description: "Understand and customize the local Trellis architecture inside a user project. Use when modifying .trellis plus platform hooks, settings, agents, skills, commands, prompts, workflows, the channel runtime (trellis channel), bundled runtime agents under .trellis/agents/, selectable workflow templates, registry-backed spec refresh, cross-session memory (trellis mem) generated by trellis init, or AI-facing bundled skills and their auto-dispatch flow."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Trellis Meta
|
|
7
7
|
|
|
8
8
|
This skill is for local Trellis users who have already run `trellis init` in a project. After reading it, an AI should understand the Trellis architecture, operating model, and customization entry points inside that user project, then modify the generated `.trellis/` and platform directory files according to the user's request.
|
|
9
9
|
|
|
10
|
-
Trellis v0.6 adds three architectural surfaces on top of the pre-v0.6 workflow / persistence / platform model. First, a multi-agent collaboration runtime: `trellis channel` coordinates multiple AI worker processes through project-scoped JSONL event logs at `~/.trellis/channels/<project>/<channel>/events.jsonl`, with worker OOM guard, forum/thread channels, durable idempotency keys, and bundled `.trellis/agents/{check,implement}.md` runtime definitions. Second, cross-session memory: `trellis mem list | search | context | extract | projects` reads raw Claude Code, Codex, and Pi Agent JSONL already on disk, slices by `--phase brainstorm|implement|all`, and never uploads anything. Third, a dual-package npm release: `@pennixrv/trellis` (CLI) and `@pennixrv/trellis-core` (SDK with `/channel`, `/task`, `/mem`, `/testing` subpaths) ship in lockstep on one version. Treat these as first-class customization surfaces alongside the per-platform integration files.
|
|
10
|
+
Trellis v0.6 adds three architectural surfaces on top of the pre-v0.6 workflow / persistence / platform model. First, a multi-agent collaboration runtime: `trellis channel` coordinates multiple AI worker processes through project-scoped JSONL event logs at `~/.trellis/channels/<project>/<channel>/events.jsonl`, with worker OOM guard, forum/thread channels, durable idempotency keys, and bundled `.trellis/agents/{check,implement,subnode}.md` runtime definitions. Second, cross-session memory: `trellis mem list | search | context | extract | projects` reads raw Claude Code, Codex, and Pi Agent JSONL already on disk, slices by `--phase brainstorm|implement|all`, and never uploads anything. Third, a dual-package npm release: `@pennixrv/trellis` (CLI) and `@pennixrv/trellis-core` (SDK with `/channel`, `/task`, `/mem`, `/testing` subpaths) ship in lockstep on one version. Treat these as first-class customization surfaces alongside the per-platform integration files.
|
|
11
11
|
|
|
12
12
|
The default operating scope is local files in the user project:
|
|
13
13
|
|
|
@@ -39,7 +39,7 @@ Do not assume the user has the Trellis source repository. Do not default to modi
|
|
|
39
39
|
- `references/local-architecture/workspace-memory.md`: `.trellis/workspace/` journals plus `trellis mem` cross-session recall and the `@pennixrv/trellis-core/mem` SDK.
|
|
40
40
|
- `references/local-architecture/context-injection.md`: Hooks, sub-agent preludes, and channel-runtime worker inbox routing.
|
|
41
41
|
- `references/local-architecture/multi-agent-channel.md`: `trellis channel` subcommands, project-scoped event store, forum/thread channels, worker OOM guard, durable idempotency, and bundled `.trellis/agents/` runtime agents.
|
|
42
|
-
- `references/local-architecture/bundled-skills.md`: Auto-dispatched bundled skills (`trellis-meta`, `trellis-
|
|
42
|
+
- `references/local-architecture/bundled-skills.md`: Auto-dispatched bundled skills (`trellis-channel`, `trellis-meta`, `trellis-research-record`, `trellis-session-insight`, `trellis-spec-bootstrap`) and how `getBundledSkillTemplates()` ships them to every platform skill root.
|
|
43
43
|
|
|
44
44
|
### Platform Files
|
|
45
45
|
|
|
@@ -68,9 +68,9 @@ Do not assume the user has the Trellis source repository. Do not default to modi
|
|
|
68
68
|
- `.trellis/spec/` stores the user's project-specific coding conventions and design constraints. When `registry.spec` is set, files are refreshed by `trellis update`; local edits surface as "modified by user" conflicts in `.trellis/.template-hashes.json`.
|
|
69
69
|
- `.trellis/tasks/` stores task PRDs, design notes, implement plans, research files, and JSONL context. Tasks form parent/child trees: `task.py create --parent <slug>`, `task.py add-subtask <parent> <child>`, `task.py remove-subtask <parent> <child>`, and `task.py list-context <task>`. `task.py create` rejects a slug already present in `.trellis/tasks/archive/**`.
|
|
70
70
|
- `.trellis/workspace/` stores **deliberately written** developer journals. Raw cross-session dialogue is **not** stored here — it lives on disk under `~/.claude/projects/`, `~/.codex/sessions/`, and `~/.pi/agent/sessions/` and is recovered via `trellis mem search|extract|context`. The bundled `trellis-session-insight` skill teaches when to reach for `mem`.
|
|
71
|
-
- `.trellis/agents/{check,implement}.md` are bundled, platform-agnostic channel runtime agent definitions loaded by `trellis channel spawn --agent <name>`. Editable; `trellis update` backfills missing ones. Editing the per-platform `trellis-implement.md` / `trellis-check.md` does **not** change channel-runtime worker behavior.
|
|
71
|
+
- `.trellis/agents/{check,implement,subnode}.md` are bundled, platform-agnostic channel runtime agent definitions loaded by `trellis channel spawn --agent <name>`. Editable; `trellis update` backfills missing ones. Editing the per-platform `trellis-implement.md` / `trellis-check.md` does **not** change channel-runtime worker behavior.
|
|
72
72
|
- `~/.trellis/channels/<project>/<channel>/events.jsonl` is the channel runtime event log per project per channel. User-owned, file-locked sequence numbering, durable `idempotencyKey` support; never under `.trellis/`.
|
|
73
|
-
- Bundled multi-file skills
|
|
73
|
+
- Bundled multi-file skills are auto-dispatched to every platform skill root by `getBundledSkillTemplates()` in `packages/cli/src/templates/common/index.ts`. Dropping a new directory under `packages/cli/src/templates/common/bundled-skills/` (upstream) ships it to every platform on the next `trellis update`.
|
|
74
74
|
- Platform settings/config files decide which hooks, agents, skills, commands, prompts, and workflows actually run. Reasonix has no settings file — behavior is encoded inside skill frontmatter.
|
|
75
75
|
- `.trellis/.template-hashes.json` and `.trellis/.runtime/` are management/runtime state files. Confirm necessity before editing them.
|
|
76
76
|
|
|
@@ -26,6 +26,7 @@ The set is discovered at runtime by listing directories under `templates/common/
|
|
|
26
26
|
| `trellis-session-insight` | Wraps the `trellis mem` CLI so an AI knows when and how to reach into past Claude Code / Codex / Pi Agent conversation logs. |
|
|
27
27
|
| `trellis-spec-bootstrap` | Platform-neutral workflow for creating or refreshing `.trellis/spec/` from the real codebase (with optional GitNexus / ABCoder integration). |
|
|
28
28
|
| `trellis-channel` | Capability skill teaching an AI when to reach for `trellis channel` for multi-agent collaboration, forum/thread persistent boards, and dispatcher-wait patterns. |
|
|
29
|
+
| `trellis-research-record` | Records verified research, audit, or review findings in the active task without creating a second task ledger. |
|
|
29
30
|
|
|
30
31
|
The list is discovered at runtime, so adding a new directory under `bundled-skills/` is the only step required to register a new skill (see "Adding a New Bundled Skill" below).
|
|
31
32
|
|
|
@@ -50,7 +50,7 @@ For a Git-tracked project, commit the durable project contract:
|
|
|
50
50
|
metadata, not hand-edited configuration; keeping them lets another clone
|
|
51
51
|
distinguish Trellis-owned templates from local changes safely;
|
|
52
52
|
- the Trellis-managed files in selected platform directories, plus the
|
|
53
|
-
root-level `AGENTS.md` managed block when Trellis created it.
|
|
53
|
+
root-level `AGENTS.md` managed block when Trellis created or merged it.
|
|
54
54
|
|
|
55
55
|
Do not commit local or ephemeral state. The generated `.trellis/.gitignore`
|
|
56
56
|
already excludes `.developer`, `.current-task`, `.runtime/`, `.ralph-state.json`,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trellis-research-record
|
|
3
|
+
description: Record verified research, audit, or review findings that affect an active Trellis task in its task artifacts. Use when the work produces reusable facts, alternatives, uncertainty, or a decision basis; do not use for routine navigation or transient observations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Trellis Research Record
|
|
7
|
+
|
|
8
|
+
Keep task-relevant evidence in the active task rather than only in session context.
|
|
9
|
+
|
|
10
|
+
1. Confirm the active task, actual modification target, and authoritative source.
|
|
11
|
+
2. Before changing scope or ending the work, record verified facts with evidence locators in that task's `research/` directory or another appropriate task artifact. Keep candidates and uncertainty separate from facts, and state one bounded next action when needed.
|
|
12
|
+
3. A subnode report is a candidate artifact. The coordinator verifies it and records the resulting conclusion; this Skill does not accept reports, alter task lifecycle, create a handoff, or create a second ledger.
|
|
13
|
+
|
|
14
|
+
Do not create a record for routine navigation, temporary tool output, waits, compaction, or observations with no task value.
|
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
<!-- TRELLIS:START -->
|
|
2
|
-
# Trellis
|
|
2
|
+
# Trellis
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Follow `.trellis/workflow.md`; read the applicable `.trellis/spec/` guidance before editing code, and keep task facts in `.trellis/tasks/`. Project-scoped helpers live in `.agents/skills/`.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- `.trellis/workflow.md` — development phases, when to create tasks, skill routing
|
|
9
|
-
- `.trellis/spec/` — package- and layer-scoped coding guidelines (read before writing code in a given layer)
|
|
10
|
-
- `.trellis/workspace/` — per-developer journals and session traces
|
|
11
|
-
- `.trellis/tasks/` — active and archived tasks (PRDs, research, jsonl context)
|
|
12
|
-
|
|
13
|
-
If a Trellis command is available on your platform (e.g. `/trellis:finish-work`, `/trellis:continue`), prefer it over manual steps. Not every platform exposes every command.
|
|
14
|
-
|
|
15
|
-
If you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:
|
|
16
|
-
- `.agents/skills/` — reusable Trellis skills
|
|
17
|
-
- `.codex/agents/` — optional custom subagents
|
|
6
|
+
When a live Trellis Channel wait returns a host continuation, resume only that continuation until it resolves, times out, or errors. Do not run another host action meanwhile, including another wait, shell command, or status/message query; use diagnostics only on demand after it returns.
|
|
18
7
|
|
|
19
8
|
Managed by Trellis. Edits outside this block are preserved; edits inside may be overwritten by a future `trellis update`.
|
|
20
9
|
|
|
@@ -50,8 +50,7 @@ sandbox claim.
|
|
|
50
50
|
**pending coordinator review**, never accepted/rejected/deferred.
|
|
51
51
|
5. A complete report includes independently checkable evidence. A non-complete
|
|
52
52
|
report explains completed scope and the blocker or error. Include the exact
|
|
53
|
-
identity, scope,
|
|
54
|
-
artifact helper.
|
|
53
|
+
identity, scope, and lens required by the artifact helper.
|
|
55
54
|
6. Send one short terminal Channel message with the status and report path.
|
|
56
55
|
Do not place the report JSON in Channel text.
|
|
57
56
|
|
|
@@ -9,7 +9,6 @@ dispatches workers, decides acceptance, or mutates task state.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import argparse
|
|
12
|
-
import hashlib
|
|
13
12
|
import json
|
|
14
13
|
import re
|
|
15
14
|
import sys
|
|
@@ -169,6 +168,42 @@ def _validate_channel_ref(value: Any) -> None:
|
|
|
169
168
|
_require_text(value.get("worker_handle"), "channel_ref.worker_handle", max_len=128)
|
|
170
169
|
|
|
171
170
|
|
|
171
|
+
def _validate_retry_target(
|
|
172
|
+
retry_of: Any,
|
|
173
|
+
task_dir: Path,
|
|
174
|
+
work_id: str,
|
|
175
|
+
subnode_id: str,
|
|
176
|
+
) -> str | None:
|
|
177
|
+
"""Validate the coordinator's explicit, already-created retry source."""
|
|
178
|
+
if retry_of is None:
|
|
179
|
+
return None
|
|
180
|
+
retry_id = _require_id(retry_of, "brief.retry_of")
|
|
181
|
+
if retry_id == subnode_id:
|
|
182
|
+
_fail("brief.retry_of must name a different subnode")
|
|
183
|
+
target_dir = _node_dir(task_dir, work_id, retry_id)
|
|
184
|
+
_assert_no_subpath_symlinks(task_dir, target_dir)
|
|
185
|
+
target_brief_path = target_dir / "brief.json"
|
|
186
|
+
if not target_brief_path.exists():
|
|
187
|
+
_fail("brief.retry_of must identify an existing subnode brief in this task and work_id")
|
|
188
|
+
target_brief, _raw = _read_json_object(
|
|
189
|
+
target_brief_path,
|
|
190
|
+
MAX_DRAFT_BYTES,
|
|
191
|
+
"brief.retry_of target brief",
|
|
192
|
+
)
|
|
193
|
+
expected_task_id = _task_id(task_dir)
|
|
194
|
+
if target_brief.get("schema_version") != SCHEMA_VERSION:
|
|
195
|
+
_fail("brief.retry_of target brief has an unsupported schema_version")
|
|
196
|
+
if target_brief.get("task_id") != expected_task_id:
|
|
197
|
+
_fail("brief.retry_of target brief does not belong to this task")
|
|
198
|
+
if target_brief.get("work_id") != work_id:
|
|
199
|
+
_fail("brief.retry_of target brief does not belong to this work_id")
|
|
200
|
+
if target_brief.get("subnode_id") != retry_id:
|
|
201
|
+
_fail("brief.retry_of target brief identity does not match its artifact directory")
|
|
202
|
+
if target_brief.get("role_id") != "subnode":
|
|
203
|
+
_fail("brief.retry_of target brief.role_id must be subnode")
|
|
204
|
+
return retry_id
|
|
205
|
+
|
|
206
|
+
|
|
172
207
|
def _validate_brief_data(
|
|
173
208
|
brief: dict[str, Any],
|
|
174
209
|
task_dir: Path,
|
|
@@ -198,11 +233,15 @@ def _validate_brief_data(
|
|
|
198
233
|
_require_text(brief.get("deadline"), "brief.deadline", max_len=128)
|
|
199
234
|
_validate_channel_ref(brief.get("channel_ref"))
|
|
200
235
|
if "retry_of" not in brief:
|
|
201
|
-
_fail("brief.retry_of must be present
|
|
202
|
-
if brief["retry_of"] is not None:
|
|
203
|
-
_fail("brief.retry_of must be null; subnodes are not retry workers")
|
|
236
|
+
_fail("brief.retry_of must be present; use null when this is not a retry")
|
|
204
237
|
if "counter_of" not in brief:
|
|
205
238
|
_fail("brief.counter_of must be present; use null when this is not counterwork")
|
|
239
|
+
_validate_retry_target(
|
|
240
|
+
brief["retry_of"],
|
|
241
|
+
task_dir,
|
|
242
|
+
work_id,
|
|
243
|
+
subnode_id,
|
|
244
|
+
)
|
|
206
245
|
counter_of = brief["counter_of"]
|
|
207
246
|
if counter_of is not None:
|
|
208
247
|
counter_id = _require_id(counter_of, "brief.counter_of")
|
|
@@ -280,16 +319,12 @@ def _validate_evidence(value: Any) -> set[tuple[str, str]]:
|
|
|
280
319
|
def _validate_report_data(
|
|
281
320
|
report: dict[str, Any],
|
|
282
321
|
brief: dict[str, Any],
|
|
283
|
-
brief_raw: bytes,
|
|
284
322
|
) -> set[tuple[str, str]]:
|
|
285
323
|
if report.get("schema_version") != SCHEMA_VERSION:
|
|
286
324
|
_fail(f"report.schema_version must be {SCHEMA_VERSION}")
|
|
287
325
|
for field in ("task_id", "work_id", "subnode_id", "role_id"):
|
|
288
326
|
if report.get(field) != brief.get(field):
|
|
289
327
|
_fail(f"report.{field} does not match brief.{field}")
|
|
290
|
-
digest = hashlib.sha256(brief_raw).hexdigest()
|
|
291
|
-
if report.get("brief_digest") != digest:
|
|
292
|
-
_fail("report.brief_digest does not match immutable brief.json")
|
|
293
328
|
if report.get("scope") != brief.get("scope"):
|
|
294
329
|
_fail("report.scope does not match brief.scope")
|
|
295
330
|
if report.get("lens") != brief.get("lens"):
|
|
@@ -315,7 +350,7 @@ def _validate_report_file(
|
|
|
315
350
|
) -> tuple[dict[str, Any], set[tuple[str, str]], dict[str, Any], Path]:
|
|
316
351
|
report_path, node_dir, _task_dir = _resolve_artifact_file(value, "report.json", repo_root)
|
|
317
352
|
brief_path = node_dir / "brief.json"
|
|
318
|
-
brief,
|
|
353
|
+
brief, _brief_raw, _brief_path, _brief_node, _brief_task = _validate_brief_file(
|
|
319
354
|
str(brief_path), repo_root
|
|
320
355
|
)
|
|
321
356
|
expected_report = _relative_to_repo(report_path, repo_root)
|
|
@@ -323,7 +358,7 @@ def _validate_report_file(
|
|
|
323
358
|
_fail("brief.report_path does not point to the report being validated")
|
|
324
359
|
report, raw = _read_json_object(report_path, MAX_REPORT_BYTES, "report")
|
|
325
360
|
_reject_obvious_secrets(raw, "report")
|
|
326
|
-
evidence = _validate_report_data(report, brief
|
|
361
|
+
evidence = _validate_report_data(report, brief)
|
|
327
362
|
return report, evidence, brief, node_dir
|
|
328
363
|
|
|
329
364
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type WriteMode = "ask" | "force" | "skip" | "append";
|
|
2
2
|
export interface WriteOptions {
|
|
3
3
|
mode: WriteMode;
|
|
4
|
+
executable?: boolean;
|
|
4
5
|
}
|
|
5
6
|
export declare function setWriteMode(mode: WriteMode): void;
|
|
6
7
|
export declare function getWriteMode(): WriteMode;
|
|
@@ -26,9 +27,7 @@ export declare function stopRecordingWrites(): void;
|
|
|
26
27
|
* - If file exists and mode is 'append': append to end
|
|
27
28
|
* - If file exists and mode is 'ask': prompt user
|
|
28
29
|
*/
|
|
29
|
-
export declare function writeFile(filePath: string, content: string, options?:
|
|
30
|
-
executable?: boolean;
|
|
31
|
-
}): Promise<boolean>;
|
|
30
|
+
export declare function writeFile(filePath: string, content: string, options?: Partial<WriteOptions>): Promise<boolean>;
|
|
32
31
|
/**
|
|
33
32
|
* Ensure directory exists
|
|
34
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AASD,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAK7D;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAsCD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAyHlB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C"}
|
|
@@ -111,9 +111,8 @@ export async function writeFile(filePath, content, options) {
|
|
|
111
111
|
// Non-TTY (CI, pipes, scripted runs): never prompt — fall back to skip
|
|
112
112
|
// rather than crash with ERR_USE_AFTER_CLOSE if a CLI flag forgot to call
|
|
113
113
|
// setWriteMode. Layer-level safety net for the init.ts mapping.
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
: globalWriteMode;
|
|
114
|
+
const requestedMode = options?.mode ?? globalWriteMode;
|
|
115
|
+
const mode = requestedMode === "ask" && !process.stdin.isTTY ? "skip" : requestedMode;
|
|
117
116
|
if (mode === "force") {
|
|
118
117
|
writeFileAtomic(filePath, content);
|
|
119
118
|
if (options?.executable) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-writer.js","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"file-writer.js","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export declare const TRELLIS_BLOCK_START = "<!-- TRELLIS:START -->";
|
|
2
2
|
export declare const TRELLIS_BLOCK_END = "<!-- TRELLIS:END -->";
|
|
3
|
+
/** Return the first complete managed block, if the document has one. */
|
|
4
|
+
export declare function getManagedMarkdownBlock(content: string, startMarker: string, endMarker: string): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* Replace a complete managed block, or append the template's block while
|
|
7
|
+
* preserving all user-authored content around it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mergeManagedMarkdownBlock(existingContent: string, templateContent: string, startMarker: string, endMarker: string): string | null;
|
|
3
10
|
/** Remove empty managed parents without deleting a managed root directory. */
|
|
4
11
|
export declare function cleanupEmptyDirs(cwd: string, dirPath: string): void;
|
|
5
12
|
//# sourceMappingURL=managed-paths.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-paths.d.ts","sourceRoot":"","sources":["../../src/utils/managed-paths.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,iBAAiB,yBAAyB,CAAC;AAExD,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAqDnE"}
|
|
1
|
+
{"version":3,"file":"managed-paths.d.ts","sourceRoot":"","sources":["../../src/utils/managed-paths.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,iBAAiB,yBAAyB,CAAC;AAExD,wEAAwE;AACxE,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAQf;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAmCf;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAqDnE"}
|
|
@@ -3,6 +3,46 @@ import path from "node:path";
|
|
|
3
3
|
import { isManagedPath, isManagedRootDir } from "../configurators/index.js";
|
|
4
4
|
export const TRELLIS_BLOCK_START = "<!-- TRELLIS:START -->";
|
|
5
5
|
export const TRELLIS_BLOCK_END = "<!-- TRELLIS:END -->";
|
|
6
|
+
/** Return the first complete managed block, if the document has one. */
|
|
7
|
+
export function getManagedMarkdownBlock(content, startMarker, endMarker) {
|
|
8
|
+
const start = content.indexOf(startMarker);
|
|
9
|
+
if (start === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const end = content.indexOf(endMarker, start);
|
|
12
|
+
if (end === -1)
|
|
13
|
+
return null;
|
|
14
|
+
return content.slice(start, end + endMarker.length);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Replace a complete managed block, or append the template's block while
|
|
18
|
+
* preserving all user-authored content around it.
|
|
19
|
+
*/
|
|
20
|
+
export function mergeManagedMarkdownBlock(existingContent, templateContent, startMarker, endMarker) {
|
|
21
|
+
const firstStart = existingContent.indexOf(startMarker);
|
|
22
|
+
const firstEnd = existingContent.indexOf(endMarker);
|
|
23
|
+
const templateBlock = getManagedMarkdownBlock(templateContent, startMarker, endMarker);
|
|
24
|
+
if (!templateBlock)
|
|
25
|
+
return templateContent;
|
|
26
|
+
if (firstStart === -1 && firstEnd === -1) {
|
|
27
|
+
const trimmed = existingContent.replace(/\s+$/, "");
|
|
28
|
+
return `${trimmed}\n\n${templateBlock}\n`;
|
|
29
|
+
}
|
|
30
|
+
if (firstStart === -1 ||
|
|
31
|
+
firstEnd === -1 ||
|
|
32
|
+
firstEnd < firstStart ||
|
|
33
|
+
existingContent.indexOf(startMarker, firstStart + startMarker.length) !==
|
|
34
|
+
-1 ||
|
|
35
|
+
existingContent.indexOf(endMarker, firstEnd + endMarker.length) !== -1) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const existingEnd = existingContent.indexOf(endMarker, firstStart);
|
|
39
|
+
if (existingEnd !== -1) {
|
|
40
|
+
return (existingContent.slice(0, firstStart) +
|
|
41
|
+
templateBlock +
|
|
42
|
+
existingContent.slice(existingEnd + endMarker.length));
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
6
46
|
/** Remove empty managed parents without deleting a managed root directory. */
|
|
7
47
|
export function cleanupEmptyDirs(cwd, dirPath) {
|
|
8
48
|
const dirPosix = dirPath.replace(/\\/g, "/");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-paths.js","sourceRoot":"","sources":["../../src/utils/managed-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE5E,MAAM,CAAC,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAExD,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAAe;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAErC,IACE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC/B,QAAQ,CAAC,IAAI,CACX,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CACnE;QACD,CAAC,aAAa,CAAC,QAAQ,CAAC;QACxB,gBAAgB,CAAC,QAAQ,CAAC,EAC1B,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,QAAQ,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACvD,IACE,QAAQ,KAAK,EAAE;QACf,QAAQ,KAAK,IAAI;QACjB,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EACzB,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO;IAErC,IAAI,CAAC;QACH,MAAM,iBAAiB,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;QACzE,IACE,iBAAiB,KAAK,EAAE;YACxB,iBAAiB,KAAK,IAAI;YAC1B,iBAAiB,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7C,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAClC,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,OAAO;QAEzD,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1C,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC5C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvE,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;IAC1E,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"managed-paths.js","sourceRoot":"","sources":["../../src/utils/managed-paths.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pennixrv/trellis",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.21",
|
|
4
4
|
"description": "AI capabilities grow like ivy — Trellis provides the structure to guide them along a disciplined path",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"inquirer": "^9.3.7",
|
|
35
35
|
"undici": "^6.21.0",
|
|
36
36
|
"zod": "^4.4.2",
|
|
37
|
-
"@pennixrv/trellis-core": "0.6.
|
|
37
|
+
"@pennixrv/trellis-core": "0.6.21"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@eslint/js": "^9.18.0",
|