@blxzer/cursor-trellis 0.4.1 → 0.4.3
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 +49 -0
- package/README.md +25 -14
- package/README.zh-CN.md +14 -10
- package/bin/smart-search.js +10 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +36 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +42 -153
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +10 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +38 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +144 -41
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/cursor.d.ts +2 -1
- package/dist/configurators/cursor.d.ts.map +1 -1
- package/dist/configurators/cursor.js +4 -2
- package/dist/configurators/cursor.js.map +1 -1
- package/dist/configurators/index.js +4 -4
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/shared.d.ts +8 -0
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +27 -1
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/workflow.d.ts +0 -9
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +12 -45
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +13 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +17 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.3.0.json +1 -1
- package/dist/templates/common/bundled-skills/cstl-check/SKILL.md +1 -1
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/hooks-and-settings.md +2 -2
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/overview.md +1 -1
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/skills-and-commands.md +2 -4
- package/dist/templates/common/bundled-skills/cstl-skill-creator/SKILL.md +10 -7
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/authoring-rules.md +93 -19
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/general-authoring.md +189 -0
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/review-checklist.md +10 -5
- package/dist/templates/common/commands/continue.md +6 -5
- package/dist/templates/common/index.d.ts +20 -0
- package/dist/templates/common/index.d.ts.map +1 -1
- package/dist/templates/common/index.js +21 -2
- package/dist/templates/common/index.js.map +1 -1
- package/dist/templates/common/optional-skills/chrome-cdp/SKILL.md +179 -0
- package/dist/templates/common/optional-skills/chrome-cdp/examples/fetch-hook-api-capture.md +149 -0
- package/dist/templates/common/optional-skills/chrome-cdp/scripts/cdp.mjs +903 -0
- package/dist/templates/common/skills/brainstorm.md +2 -2
- package/dist/templates/cursor/agents/cstl-check.md +2 -2
- package/dist/templates/cursor/agents/cstl-implement.md +1 -1
- package/dist/templates/cursor/agents/cstl-research.md +2 -2
- package/dist/templates/cursor/fixtures/expected-rules.d.ts +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.js +7 -24
- package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -1
- package/dist/templates/cursor/hooks.json +4 -0
- package/dist/templates/cursor/index.d.ts +1 -1
- package/dist/templates/cursor/index.js +1 -1
- package/dist/templates/cursor/rules/cstl-bootstrap.mdc +17 -0
- package/dist/templates/markdown/agents.md +36 -3
- package/dist/templates/markdown/{spec/guides → framework}/cursor-native-modes-guide.md.txt +13 -10
- package/dist/templates/markdown/{spec/guides → framework}/cursor-subagent-policy.md.txt +63 -127
- package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +29 -0
- package/dist/templates/markdown/{spec/guides → framework}/execution-strategy.md.txt +2 -0
- package/dist/templates/markdown/framework/index.md.txt +31 -0
- package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +45 -0
- package/dist/templates/markdown/framework/middleware-protocol.md.txt +83 -0
- package/dist/templates/markdown/framework/parallel-first-execution.md.txt +78 -0
- package/dist/templates/markdown/framework/prd-grill-frontier.md.txt +83 -0
- package/dist/templates/markdown/framework/release-boundary.md.txt +30 -0
- package/dist/templates/markdown/{spec/guides → framework}/retrieval-daily-guide.md.txt +1 -1
- package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
- package/dist/templates/markdown/{spec/guides → framework}/verification-strength-guide.md.txt +2 -2
- package/dist/templates/markdown/index.d.ts +26 -10
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +87 -11
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +1 -1
- package/dist/templates/markdown/spec/guides/index.md.txt +5 -19
- package/dist/templates/markdown/spec/guides/prototype-guide.md.txt +10 -10
- package/dist/templates/markdown/spec/guides/test-discipline-guide.md.txt +1 -1
- package/dist/templates/shared-hooks/event-bridge.py +60 -0
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/session-start.py +19 -2
- package/dist/templates/trellis/CONTEXT.md +63 -3
- package/dist/templates/trellis/config.yaml +1 -1
- package/dist/templates/trellis/gitignore.txt +39 -39
- package/dist/templates/trellis/index.d.ts +12 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +73 -15
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/pool/README.md +12 -3
- package/dist/templates/trellis/pool/plan.md +24 -5
- package/dist/templates/trellis/scripts/common/adapter_middleware.py +158 -0
- package/dist/templates/trellis/scripts/common/artifact_locale.py +12 -3
- package/dist/templates/trellis/scripts/common/cursor_retrieval_env.py +5 -2
- package/dist/templates/trellis/scripts/common/full_quality.py +237 -0
- package/dist/templates/trellis/scripts/common/git.py +6 -0
- package/dist/templates/trellis/scripts/common/git_context.py +17 -5
- package/dist/templates/trellis/scripts/common/kernel_command.py +367 -0
- package/dist/templates/trellis/scripts/common/lite_context.py +280 -0
- package/dist/templates/trellis/scripts/common/ondemand_topology.py +225 -0
- package/dist/templates/trellis/scripts/common/parent_orchestration.py +1 -1
- package/dist/templates/trellis/scripts/common/pool_store.py +16 -4
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +2 -2
- package/dist/templates/trellis/scripts/common/session_context.py +28 -2
- package/dist/templates/trellis/scripts/common/task_gates.py +73 -12
- package/dist/templates/trellis/scripts/common/task_map.py +42 -9
- package/dist/templates/trellis/scripts/common/task_store.py +293 -61
- package/dist/templates/trellis/scripts/common/test_adapter_middleware.py +56 -0
- package/dist/templates/trellis/scripts/common/test_depends_mode_block.py +9 -0
- package/dist/templates/trellis/scripts/common/test_full_quality.py +197 -0
- package/dist/templates/trellis/scripts/common/test_kernel_command.py +326 -0
- package/dist/templates/trellis/scripts/common/test_lite_path.py +190 -0
- package/dist/templates/trellis/scripts/common/test_observable_defaults.py +10 -4
- package/dist/templates/trellis/scripts/common/test_ondemand_topology.py +122 -0
- package/dist/templates/trellis/scripts/common/test_pool_store.py +17 -0
- package/dist/templates/trellis/scripts/common/test_task_store_kernel_patch.py +163 -0
- package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -0
- package/dist/templates/trellis/scripts/cursor_retrieval_probe_prompt.md +4 -5
- package/dist/templates/trellis/scripts/get_context.py +1 -0
- package/dist/templates/trellis/scripts/pool.py +5 -0
- package/dist/templates/trellis/scripts/task.py +83 -7
- package/dist/templates/trellis/workflow.md +109 -23
- package/dist/utils/cursor-retrieval-env.d.ts +2 -1
- package/dist/utils/cursor-retrieval-env.d.ts.map +1 -1
- package/dist/utils/cursor-retrieval-env.js +3 -2
- package/dist/utils/cursor-retrieval-env.js.map +1 -1
- package/dist/utils/cursor2plus-residue-cleanup.d.ts +38 -0
- package/dist/utils/cursor2plus-residue-cleanup.d.ts.map +1 -0
- package/dist/utils/cursor2plus-residue-cleanup.js +145 -0
- package/dist/utils/cursor2plus-residue-cleanup.js.map +1 -0
- package/dist/utils/manifest-prune.d.ts.map +1 -1
- package/dist/utils/manifest-prune.js +7 -2
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/p36-upgrade.d.ts +62 -0
- package/dist/utils/p36-upgrade.d.ts.map +1 -0
- package/dist/utils/p36-upgrade.js +160 -0
- package/dist/utils/p36-upgrade.js.map +1 -0
- package/dist/utils/project-capabilities.d.ts +1 -12
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +3 -100
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/readiness.d.ts +10 -0
- package/dist/utils/readiness.d.ts.map +1 -1
- package/dist/utils/readiness.js +58 -26
- package/dist/utils/readiness.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-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +11 -1
- package/dist/utils/template-hash.js.map +1 -1
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +52 -14
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/dist/utils/update-rollout-report.d.ts +14 -0
- package/dist/utils/update-rollout-report.d.ts.map +1 -1
- package/dist/utils/update-rollout-report.js +1 -0
- package/dist/utils/update-rollout-report.js.map +1 -1
- package/dist/utils/workflow-ownership.d.ts +1 -1
- package/dist/utils/workflow-ownership.js +4 -4
- package/dist/utils/workflow-ownership.js.map +1 -1
- package/package.json +5 -4
- package/scripts/postinstall.js +6 -7
- package/dist/commands/campaign/canvas-render.d.ts +0 -68
- package/dist/commands/campaign/canvas-render.d.ts.map +0 -1
- package/dist/commands/campaign/canvas-render.js +0 -414
- package/dist/commands/campaign/canvas-render.js.map +0 -1
- package/dist/commands/campaign/compose.d.ts +0 -15
- package/dist/commands/campaign/compose.d.ts.map +0 -1
- package/dist/commands/campaign/compose.js +0 -110
- package/dist/commands/campaign/compose.js.map +0 -1
- package/dist/commands/campaign/index.d.ts +0 -13
- package/dist/commands/campaign/index.d.ts.map +0 -1
- package/dist/commands/campaign/index.js +0 -134
- package/dist/commands/campaign/index.js.map +0 -1
- package/dist/commands/campaign/kind-map.d.ts +0 -6
- package/dist/commands/campaign/kind-map.d.ts.map +0 -1
- package/dist/commands/campaign/kind-map.js +0 -21
- package/dist/commands/campaign/kind-map.js.map +0 -1
- package/dist/commands/campaign/mcp-server.d.ts +0 -6
- package/dist/commands/campaign/mcp-server.d.ts.map +0 -1
- package/dist/commands/campaign/mcp-server.js +0 -167
- package/dist/commands/campaign/mcp-server.js.map +0 -1
- package/dist/commands/campaign/render.d.ts +0 -5
- package/dist/commands/campaign/render.d.ts.map +0 -1
- package/dist/commands/campaign/render.js +0 -103
- package/dist/commands/campaign/render.js.map +0 -1
- package/dist/commands/campaign/trellis-load.d.ts +0 -13
- package/dist/commands/campaign/trellis-load.d.ts.map +0 -1
- package/dist/commands/campaign/trellis-load.js +0 -122
- package/dist/commands/campaign/trellis-load.js.map +0 -1
- package/dist/commands/campaign/types.d.ts +0 -61
- package/dist/commands/campaign/types.d.ts.map +0 -1
- package/dist/commands/campaign/types.js +0 -3
- package/dist/commands/campaign/types.js.map +0 -1
- package/dist/commands/goal/index.d.ts +0 -3
- package/dist/commands/goal/index.d.ts.map +0 -1
- package/dist/commands/goal/index.js +0 -159
- package/dist/commands/goal/index.js.map +0 -1
- package/dist/commands/goal/review.d.ts +0 -6
- package/dist/commands/goal/review.d.ts.map +0 -1
- package/dist/commands/goal/review.js +0 -28
- package/dist/commands/goal/review.js.map +0 -1
- package/dist/commands/rpc/client.d.ts +0 -51
- package/dist/commands/rpc/client.d.ts.map +0 -1
- package/dist/commands/rpc/client.js +0 -147
- package/dist/commands/rpc/client.js.map +0 -1
- package/dist/commands/rpc/index.d.ts +0 -10
- package/dist/commands/rpc/index.d.ts.map +0 -1
- package/dist/commands/rpc/index.js +0 -157
- package/dist/commands/rpc/index.js.map +0 -1
- package/dist/commands/rpc/serve.d.ts +0 -23
- package/dist/commands/rpc/serve.d.ts.map +0 -1
- package/dist/commands/rpc/serve.js +0 -60
- package/dist/commands/rpc/serve.js.map +0 -1
- package/dist/commands/rpc/smoke.d.ts +0 -16
- package/dist/commands/rpc/smoke.d.ts.map +0 -1
- package/dist/commands/rpc/smoke.js +0 -92
- package/dist/commands/rpc/smoke.js.map +0 -1
- package/dist/commands/sdk/index.d.ts +0 -9
- package/dist/commands/sdk/index.d.ts.map +0 -1
- package/dist/commands/sdk/index.js +0 -58
- package/dist/commands/sdk/index.js.map +0 -1
- package/dist/commands/sdk/run.d.ts +0 -42
- package/dist/commands/sdk/run.d.ts.map +0 -1
- package/dist/commands/sdk/run.js +0 -220
- package/dist/commands/sdk/run.js.map +0 -1
- package/dist/commands/sdk/status.d.ts +0 -14
- package/dist/commands/sdk/status.d.ts.map +0 -1
- package/dist/commands/sdk/status.js +0 -69
- package/dist/commands/sdk/status.js.map +0 -1
- package/dist/configurators/cursor2plus-local.d.ts +0 -6
- package/dist/configurators/cursor2plus-local.d.ts.map +0 -1
- package/dist/configurators/cursor2plus-local.js +0 -21
- package/dist/configurators/cursor2plus-local.js.map +0 -1
- package/dist/goal/action-packet.d.ts +0 -89
- package/dist/goal/action-packet.d.ts.map +0 -1
- package/dist/goal/action-packet.js +0 -113
- package/dist/goal/action-packet.js.map +0 -1
- package/dist/goal/audit.d.ts +0 -14
- package/dist/goal/audit.d.ts.map +0 -1
- package/dist/goal/audit.js +0 -12
- package/dist/goal/audit.js.map +0 -1
- package/dist/goal/constants.d.ts +0 -26
- package/dist/goal/constants.d.ts.map +0 -1
- package/dist/goal/constants.js +0 -24
- package/dist/goal/constants.js.map +0 -1
- package/dist/goal/paths.d.ts +0 -8
- package/dist/goal/paths.d.ts.map +0 -1
- package/dist/goal/paths.js +0 -36
- package/dist/goal/paths.js.map +0 -1
- package/dist/goal/preflight.d.ts +0 -21
- package/dist/goal/preflight.d.ts.map +0 -1
- package/dist/goal/preflight.js +0 -97
- package/dist/goal/preflight.js.map +0 -1
- package/dist/goal/review-seam.d.ts +0 -44
- package/dist/goal/review-seam.d.ts.map +0 -1
- package/dist/goal/review-seam.js +0 -153
- package/dist/goal/review-seam.js.map +0 -1
- package/dist/goal/reviewer-rules.d.ts +0 -13
- package/dist/goal/reviewer-rules.d.ts.map +0 -1
- package/dist/goal/reviewer-rules.js +0 -153
- package/dist/goal/reviewer-rules.js.map +0 -1
- package/dist/goal/reviewer.d.ts +0 -9
- package/dist/goal/reviewer.d.ts.map +0 -1
- package/dist/goal/reviewer.js +0 -54
- package/dist/goal/reviewer.js.map +0 -1
- package/dist/goal/runtime.d.ts +0 -32
- package/dist/goal/runtime.d.ts.map +0 -1
- package/dist/goal/runtime.js +0 -242
- package/dist/goal/runtime.js.map +0 -1
- package/dist/goal/sdk-client.d.ts +0 -10
- package/dist/goal/sdk-client.d.ts.map +0 -1
- package/dist/goal/sdk-client.js +0 -34
- package/dist/goal/sdk-client.js.map +0 -1
- package/dist/goal/state.d.ts +0 -40
- package/dist/goal/state.d.ts.map +0 -1
- package/dist/goal/state.js +0 -37
- package/dist/goal/state.js.map +0 -1
- package/dist/goal/task-triggers.d.ts +0 -15
- package/dist/goal/task-triggers.d.ts.map +0 -1
- package/dist/goal/task-triggers.js +0 -23
- package/dist/goal/task-triggers.js.map +0 -1
- package/dist/goal/walls.d.ts +0 -12
- package/dist/goal/walls.d.ts.map +0 -1
- package/dist/goal/walls.js +0 -65
- package/dist/goal/walls.js.map +0 -1
- package/dist/goal/worker-prompt.d.ts +0 -13
- package/dist/goal/worker-prompt.d.ts.map +0 -1
- package/dist/goal/worker-prompt.js +0 -41
- package/dist/goal/worker-prompt.js.map +0 -1
- package/dist/goal/worker.d.ts +0 -42
- package/dist/goal/worker.d.ts.map +0 -1
- package/dist/goal/worker.js +0 -180
- package/dist/goal/worker.js.map +0 -1
- package/dist/templates/common/bundled-skills/cstl-cursor2plus-setup/SKILL.md +0 -63
- package/dist/templates/cursor/commands/cursor2plus-setup.md +0 -82
- package/dist/templates/cursor/rules/cstl-cursor-modes.mdc +0 -32
- package/dist/templates/cursor/rules/cstl-session-rename.mdc +0 -31
- package/dist/templates/cursor/rules/cstl-subagent-dispatch.mdc +0 -34
- package/dist/templates/cursor/rules/cstl-triage.mdc +0 -36
- package/dist/templates/cursor/rules/retrieval-routing.mdc +0 -78
- package/dist/templates/markdown/spec/guides/cursor-trellis-release-coexistence-guide.md.txt +0 -166
- package/dist/templates/markdown/spec/guides/goal-release-regression-runbook.md.txt +0 -132
- package/dist/templates/trellis/local/README.md +0 -85
- package/dist/templates/trellis/local/config.local.json.example +0 -6
- package/dist/templates/trellis/local/index.d.ts +0 -8
- package/dist/templates/trellis/local/index.d.ts.map +0 -1
- package/dist/templates/trellis/local/index.js +0 -15
- package/dist/templates/trellis/local/index.js.map +0 -1
- package/dist/templates/trellis/local/patch_wpelc8.py +0 -421
- package/dist/templates/trellis/local/smoke.py +0 -94
- package/dist/templates/trellis/local/subagent-models.json.example +0 -4
- package/dist/templates/trellis/local/trellis-task-models.json.example +0 -10
- package/dist/templates/trellis/local/trellis-task-models.json5.example +0 -45
- package/dist/templates/trellis/local/trellis_task_models_config.py +0 -200
- package/dist/utils/cursor-sdk-gate.d.ts +0 -10
- package/dist/utils/cursor-sdk-gate.d.ts.map +0 -1
- package/dist/utils/cursor-sdk-gate.js +0 -32
- package/dist/utils/cursor-sdk-gate.js.map +0 -1
- /package/dist/templates/markdown/{spec/guides → framework}/artifact-locale-guide.md.txt +0 -0
- /package/dist/templates/markdown/{spec/guides → framework}/cursor-context-injection-guide.md.txt +0 -0
- /package/dist/templates/markdown/{spec/guides → framework}/cursor-semantic-compliance.md.txt +0 -0
- /package/dist/templates/markdown/{spec/guides → framework}/injection-budget-guide.md.txt +0 -0
|
@@ -40,8 +40,17 @@ from .config import (
|
|
|
40
40
|
validate_package,
|
|
41
41
|
)
|
|
42
42
|
from .cli_environment import format_git_repo_errors, print_environment_repair_hints
|
|
43
|
-
from .git import run_git
|
|
44
|
-
from .io import read_json
|
|
43
|
+
from .git import is_git_worktree, run_git
|
|
44
|
+
from .io import read_json
|
|
45
|
+
from .kernel_command import (
|
|
46
|
+
KernelCliNotFound,
|
|
47
|
+
KernelCommandError,
|
|
48
|
+
kernel_archive,
|
|
49
|
+
kernel_create,
|
|
50
|
+
kernel_expected_revision,
|
|
51
|
+
kernel_patch,
|
|
52
|
+
print_kernel_error,
|
|
53
|
+
)
|
|
45
54
|
from .log import Colors, colored
|
|
46
55
|
from .paths import (
|
|
47
56
|
DIR_ARCHIVE,
|
|
@@ -62,10 +71,13 @@ from .task_gates import (
|
|
|
62
71
|
BASELINE_GATE,
|
|
63
72
|
archive_repair_hints,
|
|
64
73
|
build_spec_update_scaffold,
|
|
74
|
+
collect_kernel_projection_extras,
|
|
65
75
|
prepare_archive_evidence,
|
|
76
|
+
task_closeout_profile,
|
|
66
77
|
validate_archive,
|
|
67
78
|
write_gate_record,
|
|
68
79
|
)
|
|
80
|
+
from .ondemand_topology import TopologyError, assign_parent, default_topology
|
|
69
81
|
from .task_map import (
|
|
70
82
|
CHILD_STATES,
|
|
71
83
|
CHILD_REPORT_STATES,
|
|
@@ -257,10 +269,12 @@ _SUBAGENT_CONFIG_DIRS: tuple[str, ...] = (
|
|
|
257
269
|
".pi", # Pi Agent
|
|
258
270
|
)
|
|
259
271
|
|
|
260
|
-
|
|
272
|
+
# Stable seed paths for jsonl create: one user-owned thinking-guide index plus
|
|
273
|
+
# framework-owned verification/injection docs (both always present after init).
|
|
274
|
+
_STABLE_SEED_PATHS: tuple[str, ...] = (
|
|
261
275
|
".cstl/spec/guides/index.md",
|
|
262
|
-
".cstl/
|
|
263
|
-
".cstl/
|
|
276
|
+
".cstl/framework/verification-strength-guide.md",
|
|
277
|
+
".cstl/framework/injection-budget-guide.md",
|
|
264
278
|
)
|
|
265
279
|
|
|
266
280
|
|
|
@@ -289,7 +303,7 @@ def _resolve_seed_spec_paths(
|
|
|
289
303
|
for path in suggest_spec_targets(repo_root, task_dir, task_data):
|
|
290
304
|
if path not in candidates:
|
|
291
305
|
candidates.append(path)
|
|
292
|
-
for rel in
|
|
306
|
+
for rel in _STABLE_SEED_PATHS:
|
|
293
307
|
if rel not in candidates:
|
|
294
308
|
candidates.append(rel)
|
|
295
309
|
|
|
@@ -298,7 +312,7 @@ def _resolve_seed_spec_paths(
|
|
|
298
312
|
return existing[:3]
|
|
299
313
|
|
|
300
314
|
fallback = [
|
|
301
|
-
rel for rel in
|
|
315
|
+
rel for rel in _STABLE_SEED_PATHS if (repo_root / rel).is_file()
|
|
302
316
|
]
|
|
303
317
|
return fallback[:3]
|
|
304
318
|
|
|
@@ -343,6 +357,35 @@ def _default_prd_content(
|
|
|
343
357
|
return default_prd_content(title, description, locale, root)
|
|
344
358
|
|
|
345
359
|
|
|
360
|
+
def _kernel_patch_task_json(
|
|
361
|
+
task_dir: Path,
|
|
362
|
+
data: dict,
|
|
363
|
+
*,
|
|
364
|
+
actor: str,
|
|
365
|
+
op: str,
|
|
366
|
+
evidence: str,
|
|
367
|
+
) -> bool:
|
|
368
|
+
"""Persist mutated task.json fields through Kernel patch (not task-map.md)."""
|
|
369
|
+
extras = collect_kernel_projection_extras(data)
|
|
370
|
+
if "depends_on" in data:
|
|
371
|
+
extras["depends_on"] = data["depends_on"]
|
|
372
|
+
try:
|
|
373
|
+
expected = kernel_expected_revision(task_dir)
|
|
374
|
+
kernel_patch(
|
|
375
|
+
task_dir,
|
|
376
|
+
data,
|
|
377
|
+
extras,
|
|
378
|
+
expected_revision=expected,
|
|
379
|
+
actor=actor,
|
|
380
|
+
idempotency_key=f"patch:{op}:{task_dir.name}:r{expected}",
|
|
381
|
+
evidence=evidence,
|
|
382
|
+
)
|
|
383
|
+
return True
|
|
384
|
+
except (KernelCliNotFound, KernelCommandError) as err:
|
|
385
|
+
print_kernel_error(err)
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
|
|
346
389
|
# =============================================================================
|
|
347
390
|
# Command: create
|
|
348
391
|
# =============================================================================
|
|
@@ -443,7 +486,33 @@ def cmd_create(args: argparse.Namespace) -> int:
|
|
|
443
486
|
"meta": {},
|
|
444
487
|
}
|
|
445
488
|
|
|
446
|
-
|
|
489
|
+
parent_dir = None
|
|
490
|
+
parent_data = None
|
|
491
|
+
if args.parent:
|
|
492
|
+
parent_dir = resolve_task_dir(args.parent, repo_root)
|
|
493
|
+
parent_json_path = parent_dir / FILE_TASK_JSON
|
|
494
|
+
if not parent_json_path.is_file():
|
|
495
|
+
print(colored(f"Warning: Parent task.json not found: {args.parent}", Colors.YELLOW), file=sys.stderr)
|
|
496
|
+
else:
|
|
497
|
+
parent_data = read_json(parent_json_path)
|
|
498
|
+
if parent_data:
|
|
499
|
+
task_data["parent"] = parent_dir.name
|
|
500
|
+
|
|
501
|
+
try:
|
|
502
|
+
kernel_create(
|
|
503
|
+
task_dir,
|
|
504
|
+
task_data,
|
|
505
|
+
actor="task.py create",
|
|
506
|
+
idempotency_key=f"create:{slug}",
|
|
507
|
+
evidence="task.py create",
|
|
508
|
+
)
|
|
509
|
+
except (KernelCliNotFound, KernelCommandError) as err:
|
|
510
|
+
print_kernel_error(err)
|
|
511
|
+
return 1
|
|
512
|
+
|
|
513
|
+
persisted = read_json(task_json_path)
|
|
514
|
+
if persisted:
|
|
515
|
+
task_data = persisted
|
|
447
516
|
|
|
448
517
|
prd_path = task_dir / "prd.md"
|
|
449
518
|
if not prd_path.exists():
|
|
@@ -471,39 +540,35 @@ def cmd_create(args: argparse.Namespace) -> int:
|
|
|
471
540
|
_write_seed_jsonl(jsonl_path, repo_root, task_dir, task_data)
|
|
472
541
|
seeded_jsonl = True
|
|
473
542
|
|
|
474
|
-
# Handle --parent:
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if not
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
list(parent_data.get("children", [])),
|
|
497
|
-
f"Linked Child `{dir_name}`.",
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
print(colored(f"Linked as child of: {parent_dir.name}", Colors.GREEN), file=sys.stderr)
|
|
543
|
+
# Handle --parent: child's `parent` is in the Kernel create record above;
|
|
544
|
+
# parent `children[]` goes through Kernel patch. task-map.md stays Python.
|
|
545
|
+
if parent_dir is not None and parent_data:
|
|
546
|
+
parent_children = parent_data.get("children", [])
|
|
547
|
+
if dir_name not in parent_children:
|
|
548
|
+
parent_children.append(dir_name)
|
|
549
|
+
parent_data["children"] = parent_children
|
|
550
|
+
if not _kernel_patch_task_json(
|
|
551
|
+
parent_dir,
|
|
552
|
+
parent_data,
|
|
553
|
+
actor="task.py create",
|
|
554
|
+
op="create-parent-link",
|
|
555
|
+
evidence="children[]",
|
|
556
|
+
):
|
|
557
|
+
return 1
|
|
558
|
+
ensure_task_map(
|
|
559
|
+
parent_dir,
|
|
560
|
+
parent_data,
|
|
561
|
+
list(parent_data.get("children", [])),
|
|
562
|
+
f"Linked Child `{dir_name}`.",
|
|
563
|
+
)
|
|
564
|
+
print(colored(f"Linked as child of: {parent_dir.name}", Colors.GREEN), file=sys.stderr)
|
|
501
565
|
|
|
502
566
|
print(colored(f"Created task: {dir_name}", Colors.GREEN), file=sys.stderr)
|
|
503
567
|
print("", file=sys.stderr)
|
|
504
568
|
print(colored("Next steps:", Colors.BLUE), file=sys.stderr)
|
|
505
569
|
print(" - Fill prd.md with requirements and acceptance criteria", file=sys.stderr)
|
|
506
570
|
print(f" - Select it when ready: python ./.cstl/scripts/task.py select {DIR_WORKFLOW}/{DIR_TASKS}/{dir_name}", file=sys.stderr)
|
|
571
|
+
print(" - Personal Lite: Definition=prd.md, Evidence=verify.md; start-execution --check is not approval", file=sys.stderr)
|
|
507
572
|
print(" - Lightweight task: PRD-only is valid", file=sys.stderr)
|
|
508
573
|
print(" - Complex task: add design.md and implement.md before task.py start-execution --check", file=sys.stderr)
|
|
509
574
|
if seeded_jsonl:
|
|
@@ -634,7 +699,21 @@ def _archive_one_task(
|
|
|
634
699
|
write_gate_record(data, "full-task-complete", BASELINE_GATE, guard.baseline_record)
|
|
635
700
|
data["status"] = "completed"
|
|
636
701
|
data["completedAt"] = today
|
|
637
|
-
|
|
702
|
+
extras = collect_kernel_projection_extras(data)
|
|
703
|
+
try:
|
|
704
|
+
expected = kernel_expected_revision(task_dir)
|
|
705
|
+
kernel_archive(
|
|
706
|
+
task_dir,
|
|
707
|
+
data,
|
|
708
|
+
extras,
|
|
709
|
+
expected_revision=expected,
|
|
710
|
+
actor="task.py archive",
|
|
711
|
+
idempotency_key=f"archive:{dir_name}:{today}",
|
|
712
|
+
evidence="task.py archive",
|
|
713
|
+
)
|
|
714
|
+
except (KernelCliNotFound, KernelCommandError) as err:
|
|
715
|
+
print_kernel_error(err)
|
|
716
|
+
return False, [], None
|
|
638
717
|
|
|
639
718
|
task_children = data.get("children", [])
|
|
640
719
|
if task_children:
|
|
@@ -646,14 +725,32 @@ def _archive_one_task(
|
|
|
646
725
|
child_data = read_json(child_json)
|
|
647
726
|
if child_data:
|
|
648
727
|
child_data["parent"] = None
|
|
649
|
-
|
|
728
|
+
if not _kernel_patch_task_json(
|
|
729
|
+
child_dir_path,
|
|
730
|
+
child_data,
|
|
731
|
+
actor="task.py archive",
|
|
732
|
+
op="archive-clear-parent",
|
|
733
|
+
evidence="parent",
|
|
734
|
+
):
|
|
735
|
+
return False, modified_children, None
|
|
650
736
|
modified_children.append(child_dir_path.name)
|
|
651
737
|
|
|
652
738
|
from .active_task import clear_task_from_sessions
|
|
653
739
|
|
|
740
|
+
profile = task_closeout_profile(task_dir, task_data) if task_data else "lite"
|
|
654
741
|
clear_task_from_sessions(str(task_dir), repo_root)
|
|
655
742
|
result = archive_task_complete(task_dir, repo_root)
|
|
656
743
|
if "archived_to" not in result:
|
|
744
|
+
if profile == "lite":
|
|
745
|
+
print(
|
|
746
|
+
colored(
|
|
747
|
+
"Close Outcome written; physical archive/retention skipped "
|
|
748
|
+
"(not a Lite completion condition).",
|
|
749
|
+
Colors.YELLOW,
|
|
750
|
+
),
|
|
751
|
+
file=sys.stderr,
|
|
752
|
+
)
|
|
753
|
+
return True, modified_children, f"{DIR_WORKFLOW}/{DIR_TASKS}/{dir_name}"
|
|
657
754
|
return False, modified_children, None
|
|
658
755
|
|
|
659
756
|
archive_dest = Path(result["archived_to"])
|
|
@@ -665,15 +762,25 @@ def _archive_one_task(
|
|
|
665
762
|
|
|
666
763
|
if not no_commit:
|
|
667
764
|
if not _auto_commit_archive(dir_name, repo_root, modified_children):
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
765
|
+
if profile == "lite":
|
|
766
|
+
print(
|
|
767
|
+
colored(
|
|
768
|
+
"Lite Close Outcome stands; git auto-commit skipped or failed "
|
|
769
|
+
"(VCS is On-demand, not a completion condition).",
|
|
770
|
+
Colors.YELLOW,
|
|
771
|
+
),
|
|
772
|
+
file=sys.stderr,
|
|
773
|
+
)
|
|
774
|
+
else:
|
|
775
|
+
print(
|
|
776
|
+
colored(
|
|
777
|
+
"Archive moved on disk, but git auto-commit did not complete. "
|
|
778
|
+
"Resolve `git status` before continuing.",
|
|
779
|
+
Colors.RED,
|
|
780
|
+
),
|
|
781
|
+
file=sys.stderr,
|
|
782
|
+
)
|
|
783
|
+
return False, modified_children, None
|
|
677
784
|
|
|
678
785
|
rel = f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}/{year_month}/{dir_name}"
|
|
679
786
|
archived_json = archive_dest / FILE_TASK_JSON
|
|
@@ -856,6 +963,14 @@ def _auto_commit_archive(
|
|
|
856
963
|
set to ``false``, this function returns immediately without
|
|
857
964
|
touching git (the archive directory move on disk is unaffected).
|
|
858
965
|
"""
|
|
966
|
+
if not is_git_worktree(repo_root):
|
|
967
|
+
print(
|
|
968
|
+
"[OK] no Git worktree — skipping archive auto-commit "
|
|
969
|
+
"(Close Outcome already written).",
|
|
970
|
+
file=sys.stderr,
|
|
971
|
+
)
|
|
972
|
+
return True
|
|
973
|
+
|
|
859
974
|
if not get_session_auto_commit(repo_root):
|
|
860
975
|
print(
|
|
861
976
|
"[OK] session_auto_commit: false — skipping git stage/commit.",
|
|
@@ -965,9 +1080,49 @@ def cmd_add_subtask(args: argparse.Namespace) -> int:
|
|
|
965
1080
|
# Set parent in child's task.json
|
|
966
1081
|
child_data["parent"] = parent_dir.name
|
|
967
1082
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1083
|
+
parent_id = str(parent_data.get("id") or parent_dir.name)
|
|
1084
|
+
parent_existing = (
|
|
1085
|
+
parent_data.get("topology")
|
|
1086
|
+
if isinstance(parent_data.get("topology"), dict)
|
|
1087
|
+
else {}
|
|
1088
|
+
)
|
|
1089
|
+
parent_data["topology"] = default_topology(
|
|
1090
|
+
parent=parent_existing.get("parent_id") or parent_data.get("parent"),
|
|
1091
|
+
children=parent_children,
|
|
1092
|
+
)
|
|
1093
|
+
child_existing = (
|
|
1094
|
+
child_data.get("topology")
|
|
1095
|
+
if isinstance(child_data.get("topology"), dict)
|
|
1096
|
+
else {}
|
|
1097
|
+
)
|
|
1098
|
+
child_children = list(
|
|
1099
|
+
child_existing.get("children") or child_data.get("children") or []
|
|
1100
|
+
)
|
|
1101
|
+
try:
|
|
1102
|
+
child_data["topology"] = assign_parent(
|
|
1103
|
+
default_topology(parent=None, children=child_children),
|
|
1104
|
+
parent_id,
|
|
1105
|
+
)
|
|
1106
|
+
except TopologyError as err:
|
|
1107
|
+
print(colored(f"Error: {err}", Colors.RED), file=sys.stderr)
|
|
1108
|
+
return 1
|
|
1109
|
+
|
|
1110
|
+
if not _kernel_patch_task_json(
|
|
1111
|
+
parent_dir,
|
|
1112
|
+
parent_data,
|
|
1113
|
+
actor="task.py add-subtask",
|
|
1114
|
+
op="add-subtask",
|
|
1115
|
+
evidence="children[]",
|
|
1116
|
+
):
|
|
1117
|
+
return 1
|
|
1118
|
+
if not _kernel_patch_task_json(
|
|
1119
|
+
child_dir,
|
|
1120
|
+
child_data,
|
|
1121
|
+
actor="task.py add-subtask",
|
|
1122
|
+
op="add-subtask",
|
|
1123
|
+
evidence="parent",
|
|
1124
|
+
):
|
|
1125
|
+
return 1
|
|
971
1126
|
ensure_task_map(
|
|
972
1127
|
parent_dir,
|
|
973
1128
|
parent_data,
|
|
@@ -1018,9 +1173,41 @@ def cmd_remove_subtask(args: argparse.Namespace) -> int:
|
|
|
1018
1173
|
# Clear parent in child's task.json
|
|
1019
1174
|
child_data["parent"] = None
|
|
1020
1175
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1176
|
+
parent_existing = (
|
|
1177
|
+
parent_data.get("topology")
|
|
1178
|
+
if isinstance(parent_data.get("topology"), dict)
|
|
1179
|
+
else {}
|
|
1180
|
+
)
|
|
1181
|
+
parent_data["topology"] = default_topology(
|
|
1182
|
+
parent=parent_existing.get("parent_id") or parent_data.get("parent"),
|
|
1183
|
+
children=parent_children,
|
|
1184
|
+
)
|
|
1185
|
+
child_existing = (
|
|
1186
|
+
child_data.get("topology")
|
|
1187
|
+
if isinstance(child_data.get("topology"), dict)
|
|
1188
|
+
else {}
|
|
1189
|
+
)
|
|
1190
|
+
child_data["topology"] = default_topology(
|
|
1191
|
+
parent=None,
|
|
1192
|
+
children=list(child_existing.get("children") or child_data.get("children") or []),
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
if not _kernel_patch_task_json(
|
|
1196
|
+
parent_dir,
|
|
1197
|
+
parent_data,
|
|
1198
|
+
actor="task.py remove-subtask",
|
|
1199
|
+
op="remove-subtask",
|
|
1200
|
+
evidence="children[]",
|
|
1201
|
+
):
|
|
1202
|
+
return 1
|
|
1203
|
+
if not _kernel_patch_task_json(
|
|
1204
|
+
child_dir,
|
|
1205
|
+
child_data,
|
|
1206
|
+
actor="task.py remove-subtask",
|
|
1207
|
+
op="remove-subtask",
|
|
1208
|
+
evidence="parent",
|
|
1209
|
+
):
|
|
1210
|
+
return 1
|
|
1024
1211
|
remove_child_from_task_map(parent_dir, parent_data, child_dir_name)
|
|
1025
1212
|
|
|
1026
1213
|
print(colored(f"Unlinked: {child_dir.name} from {parent_dir.name}", Colors.GREEN), file=sys.stderr)
|
|
@@ -1106,7 +1293,14 @@ def cmd_prepare_child_worktree(args: argparse.Namespace) -> int:
|
|
|
1106
1293
|
|
|
1107
1294
|
child_data["branch"] = branch
|
|
1108
1295
|
child_data["worktree_path"] = worktree_rel
|
|
1109
|
-
|
|
1296
|
+
if not _kernel_patch_task_json(
|
|
1297
|
+
child_dir,
|
|
1298
|
+
child_data,
|
|
1299
|
+
actor="task.py prepare-child-worktree",
|
|
1300
|
+
op="prepare-child-worktree",
|
|
1301
|
+
evidence="branch,worktree_path",
|
|
1302
|
+
):
|
|
1303
|
+
return 1
|
|
1110
1304
|
|
|
1111
1305
|
ok, map_errors = record_child_worktree(
|
|
1112
1306
|
parent_dir,
|
|
@@ -1145,7 +1339,7 @@ def append_depends_ignore_event(
|
|
|
1145
1339
|
"""Append a depends-ignore audit event to meta.depends_ignore_events.
|
|
1146
1340
|
|
|
1147
1341
|
Mutates task_data in memory; the caller persists it in the SAME
|
|
1148
|
-
|
|
1342
|
+
Kernel patch as the mutation it accompanies (execution approval / child
|
|
1149
1343
|
state), so the event can never dangle as a separate stale write. The
|
|
1150
1344
|
list is capped at MAX_IGNORE_EVENTS (FIFO drops the oldest entry).
|
|
1151
1345
|
"""
|
|
@@ -1234,8 +1428,13 @@ def _guard_child_working_deps(
|
|
|
1234
1428
|
evidence=args.evidence,
|
|
1235
1429
|
reason=getattr(args, "reason", None),
|
|
1236
1430
|
)
|
|
1237
|
-
|
|
1238
|
-
|
|
1431
|
+
if not _kernel_patch_task_json(
|
|
1432
|
+
child_dir,
|
|
1433
|
+
child_data,
|
|
1434
|
+
actor="task.py set-child-state",
|
|
1435
|
+
op="depends-ignore",
|
|
1436
|
+
evidence=str(args.evidence or "ignore-deps"),
|
|
1437
|
+
):
|
|
1239
1438
|
print(
|
|
1240
1439
|
colored("Error: failed to write task.json (ignore event)", Colors.RED),
|
|
1241
1440
|
file=sys.stderr,
|
|
@@ -1770,7 +1969,14 @@ def cmd_set_branch(args: argparse.Namespace) -> int:
|
|
|
1770
1969
|
return 1
|
|
1771
1970
|
|
|
1772
1971
|
data["branch"] = branch
|
|
1773
|
-
|
|
1972
|
+
if not _kernel_patch_task_json(
|
|
1973
|
+
target_dir,
|
|
1974
|
+
data,
|
|
1975
|
+
actor="task.py set-branch",
|
|
1976
|
+
op="set-branch",
|
|
1977
|
+
evidence="branch",
|
|
1978
|
+
):
|
|
1979
|
+
return 1
|
|
1774
1980
|
|
|
1775
1981
|
print(colored(f"✓ Branch set to: {branch}", Colors.GREEN))
|
|
1776
1982
|
return 0
|
|
@@ -1804,7 +2010,14 @@ def cmd_set_base_branch(args: argparse.Namespace) -> int:
|
|
|
1804
2010
|
return 1
|
|
1805
2011
|
|
|
1806
2012
|
data["base_branch"] = base_branch
|
|
1807
|
-
|
|
2013
|
+
if not _kernel_patch_task_json(
|
|
2014
|
+
target_dir,
|
|
2015
|
+
data,
|
|
2016
|
+
actor="task.py set-base-branch",
|
|
2017
|
+
op="set-base-branch",
|
|
2018
|
+
evidence="base_branch",
|
|
2019
|
+
):
|
|
2020
|
+
return 1
|
|
1808
2021
|
|
|
1809
2022
|
print(colored(f"✓ Base branch set to: {base_branch}", Colors.GREEN))
|
|
1810
2023
|
print(f" PR will target: {base_branch}")
|
|
@@ -1836,7 +2049,14 @@ def cmd_set_scope(args: argparse.Namespace) -> int:
|
|
|
1836
2049
|
return 1
|
|
1837
2050
|
|
|
1838
2051
|
data["scope"] = scope
|
|
1839
|
-
|
|
2052
|
+
if not _kernel_patch_task_json(
|
|
2053
|
+
target_dir,
|
|
2054
|
+
data,
|
|
2055
|
+
actor="task.py set-scope",
|
|
2056
|
+
op="set-scope",
|
|
2057
|
+
evidence="scope",
|
|
2058
|
+
):
|
|
2059
|
+
return 1
|
|
1840
2060
|
|
|
1841
2061
|
print(colored(f"✓ Scope set to: {scope}", Colors.GREEN))
|
|
1842
2062
|
return 0
|
|
@@ -1878,7 +2098,13 @@ def cmd_set_deps(args: argparse.Namespace) -> int:
|
|
|
1878
2098
|
if resolve_dep_ref(ref, repo_root=repo_root).kind == KIND_MISSING
|
|
1879
2099
|
]
|
|
1880
2100
|
|
|
1881
|
-
if not
|
|
2101
|
+
if not _kernel_patch_task_json(
|
|
2102
|
+
target_dir,
|
|
2103
|
+
data,
|
|
2104
|
+
actor="task.py set-deps",
|
|
2105
|
+
op="set-deps",
|
|
2106
|
+
evidence="depends_on",
|
|
2107
|
+
):
|
|
1882
2108
|
print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
|
|
1883
2109
|
return 1
|
|
1884
2110
|
|
|
@@ -1948,7 +2174,13 @@ def cmd_set_depends_mode(args: argparse.Namespace) -> int:
|
|
|
1948
2174
|
data["meta"] = meta
|
|
1949
2175
|
meta["depends_mode"] = args.mode
|
|
1950
2176
|
|
|
1951
|
-
if not
|
|
2177
|
+
if not _kernel_patch_task_json(
|
|
2178
|
+
target_dir,
|
|
2179
|
+
data,
|
|
2180
|
+
actor="task.py set-depends-mode",
|
|
2181
|
+
op="set-depends-mode",
|
|
2182
|
+
evidence="meta.depends_mode",
|
|
2183
|
+
):
|
|
1952
2184
|
print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
|
|
1953
2185
|
return 1
|
|
1954
2186
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Stage 6 Event Bridge / Middleware Python projection."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
12
|
+
|
|
13
|
+
from common.adapter_middleware import (
|
|
14
|
+
EXTERNAL_KNOWLEDGE_CAPABILITY,
|
|
15
|
+
RETRIEVAL_INTENTS,
|
|
16
|
+
AdapterMiddlewareError,
|
|
17
|
+
assert_external_knowledge,
|
|
18
|
+
dispatch_hook_event,
|
|
19
|
+
normalize_capability_router,
|
|
20
|
+
probe_smart_search_readiness,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_dispatch_skips_unsubscribed_modules() -> None:
|
|
25
|
+
last = dispatch_hook_event(
|
|
26
|
+
{
|
|
27
|
+
"subscriptions": [
|
|
28
|
+
{"event": "sessionStart", "module": "observability-local"},
|
|
29
|
+
{"event": "stop", "module": "retrieval-extended"},
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"sessionStart",
|
|
33
|
+
source="cursor-hooks",
|
|
34
|
+
)
|
|
35
|
+
assert last["delivered"] == ["observability-local"]
|
|
36
|
+
assert last["skipped"] == ["retrieval-extended"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_missing_smart_search_is_not_ready() -> None:
|
|
40
|
+
readiness = probe_smart_search_readiness(available=False)
|
|
41
|
+
assert readiness["status"] == "missing"
|
|
42
|
+
assert readiness["capability"] == EXTERNAL_KNOWLEDGE_CAPABILITY
|
|
43
|
+
extras = {"required_capabilities": [EXTERNAL_KNOWLEDGE_CAPABILITY]}
|
|
44
|
+
with pytest.raises(AdapterMiddlewareError, match="not ready"):
|
|
45
|
+
assert_external_knowledge(extras, readiness, phase="start")
|
|
46
|
+
extras["external_knowledge_policy"] = "degrade"
|
|
47
|
+
assert_external_knowledge(extras, readiness, phase="start")
|
|
48
|
+
assert extras["profile_health"] == "degraded"
|
|
49
|
+
assert_external_knowledge({}, readiness, phase="archive")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_capability_router_rejects_optional_tool_names() -> None:
|
|
53
|
+
router = normalize_capability_router(None)
|
|
54
|
+
assert tuple(key for key in RETRIEVAL_INTENTS if router.get(key)) == RETRIEVAL_INTENTS
|
|
55
|
+
with pytest.raises(AdapterMiddlewareError, match="Optional tool"):
|
|
56
|
+
normalize_capability_router({"codegraph": True})
|
|
@@ -25,6 +25,8 @@ from common.task_dependencies import (
|
|
|
25
25
|
read_depends_mode,
|
|
26
26
|
)
|
|
27
27
|
from common.task_gates import validate_start_execution, validate_start_execution_check
|
|
28
|
+
from common import kernel_command as kernel_command_mod
|
|
29
|
+
from common.test_kernel_command import FAKE_KERNEL
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
# =============================================================================
|
|
@@ -69,6 +71,13 @@ def sandbox(tmp_path, monkeypatch):
|
|
|
69
71
|
tasks_dir.mkdir(parents=True)
|
|
70
72
|
monkeypatch.setattr("common.task_dependencies.get_repo_root", lambda: repo)
|
|
71
73
|
monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
|
|
74
|
+
script = tmp_path / "fake_kernel.py"
|
|
75
|
+
script.write_text(FAKE_KERNEL, encoding="utf-8")
|
|
76
|
+
monkeypatch.setattr(
|
|
77
|
+
kernel_command_mod,
|
|
78
|
+
"kernel_cli_argv",
|
|
79
|
+
lambda: [sys.executable, str(script)],
|
|
80
|
+
)
|
|
72
81
|
return repo, tasks_dir
|
|
73
82
|
|
|
74
83
|
|