@pennixrv/trellis 0.6.18 → 0.6.20
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/adapters/codex.d.ts +14 -0
- package/dist/commands/channel/adapters/codex.d.ts.map +1 -1
- package/dist/commands/channel/adapters/codex.js +37 -0
- package/dist/commands/channel/adapters/codex.js.map +1 -1
- package/dist/commands/channel/adapters/index.d.ts.map +1 -1
- package/dist/commands/channel/adapters/index.js +49 -13
- package/dist/commands/channel/adapters/index.js.map +1 -1
- 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/migrations/manifests/0.6.19.json +9 -0
- package/dist/migrations/manifests/0.6.20.json +9 -0
- package/dist/templates/common/bundled-skills/trellis-channel/SKILL.md +2 -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 +159 -0
- package/dist/templates/common/bundled-skills/trellis-channel/references/workflows.md +6 -3
- package/dist/templates/shared-hooks/inject-workflow-state.py +17 -16
- package/dist/templates/trellis/agents/subnode.md +62 -0
- package/dist/templates/trellis/config.yaml +9 -9
- package/dist/templates/trellis/index.d.ts +3 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +6 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/config.py +5 -4
- package/dist/templates/trellis/scripts/common/task_store.py +3 -3
- package/dist/templates/trellis/scripts/common/workflow_phase.py +1 -1
- package/dist/templates/trellis/scripts/subnode_artifact.py +498 -0
- package/dist/templates/trellis/scripts/workspace_note.py +126 -0
- package/dist/templates/trellis/workflow.md +5 -5
- package/package.json +2 -2
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Append one bounded coordinator note to the current developer workspace."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import NoReturn
|
|
13
|
+
|
|
14
|
+
from common.paths import DIR_WORKFLOW, DIR_WORKSPACE, get_developer, get_repo_root, get_workspace_dir
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ALLOWED_KINDS = {"observation", "decision", "open-question", "blocker"}
|
|
18
|
+
MAX_SUMMARY_LENGTH = 600
|
|
19
|
+
MAX_SOURCES = 5
|
|
20
|
+
MAX_SOURCE_LENGTH = 1024
|
|
21
|
+
SECRET_PATTERNS = (
|
|
22
|
+
re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"),
|
|
23
|
+
re.compile(r"\bsk-[A-Za-z0-9]{20,}\b"),
|
|
24
|
+
re.compile(r"\bgh[pousr]_[A-Za-z0-9]{20,}\b"),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WorkspaceNoteError(Exception):
|
|
29
|
+
"""A user-correctable workspace-note failure."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _fail(message: str) -> NoReturn:
|
|
33
|
+
raise WorkspaceNoteError(message)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _validate_text(value: str, field: str, max_length: int) -> str:
|
|
37
|
+
if not value.strip() or len(value) > max_length:
|
|
38
|
+
_fail(f"{field} must be a non-empty string of at most {max_length} characters")
|
|
39
|
+
if "\n" in value or "\r" in value or "\x00" in value:
|
|
40
|
+
_fail(f"{field} must be a single line without control characters")
|
|
41
|
+
for pattern in SECRET_PATTERNS:
|
|
42
|
+
if pattern.search(value):
|
|
43
|
+
_fail(f"{field} appears to contain a credential")
|
|
44
|
+
return value
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _workspace_path(repo_root: Path) -> Path:
|
|
48
|
+
developer = get_developer(repo_root)
|
|
49
|
+
workspace_dir = get_workspace_dir(repo_root)
|
|
50
|
+
if not developer or workspace_dir is None:
|
|
51
|
+
_fail("developer is not initialized; run init_developer.py first")
|
|
52
|
+
workspace_root = repo_root / DIR_WORKFLOW / DIR_WORKSPACE
|
|
53
|
+
if workspace_dir.is_symlink():
|
|
54
|
+
_fail(f"refusing symlinked developer workspace: {workspace_dir}")
|
|
55
|
+
try:
|
|
56
|
+
workspace_root_resolved = workspace_root.resolve(strict=True)
|
|
57
|
+
workspace_resolved = workspace_dir.resolve(strict=True)
|
|
58
|
+
except (OSError, RuntimeError) as exc:
|
|
59
|
+
_fail(f"could not resolve developer workspace: {exc}")
|
|
60
|
+
if workspace_resolved.parent != workspace_root_resolved:
|
|
61
|
+
_fail("developer workspace is not a direct workspace child")
|
|
62
|
+
if workspace_dir.name != developer:
|
|
63
|
+
_fail("developer identity does not name its workspace directory")
|
|
64
|
+
return workspace_dir / "working-notes.md"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _append_record(path: Path, record: str) -> None:
|
|
68
|
+
if path.is_symlink():
|
|
69
|
+
_fail(f"refusing symlinked working notes file: {path}")
|
|
70
|
+
flags = os.O_APPEND | os.O_CREAT | os.O_WRONLY
|
|
71
|
+
if hasattr(os, "O_BINARY"):
|
|
72
|
+
flags |= os.O_BINARY
|
|
73
|
+
try:
|
|
74
|
+
descriptor = os.open(path, flags, 0o600)
|
|
75
|
+
try:
|
|
76
|
+
data = record.encode("utf-8")
|
|
77
|
+
written = os.write(descriptor, data)
|
|
78
|
+
if written != len(data):
|
|
79
|
+
_fail("could not append the complete workspace note")
|
|
80
|
+
os.fsync(descriptor)
|
|
81
|
+
finally:
|
|
82
|
+
os.close(descriptor)
|
|
83
|
+
except OSError as exc:
|
|
84
|
+
_fail(f"could not append workspace note {path}: {exc}")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _main(args: argparse.Namespace) -> None:
|
|
88
|
+
if args.kind not in ALLOWED_KINDS:
|
|
89
|
+
_fail(f"--kind must be one of: {', '.join(sorted(ALLOWED_KINDS))}")
|
|
90
|
+
summary = _validate_text(args.summary, "--summary", MAX_SUMMARY_LENGTH)
|
|
91
|
+
if len(args.source) > MAX_SOURCES:
|
|
92
|
+
_fail(f"at most {MAX_SOURCES} --source values are allowed")
|
|
93
|
+
sources = [
|
|
94
|
+
_validate_text(value, "--source", MAX_SOURCE_LENGTH)
|
|
95
|
+
for value in args.source
|
|
96
|
+
]
|
|
97
|
+
repo_root = get_repo_root()
|
|
98
|
+
path = _workspace_path(repo_root)
|
|
99
|
+
timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
|
100
|
+
lines = [f"## {timestamp} | {args.kind}", "", summary]
|
|
101
|
+
if sources:
|
|
102
|
+
lines.extend(["", "Sources:"])
|
|
103
|
+
lines.extend(f"- {source}" for source in sources)
|
|
104
|
+
_append_record(path, "\n".join(lines) + "\n\n")
|
|
105
|
+
print(path.relative_to(repo_root).as_posix())
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _parser() -> argparse.ArgumentParser:
|
|
109
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
110
|
+
parser.add_argument("--kind", required=True, choices=sorted(ALLOWED_KINDS))
|
|
111
|
+
parser.add_argument("--summary", required=True)
|
|
112
|
+
parser.add_argument("--source", action="append", default=[])
|
|
113
|
+
return parser
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def main() -> int:
|
|
117
|
+
try:
|
|
118
|
+
_main(_parser().parse_args())
|
|
119
|
+
except WorkspaceNoteError as exc:
|
|
120
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
121
|
+
return 1
|
|
122
|
+
return 0
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
sys.exit(main())
|
|
@@ -207,8 +207,8 @@ Multi-deliverable scope: consider a parent task plus independently verifiable ch
|
|
|
207
207
|
Sub-agent mode: curate `implement.jsonl` and `check.jsonl` as spec/research manifests before start.
|
|
208
208
|
[/workflow-state:planning]
|
|
209
209
|
|
|
210
|
-
<!-- Per-turn breadcrumb: shown throughout Phase 1 when
|
|
211
|
-
Codex-only
|
|
210
|
+
<!-- Per-turn breadcrumb: shown throughout Phase 1 when Codex uses its default
|
|
211
|
+
codex.dispatch_mode=inline. Codex-only alternate to [workflow-state:planning]. The main agent
|
|
212
212
|
edits code directly in Phase 2, so jsonl curation is skipped —
|
|
213
213
|
the inline workflow loads `trellis-before-dev` instead of injecting JSONL
|
|
214
214
|
into a sub-agent. -->
|
|
@@ -236,12 +236,12 @@ Sub-agent dispatch protocol applies to all platforms and all sub-agents, includi
|
|
|
236
236
|
[workflow-state:in_progress]
|
|
237
237
|
Tools: `trellis-implement` / `trellis-research` are sub-agent types only (Task/Agent tool, NOT Skill; there is no skill by these names). `trellis-update-spec` is a skill. `trellis-check` exists as both; prefer the Agent form when verifying after code changes.
|
|
238
238
|
Flow: `trellis-implement` -> `trellis-check` -> `trellis-update-spec` -> commit (Phase 3.4) -> `/trellis:finish-work`.
|
|
239
|
-
|
|
239
|
+
Use this block only when `codex.dispatch_mode: auto` is explicitly selected. Sub-agent self-exemption: if already running as `trellis-implement`, do NOT spawn another `trellis-implement` or `trellis-check`; if already running as `trellis-check`, do NOT spawn another `trellis-check` or `trellis-implement`. Dispatch is main session only.
|
|
240
240
|
Dispatch prompt starts with `Active task: <task path from task.py current>`. Read context: jsonl entries -> `prd.md` -> `design.md if present` -> `implement.md if present`.
|
|
241
241
|
[/workflow-state:in_progress]
|
|
242
242
|
|
|
243
|
-
<!-- Per-turn breadcrumb: shown while status='in_progress' when
|
|
244
|
-
codex.dispatch_mode=inline. Codex-only
|
|
243
|
+
<!-- Per-turn breadcrumb: shown while status='in_progress' when Codex uses its
|
|
244
|
+
default codex.dispatch_mode=inline. Codex-only alternate to
|
|
245
245
|
[workflow-state:in_progress]. The main session edits code directly
|
|
246
246
|
instead of dispatching sub-agents. -->
|
|
247
247
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pennixrv/trellis",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.20",
|
|
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.20"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@eslint/js": "^9.18.0",
|