@pennixrv/trellis 0.7.0-beta.23 → 0.7.0-beta.25
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/migrations/manifests/0.7.0-beta.24.json +9 -0
- package/dist/migrations/manifests/0.7.0-beta.25.json +9 -0
- package/dist/templates/common/commands/continue.md +11 -0
- package/dist/templates/trellis/agents/subnode-profiles.json +2 -3
- package/dist/templates/trellis/scripts/common/active_task.py +6 -6
- package/dist/templates/trellis/scripts/common/ownership_record.py +8 -5
- package/dist/templates/trellis/workflow.md +3 -3
- package/package.json +2 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.7.0-beta.24",
|
|
3
|
+
"description": "Refresh shipped subnode model defaults",
|
|
4
|
+
"breaking": false,
|
|
5
|
+
"recommendMigrate": false,
|
|
6
|
+
"changelog": "Generated subnode profiles use gpt-6.1-sol by default and gpt-5.6-luna/xhigh for docs_source. The redundant code_path preset is removed; six judgment profiles retain high and evidence_synthesis retains medium.",
|
|
7
|
+
"migrations": [],
|
|
8
|
+
"notes": "Run trellis update after upgrading. Unmodified profiles receive the new defaults; customized profiles remain protected. Refresh the separately selected Marketplace workflow through trellis workflow with an explicit immutable ref. The generic resolver and supported effort values are unchanged."
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.7.0-beta.25",
|
|
3
|
+
"description": "Preserve identity during unbound task recovery",
|
|
4
|
+
"breaking": false,
|
|
5
|
+
"recommendMigrate": false,
|
|
6
|
+
"changelog": "Unbound task projections retain resolved direct session identity. Formal ownership retirement and claim distinguish read-only candidates from direct bindings. Recovery guidance checks identity separately and preserves planning activation gates.",
|
|
7
|
+
"migrations": [],
|
|
8
|
+
"notes": "Run trellis update after upgrading. Refresh a separately selected Marketplace workflow using its explicit immutable ref. Candidate projections remain read-only; foreign-session isolation and ownership fencing remain enforced. No identity injection or automatic task selection is required."
|
|
9
|
+
}
|
|
@@ -8,10 +8,21 @@ Resume work on the current task — pick up at the right phase/step in `.trellis
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
{{PYTHON_CMD}} ./.trellis/scripts/get_context.py
|
|
11
|
+
{{PYTHON_CMD}} ./.trellis/scripts/task.py current --json
|
|
11
12
|
```
|
|
12
13
|
|
|
13
14
|
Confirms: current task, git state, recent commits.
|
|
14
15
|
|
|
16
|
+
Before routing by status, distinguish identity from task binding. A non-null
|
|
17
|
+
`session_source` confirms available identity; only `source=session:...` confirms
|
|
18
|
+
a direct task binding. For `unbound` / `unbound_ambiguous`, review existing task
|
|
19
|
+
artifacts and select by the user's explicit intent. Exit code 1 for ambiguity
|
|
20
|
+
does not mean identity is absent. Do not guess, duplicate tasks, invent identity,
|
|
21
|
+
or edit runtime pointers. Return a planning candidate to the planning gates below;
|
|
22
|
+
use native `task.py start <task>` only when its activation contract permits it.
|
|
23
|
+
An eligible `analysis_only` candidate remains in planning without start.
|
|
24
|
+
If `session_source` is null, report unavailable identity separately.
|
|
25
|
+
|
|
15
26
|
## Step 2: Load the Phase Index
|
|
16
27
|
|
|
17
28
|
```bash
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"default_model": "gpt-6-sol",
|
|
2
|
+
"default_model": "gpt-6.1-sol",
|
|
3
3
|
"profiles": {
|
|
4
|
-
"
|
|
5
|
-
"docs_source": { "reasoning_effort": "medium" },
|
|
4
|
+
"docs_source": { "model": "gpt-5.6-luna", "reasoning_effort": "xhigh" },
|
|
6
5
|
"fault_diagnosis": { "reasoning_effort": "high" },
|
|
7
6
|
"correctness_test": { "reasoning_effort": "high" },
|
|
8
7
|
"security_permission": { "reasoning_effort": "high" },
|
|
@@ -694,7 +694,7 @@ def resolve_active_task(
|
|
|
694
694
|
active = _active_from_ref(task_ref, repo_root, "session", context_key)
|
|
695
695
|
if active:
|
|
696
696
|
return active
|
|
697
|
-
unbound = _resolve_unbound_task(repo_root)
|
|
697
|
+
unbound = _resolve_unbound_task(repo_root, context_key)
|
|
698
698
|
if unbound is not None:
|
|
699
699
|
return unbound
|
|
700
700
|
return ActiveTask(None, "none", context_key)
|
|
@@ -736,8 +736,8 @@ def _resolve_single_session_fallback(repo_root: Path) -> ActiveTask | None:
|
|
|
736
736
|
return _active_from_ref(task_ref, repo_root, "session-fallback", fallback_key)
|
|
737
737
|
|
|
738
738
|
|
|
739
|
-
def _resolve_unbound_task(repo_root: Path) -> ActiveTask | None:
|
|
740
|
-
"""Expose
|
|
739
|
+
def _resolve_unbound_task(repo_root: Path, context_key: str | None = None) -> ActiveTask | None:
|
|
740
|
+
"""Expose read-only candidates without discarding a resolved identity."""
|
|
741
741
|
sessions_dir = _runtime_sessions_dir(repo_root)
|
|
742
742
|
if sessions_dir.is_dir():
|
|
743
743
|
session_files = sorted(sessions_dir.glob("*.json"))
|
|
@@ -764,8 +764,8 @@ def _resolve_unbound_task(repo_root: Path) -> ActiveTask | None:
|
|
|
764
764
|
for task in candidates
|
|
765
765
|
))
|
|
766
766
|
if len(task_paths) == 1:
|
|
767
|
-
return ActiveTask(task_paths[0], "unbound",
|
|
768
|
-
return ActiveTask(None, "unbound_ambiguous",
|
|
767
|
+
return ActiveTask(task_paths[0], "unbound", context_key)
|
|
768
|
+
return ActiveTask(None, "unbound_ambiguous", context_key, candidate_paths=task_paths)
|
|
769
769
|
|
|
770
770
|
|
|
771
771
|
def _utc_now() -> str:
|
|
@@ -834,7 +834,7 @@ def clear_active_task(
|
|
|
834
834
|
return ActiveTask(None, "none")
|
|
835
835
|
|
|
836
836
|
previous = resolve_active_task(repo_root, platform_input, platform)
|
|
837
|
-
if not previous.task_path or not previous.context_key:
|
|
837
|
+
if previous.source_type != "session" or not previous.task_path or not previous.context_key:
|
|
838
838
|
return previous
|
|
839
839
|
|
|
840
840
|
context_path = _context_path(repo_root, previous.context_key)
|
|
@@ -10,7 +10,7 @@ from datetime import datetime, timezone
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
|
-
from .active_task import clear_active_task, clear_active_task_for_context, resolve_active_task, resolve_context_key, set_active_task
|
|
13
|
+
from .active_task import ActiveTask, clear_active_task, clear_active_task_for_context, resolve_active_task, resolve_context_key, set_active_task
|
|
14
14
|
from .continuation_record import (
|
|
15
15
|
ContinuationError,
|
|
16
16
|
SAFE_ID,
|
|
@@ -83,6 +83,9 @@ def _direct_context(root: Path, require_task: bool = False) -> tuple[str, Any]:
|
|
|
83
83
|
raise OwnershipError("session_fallback_untrusted")
|
|
84
84
|
if active.context_key != context_key:
|
|
85
85
|
raise OwnershipError("direct_session_identity_unstable")
|
|
86
|
+
if active.source_type in {"unbound", "unbound_ambiguous"}:
|
|
87
|
+
# Candidate paths are recovery context, never an owned session pointer.
|
|
88
|
+
active = ActiveTask(None, "none", context_key)
|
|
86
89
|
if require_task and not active.task_path:
|
|
87
90
|
raise OwnershipError("no_direct_current_task")
|
|
88
91
|
return context_key, active
|
|
@@ -273,14 +276,14 @@ def retire(root: Path, task_id: str, handoff_id: str, core_digest: str, expected
|
|
|
273
276
|
elif record["archive_observation"] != archive_observation:
|
|
274
277
|
raise OwnershipError("archive observation does not match retirement")
|
|
275
278
|
|
|
276
|
-
active =
|
|
279
|
+
_, active = _direct_context(root)
|
|
277
280
|
if active.context_key != actor:
|
|
278
281
|
raise OwnershipError("direct_session_identity_unstable")
|
|
279
282
|
if active.task_path == record["task"]["path"]:
|
|
280
283
|
clear_active_task(root)
|
|
281
284
|
elif active.task_path:
|
|
282
285
|
raise OwnershipError("source task pointer changed during retirement")
|
|
283
|
-
active =
|
|
286
|
+
_, active = _direct_context(root)
|
|
284
287
|
if active.context_key != actor or active.task_path:
|
|
285
288
|
raise OwnershipError("source task retirement could not be verified; recovery_required")
|
|
286
289
|
record["previous_event_digest"] = record["integrity"]["record_digest"]
|
|
@@ -334,7 +337,7 @@ def claim(root: Path, task_id: str, task_path: str, handoff_id: str, core_digest
|
|
|
334
337
|
bound = set_active_task(record["task"]["path"], root)
|
|
335
338
|
if not bound:
|
|
336
339
|
raise OwnershipError("target task binding failed; recovery_required")
|
|
337
|
-
active =
|
|
340
|
+
_, active = _direct_context(root)
|
|
338
341
|
if active.context_key != actor or active.task_path != record["task"]["path"]:
|
|
339
342
|
raise OwnershipError("target task binding could not be verified; recovery_required")
|
|
340
343
|
record["previous_event_digest"] = record["integrity"]["record_digest"]
|
|
@@ -361,7 +364,7 @@ def claim(root: Path, task_id: str, task_path: str, handoff_id: str, core_digest
|
|
|
361
364
|
bound = set_active_task(task["path"], root)
|
|
362
365
|
if not bound:
|
|
363
366
|
raise OwnershipError("target task binding failed; recovery_required")
|
|
364
|
-
active =
|
|
367
|
+
_, active = _direct_context(root)
|
|
365
368
|
if active.context_key != actor or active.task_path != task["path"]:
|
|
366
369
|
raise OwnershipError("target task binding could not be verified; recovery_required")
|
|
367
370
|
record["previous_event_digest"] = record["integrity"]["record_digest"]
|
|
@@ -200,17 +200,17 @@ Complex task: ask the user if you can create a Trellis task and enter the planni
|
|
|
200
200
|
<!-- Per-turn breadcrumb: shown when one resumable task exists without a direct session binding. -->
|
|
201
201
|
|
|
202
202
|
[workflow-state:unbound_task]
|
|
203
|
-
An existing task
|
|
203
|
+
An existing developer-owned task has no direct session binding. Inspect native `task.py current --json`: a non-null `session_source` means direct identity is already available; an unbound source still means no task binding. Select the existing task from the user's explicit intent; do not guess or create a duplicate. Resume its planning/status gates first. Run native `task.py start <task>` only when its activation contract permits it, after the Planning Seal and implementation authorization for a planning change-bearing task. An eligible `analysis_only` task stays in planning without start. If identity is absent, report that separately; never invent an identity or edit runtime pointers.
|
|
204
204
|
[/workflow-state:unbound_task]
|
|
205
205
|
|
|
206
206
|
<!-- Per-turn breadcrumb shown when multiple resumable tasks exist without a direct session binding. -->
|
|
207
207
|
|
|
208
208
|
[workflow-state:unbound_ambiguous]
|
|
209
|
-
Multiple
|
|
209
|
+
Multiple developer-owned tasks have no direct session binding. Inspect native `task.py current --json`: a non-null `session_source` means direct identity is already available; an unbound source still means no task binding. Select the existing task from the user's explicit intent; do not guess or create a duplicate. Resume its planning/status gates first. Run native `task.py start <task>` only when its activation contract permits it, after the Planning Seal and implementation authorization for a planning change-bearing task. An eligible `analysis_only` task stays in planning without start. If identity is absent, report that separately; never invent an identity or edit runtime pointers.
|
|
210
210
|
[/workflow-state:unbound_ambiguous]
|
|
211
211
|
|
|
212
212
|
[workflow-state:unbound_ambiguous-inline]
|
|
213
|
-
Multiple
|
|
213
|
+
Multiple developer-owned tasks have no direct session binding. Inspect native `task.py current --json`: a non-null `session_source` means direct identity is already available; an unbound source still means no task binding. Select the existing task from the user's explicit intent; do not guess or create a duplicate. Resume its planning/status gates first. Run native `task.py start <task>` only when its activation contract permits it, after the Planning Seal and implementation authorization for a planning change-bearing task. An eligible `analysis_only` task stays in planning without start. If identity is absent, report that separately; never invent an identity or edit runtime pointers.
|
|
214
214
|
[/workflow-state:unbound_ambiguous-inline]
|
|
215
215
|
|
|
216
216
|
<!-- Per-turn breadcrumb: shown when the active task record cannot be read. -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pennixrv/trellis",
|
|
3
|
-
"version": "0.7.0-beta.
|
|
3
|
+
"version": "0.7.0-beta.25",
|
|
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.7.0-beta.
|
|
37
|
+
"@pennixrv/trellis-core": "0.7.0-beta.25"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@eslint/js": "^9.18.0",
|