@blxzer/cursor-trellis 0.3.0 → 0.3.2
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/CHANGELOG.md +30 -0
- package/README.md +51 -10
- package/README.zh-CN.md +21 -7
- package/bin/cstl.js +1 -1
- package/bin/smart-search.js +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +17 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/capability-smoke.js +2 -2
- package/dist/commands/capability-smoke.js.map +1 -1
- package/dist/commands/channel/agent-loader.d.ts +1 -1
- package/dist/commands/channel/agent-loader.js +4 -4
- package/dist/commands/channel/agent-loader.js.map +1 -1
- package/dist/commands/channel/guard.d.ts +2 -2
- package/dist/commands/channel/guard.js +3 -3
- package/dist/commands/channel/guard.js.map +1 -1
- package/dist/commands/channel/index.js +3 -3
- package/dist/commands/channel/index.js.map +1 -1
- package/dist/commands/channel/list.d.ts +1 -1
- package/dist/commands/channel/list.js +1 -1
- package/dist/commands/channel/rm.d.ts +1 -1
- package/dist/commands/channel/rm.js +1 -1
- package/dist/commands/channel/store/lock.d.ts +1 -1
- package/dist/commands/channel/store/lock.js +1 -1
- package/dist/commands/channel/store/paths.js +1 -1
- package/dist/commands/channel/store/paths.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +105 -59
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/uninstall.d.ts +3 -3
- package/dist/commands/uninstall.js +10 -10
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts +6 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +83 -28
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/workflow.d.ts +4 -4
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +10 -9
- package/dist/commands/workflow.js.map +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +1 -1
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/shared.js +6 -6
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/workflow.d.ts +4 -4
- package/dist/configurators/workflow.js +1 -1
- package/dist/constants/paths.d.ts +24 -24
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +16 -16
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.3.1.json +32 -0
- package/dist/templates/common/bundled-skills/cstl-cursor2plus-setup/SKILL.md +11 -11
- package/dist/templates/common/bundled-skills/cstl-meta/SKILL.md +15 -15
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/add-project-local-conventions.md +12 -12
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-agents.md +2 -2
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-context-loading.md +21 -21
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-hooks.md +9 -9
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-skills-or-commands.md +7 -7
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-spec-structure.md +15 -15
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-task-lifecycle.md +27 -27
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/change-workflow.md +7 -7
- package/dist/templates/common/bundled-skills/cstl-meta/references/customize-local/overview.md +11 -11
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/context-injection.md +12 -12
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/generated-files.md +21 -21
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/overview.md +14 -14
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/spec-system.md +12 -12
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/task-system.md +23 -23
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/workflow.md +3 -3
- package/dist/templates/common/bundled-skills/cstl-meta/references/local-architecture/workspace-memory.md +16 -16
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/agents.md +2 -2
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/hooks-and-settings.md +6 -6
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/overview.md +5 -5
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/platform-map.md +3 -3
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/skills-and-commands.md +5 -5
- package/dist/templates/common/bundled-skills/cstl-skill-creator/SKILL.md +2 -2
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/review-checklist.md +1 -1
- package/dist/templates/common/bundled-skills/cstl-spec-bootstrap/SKILL.md +5 -5
- package/dist/templates/common/bundled-skills/cstl-spec-bootstrap/references/repository-analysis.md +1 -1
- package/dist/templates/common/bundled-skills/cstl-spec-bootstrap/references/spec-task-planning.md +3 -3
- package/dist/templates/common/bundled-skills/cstl-spec-bootstrap/references/spec-writing.md +1 -1
- package/dist/templates/common/commands/continue.md +6 -6
- package/dist/templates/common/commands/finish-work.md +5 -5
- package/dist/templates/common/commands/start.md +8 -8
- package/dist/templates/common/skills/before-dev.md +4 -4
- package/dist/templates/common/skills/brainstorm.md +5 -5
- package/dist/templates/common/skills/break-loop.md +3 -3
- package/dist/templates/common/skills/check.md +5 -5
- package/dist/templates/common/skills/update-spec.md +4 -4
- package/dist/templates/cursor/agents/cstl-check.md +6 -6
- package/dist/templates/cursor/agents/cstl-implement.md +7 -7
- package/dist/templates/cursor/agents/cstl-research.md +9 -9
- package/dist/templates/cursor/commands/cursor2plus-setup.md +10 -10
- package/dist/templates/cursor/rules/cstl-subagent-dispatch.mdc +2 -2
- package/dist/templates/cursor/rules/cstl-triage.mdc +2 -2
- package/dist/templates/cursor/rules/retrieval-routing.mdc +4 -4
- package/dist/templates/extract.d.ts +1 -1
- package/dist/templates/extract.js +1 -1
- package/dist/templates/markdown/agents.md +11 -11
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +1 -1
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +5 -5
- package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +3 -3
- package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +1 -1
- package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +11 -11
- package/dist/templates/markdown/spec/guides/durable-learning-decision-guide.md.txt +8 -8
- package/dist/templates/markdown/spec/guides/execution-strategy.md.txt +3 -3
- package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +10 -10
- package/dist/templates/markdown/workspace-index.md +3 -3
- package/dist/templates/markdown/worktree.yaml.txt +1 -1
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.js +1 -1
- package/dist/templates/shared-hooks/inject-retrieval-plan.py +3 -3
- package/dist/templates/shared-hooks/inject-shell-session-context.py +7 -7
- package/dist/templates/shared-hooks/inject-subagent-context.py +1 -1
- package/dist/templates/shared-hooks/inject-workflow-state.py +11 -11
- package/dist/templates/shared-hooks/research-end-retrieval-pack.py +1 -1
- package/dist/templates/shared-hooks/session-start.py +13 -13
- package/dist/templates/trellis/config.yaml +2 -22
- package/dist/templates/trellis/index.d.ts +2 -2
- package/dist/templates/trellis/index.js +2 -2
- package/dist/templates/trellis/local/README.md +3 -3
- package/dist/templates/trellis/local/patch_wpelc8.py +4 -4
- package/dist/templates/trellis/scripts/add_session.py +20 -20
- package/dist/templates/trellis/scripts/common/active_task.py +2 -2
- package/dist/templates/trellis/scripts/common/artifact_search.py +587 -587
- package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +6 -6
- package/dist/templates/trellis/scripts/common/config.py +3 -3
- package/dist/templates/trellis/scripts/common/developer.py +2 -2
- package/dist/templates/trellis/scripts/common/packages_context.py +23 -23
- package/dist/templates/trellis/scripts/common/parent_orchestration.py +16 -16
- package/dist/templates/trellis/scripts/common/paths.py +107 -107
- package/dist/templates/trellis/scripts/common/project_file_stats.py +1 -1
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +1 -1
- package/dist/templates/trellis/scripts/common/safe_commit.py +31 -31
- package/dist/templates/trellis/scripts/common/session_memory.py +360 -360
- package/dist/templates/trellis/scripts/common/smart_search_evidence.py +514 -514
- package/dist/templates/trellis/scripts/common/smart_search_resolve.py +1 -1
- package/dist/templates/trellis/scripts/common/subagent_dispatch.py +2 -2
- package/dist/templates/trellis/scripts/common/task_context.py +1 -1
- package/dist/templates/trellis/scripts/common/task_dashboard.py +140 -140
- package/dist/templates/trellis/scripts/common/task_gates.py +23 -23
- package/dist/templates/trellis/scripts/common/task_store.py +5 -5
- package/dist/templates/trellis/scripts/common/task_utils.py +3 -3
- package/dist/templates/trellis/scripts/common/tasks.py +1 -1
- package/dist/templates/trellis/scripts/common/trellis_config.py +3 -3
- package/dist/templates/trellis/scripts/common/workflow_phase.py +1 -1
- package/dist/templates/trellis/scripts/cursor_retrieval_probe.py +3 -3
- package/dist/templates/trellis/scripts/cursor_retrieval_probe_prompt.md +11 -11
- package/dist/templates/trellis/scripts/hooks/linear_sync.py +8 -8
- package/dist/templates/trellis/scripts/init_developer.py +2 -2
- package/dist/templates/trellis/scripts/retrieval_probe_matrix_template.json +4 -4
- package/dist/templates/trellis/scripts/route_codebase_retrieval.py +1 -1
- package/dist/templates/trellis/scripts/task.py +918 -918
- package/dist/templates/trellis/tasks/templates/release-readiness/implement.md +2 -2
- package/dist/templates/trellis/workflow.md +64 -64
- package/dist/types/migration.d.ts +1 -1
- package/dist/types/migration.d.ts.map +1 -1
- package/dist/utils/agents-md.d.ts +37 -0
- package/dist/utils/agents-md.d.ts.map +1 -0
- package/dist/utils/agents-md.js +82 -0
- package/dist/utils/agents-md.js.map +1 -0
- package/dist/utils/codebase-retrieval-router.js +5 -5
- package/dist/utils/codebase-retrieval-router.js.map +1 -1
- package/dist/utils/manifest-prune.d.ts +2 -2
- package/dist/utils/manifest-prune.js +4 -4
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/mirror-check.d.ts +3 -1
- package/dist/utils/mirror-check.d.ts.map +1 -1
- package/dist/utils/mirror-check.js +22 -11
- package/dist/utils/mirror-check.js.map +1 -1
- package/dist/utils/project-capabilities.js +5 -5
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/retrieval-agent-instructions.js +1 -1
- package/dist/utils/retrieval-agent-instructions.js.map +1 -1
- package/dist/utils/retrieval-execution-telemetry.js +1 -1
- package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
- package/dist/utils/template-fetcher.js +1 -1
- package/dist/utils/template-fetcher.js.map +1 -1
- package/dist/utils/template-hash.d.ts +2 -2
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +12 -10
- package/dist/utils/template-hash.js.map +1 -1
- package/dist/utils/workflow-dir.d.ts +13 -0
- package/dist/utils/workflow-dir.d.ts.map +1 -0
- package/dist/utils/workflow-dir.js +35 -0
- package/dist/utils/workflow-dir.js.map +1 -0
- package/dist/utils/workflow-ownership.d.ts +36 -0
- package/dist/utils/workflow-ownership.d.ts.map +1 -0
- package/dist/utils/workflow-ownership.js +137 -0
- package/dist/utils/workflow-ownership.js.map +1 -0
- package/dist/utils/workflow-resolver.d.ts +1 -1
- package/dist/utils/workflow-resolver.js +1 -1
- package/package.json +2 -2
|
@@ -350,7 +350,7 @@ def _verification_for_intents(intents: list[dict[str, object]]) -> list[dict[str
|
|
|
350
350
|
"id": "policy-doc-top1",
|
|
351
351
|
"requirement": (
|
|
352
352
|
"For policy/document intents, confirm Top-1 policy evidence from "
|
|
353
|
-
"AGENTS.md or .
|
|
353
|
+
"AGENTS.md or .cstl/spec before ranking implementation modules first."
|
|
354
354
|
),
|
|
355
355
|
"appliesToRoles": ["exact", "semantic"],
|
|
356
356
|
},
|
|
@@ -561,7 +561,7 @@ def _ordered_routes(
|
|
|
561
561
|
"sourceFamily": "policy-docs",
|
|
562
562
|
"commands": [
|
|
563
563
|
'rg -i "storage default|sidecar|sqlite only" AGENTS.md "**/AGENTS.md" '
|
|
564
|
-
"README.md CONTRIBUTING.md .
|
|
564
|
+
"README.md CONTRIBUTING.md .cstl/spec"
|
|
565
565
|
],
|
|
566
566
|
"rationale": "Policy/document intent: search instruction and spec docs first.",
|
|
567
567
|
})
|
|
@@ -589,7 +589,7 @@ def _ordered_routes(
|
|
|
589
589
|
"sourceFamily": "policy-docs",
|
|
590
590
|
"commands": [
|
|
591
591
|
'rg -i "storage default|sidecar|sqlite only" AGENTS.md "**/AGENTS.md" '
|
|
592
|
-
"README.md CONTRIBUTING.md .
|
|
592
|
+
"README.md CONTRIBUTING.md .cstl/spec"
|
|
593
593
|
],
|
|
594
594
|
"rationale": "Policy/document intent: search instruction and spec docs first.",
|
|
595
595
|
})
|
|
@@ -615,7 +615,7 @@ def _ordered_routes(
|
|
|
615
615
|
"sourceFamily": "policy-docs",
|
|
616
616
|
"commands": [
|
|
617
617
|
'rg -i "storage default|sidecar|sqlite only" AGENTS.md "**/AGENTS.md" '
|
|
618
|
-
"README.md CONTRIBUTING.md .
|
|
618
|
+
"README.md CONTRIBUTING.md .cstl/spec"
|
|
619
619
|
],
|
|
620
620
|
"rationale": "Policy/document branch after exact-primary when both intents match.",
|
|
621
621
|
})
|
|
@@ -733,7 +733,7 @@ def _fallback_hints(
|
|
|
733
733
|
if any(str(item["id"]) == INTENT_POLICY for item in intents):
|
|
734
734
|
hints.append({
|
|
735
735
|
"when": "semantic Top-1 is implementation-only for policy query",
|
|
736
|
-
"action": "Fall back to policy-doc rg and AGENTS.md/.
|
|
736
|
+
"action": "Fall back to policy-doc rg and AGENTS.md/.cstl/spec reads.",
|
|
737
737
|
"replacesRole": "semantic",
|
|
738
738
|
})
|
|
739
739
|
semantic_route = next(
|
|
@@ -861,7 +861,7 @@ def codebase_retrieval_selected_from_capabilities(
|
|
|
861
861
|
def load_capabilities_json(repo_root: Path | None) -> dict[str, Any] | None:
|
|
862
862
|
if repo_root is None:
|
|
863
863
|
return None
|
|
864
|
-
path = repo_root / ".
|
|
864
|
+
path = repo_root / ".cstl" / "capabilities.json"
|
|
865
865
|
if not path.is_file():
|
|
866
866
|
return None
|
|
867
867
|
try:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Trellis configuration reader.
|
|
4
4
|
|
|
5
|
-
Reads settings from .
|
|
5
|
+
Reads settings from .cstl/config.yaml with sensible defaults.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
@@ -219,7 +219,7 @@ def get_session_auto_commit(repo_root: Path | None = None) -> bool:
|
|
|
219
219
|
``task_store.py:_auto_commit_archive``.
|
|
220
220
|
|
|
221
221
|
Default: ``True`` (existing behavior — auto-stage + auto-commit).
|
|
222
|
-
Set ``session_auto_commit: false`` in ``.
|
|
222
|
+
Set ``session_auto_commit: false`` in ``.cstl/config.yaml`` to skip
|
|
223
223
|
auto-staging entirely; the journal/archive files are still written to
|
|
224
224
|
disk, but the user manages ``git add`` / ``git commit`` themselves.
|
|
225
225
|
|
|
@@ -370,7 +370,7 @@ def is_monorepo(repo_root: Path | None = None) -> bool:
|
|
|
370
370
|
|
|
371
371
|
|
|
372
372
|
def get_spec_base(package: str | None = None, repo_root: Path | None = None) -> str:
|
|
373
|
-
"""Get the spec directory base path relative to .
|
|
373
|
+
"""Get the spec directory base path relative to .cstl/.
|
|
374
374
|
|
|
375
375
|
Single-repo: returns "spec"
|
|
376
376
|
Monorepo with package: returns "spec/<package>"
|
|
@@ -34,8 +34,8 @@ def init_developer(name: str, repo_root: Path | None = None) -> bool:
|
|
|
34
34
|
"""Initialize developer.
|
|
35
35
|
|
|
36
36
|
Creates:
|
|
37
|
-
- .
|
|
38
|
-
- .
|
|
37
|
+
- .cstl/.developer file with developer info
|
|
38
|
+
- .cstl/workspace/<name>/ directory structure
|
|
39
39
|
- Initial journal file and index.md
|
|
40
40
|
|
|
41
41
|
Args:
|
|
@@ -14,12 +14,12 @@ from __future__ import annotations
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
from .config import _is_true_config_value, get_default_package, get_packages, get_spec_scope
|
|
17
|
-
from .paths import (
|
|
18
|
-
DIR_SPEC,
|
|
19
|
-
DIR_WORKFLOW,
|
|
20
|
-
get_selected_task,
|
|
21
|
-
get_repo_root,
|
|
22
|
-
)
|
|
17
|
+
from .paths import (
|
|
18
|
+
DIR_SPEC,
|
|
19
|
+
DIR_WORKFLOW,
|
|
20
|
+
get_selected_task,
|
|
21
|
+
get_repo_root,
|
|
22
|
+
)
|
|
23
23
|
from .tasks import load_task
|
|
24
24
|
|
|
25
25
|
|
|
@@ -41,13 +41,13 @@ def _scan_spec_layers(spec_dir: Path, package: str | None = None) -> list[str]:
|
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def _get_selected_task_package(repo_root: Path) -> str | None:
|
|
45
|
-
"""Get the package field from the selected task's task.json."""
|
|
46
|
-
selected = get_selected_task(repo_root)
|
|
47
|
-
if not selected:
|
|
48
|
-
return None
|
|
49
|
-
ct = load_task(repo_root / selected)
|
|
50
|
-
return ct.package if ct and ct.package else None
|
|
44
|
+
def _get_selected_task_package(repo_root: Path) -> str | None:
|
|
45
|
+
"""Get the package field from the selected task's task.json."""
|
|
46
|
+
selected = get_selected_task(repo_root)
|
|
47
|
+
if not selected:
|
|
48
|
+
return None
|
|
49
|
+
ct = load_task(repo_root / selected)
|
|
50
|
+
return ct.package if ct and ct.package else None
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def _resolve_scope_set(
|
|
@@ -175,7 +175,7 @@ def get_context_packages_text(repo_root: Path | None = None) -> str:
|
|
|
175
175
|
packages_dict = get_packages(repo_root) or {}
|
|
176
176
|
default_pkg = get_default_package(repo_root)
|
|
177
177
|
spec_scope = get_spec_scope(repo_root)
|
|
178
|
-
task_pkg = _get_selected_task_package(repo_root)
|
|
178
|
+
task_pkg = _get_selected_task_package(repo_root)
|
|
179
179
|
scope_set = _resolve_scope_set(packages_dict, spec_scope, task_pkg, default_pkg)
|
|
180
180
|
|
|
181
181
|
lines.append("## PACKAGES")
|
|
@@ -195,7 +195,7 @@ def get_context_packages_text(repo_root: Path | None = None) -> str:
|
|
|
195
195
|
if pkg["specLayers"]:
|
|
196
196
|
lines.append(f"Spec layers: {', '.join(pkg['specLayers'])}")
|
|
197
197
|
for layer in pkg["specLayers"]:
|
|
198
|
-
lines.append(f" - .
|
|
198
|
+
lines.append(f" - .cstl/spec/{pkg['name']}/{layer}/index.md")
|
|
199
199
|
else:
|
|
200
200
|
lines.append("Spec: not configured")
|
|
201
201
|
lines.append("")
|
|
@@ -204,7 +204,7 @@ def get_context_packages_text(repo_root: Path | None = None) -> str:
|
|
|
204
204
|
guides_dir = repo_root / DIR_WORKFLOW / DIR_SPEC / "guides"
|
|
205
205
|
if guides_dir.is_dir():
|
|
206
206
|
lines.append("### Shared Guides (always included)")
|
|
207
|
-
lines.append("Path: .
|
|
207
|
+
lines.append("Path: .cstl/spec/guides/index.md")
|
|
208
208
|
lines.append("")
|
|
209
209
|
|
|
210
210
|
return "\n".join(lines)
|
|
@@ -230,10 +230,10 @@ def get_context_packages_json(repo_root: Path | None = None) -> dict:
|
|
|
230
230
|
task_pkg = _get_active_task_package(repo_root)
|
|
231
231
|
|
|
232
232
|
return {
|
|
233
|
-
"mode": "monorepo",
|
|
234
|
-
"packages": pkg_info,
|
|
235
|
-
"defaultPackage": default_pkg,
|
|
236
|
-
"specScope": spec_scope,
|
|
237
|
-
"activeTaskPackage": task_pkg,
|
|
238
|
-
"selectedTaskPackage": task_pkg,
|
|
239
|
-
}
|
|
233
|
+
"mode": "monorepo",
|
|
234
|
+
"packages": pkg_info,
|
|
235
|
+
"defaultPackage": default_pkg,
|
|
236
|
+
"specScope": spec_scope,
|
|
237
|
+
"activeTaskPackage": task_pkg,
|
|
238
|
+
"selectedTaskPackage": task_pkg,
|
|
239
|
+
}
|
|
@@ -41,14 +41,14 @@ Validation baseline:
|
|
|
41
41
|
- Run typecheck when touching TypeScript.
|
|
42
42
|
- Run ESLint for changed TypeScript test/source files when applicable.
|
|
43
43
|
- Run Python compile checks when touching Python scripts/templates.
|
|
44
|
-
- Run `python ./.
|
|
44
|
+
- Run `python ./.cstl/scripts/task.py validate <your-child-task>` before handoff."""
|
|
45
45
|
|
|
46
46
|
_VALIDATION_BASELINE = """Validation baseline:
|
|
47
47
|
- Run focused tests for touched behavior.
|
|
48
48
|
- Run typecheck when touching TypeScript.
|
|
49
49
|
- Run ESLint for changed TypeScript test/source files when applicable.
|
|
50
50
|
- Run Python compile checks when touching Python scripts/templates.
|
|
51
|
-
- Run `python ./.
|
|
51
|
+
- Run `python ./.cstl/scripts/task.py validate <child-dir>` before handoff."""
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def _utc_now() -> str:
|
|
@@ -141,13 +141,13 @@ def _child_prompt_section(
|
|
|
141
141
|
lines.append("### Suggested child worker commands")
|
|
142
142
|
lines.append("")
|
|
143
143
|
lines.append("```bash")
|
|
144
|
-
lines.append(f"python ./.
|
|
144
|
+
lines.append(f"python ./.cstl/scripts/task.py select {child_rel}")
|
|
145
145
|
lines.append(
|
|
146
|
-
f"python ./.
|
|
146
|
+
f"python ./.cstl/scripts/task.py set-child-state {parent_rel} {child_rel} working --evidence implement.md"
|
|
147
147
|
)
|
|
148
148
|
lines.append("# ... implement ...")
|
|
149
149
|
lines.append(
|
|
150
|
-
f"python ./.
|
|
150
|
+
f"python ./.cstl/scripts/task.py set-child-state {parent_rel} {child_rel} review --evidence verify.md"
|
|
151
151
|
)
|
|
152
152
|
lines.append("```")
|
|
153
153
|
lines.append("")
|
|
@@ -266,7 +266,7 @@ def build_child_prompt(
|
|
|
266
266
|
f"Selected task: {child_rel}",
|
|
267
267
|
"",
|
|
268
268
|
"Delivery mode: subagent (Cursor)",
|
|
269
|
-
"- **Default:** Parent session dispatches **Task** with `subagent_type=cstl-implement` and this prompt as the task description (writable sub-agent). Model under Cursor++ BYOK comes from `.
|
|
269
|
+
"- **Default:** Parent session dispatches **Task** with `subagent_type=cstl-implement` and this prompt as the task description (writable sub-agent). Model under Cursor++ BYOK comes from `.cstl/local/cursor2plus/` routing (see `cursor-subagent-policy.md` Method 2.5/2.6).",
|
|
270
270
|
"- **Exception:** If parent `child-prompts.md` or the user names this child for a **separate writable Agent chat**, open a new Agent session, pick the model manually, paste this prompt — do not use Task from Parent.",
|
|
271
271
|
"- Parent retains `review-child` / `integrate-child`. Child must not nest further `cstl-research` / `cstl-implement` / `cstl-check` Task dispatches.",
|
|
272
272
|
f"- Parent orchestration: `execution_topology={topo}`, `merge_limit={merge_lim}`.",
|
|
@@ -353,11 +353,11 @@ def build_parent_status(parent_dir: Path) -> str:
|
|
|
353
353
|
lines.append("## Suggested parent commands")
|
|
354
354
|
lines.append("")
|
|
355
355
|
lines.append("```bash")
|
|
356
|
-
lines.append(f"python ./.
|
|
357
|
-
lines.append(f"python ./.
|
|
358
|
-
lines.append(f"python ./.
|
|
359
|
-
lines.append(f"python ./.
|
|
360
|
-
lines.append(f"python ./.
|
|
356
|
+
lines.append(f"python ./.cstl/scripts/task.py parent-status {parent_rel}")
|
|
357
|
+
lines.append(f"python ./.cstl/scripts/task.py generate-child-prompt {parent_rel} <child> --mode subagent")
|
|
358
|
+
lines.append(f"python ./.cstl/scripts/task.py generate-child-prompt {parent_rel} <child> --mode inline")
|
|
359
|
+
lines.append(f"python ./.cstl/scripts/task.py review-child {parent_rel} <child> --check")
|
|
360
|
+
lines.append(f"python ./.cstl/scripts/task.py review-child {parent_rel} <child> --decision accept --ref <ref>")
|
|
361
361
|
lines.append("```")
|
|
362
362
|
return "\n".join(lines)
|
|
363
363
|
|
|
@@ -421,10 +421,10 @@ def _learning_decision_review_lines(
|
|
|
421
421
|
"Child verify.md has no grep-friendly durable-learning line yet. Pick one outcome:",
|
|
422
422
|
"",
|
|
423
423
|
"- `Durable learning decision: no durable learning` — routine scope, no reusable contract.",
|
|
424
|
-
"- `Spec update evidence: .
|
|
424
|
+
"- `Spec update evidence: .cstl/spec/<path>` — after `/cstl:update-spec` with reviewer confirmation.",
|
|
425
425
|
f"- `Learning artifact: {child_rel}/handoff.md` — handoff already captures the insight.",
|
|
426
426
|
"",
|
|
427
|
-
f"Helper: `python ./.
|
|
427
|
+
f"Helper: `python ./.cstl/scripts/task.py prepare-archive-evidence {child_rel}`",
|
|
428
428
|
"",
|
|
429
429
|
]
|
|
430
430
|
|
|
@@ -524,7 +524,7 @@ def build_review_report(
|
|
|
524
524
|
"transition": "parent-accepted",
|
|
525
525
|
"optional": True,
|
|
526
526
|
"hint": (
|
|
527
|
-
f"Optional audit: python ./.
|
|
527
|
+
f"Optional audit: python ./.cstl/scripts/task.py record-gate {parent_dir.name} "
|
|
528
528
|
f"--transition parent-accepted --gate code-review --result PASS "
|
|
529
529
|
f"--reviewer parent --evidence review-{child_name}.md"
|
|
530
530
|
),
|
|
@@ -538,7 +538,7 @@ def build_review_report(
|
|
|
538
538
|
"transition": "child-review",
|
|
539
539
|
"optional": False,
|
|
540
540
|
"hint": (
|
|
541
|
-
f"Required before accept: python ./.
|
|
541
|
+
f"Required before accept: python ./.cstl/scripts/task.py record-gate {child_name} "
|
|
542
542
|
f"--transition child-review --gate code-review --result PASS "
|
|
543
543
|
f"--reviewer parent --evidence verify.md"
|
|
544
544
|
),
|
|
@@ -640,7 +640,7 @@ def build_review_report(
|
|
|
640
640
|
"transition": "parent-integrated",
|
|
641
641
|
"optional": False,
|
|
642
642
|
"hint": (
|
|
643
|
-
f"Required before parent archive: python ./.
|
|
643
|
+
f"Required before parent archive: python ./.cstl/scripts/task.py record-gate {parent_dir.name} "
|
|
644
644
|
f"--transition parent-integrated --gate integration-review --result PASS "
|
|
645
645
|
f"--reviewer parent --evidence task-map.md"
|
|
646
646
|
),
|
|
@@ -22,7 +22,7 @@ from pathlib import Path
|
|
|
22
22
|
# =============================================================================
|
|
23
23
|
|
|
24
24
|
# Directory names
|
|
25
|
-
DIR_WORKFLOW = ".
|
|
25
|
+
DIR_WORKFLOW = ".cstl"
|
|
26
26
|
DIR_WORKSPACE = "workspace"
|
|
27
27
|
DIR_TASKS = "tasks"
|
|
28
28
|
DIR_ARCHIVE = "archive"
|
|
@@ -41,7 +41,7 @@ FILE_JOURNAL_PREFIX = "journal-"
|
|
|
41
41
|
# =============================================================================
|
|
42
42
|
|
|
43
43
|
def get_repo_root(start_path: Path | None = None) -> Path:
|
|
44
|
-
"""Find the nearest directory containing .
|
|
44
|
+
"""Find the nearest directory containing .cstl/ folder.
|
|
45
45
|
|
|
46
46
|
This handles nested git repos correctly (e.g., test project inside another repo).
|
|
47
47
|
|
|
@@ -49,7 +49,7 @@ def get_repo_root(start_path: Path | None = None) -> Path:
|
|
|
49
49
|
start_path: Starting directory to search from. Defaults to current directory.
|
|
50
50
|
|
|
51
51
|
Returns:
|
|
52
|
-
Path to repository root, or current directory if no .
|
|
52
|
+
Path to repository root, or current directory if no .cstl/ found.
|
|
53
53
|
"""
|
|
54
54
|
current = (start_path or Path.cwd()).resolve()
|
|
55
55
|
|
|
@@ -58,7 +58,7 @@ def get_repo_root(start_path: Path | None = None) -> Path:
|
|
|
58
58
|
return current
|
|
59
59
|
current = current.parent
|
|
60
60
|
|
|
61
|
-
# Fallback to current directory if no .
|
|
61
|
+
# Fallback to current directory if no .cstl/ found
|
|
62
62
|
return Path.cwd().resolve()
|
|
63
63
|
|
|
64
64
|
|
|
@@ -204,14 +204,14 @@ def count_lines(file_path: Path) -> int:
|
|
|
204
204
|
|
|
205
205
|
|
|
206
206
|
# =============================================================================
|
|
207
|
-
# Selected Task Management
|
|
207
|
+
# Selected Task Management
|
|
208
208
|
# =============================================================================
|
|
209
209
|
|
|
210
|
-
def normalize_task_ref(task_ref: str) -> str:
|
|
210
|
+
def normalize_task_ref(task_ref: str) -> str:
|
|
211
211
|
"""Normalize a task ref for stable runtime storage.
|
|
212
212
|
|
|
213
213
|
Stored refs should prefer repo-relative POSIX paths like
|
|
214
|
-
`.
|
|
214
|
+
`.cstl/tasks/03-27-my-task`, even on Windows. Absolute paths are preserved
|
|
215
215
|
unless they can later be converted back to repo-relative form by callers.
|
|
216
216
|
"""
|
|
217
217
|
normalized = task_ref.strip()
|
|
@@ -251,70 +251,70 @@ def resolve_task_ref(task_ref: str, repo_root: Path | None = None) -> Path | Non
|
|
|
251
251
|
return repo_root / DIR_WORKFLOW / DIR_TASKS / path_obj
|
|
252
252
|
|
|
253
253
|
|
|
254
|
-
def get_selected_task(
|
|
255
|
-
repo_root: Path | None = None,
|
|
256
|
-
platform_input: dict | None = None,
|
|
257
|
-
platform: str | None = None,
|
|
258
|
-
) -> str | None:
|
|
259
|
-
"""Get selected task directory path (relative to repo_root).
|
|
260
|
-
|
|
261
|
-
Args:
|
|
262
|
-
repo_root: Repository root path. Defaults to auto-detected.
|
|
263
|
-
|
|
264
|
-
Returns:
|
|
265
|
-
Relative path to selected task directory or None.
|
|
266
|
-
"""
|
|
267
|
-
if repo_root is None:
|
|
268
|
-
repo_root = get_repo_root()
|
|
269
|
-
|
|
270
|
-
from .active_task import resolve_selected_task
|
|
271
|
-
|
|
272
|
-
return resolve_selected_task(repo_root, platform_input, platform).task_path
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
def get_selected_task_abs(
|
|
276
|
-
repo_root: Path | None = None,
|
|
277
|
-
platform_input: dict | None = None,
|
|
278
|
-
platform: str | None = None,
|
|
279
|
-
) -> Path | None:
|
|
280
|
-
"""Get selected task directory absolute path.
|
|
281
|
-
|
|
282
|
-
Args:
|
|
283
|
-
repo_root: Repository root path. Defaults to auto-detected.
|
|
284
|
-
|
|
285
|
-
Returns:
|
|
286
|
-
Absolute path to selected task directory or None.
|
|
287
|
-
"""
|
|
288
|
-
if repo_root is None:
|
|
289
|
-
repo_root = get_repo_root()
|
|
290
|
-
|
|
291
|
-
relative = get_selected_task(repo_root, platform_input, platform)
|
|
292
|
-
if relative:
|
|
293
|
-
return resolve_task_ref(relative, repo_root)
|
|
294
|
-
return None
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
def get_selected_task_source(
|
|
298
|
-
repo_root: Path | None = None,
|
|
299
|
-
platform_input: dict | None = None,
|
|
300
|
-
platform: str | None = None,
|
|
301
|
-
) -> tuple[str, str | None, str | None]:
|
|
302
|
-
"""Get selected task source as (`source`, `context_key`, `task_path`)."""
|
|
303
|
-
if repo_root is None:
|
|
304
|
-
repo_root = get_repo_root()
|
|
305
|
-
|
|
306
|
-
from .active_task import get_selected_task_source as _get_source
|
|
307
|
-
|
|
308
|
-
return _get_source(repo_root, platform_input, platform)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def set_selected_task(
|
|
312
|
-
task_path: str,
|
|
313
|
-
repo_root: Path | None = None,
|
|
314
|
-
platform_input: dict | None = None,
|
|
315
|
-
platform: str | None = None,
|
|
316
|
-
) -> bool:
|
|
317
|
-
"""Set selected task in session scope.
|
|
254
|
+
def get_selected_task(
|
|
255
|
+
repo_root: Path | None = None,
|
|
256
|
+
platform_input: dict | None = None,
|
|
257
|
+
platform: str | None = None,
|
|
258
|
+
) -> str | None:
|
|
259
|
+
"""Get selected task directory path (relative to repo_root).
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
repo_root: Repository root path. Defaults to auto-detected.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Relative path to selected task directory or None.
|
|
266
|
+
"""
|
|
267
|
+
if repo_root is None:
|
|
268
|
+
repo_root = get_repo_root()
|
|
269
|
+
|
|
270
|
+
from .active_task import resolve_selected_task
|
|
271
|
+
|
|
272
|
+
return resolve_selected_task(repo_root, platform_input, platform).task_path
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_selected_task_abs(
|
|
276
|
+
repo_root: Path | None = None,
|
|
277
|
+
platform_input: dict | None = None,
|
|
278
|
+
platform: str | None = None,
|
|
279
|
+
) -> Path | None:
|
|
280
|
+
"""Get selected task directory absolute path.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
repo_root: Repository root path. Defaults to auto-detected.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Absolute path to selected task directory or None.
|
|
287
|
+
"""
|
|
288
|
+
if repo_root is None:
|
|
289
|
+
repo_root = get_repo_root()
|
|
290
|
+
|
|
291
|
+
relative = get_selected_task(repo_root, platform_input, platform)
|
|
292
|
+
if relative:
|
|
293
|
+
return resolve_task_ref(relative, repo_root)
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_selected_task_source(
|
|
298
|
+
repo_root: Path | None = None,
|
|
299
|
+
platform_input: dict | None = None,
|
|
300
|
+
platform: str | None = None,
|
|
301
|
+
) -> tuple[str, str | None, str | None]:
|
|
302
|
+
"""Get selected task source as (`source`, `context_key`, `task_path`)."""
|
|
303
|
+
if repo_root is None:
|
|
304
|
+
repo_root = get_repo_root()
|
|
305
|
+
|
|
306
|
+
from .active_task import get_selected_task_source as _get_source
|
|
307
|
+
|
|
308
|
+
return _get_source(repo_root, platform_input, platform)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def set_selected_task(
|
|
312
|
+
task_path: str,
|
|
313
|
+
repo_root: Path | None = None,
|
|
314
|
+
platform_input: dict | None = None,
|
|
315
|
+
platform: str | None = None,
|
|
316
|
+
) -> bool:
|
|
317
|
+
"""Set selected task in session scope.
|
|
318
318
|
|
|
319
319
|
Args:
|
|
320
320
|
task_path: Task directory path (relative to repo_root).
|
|
@@ -326,22 +326,22 @@ def set_selected_task(
|
|
|
326
326
|
if repo_root is None:
|
|
327
327
|
repo_root = get_repo_root()
|
|
328
328
|
|
|
329
|
-
from .active_task import set_selected_task as _set_selected_task
|
|
330
|
-
|
|
331
|
-
return _set_selected_task(
|
|
332
|
-
task_path,
|
|
333
|
-
repo_root,
|
|
334
|
-
platform_input=platform_input,
|
|
329
|
+
from .active_task import set_selected_task as _set_selected_task
|
|
330
|
+
|
|
331
|
+
return _set_selected_task(
|
|
332
|
+
task_path,
|
|
333
|
+
repo_root,
|
|
334
|
+
platform_input=platform_input,
|
|
335
335
|
platform=platform,
|
|
336
336
|
) is not None
|
|
337
337
|
|
|
338
338
|
|
|
339
|
-
def clear_selected_task(
|
|
340
|
-
repo_root: Path | None = None,
|
|
341
|
-
platform_input: dict | None = None,
|
|
342
|
-
platform: str | None = None,
|
|
343
|
-
) -> bool:
|
|
344
|
-
"""Clear selected task in session scope.
|
|
339
|
+
def clear_selected_task(
|
|
340
|
+
repo_root: Path | None = None,
|
|
341
|
+
platform_input: dict | None = None,
|
|
342
|
+
platform: str | None = None,
|
|
343
|
+
) -> bool:
|
|
344
|
+
"""Clear selected task in session scope.
|
|
345
345
|
|
|
346
346
|
Args:
|
|
347
347
|
repo_root: Repository root path. Defaults to auto-detected.
|
|
@@ -352,36 +352,36 @@ def clear_selected_task(
|
|
|
352
352
|
if repo_root is None:
|
|
353
353
|
repo_root = get_repo_root()
|
|
354
354
|
|
|
355
|
-
from .active_task import clear_selected_task as _clear_selected_task
|
|
356
|
-
|
|
357
|
-
_clear_selected_task(
|
|
358
|
-
repo_root,
|
|
359
|
-
platform_input=platform_input,
|
|
360
|
-
platform=platform,
|
|
355
|
+
from .active_task import clear_selected_task as _clear_selected_task
|
|
356
|
+
|
|
357
|
+
_clear_selected_task(
|
|
358
|
+
repo_root,
|
|
359
|
+
platform_input=platform_input,
|
|
360
|
+
platform=platform,
|
|
361
361
|
)
|
|
362
362
|
return True
|
|
363
363
|
|
|
364
364
|
|
|
365
|
-
def has_selected_task(repo_root: Path | None = None) -> bool:
|
|
366
|
-
"""Check if a selected task exists.
|
|
365
|
+
def has_selected_task(repo_root: Path | None = None) -> bool:
|
|
366
|
+
"""Check if a selected task exists.
|
|
367
367
|
|
|
368
368
|
Args:
|
|
369
369
|
repo_root: Repository root path. Defaults to auto-detected.
|
|
370
370
|
|
|
371
371
|
Returns:
|
|
372
|
-
True if selected task is set.
|
|
373
|
-
"""
|
|
374
|
-
return get_selected_task(repo_root) is not None
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
# Internal compatibility aliases. New user-facing code should use selected-task
|
|
378
|
-
# names; existing internal helpers can migrate incrementally.
|
|
379
|
-
get_current_task = get_selected_task
|
|
380
|
-
get_current_task_abs = get_selected_task_abs
|
|
381
|
-
get_current_task_source = get_selected_task_source
|
|
382
|
-
set_current_task = set_selected_task
|
|
383
|
-
clear_current_task = clear_selected_task
|
|
384
|
-
has_current_task = has_selected_task
|
|
372
|
+
True if selected task is set.
|
|
373
|
+
"""
|
|
374
|
+
return get_selected_task(repo_root) is not None
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
# Internal compatibility aliases. New user-facing code should use selected-task
|
|
378
|
+
# names; existing internal helpers can migrate incrementally.
|
|
379
|
+
get_current_task = get_selected_task
|
|
380
|
+
get_current_task_abs = get_selected_task_abs
|
|
381
|
+
get_current_task_source = get_selected_task_source
|
|
382
|
+
set_current_task = set_selected_task
|
|
383
|
+
clear_current_task = clear_selected_task
|
|
384
|
+
has_current_task = has_selected_task
|
|
385
385
|
|
|
386
386
|
|
|
387
387
|
# =============================================================================
|
|
@@ -405,8 +405,8 @@ def generate_task_date_prefix() -> str:
|
|
|
405
405
|
def get_spec_dir(package: str | None = None, repo_root: Path | None = None) -> Path:
|
|
406
406
|
"""Get the spec directory path.
|
|
407
407
|
|
|
408
|
-
Single-repo: .
|
|
409
|
-
Monorepo with package: .
|
|
408
|
+
Single-repo: .cstl/spec
|
|
409
|
+
Monorepo with package: .cstl/spec/<package>
|
|
410
410
|
|
|
411
411
|
Uses lazy import to avoid circular dependency with config.py.
|
|
412
412
|
"""
|
|
@@ -454,4 +454,4 @@ if __name__ == "__main__":
|
|
|
454
454
|
print(f"Tasks dir: {get_tasks_dir(repo)}")
|
|
455
455
|
print(f"Workspace dir: {get_workspace_dir(repo)}")
|
|
456
456
|
print(f"Journal file: {get_active_journal_file(repo)}")
|
|
457
|
-
print(f"Selected task: {get_selected_task(repo)}")
|
|
457
|
+
print(f"Selected task: {get_selected_task(repo)}")
|
|
@@ -181,7 +181,7 @@ def _cursor_step_for_route(
|
|
|
181
181
|
|
|
182
182
|
if route_id == "policy-docs-rg" or str(route.get("sourceFamily")) == "policy-docs":
|
|
183
183
|
return (
|
|
184
|
-
"使用 **Grep** 在 `AGENTS.md`、`**/AGENTS.md`、`.
|
|
184
|
+
"使用 **Grep** 在 `AGENTS.md`、`**/AGENTS.md`、`.cstl/spec`、`README.md` "
|
|
185
185
|
"中搜索策略/边界关键词。"
|
|
186
186
|
)
|
|
187
187
|
|