@mindfoldhq/trellis 0.6.0-beta.3 → 0.6.0-beta.5
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/mem.d.ts +2 -2
- package/dist/commands/mem.d.ts.map +1 -1
- package/dist/commands/mem.js +28 -258
- package/dist/commands/mem.js.map +1 -1
- package/dist/migrations/manifests/0.5.10.json +9 -0
- package/dist/migrations/manifests/0.6.0-beta.4.json +9 -0
- package/dist/migrations/manifests/0.6.0-beta.5.json +9 -0
- package/dist/templates/common/commands/start.md +2 -0
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +39 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +289 -43
- package/dist/templates/pi/extensions/trellis/index.ts.txt +179 -4
- package/dist/templates/pi/settings.json +9 -0
- package/dist/templates/trellis/index.d.ts +1 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +2 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +44 -24
- package/dist/templates/trellis/scripts/common/safe_commit.py +229 -0
- package/dist/templates/trellis/scripts/common/session_context.py +170 -0
- package/dist/templates/trellis/scripts/common/task_store.py +34 -5
- package/dist/utils/uninstall-scrubbers.d.ts +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +21 -0
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/package.json +1 -3
|
@@ -36,6 +36,7 @@ export declare const commonSessionContext: string;
|
|
|
36
36
|
export declare const commonPackagesContext: string;
|
|
37
37
|
export declare const commonWorkflowPhase: string;
|
|
38
38
|
export declare const commonTrellisConfig: string;
|
|
39
|
+
export declare const commonSafeCommit: string;
|
|
39
40
|
export declare const getDeveloperScript: string;
|
|
40
41
|
export declare const initDeveloperScript: string;
|
|
41
42
|
export declare const taskScript: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAG9E,eAAO,MAAM,kBAAkB,QAA2C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAC7E,eAAO,MAAM,UAAU,QAAkC,CAAC;AAC1D,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAGvE,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAE/D;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqCnD"}
|
|
@@ -46,6 +46,7 @@ export const commonSessionContext = readTemplate("scripts/common/session_context
|
|
|
46
46
|
export const commonPackagesContext = readTemplate("scripts/common/packages_context.py");
|
|
47
47
|
export const commonWorkflowPhase = readTemplate("scripts/common/workflow_phase.py");
|
|
48
48
|
export const commonTrellisConfig = readTemplate("scripts/common/trellis_config.py");
|
|
49
|
+
export const commonSafeCommit = readTemplate("scripts/common/safe_commit.py");
|
|
49
50
|
// Python scripts - main
|
|
50
51
|
export const getDeveloperScript = readTemplate("scripts/get_developer.py");
|
|
51
52
|
export const initDeveloperScript = readTemplate("scripts/init_developer.py");
|
|
@@ -84,6 +85,7 @@ export function getAllScripts() {
|
|
|
84
85
|
scripts.set("common/packages_context.py", commonPackagesContext);
|
|
85
86
|
scripts.set("common/workflow_phase.py", commonWorkflowPhase);
|
|
86
87
|
scripts.set("common/trellis_config.py", commonTrellisConfig);
|
|
88
|
+
scripts.set("common/safe_commit.py", commonSafeCommit);
|
|
87
89
|
// Main
|
|
88
90
|
scripts.set("get_developer.py", getDeveloperScript);
|
|
89
91
|
scripts.set("init_developer.py", initDeveloperScript);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAE/D,0BAA0B;AAC1B,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC,4BAA4B,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,6BAA6B,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAG,YAAY,CAAC,0BAA0B,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC,sBAAsB,CAAC,CAAC;AAC7D,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC,uBAAuB,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC,uBAAuB,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,gCAAgC,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAC9C,mCAAmC,CACpC,CAAC;AACF,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAC/C,oCAAoC,CACrC,CAAC;AACF,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAC7C,kCAAkC,CACnC,CAAC;AACF,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAC7C,kCAAkC,CACnC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,6 @@ from __future__ import annotations
|
|
|
23
23
|
|
|
24
24
|
import argparse
|
|
25
25
|
import re
|
|
26
|
-
import subprocess
|
|
27
26
|
import sys
|
|
28
27
|
from datetime import datetime
|
|
29
28
|
from pathlib import Path
|
|
@@ -37,6 +36,11 @@ from common.paths import (
|
|
|
37
36
|
)
|
|
38
37
|
from common.developer import ensure_developer
|
|
39
38
|
from common.git import run_git
|
|
39
|
+
from common.safe_commit import (
|
|
40
|
+
print_gitignore_warning,
|
|
41
|
+
safe_git_add,
|
|
42
|
+
safe_trellis_paths_to_add,
|
|
43
|
+
)
|
|
40
44
|
from common.tasks import load_task
|
|
41
45
|
from common.config import (
|
|
42
46
|
get_packages,
|
|
@@ -314,36 +318,52 @@ def update_index(
|
|
|
314
318
|
# =============================================================================
|
|
315
319
|
|
|
316
320
|
def _auto_commit_workspace(repo_root: Path) -> None:
|
|
317
|
-
"""Stage
|
|
321
|
+
"""Stage Trellis-owned workspace + task paths and commit.
|
|
322
|
+
|
|
323
|
+
Path scope is restricted to specific products (journal files, index.md,
|
|
324
|
+
active task dirs, the archive subtree). We never `git add` the whole
|
|
325
|
+
`.trellis/` tree, and if `.gitignore` blocks the specific paths we retry
|
|
326
|
+
with `git add -f <those-specific-paths>` — never `-f .trellis/`.
|
|
327
|
+
"""
|
|
318
328
|
commit_msg = get_session_commit_message(repo_root)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
)
|
|
325
|
-
if
|
|
326
|
-
|
|
327
|
-
|
|
329
|
+
paths = safe_trellis_paths_to_add(repo_root)
|
|
330
|
+
if not paths:
|
|
331
|
+
print("[OK] No workspace changes to commit.", file=sys.stderr)
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
success, used_force, err = safe_git_add(paths, repo_root)
|
|
335
|
+
if not success:
|
|
336
|
+
if err and "ignored by" in err.lower():
|
|
337
|
+
print_gitignore_warning(paths)
|
|
338
|
+
else:
|
|
339
|
+
print(
|
|
340
|
+
f"[WARN] git add failed: {err.strip() if err else 'unknown error'}",
|
|
341
|
+
file=sys.stderr,
|
|
342
|
+
)
|
|
328
343
|
return
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
344
|
+
|
|
345
|
+
if used_force:
|
|
346
|
+
print(
|
|
347
|
+
"[OK] Staged Trellis-owned paths with -f (specific paths, not .trellis/).",
|
|
348
|
+
file=sys.stderr,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Check if there are staged changes for the paths we just staged.
|
|
352
|
+
rc, _, _ = run_git(
|
|
353
|
+
["diff", "--cached", "--quiet", "--", *paths], cwd=repo_root
|
|
333
354
|
)
|
|
334
|
-
if
|
|
355
|
+
if rc == 0:
|
|
335
356
|
print("[OK] No workspace changes to commit.", file=sys.stderr)
|
|
336
357
|
return
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
capture_output=True,
|
|
341
|
-
text=True,
|
|
342
|
-
)
|
|
343
|
-
if commit_result.returncode == 0:
|
|
358
|
+
|
|
359
|
+
rc, _, commit_err = run_git(["commit", "-m", commit_msg], cwd=repo_root)
|
|
360
|
+
if rc == 0:
|
|
344
361
|
print(f"[OK] Auto-committed: {commit_msg}", file=sys.stderr)
|
|
345
362
|
else:
|
|
346
|
-
print(
|
|
363
|
+
print(
|
|
364
|
+
f"[WARN] Auto-commit failed: {commit_err.strip()}",
|
|
365
|
+
file=sys.stderr,
|
|
366
|
+
)
|
|
347
367
|
|
|
348
368
|
|
|
349
369
|
def add_session(
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Safe git-add helpers for Trellis-owned paths.
|
|
3
|
+
|
|
4
|
+
Why this module exists
|
|
5
|
+
----------------------
|
|
6
|
+
A real user incident: a project's `.gitignore` listed `.trellis/` (company-wide
|
|
7
|
+
template / personal habit). When `add_session.py` and `task.py archive` ran
|
|
8
|
+
their auto-commit and `git add` failed with `ignored by .gitignore`, the AI
|
|
9
|
+
agent driving the workflow "fixed" it by retrying with
|
|
10
|
+
`git add -f .trellis/` — which fan-out-included every ignored subtree
|
|
11
|
+
(`.trellis/.backup-*/`, `.trellis/worktrees/`, `.trellis/.template-hashes.json`,
|
|
12
|
+
`.trellis/.runtime/`), committing 548 files / 83474 lines of caches/backups.
|
|
13
|
+
|
|
14
|
+
Design
|
|
15
|
+
------
|
|
16
|
+
- Scripts only stage SPECIFIC product paths (journal files, index.md, the
|
|
17
|
+
current task dir, the archive dir). Never the whole `.trellis/` tree.
|
|
18
|
+
- If plain `git add <specific>` fails with "ignored by", retry with
|
|
19
|
+
`git add -f <specific>` — forcing only the paths the script knows it owns.
|
|
20
|
+
This is safe because the paths are narrow; it is NOT equivalent to
|
|
21
|
+
`git add -f .trellis/` (which would fan out to backups/worktrees/runtime).
|
|
22
|
+
- If the -f retry also fails, print an explicit warning that includes a
|
|
23
|
+
negative example: ``Do NOT use `git add -f .trellis/` ...``
|
|
24
|
+
|
|
25
|
+
The wider-grain forbidden command stays forbidden.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import sys
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
from .git import run_git
|
|
34
|
+
from .paths import (
|
|
35
|
+
DIR_ARCHIVE,
|
|
36
|
+
DIR_TASKS,
|
|
37
|
+
DIR_WORKFLOW,
|
|
38
|
+
DIR_WORKSPACE,
|
|
39
|
+
FILE_JOURNAL_PREFIX,
|
|
40
|
+
get_developer,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Paths under .trellis/ that must NEVER be auto-staged. Listed here so the
|
|
45
|
+
# warning to the user can show concrete subpaths to ignore individually
|
|
46
|
+
# instead of ignoring the whole `.trellis/` tree.
|
|
47
|
+
TRELLIS_IGNORED_SUBPATHS = (
|
|
48
|
+
".trellis/.backup-*",
|
|
49
|
+
".trellis/worktrees/",
|
|
50
|
+
".trellis/.template-hashes.json",
|
|
51
|
+
".trellis/.runtime/",
|
|
52
|
+
".trellis/.cache/",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def safe_trellis_paths_to_add(repo_root: Path) -> list[str]:
|
|
57
|
+
"""Return the list of repo-relative paths the auto-commit should stage.
|
|
58
|
+
|
|
59
|
+
Only includes paths that exist on disk so callers don't pass non-existent
|
|
60
|
+
arguments to git. The caller is responsible for `git diff --cached`
|
|
61
|
+
checking afterwards.
|
|
62
|
+
|
|
63
|
+
Included:
|
|
64
|
+
- .trellis/workspace/<developer>/journal-*.md
|
|
65
|
+
- .trellis/workspace/<developer>/index.md
|
|
66
|
+
- .trellis/tasks/<task-dir>/ (every active task directory)
|
|
67
|
+
- .trellis/tasks/archive/ (whole archive subtree, if present)
|
|
68
|
+
|
|
69
|
+
Excluded (intentionally — these must not be staged):
|
|
70
|
+
- .trellis/.backup-*, .trellis/worktrees/,
|
|
71
|
+
.trellis/.template-hashes.json, .trellis/.runtime/, .trellis/.cache/
|
|
72
|
+
"""
|
|
73
|
+
paths: list[str] = []
|
|
74
|
+
|
|
75
|
+
# Workspace journal files + index.md
|
|
76
|
+
developer = get_developer(repo_root)
|
|
77
|
+
if developer:
|
|
78
|
+
ws = repo_root / DIR_WORKFLOW / DIR_WORKSPACE / developer
|
|
79
|
+
if ws.is_dir():
|
|
80
|
+
for f in sorted(ws.glob(f"{FILE_JOURNAL_PREFIX}*.md")):
|
|
81
|
+
if f.is_file():
|
|
82
|
+
paths.append(
|
|
83
|
+
f"{DIR_WORKFLOW}/{DIR_WORKSPACE}/{developer}/{f.name}"
|
|
84
|
+
)
|
|
85
|
+
index_md = ws / "index.md"
|
|
86
|
+
if index_md.is_file():
|
|
87
|
+
paths.append(
|
|
88
|
+
f"{DIR_WORKFLOW}/{DIR_WORKSPACE}/{developer}/index.md"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Active tasks: each direct child of tasks/ that is a directory and not
|
|
92
|
+
# the archive root. The archive subtree is added as a single path below.
|
|
93
|
+
tasks_dir = repo_root / DIR_WORKFLOW / DIR_TASKS
|
|
94
|
+
if tasks_dir.is_dir():
|
|
95
|
+
for child in sorted(tasks_dir.iterdir()):
|
|
96
|
+
if not child.is_dir():
|
|
97
|
+
continue
|
|
98
|
+
if child.name == DIR_ARCHIVE:
|
|
99
|
+
continue
|
|
100
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child.name}")
|
|
101
|
+
|
|
102
|
+
archive_dir = tasks_dir / DIR_ARCHIVE
|
|
103
|
+
if archive_dir.is_dir():
|
|
104
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}")
|
|
105
|
+
|
|
106
|
+
return paths
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def safe_archive_paths_to_add(repo_root: Path) -> list[str]:
|
|
110
|
+
"""Return paths to stage after `task.py archive`.
|
|
111
|
+
|
|
112
|
+
Limited to the archive subtree (where the freshly-moved task lives) plus
|
|
113
|
+
the source task directory's parent area to capture the deletion in the
|
|
114
|
+
same commit. We pass the whole `.trellis/tasks/` path so deletions of the
|
|
115
|
+
pre-move path are tracked, but only as a SPECIFIC subpath — not the whole
|
|
116
|
+
`.trellis/` tree.
|
|
117
|
+
"""
|
|
118
|
+
paths: list[str] = []
|
|
119
|
+
tasks_dir = repo_root / DIR_WORKFLOW / DIR_TASKS
|
|
120
|
+
if tasks_dir.is_dir():
|
|
121
|
+
# The archive copy.
|
|
122
|
+
archive_dir = tasks_dir / DIR_ARCHIVE
|
|
123
|
+
if archive_dir.is_dir():
|
|
124
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}")
|
|
125
|
+
# Active tasks (some may have been re-touched, e.g. parent's
|
|
126
|
+
# children list). This captures the source-path deletion too because
|
|
127
|
+
# `git add` on a directory records removals.
|
|
128
|
+
for child in sorted(tasks_dir.iterdir()):
|
|
129
|
+
if not child.is_dir():
|
|
130
|
+
continue
|
|
131
|
+
if child.name == DIR_ARCHIVE:
|
|
132
|
+
continue
|
|
133
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child.name}")
|
|
134
|
+
return paths
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _stderr_indicates_ignored(stderr: str) -> bool:
|
|
138
|
+
"""git add error indicates the path is excluded by .gitignore."""
|
|
139
|
+
if not stderr:
|
|
140
|
+
return False
|
|
141
|
+
lowered = stderr.lower()
|
|
142
|
+
return "ignored by" in lowered
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def safe_git_add(
|
|
146
|
+
paths: list[str], repo_root: Path
|
|
147
|
+
) -> tuple[bool, bool, str]:
|
|
148
|
+
"""Run `git add` on specific paths, retrying with -f if .gitignore blocks.
|
|
149
|
+
|
|
150
|
+
Returns (success, used_force, stderr). On success, callers should still
|
|
151
|
+
`git diff --cached` to detect whether anything was actually staged.
|
|
152
|
+
|
|
153
|
+
Behavior:
|
|
154
|
+
- No paths passed → success, no force, empty stderr.
|
|
155
|
+
- Plain `git add <paths>` succeeds → return.
|
|
156
|
+
- Plain fails with "ignored by" → retry with `git add -f <paths>`.
|
|
157
|
+
- Retry succeeds → return success with used_force=True.
|
|
158
|
+
- Retry fails → return failure; caller should print the gitignore
|
|
159
|
+
warning (see :func:`print_gitignore_warning`).
|
|
160
|
+
- Plain fails with a non-ignored error → return failure; do NOT retry
|
|
161
|
+
with -f (we only force when ignore is the cause).
|
|
162
|
+
"""
|
|
163
|
+
if not paths:
|
|
164
|
+
return True, False, ""
|
|
165
|
+
|
|
166
|
+
rc, _, err = run_git(["add", "--", *paths], cwd=repo_root)
|
|
167
|
+
if rc == 0:
|
|
168
|
+
return True, False, ""
|
|
169
|
+
|
|
170
|
+
if not _stderr_indicates_ignored(err):
|
|
171
|
+
return False, False, err
|
|
172
|
+
|
|
173
|
+
rc2, _, err2 = run_git(["add", "-f", "--", *paths], cwd=repo_root)
|
|
174
|
+
if rc2 == 0:
|
|
175
|
+
return True, True, err2 or err
|
|
176
|
+
return False, True, err2 or err
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def print_gitignore_warning(paths: list[str]) -> None:
|
|
180
|
+
"""Explain to the user (and any AI reading the log) what to do.
|
|
181
|
+
|
|
182
|
+
CRITICAL: includes the negative example
|
|
183
|
+
``Do NOT use `git add -f .trellis/``` — agents reading the warning are
|
|
184
|
+
known to invent that command, which fans out to ignored caches/backups.
|
|
185
|
+
"""
|
|
186
|
+
print(
|
|
187
|
+
"[WARN] git add failed because .trellis/ paths are ignored by your .gitignore.",
|
|
188
|
+
file=sys.stderr,
|
|
189
|
+
)
|
|
190
|
+
print(
|
|
191
|
+
"[WARN] Trellis manages these specific paths and they should be tracked:",
|
|
192
|
+
file=sys.stderr,
|
|
193
|
+
)
|
|
194
|
+
if paths:
|
|
195
|
+
for p in paths:
|
|
196
|
+
print(f"[WARN] {p}", file=sys.stderr)
|
|
197
|
+
else:
|
|
198
|
+
print(
|
|
199
|
+
"[WARN] .trellis/workspace/<developer>/{journal-*.md,index.md}",
|
|
200
|
+
file=sys.stderr,
|
|
201
|
+
)
|
|
202
|
+
print(
|
|
203
|
+
"[WARN] .trellis/tasks/<task-dir>/",
|
|
204
|
+
file=sys.stderr,
|
|
205
|
+
)
|
|
206
|
+
print(
|
|
207
|
+
"[WARN] .trellis/tasks/archive/",
|
|
208
|
+
file=sys.stderr,
|
|
209
|
+
)
|
|
210
|
+
print("[WARN]", file=sys.stderr)
|
|
211
|
+
print(
|
|
212
|
+
"[WARN] Recommended: change your .gitignore from `.trellis/` to specific",
|
|
213
|
+
file=sys.stderr,
|
|
214
|
+
)
|
|
215
|
+
print(
|
|
216
|
+
"[WARN] subpaths that should remain ignored, e.g.:",
|
|
217
|
+
file=sys.stderr,
|
|
218
|
+
)
|
|
219
|
+
for sub in TRELLIS_IGNORED_SUBPATHS:
|
|
220
|
+
print(f"[WARN] {sub}", file=sys.stderr)
|
|
221
|
+
print("[WARN]", file=sys.stderr)
|
|
222
|
+
print(
|
|
223
|
+
"[WARN] Do NOT use `git add -f .trellis/` — it pulls in backups, worktrees,",
|
|
224
|
+
file=sys.stderr,
|
|
225
|
+
)
|
|
226
|
+
print(
|
|
227
|
+
"[WARN] and runtime caches that should never be committed.",
|
|
228
|
+
file=sys.stderr,
|
|
229
|
+
)
|
|
@@ -14,8 +14,12 @@ Provides:
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
|
+
import os
|
|
18
|
+
import re
|
|
19
|
+
import subprocess
|
|
17
20
|
from pathlib import Path
|
|
18
21
|
|
|
22
|
+
from .active_task import resolve_context_key
|
|
19
23
|
from .config import get_git_packages
|
|
20
24
|
from .git import run_git
|
|
21
25
|
from .packages_context import get_packages_section
|
|
@@ -40,6 +44,14 @@ from .paths import (
|
|
|
40
44
|
# Helpers
|
|
41
45
|
# =============================================================================
|
|
42
46
|
|
|
47
|
+
_PACKAGE_NAME = "@mindfoldhq/trellis"
|
|
48
|
+
_UPDATE_CHECK_TIMEOUT_SECONDS = 1.0
|
|
49
|
+
_VERSION_RE = re.compile(
|
|
50
|
+
r"^\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?\s*$"
|
|
51
|
+
)
|
|
52
|
+
_VERSION_TOKEN_RE = re.compile(r"\b\d+(?:\.\d+){1,2}(?:-[0-9A-Za-z.-]+)?\b")
|
|
53
|
+
|
|
54
|
+
|
|
43
55
|
def _collect_package_git_info(repo_root: Path) -> list[dict]:
|
|
44
56
|
"""Collect git status and recent commits for packages with independent git repos.
|
|
45
57
|
|
|
@@ -109,6 +121,158 @@ def _append_package_git_context(lines: list[str], package_git_info: list[dict])
|
|
|
109
121
|
lines.append("")
|
|
110
122
|
|
|
111
123
|
|
|
124
|
+
def _read_project_version(repo_root: Path) -> str | None:
|
|
125
|
+
try:
|
|
126
|
+
version = (repo_root / DIR_WORKFLOW / ".version").read_text(
|
|
127
|
+
encoding="utf-8"
|
|
128
|
+
).strip()
|
|
129
|
+
except OSError:
|
|
130
|
+
return None
|
|
131
|
+
return version or None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _fetch_trellis_version_output() -> str | None:
|
|
135
|
+
try:
|
|
136
|
+
result = subprocess.run(
|
|
137
|
+
["trellis", "--version"],
|
|
138
|
+
capture_output=True,
|
|
139
|
+
text=True,
|
|
140
|
+
encoding="utf-8",
|
|
141
|
+
errors="replace",
|
|
142
|
+
timeout=_UPDATE_CHECK_TIMEOUT_SECONDS,
|
|
143
|
+
)
|
|
144
|
+
except (OSError, subprocess.SubprocessError, TimeoutError):
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
if result.returncode != 0:
|
|
148
|
+
return None
|
|
149
|
+
output = f"{result.stdout}\n{result.stderr}".strip()
|
|
150
|
+
return output or None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _extract_available_update_version(output: str) -> str | None:
|
|
154
|
+
update_match = re.search(
|
|
155
|
+
r"Trellis update available:\s*"
|
|
156
|
+
r"(?P<current>\S+)\s*(?:→|->)\s*(?P<latest>\S+)",
|
|
157
|
+
output,
|
|
158
|
+
)
|
|
159
|
+
if update_match:
|
|
160
|
+
return update_match.group("latest").strip()
|
|
161
|
+
candidates = _VERSION_TOKEN_RE.findall(output)
|
|
162
|
+
return candidates[-1] if candidates else None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _resolve_available_update_version() -> str | None:
|
|
166
|
+
output = _fetch_trellis_version_output()
|
|
167
|
+
if not output:
|
|
168
|
+
return None
|
|
169
|
+
return _extract_available_update_version(output)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _parse_version(version: str) -> tuple[tuple[int, int, int], tuple[str, ...] | None] | None:
|
|
173
|
+
match = _VERSION_RE.match(version)
|
|
174
|
+
if not match:
|
|
175
|
+
return None
|
|
176
|
+
major, minor, patch, prerelease = match.groups()
|
|
177
|
+
numbers = (int(major), int(minor or "0"), int(patch or "0"))
|
|
178
|
+
prerelease_parts = tuple(prerelease.split(".")) if prerelease else None
|
|
179
|
+
return numbers, prerelease_parts
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _compare_prerelease(
|
|
183
|
+
left: tuple[str, ...] | None,
|
|
184
|
+
right: tuple[str, ...] | None,
|
|
185
|
+
) -> int:
|
|
186
|
+
if left is None and right is None:
|
|
187
|
+
return 0
|
|
188
|
+
if left is None:
|
|
189
|
+
return 1
|
|
190
|
+
if right is None:
|
|
191
|
+
return -1
|
|
192
|
+
|
|
193
|
+
for left_part, right_part in zip(left, right):
|
|
194
|
+
if left_part == right_part:
|
|
195
|
+
continue
|
|
196
|
+
left_numeric = left_part.isdigit()
|
|
197
|
+
right_numeric = right_part.isdigit()
|
|
198
|
+
if left_numeric and right_numeric:
|
|
199
|
+
left_int = int(left_part)
|
|
200
|
+
right_int = int(right_part)
|
|
201
|
+
return (left_int > right_int) - (left_int < right_int)
|
|
202
|
+
if left_numeric:
|
|
203
|
+
return -1
|
|
204
|
+
if right_numeric:
|
|
205
|
+
return 1
|
|
206
|
+
return (left_part > right_part) - (left_part < right_part)
|
|
207
|
+
|
|
208
|
+
return (len(left) > len(right)) - (len(left) < len(right))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _compare_versions(left: str, right: str) -> int | None:
|
|
212
|
+
parsed_left = _parse_version(left)
|
|
213
|
+
parsed_right = _parse_version(right)
|
|
214
|
+
if parsed_left is None or parsed_right is None:
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
left_numbers, left_prerelease = parsed_left
|
|
218
|
+
right_numbers, right_prerelease = parsed_right
|
|
219
|
+
if left_numbers != right_numbers:
|
|
220
|
+
return (left_numbers > right_numbers) - (left_numbers < right_numbers)
|
|
221
|
+
return _compare_prerelease(left_prerelease, right_prerelease)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _update_marker_path(repo_root: Path) -> Path:
|
|
225
|
+
context_key = resolve_context_key()
|
|
226
|
+
if not context_key:
|
|
227
|
+
terminal_key = os.environ.get("TERM_SESSION_ID", "").strip()
|
|
228
|
+
context_key = terminal_key or f"ppid-{os.getppid()}"
|
|
229
|
+
safe_key = re.sub(r"[^A-Za-z0-9._-]+", "_", context_key).strip("._-")
|
|
230
|
+
if not safe_key:
|
|
231
|
+
safe_key = "session"
|
|
232
|
+
return (
|
|
233
|
+
repo_root
|
|
234
|
+
/ DIR_WORKFLOW
|
|
235
|
+
/ ".runtime"
|
|
236
|
+
/ f"update-check-{safe_key[:160]}.marker"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _mark_update_check_attempted(repo_root: Path) -> bool:
|
|
241
|
+
marker_path = _update_marker_path(repo_root)
|
|
242
|
+
if marker_path.exists():
|
|
243
|
+
return False
|
|
244
|
+
try:
|
|
245
|
+
marker_path.parent.mkdir(parents=True, exist_ok=True)
|
|
246
|
+
marker_path.write_text("checked\n", encoding="utf-8")
|
|
247
|
+
except OSError:
|
|
248
|
+
pass
|
|
249
|
+
return True
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _get_update_hint(repo_root: Path) -> str | None:
|
|
253
|
+
marker_path = _update_marker_path(repo_root)
|
|
254
|
+
if marker_path.exists():
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
current_version = _read_project_version(repo_root)
|
|
258
|
+
if not current_version:
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
latest_version = _resolve_available_update_version()
|
|
262
|
+
if not latest_version:
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
_mark_update_check_attempted(repo_root)
|
|
266
|
+
comparison = _compare_versions(current_version, latest_version)
|
|
267
|
+
if comparison is None or comparison >= 0:
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
f"Trellis update available: {current_version} -> {latest_version}, "
|
|
272
|
+
f"run npm install -g {_PACKAGE_NAME}@latest"
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
112
276
|
# =============================================================================
|
|
113
277
|
# JSON Output
|
|
114
278
|
# =============================================================================
|
|
@@ -571,4 +735,10 @@ def output_text(repo_root: Path | None = None) -> None:
|
|
|
571
735
|
Args:
|
|
572
736
|
repo_root: Repository root path. Defaults to auto-detected.
|
|
573
737
|
"""
|
|
738
|
+
if repo_root is None:
|
|
739
|
+
repo_root = get_repo_root()
|
|
740
|
+
update_hint = _get_update_hint(repo_root)
|
|
741
|
+
if update_hint:
|
|
742
|
+
print(update_hint)
|
|
743
|
+
print("")
|
|
574
744
|
print(get_context_text(repo_root))
|
|
@@ -41,6 +41,11 @@ from .paths import (
|
|
|
41
41
|
get_repo_root,
|
|
42
42
|
get_tasks_dir,
|
|
43
43
|
)
|
|
44
|
+
from .safe_commit import (
|
|
45
|
+
print_gitignore_warning,
|
|
46
|
+
safe_archive_paths_to_add,
|
|
47
|
+
safe_git_add,
|
|
48
|
+
)
|
|
44
49
|
from .task_utils import (
|
|
45
50
|
archive_task_complete,
|
|
46
51
|
find_task_by_name,
|
|
@@ -383,13 +388,37 @@ def cmd_archive(args: argparse.Namespace) -> int:
|
|
|
383
388
|
|
|
384
389
|
|
|
385
390
|
def _auto_commit_archive(task_name: str, repo_root: Path) -> None:
|
|
386
|
-
"""Stage
|
|
387
|
-
|
|
388
|
-
|
|
391
|
+
"""Stage Trellis-owned task paths and commit after archive.
|
|
392
|
+
|
|
393
|
+
Only stages specific subpaths (the archive subtree and active task dirs),
|
|
394
|
+
never the whole `.trellis/` tree. If `.gitignore` excludes `.trellis/`,
|
|
395
|
+
falls back to `git add -f <specific>` and emits a warning that explicitly
|
|
396
|
+
forbids `git add -f .trellis/` (which would fan out to caches/backups).
|
|
397
|
+
"""
|
|
398
|
+
paths = safe_archive_paths_to_add(repo_root)
|
|
399
|
+
if not paths:
|
|
400
|
+
print("[OK] No task changes to commit.", file=sys.stderr)
|
|
401
|
+
return
|
|
402
|
+
|
|
403
|
+
success, used_force, err = safe_git_add(paths, repo_root)
|
|
404
|
+
if not success:
|
|
405
|
+
if err and "ignored by" in err.lower():
|
|
406
|
+
print_gitignore_warning(paths)
|
|
407
|
+
else:
|
|
408
|
+
print(
|
|
409
|
+
f"[WARN] git add failed: {err.strip() if err else 'unknown error'}",
|
|
410
|
+
file=sys.stderr,
|
|
411
|
+
)
|
|
412
|
+
return
|
|
413
|
+
|
|
414
|
+
if used_force:
|
|
415
|
+
print(
|
|
416
|
+
"[OK] Staged Trellis-owned paths with -f (specific paths, not .trellis/).",
|
|
417
|
+
file=sys.stderr,
|
|
418
|
+
)
|
|
389
419
|
|
|
390
|
-
# Check if there are staged changes
|
|
391
420
|
rc, _, _ = run_git(
|
|
392
|
-
["diff", "--cached", "--quiet", "--",
|
|
421
|
+
["diff", "--cached", "--quiet", "--", *paths], cwd=repo_root
|
|
393
422
|
)
|
|
394
423
|
if rc == 0:
|
|
395
424
|
print("[OK] No task changes to commit.", file=sys.stderr)
|
|
@@ -38,6 +38,7 @@ export declare function scrubOpencodePackageJson(content: string): ScrubResult;
|
|
|
38
38
|
* Scrub `.pi/settings.json`:
|
|
39
39
|
* - drop `enableSkillCommands` (trellis-flagged)
|
|
40
40
|
* - remove trellis entries from `extensions`/`skills`/`prompts` arrays
|
|
41
|
+
* - remove trellis-managed `packages["npm:pi-subagents"]` isolation override
|
|
41
42
|
* - drop arrays that become empty
|
|
42
43
|
*/
|
|
43
44
|
export declare function scrubPiSettings(content: string): ScrubResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall-scrubbers.d.ts","sourceRoot":"","sources":["../../src/utils/uninstall-scrubbers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB;AAmDD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,IAAI,EAAE,QAAQ,GAAG,MAAM,GACtB,WAAW,CAgGb;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA+BrE;
|
|
1
|
+
{"version":3,"file":"uninstall-scrubbers.d.ts","sourceRoot":"","sources":["../../src/utils/uninstall-scrubbers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB;AAmDD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,IAAI,EAAE,QAAQ,GAAG,MAAM,GACtB,WAAW,CAgGb;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA+BrE;AAiBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA4D5D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAoDjE"}
|