@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
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Stage 3 Personal Lite: no-Git Close, dual surfaces, budgeted context pack."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
14
|
+
|
|
15
|
+
from common import kernel_command as kernel_command_mod
|
|
16
|
+
from common.kernel_command import kernel_start, kernel_expected_revision
|
|
17
|
+
from common.lite_context import (
|
|
18
|
+
LITE_BASELINE_MODULES,
|
|
19
|
+
LITE_PACK_SOURCE,
|
|
20
|
+
LiteContextPackError,
|
|
21
|
+
build_lite_context_pack,
|
|
22
|
+
)
|
|
23
|
+
from common.task_gates import validate_archive, validate_start_execution_check
|
|
24
|
+
from common.task_store import cmd_archive, cmd_create
|
|
25
|
+
from common.test_kernel_command import FAKE_KERNEL, _record
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
LITE_VERIFY = """# Verification Evidence
|
|
29
|
+
|
|
30
|
+
- validation: python -c "print('ok')"
|
|
31
|
+
- acceptance: Lite path completed without Parent or Git
|
|
32
|
+
- durable learning: no durable learning
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
PLACEHOLDER_VERIFY = """# Verification Evidence
|
|
36
|
+
|
|
37
|
+
- validation: TBD
|
|
38
|
+
- acceptance: TODO
|
|
39
|
+
- durable learning: TBD
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.fixture
|
|
44
|
+
def lite_repo(tmp_path, monkeypatch):
|
|
45
|
+
repo = tmp_path / "repo"
|
|
46
|
+
(repo / ".cstl" / "tasks").mkdir(parents=True)
|
|
47
|
+
(repo / ".cstl" / ".developer").write_text("tester\n", encoding="utf-8")
|
|
48
|
+
script = tmp_path / "fake_kernel.py"
|
|
49
|
+
script.write_text(FAKE_KERNEL, encoding="utf-8")
|
|
50
|
+
monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
|
|
51
|
+
monkeypatch.setattr("common.task_store.get_developer", lambda _repo=None: "tester")
|
|
52
|
+
monkeypatch.setattr("common.task_store.is_monorepo", lambda _repo: False)
|
|
53
|
+
monkeypatch.setattr("common.task_store._has_subagent_platform", lambda _repo: False)
|
|
54
|
+
monkeypatch.setattr("common.paths.get_repo_root", lambda: repo)
|
|
55
|
+
monkeypatch.setattr("common.artifact_locale.get_repo_root", lambda: repo)
|
|
56
|
+
monkeypatch.setattr(
|
|
57
|
+
kernel_command_mod,
|
|
58
|
+
"kernel_cli_argv",
|
|
59
|
+
lambda: [sys.executable, str(script)],
|
|
60
|
+
)
|
|
61
|
+
assert not (repo / ".git").exists()
|
|
62
|
+
return repo
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _only_task_dir(repo: Path) -> Path:
|
|
66
|
+
tasks = [
|
|
67
|
+
p
|
|
68
|
+
for p in (repo / ".cstl" / "tasks").iterdir()
|
|
69
|
+
if p.is_dir() and p.name != "archive"
|
|
70
|
+
]
|
|
71
|
+
assert len(tasks) == 1
|
|
72
|
+
return tasks[0]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_lite_context_pack_budget_and_exclusions() -> None:
|
|
76
|
+
pack = build_lite_context_pack(
|
|
77
|
+
phase="verify",
|
|
78
|
+
artifacts=[
|
|
79
|
+
{
|
|
80
|
+
"role": "definition",
|
|
81
|
+
"path": "prd.md",
|
|
82
|
+
"content": "# Lite\n\n## Acceptance Criteria\n\n- [x] Close without Git\n",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"role": "evidence",
|
|
86
|
+
"path": "verify.md",
|
|
87
|
+
"content": "- validation: core test\n- acceptance: done\n",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
)
|
|
91
|
+
assert pack["source"] == LITE_PACK_SOURCE
|
|
92
|
+
assert pack["modules"]["baseline"] == list(LITE_BASELINE_MODULES)
|
|
93
|
+
assert pack["budget"]["estimatedTokens"] <= pack["budget"]["maxEstimatedTokens"]
|
|
94
|
+
assert any(item["role"] == "retrieval-router" for item in pack["selected"])
|
|
95
|
+
assert not any(
|
|
96
|
+
item["module"]
|
|
97
|
+
in (
|
|
98
|
+
"parent-child",
|
|
99
|
+
"vcs-integration",
|
|
100
|
+
"personal-memory",
|
|
101
|
+
"retention-storage",
|
|
102
|
+
"retrieval-extended",
|
|
103
|
+
)
|
|
104
|
+
for item in pack["selected"]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
with pytest.raises(LiteContextPackError) as dump:
|
|
108
|
+
build_lite_context_pack(phase="define", include_full_workflow=True)
|
|
109
|
+
assert dump.value.code == "WORKFLOW_DUMP"
|
|
110
|
+
|
|
111
|
+
with pytest.raises(LiteContextPackError) as parent:
|
|
112
|
+
build_lite_context_pack(phase="execute", activated_modules=["parent-child"])
|
|
113
|
+
assert parent.value.code == "ON_DEMAND_INACTIVE"
|
|
114
|
+
|
|
115
|
+
tight = build_lite_context_pack(
|
|
116
|
+
phase="verify",
|
|
117
|
+
max_items=1,
|
|
118
|
+
max_estimated_tokens=80,
|
|
119
|
+
artifacts=[
|
|
120
|
+
{"role": "definition", "path": "prd.md", "content": "x" * 400},
|
|
121
|
+
{"role": "evidence", "path": "verify.md", "content": "y" * 400},
|
|
122
|
+
],
|
|
123
|
+
)
|
|
124
|
+
assert tight["budget"]["itemsUsed"] == 1
|
|
125
|
+
assert tight["omitted"]
|
|
126
|
+
assert "budget limits caused Lite pack omission" in tight["warnings"]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_create_start_check_and_no_git_archive(lite_repo: Path) -> None:
|
|
130
|
+
rc = cmd_create(
|
|
131
|
+
argparse.Namespace(
|
|
132
|
+
title="Personal Lite Slice",
|
|
133
|
+
slug="personal-lite-slice",
|
|
134
|
+
description="no parent no git",
|
|
135
|
+
assignee="tester",
|
|
136
|
+
priority="P2",
|
|
137
|
+
parent=None,
|
|
138
|
+
package=None,
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
assert rc == 0
|
|
142
|
+
task_dir = _only_task_dir(lite_repo)
|
|
143
|
+
assert (task_dir / "prd.md").is_file()
|
|
144
|
+
assert (task_dir / "verify.md").is_file()
|
|
145
|
+
assert not (task_dir / "task-map.md").is_file()
|
|
146
|
+
data = json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
|
|
147
|
+
assert data["status"] == "planning"
|
|
148
|
+
assert data["parent"] is None
|
|
149
|
+
assert data["children"] == []
|
|
150
|
+
|
|
151
|
+
check = validate_start_execution_check(task_dir, data)
|
|
152
|
+
assert check.ok
|
|
153
|
+
assert data.get("execution_approval") is None
|
|
154
|
+
|
|
155
|
+
(task_dir / "verify.md").write_text(PLACEHOLDER_VERIFY, encoding="utf-8")
|
|
156
|
+
fake = validate_archive(task_dir, data)
|
|
157
|
+
assert not fake.ok
|
|
158
|
+
assert any("verify.md" in err for err in fake.errors)
|
|
159
|
+
|
|
160
|
+
(task_dir / "verify.md").write_text(LITE_VERIFY, encoding="utf-8")
|
|
161
|
+
started = kernel_start(
|
|
162
|
+
task_dir,
|
|
163
|
+
_record(
|
|
164
|
+
id=data["id"],
|
|
165
|
+
name=data["name"],
|
|
166
|
+
title=data["title"],
|
|
167
|
+
status="in_progress",
|
|
168
|
+
),
|
|
169
|
+
{"execution_approval": {"approved_by": "user"}},
|
|
170
|
+
expected_revision=kernel_expected_revision(task_dir),
|
|
171
|
+
actor="task.py start-execution --approved",
|
|
172
|
+
idempotency_key="start:personal-lite-slice",
|
|
173
|
+
)
|
|
174
|
+
assert started["legacy"]["status"] == "in_progress"
|
|
175
|
+
|
|
176
|
+
rc = cmd_archive(
|
|
177
|
+
argparse.Namespace(
|
|
178
|
+
name=task_dir.name,
|
|
179
|
+
check=False,
|
|
180
|
+
no_commit=False,
|
|
181
|
+
archive_integrated_children=False,
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
assert rc == 0
|
|
185
|
+
assert not (lite_repo / ".git").exists()
|
|
186
|
+
archived_root = lite_repo / ".cstl" / "tasks" / "archive"
|
|
187
|
+
archived = list(archived_root.rglob("task.json")) if archived_root.is_dir() else []
|
|
188
|
+
assert archived, "Lite Close should still move or keep Outcome on disk"
|
|
189
|
+
closed = json.loads(archived[0].read_text(encoding="utf-8"))
|
|
190
|
+
assert closed["status"] == "completed"
|
|
@@ -32,8 +32,11 @@ def test_write_seed_jsonl_uses_real_spec_paths(tmp_path: Path) -> None:
|
|
|
32
32
|
repo_root = tmp_path / "repo"
|
|
33
33
|
spec_root = repo_root / ".cstl" / "spec" / "guides"
|
|
34
34
|
spec_root.mkdir(parents=True)
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
(spec_root / "index.md").write_text("# index.md\n", encoding="utf-8")
|
|
36
|
+
framework_root = repo_root / ".cstl" / "framework"
|
|
37
|
+
framework_root.mkdir(parents=True)
|
|
38
|
+
for name in ("verification-strength-guide.md", "injection-budget-guide.md"):
|
|
39
|
+
(framework_root / name).write_text(f"# {name}\n", encoding="utf-8")
|
|
37
40
|
|
|
38
41
|
task_dir = repo_root / ".cstl" / "tasks" / "08-07-test-seed"
|
|
39
42
|
task_dir.mkdir(parents=True)
|
|
@@ -44,7 +47,8 @@ def test_write_seed_jsonl_uses_real_spec_paths(tmp_path: Path) -> None:
|
|
|
44
47
|
|
|
45
48
|
rows = [json.loads(line) for line in jsonl_path.read_text(encoding="utf-8").splitlines() if line.strip()]
|
|
46
49
|
assert len(rows) >= 2
|
|
47
|
-
assert all("file" in row
|
|
50
|
+
assert all("file" in row for row in rows)
|
|
51
|
+
assert all(row["file"].startswith(".cstl/spec/") or row["file"].startswith(".cstl/framework/") for row in rows)
|
|
48
52
|
assert all("_example" not in row for row in rows)
|
|
49
53
|
for row in rows:
|
|
50
54
|
assert (repo_root / row["file"]).is_file()
|
|
@@ -55,7 +59,9 @@ def test_resolve_seed_spec_paths_prefers_existing_guides(tmp_path: Path) -> None
|
|
|
55
59
|
guides = repo_root / ".cstl" / "spec" / "guides"
|
|
56
60
|
guides.mkdir(parents=True)
|
|
57
61
|
(guides / "index.md").write_text("# index\n", encoding="utf-8")
|
|
58
|
-
|
|
62
|
+
framework_root = repo_root / ".cstl" / "framework"
|
|
63
|
+
framework_root.mkdir(parents=True)
|
|
64
|
+
(framework_root / "verification-strength-guide.md").write_text("# verify\n", encoding="utf-8")
|
|
59
65
|
|
|
60
66
|
task_dir = repo_root / ".cstl" / "tasks" / "08-07-test-paths"
|
|
61
67
|
task_dir.mkdir(parents=True)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Stage 5 Topology / On-demand 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.ondemand_topology import (
|
|
14
|
+
ONDEMAND_OWNERS,
|
|
15
|
+
STAGE5_ONDEMAND_MODULES,
|
|
16
|
+
TopologyError,
|
|
17
|
+
apply_kernel_graph_projection,
|
|
18
|
+
apply_retention,
|
|
19
|
+
assert_integration_authority,
|
|
20
|
+
assign_parent,
|
|
21
|
+
capture_candidate,
|
|
22
|
+
confirm_decompose,
|
|
23
|
+
default_topology,
|
|
24
|
+
expand_depends_on_to_requires,
|
|
25
|
+
project_task_map_graph,
|
|
26
|
+
propose_decompose,
|
|
27
|
+
resident_on_demand_modules,
|
|
28
|
+
unmet_requires,
|
|
29
|
+
)
|
|
30
|
+
from common.task_map import ensure_task_map
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_capture_and_decompose_do_not_create() -> None:
|
|
34
|
+
candidate = capture_candidate("later")
|
|
35
|
+
assert candidate["task_created"] is False
|
|
36
|
+
proposal = propose_decompose("parent-a", ["child-a"])
|
|
37
|
+
assert proposal["confirmed"] is False
|
|
38
|
+
assert proposal["children_created"] == []
|
|
39
|
+
confirmed = confirm_decompose(proposal)
|
|
40
|
+
assert confirmed["confirmed"] is True
|
|
41
|
+
assert confirmed["children_created"] == ["child-a"]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_default_topology_parent_id_alone_is_single() -> None:
|
|
45
|
+
linked = default_topology(parent="parent-a", children=[])
|
|
46
|
+
assert linked["kind"] == "single"
|
|
47
|
+
assert linked["parent_id"] == "parent-a"
|
|
48
|
+
controller = default_topology(parent=None, children=["child-a"])
|
|
49
|
+
assert controller["kind"] == "parent-child"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_assign_parent_keeps_ordinary_child_single() -> None:
|
|
53
|
+
linked = assign_parent({"parent_id": None, "children": []}, "parent-a")
|
|
54
|
+
assert linked["kind"] == "single"
|
|
55
|
+
assert linked["parent_id"] == "parent-a"
|
|
56
|
+
nested = assign_parent({"parent_id": None, "children": ["child-a"]}, "grand")
|
|
57
|
+
assert nested["kind"] == "parent-child"
|
|
58
|
+
assert nested["children"] == ["child-a"]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_second_parent_and_child_integrate_rejected() -> None:
|
|
62
|
+
topology = {"parent_id": "parent-a", "children": []}
|
|
63
|
+
with pytest.raises(TopologyError, match="second parent"):
|
|
64
|
+
assign_parent(topology, "parent-b")
|
|
65
|
+
with pytest.raises(TopologyError, match="Integration authority"):
|
|
66
|
+
assert_integration_authority("child")
|
|
67
|
+
assert_integration_authority("parent")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_requires_blocks_advisory_does_not() -> None:
|
|
71
|
+
graph = expand_depends_on_to_requires(
|
|
72
|
+
{"edges": [{"from": "here", "to": "hint", "type": "advisory"}]},
|
|
73
|
+
"here",
|
|
74
|
+
["upstream"],
|
|
75
|
+
)
|
|
76
|
+
assert unmet_requires(graph, [], from_id="here") == ["upstream"]
|
|
77
|
+
assert unmet_requires(graph, ["upstream"], from_id="here") == []
|
|
78
|
+
assert unmet_requires(graph, [], from_id="other") == []
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_task_map_is_kernel_graph_projection(tmp_path: Path) -> None:
|
|
82
|
+
parent_dir = tmp_path / "parent"
|
|
83
|
+
parent_dir.mkdir()
|
|
84
|
+
extras = {
|
|
85
|
+
"topology": {
|
|
86
|
+
"kind": "parent-child",
|
|
87
|
+
"parent_id": "parent-a",
|
|
88
|
+
"children": ["child-a"],
|
|
89
|
+
},
|
|
90
|
+
"dependency_graph": {
|
|
91
|
+
"edges": [{"from": "child-a", "to": "upstream", "type": "requires"}],
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
projection = project_task_map_graph(extras["topology"], extras["dependency_graph"])
|
|
95
|
+
assert projection["graph_authority"] == "kernel-extras"
|
|
96
|
+
assert projection["children"] == [{"id": "child-a", "depends_on": ["upstream"]}]
|
|
97
|
+
|
|
98
|
+
data = ensure_task_map(
|
|
99
|
+
parent_dir,
|
|
100
|
+
{"id": "parent-a", **extras},
|
|
101
|
+
["child-a"],
|
|
102
|
+
)
|
|
103
|
+
assert data["graph_authority"] == "kernel-extras"
|
|
104
|
+
assert data["topology_kind"] == "parent-child"
|
|
105
|
+
child = next(item for item in data["children"] if item["id"] == "child-a")
|
|
106
|
+
assert child["depends_on"] == ["upstream"]
|
|
107
|
+
apply_kernel_graph_projection(data, extras)
|
|
108
|
+
assert data["graph_authority"] == "kernel-extras"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_ondemand_defaults_and_retention_outcome() -> None:
|
|
112
|
+
extras = {
|
|
113
|
+
"ondemand_modules": {
|
|
114
|
+
"registered": list(STAGE5_ONDEMAND_MODULES),
|
|
115
|
+
"active": [],
|
|
116
|
+
"owners": dict(ONDEMAND_OWNERS),
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
assert resident_on_demand_modules(extras) == []
|
|
120
|
+
assert ONDEMAND_OWNERS["integration-handoff"] == "parent-child"
|
|
121
|
+
assert ONDEMAND_OWNERS["session-transfer"] == "session-transfer"
|
|
122
|
+
assert apply_retention("completed") == "completed"
|
|
@@ -11,6 +11,7 @@ import pytest
|
|
|
11
11
|
|
|
12
12
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
13
13
|
|
|
14
|
+
from common import kernel_command as kernel_command_mod
|
|
14
15
|
from common.pool_store import (
|
|
15
16
|
check_plan,
|
|
16
17
|
find_item_path,
|
|
@@ -26,6 +27,19 @@ from common.pool_store import (
|
|
|
26
27
|
validate_pool,
|
|
27
28
|
write_item_frontmatter,
|
|
28
29
|
)
|
|
30
|
+
from common.test_kernel_command import FAKE_KERNEL
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(autouse=True)
|
|
34
|
+
def fake_kernel(tmp_path, monkeypatch):
|
|
35
|
+
script = tmp_path / "fake_kernel.py"
|
|
36
|
+
script.write_text(FAKE_KERNEL, encoding="utf-8")
|
|
37
|
+
monkeypatch.setattr(
|
|
38
|
+
kernel_command_mod,
|
|
39
|
+
"kernel_cli_argv",
|
|
40
|
+
lambda: [sys.executable, str(script)],
|
|
41
|
+
)
|
|
42
|
+
return script
|
|
29
43
|
|
|
30
44
|
ITEM_TEMPLATE = """\
|
|
31
45
|
---
|
|
@@ -205,6 +219,9 @@ def test_link_item_task_writes_both_sides_idempotent(tmp_path: Path) -> None:
|
|
|
205
219
|
assert get_linked_tasks(item) == ["08-09-some-task"]
|
|
206
220
|
data = json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
|
|
207
221
|
assert get_pool_items(data) == ["P01"]
|
|
222
|
+
kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
223
|
+
assert kernel["revision"] >= 1
|
|
224
|
+
assert kernel["audit"][-1]["idempotencyKey"].startswith("patch:pool-link:")
|
|
208
225
|
|
|
209
226
|
second = link_item_task(repo, "P01", "08-09-some-task")
|
|
210
227
|
assert second.ok
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Parent-Child / VCS task.json writers go through Kernel patch."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
14
|
+
|
|
15
|
+
from common import kernel_command as kernel_command_mod
|
|
16
|
+
from common.kernel_command import KernelCliNotFound
|
|
17
|
+
from common.task_store import (
|
|
18
|
+
cmd_add_subtask,
|
|
19
|
+
cmd_remove_subtask,
|
|
20
|
+
cmd_set_base_branch,
|
|
21
|
+
cmd_set_branch,
|
|
22
|
+
cmd_set_depends_mode,
|
|
23
|
+
cmd_set_deps,
|
|
24
|
+
cmd_set_scope,
|
|
25
|
+
)
|
|
26
|
+
from common.test_kernel_command import FAKE_KERNEL
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _write_task(tasks_dir: Path, dir_name: str, **fields) -> Path:
|
|
30
|
+
task_dir = tasks_dir / dir_name
|
|
31
|
+
task_dir.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
data = {
|
|
33
|
+
"id": dir_name,
|
|
34
|
+
"name": dir_name,
|
|
35
|
+
"title": dir_name,
|
|
36
|
+
"status": "planning",
|
|
37
|
+
"children": [],
|
|
38
|
+
"parent": None,
|
|
39
|
+
"meta": {},
|
|
40
|
+
}
|
|
41
|
+
data.update(fields)
|
|
42
|
+
(task_dir / "task.json").write_text(
|
|
43
|
+
json.dumps(data, indent=2, ensure_ascii=False),
|
|
44
|
+
encoding="utf-8",
|
|
45
|
+
)
|
|
46
|
+
return task_dir
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _read(task_dir: Path) -> dict:
|
|
50
|
+
return json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.fixture
|
|
54
|
+
def sandbox(tmp_path, monkeypatch):
|
|
55
|
+
repo = tmp_path / "repo"
|
|
56
|
+
tasks_dir = repo / ".cstl" / "tasks"
|
|
57
|
+
tasks_dir.mkdir(parents=True)
|
|
58
|
+
monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
|
|
59
|
+
monkeypatch.setattr("common.task_dependencies.get_repo_root", lambda: repo)
|
|
60
|
+
script = tmp_path / "fake_kernel.py"
|
|
61
|
+
script.write_text(FAKE_KERNEL, encoding="utf-8")
|
|
62
|
+
monkeypatch.setattr(
|
|
63
|
+
kernel_command_mod,
|
|
64
|
+
"kernel_cli_argv",
|
|
65
|
+
lambda: [sys.executable, str(script)],
|
|
66
|
+
)
|
|
67
|
+
return repo, tasks_dir
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_add_and_remove_subtask_go_through_kernel(sandbox) -> None:
|
|
71
|
+
_repo, tasks_dir = sandbox
|
|
72
|
+
parent_dir = _write_task(tasks_dir, "parent-x")
|
|
73
|
+
child_dir = _write_task(tasks_dir, "child-a")
|
|
74
|
+
|
|
75
|
+
rc = cmd_add_subtask(
|
|
76
|
+
argparse.Namespace(parent_dir="parent-x", child_dir="child-a")
|
|
77
|
+
)
|
|
78
|
+
assert rc == 0
|
|
79
|
+
|
|
80
|
+
parent = _read(parent_dir)
|
|
81
|
+
child = _read(child_dir)
|
|
82
|
+
assert parent["children"] == ["child-a"]
|
|
83
|
+
assert child["parent"] == "parent-x"
|
|
84
|
+
assert parent["status"] == "planning"
|
|
85
|
+
assert child["status"] == "planning"
|
|
86
|
+
assert (parent_dir / "kernel.json").is_file()
|
|
87
|
+
assert (child_dir / "kernel.json").is_file()
|
|
88
|
+
parent_kernel = json.loads((parent_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
89
|
+
child_kernel = json.loads((child_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
90
|
+
assert parent_kernel["revision"] >= 1
|
|
91
|
+
assert child_kernel["revision"] >= 1
|
|
92
|
+
assert (parent_dir / "task-map.md").is_file()
|
|
93
|
+
|
|
94
|
+
rc = cmd_remove_subtask(
|
|
95
|
+
argparse.Namespace(parent_dir="parent-x", child_dir="child-a")
|
|
96
|
+
)
|
|
97
|
+
assert rc == 0
|
|
98
|
+
parent = _read(parent_dir)
|
|
99
|
+
child = _read(child_dir)
|
|
100
|
+
assert parent["children"] == []
|
|
101
|
+
assert child["parent"] is None
|
|
102
|
+
assert parent["status"] == "planning"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_set_branch_base_and_scope_go_through_kernel(sandbox) -> None:
|
|
106
|
+
_repo, tasks_dir = sandbox
|
|
107
|
+
task_dir = _write_task(tasks_dir, "task-x")
|
|
108
|
+
|
|
109
|
+
assert cmd_set_branch(argparse.Namespace(dir="task-x", branch="feat/demo")) == 0
|
|
110
|
+
data = _read(task_dir)
|
|
111
|
+
assert data["branch"] == "feat/demo"
|
|
112
|
+
assert data["status"] == "planning"
|
|
113
|
+
kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
114
|
+
assert kernel["revision"] >= 1
|
|
115
|
+
first_revision = kernel["revision"]
|
|
116
|
+
|
|
117
|
+
assert cmd_set_base_branch(
|
|
118
|
+
argparse.Namespace(dir="task-x", base_branch="feat/stage0-clean-baseline")
|
|
119
|
+
) == 0
|
|
120
|
+
data = _read(task_dir)
|
|
121
|
+
assert data["base_branch"] == "feat/stage0-clean-baseline"
|
|
122
|
+
assert data["branch"] == "feat/demo"
|
|
123
|
+
kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
124
|
+
assert kernel["revision"] > first_revision
|
|
125
|
+
|
|
126
|
+
assert cmd_set_scope(argparse.Namespace(dir="task-x", scope="cli")) == 0
|
|
127
|
+
data = _read(task_dir)
|
|
128
|
+
assert data["scope"] == "cli"
|
|
129
|
+
assert data["status"] == "planning"
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_set_deps_and_depends_mode_go_through_kernel(sandbox) -> None:
|
|
133
|
+
_repo, tasks_dir = sandbox
|
|
134
|
+
task_dir = _write_task(tasks_dir, "task-x")
|
|
135
|
+
|
|
136
|
+
assert cmd_set_deps(argparse.Namespace(dir="task-x", dep=["dep-a", "pool:P28"])) == 0
|
|
137
|
+
data = _read(task_dir)
|
|
138
|
+
assert data["depends_on"] == ["dep-a", "pool:P28"]
|
|
139
|
+
assert data["status"] == "planning"
|
|
140
|
+
kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
|
|
141
|
+
assert kernel["revision"] >= 1
|
|
142
|
+
assert kernel["audit"][-1]["idempotencyKey"].startswith("patch:set-deps:")
|
|
143
|
+
|
|
144
|
+
assert cmd_set_depends_mode(argparse.Namespace(dir="task-x", mode="block")) == 0
|
|
145
|
+
data = _read(task_dir)
|
|
146
|
+
assert data["meta"]["depends_mode"] == "block"
|
|
147
|
+
assert data["depends_on"] == ["dep-a", "pool:P28"]
|
|
148
|
+
assert data["status"] == "planning"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_set_branch_does_not_fallback_when_kernel_cli_missing(sandbox, monkeypatch) -> None:
|
|
152
|
+
_repo, tasks_dir = sandbox
|
|
153
|
+
task_dir = _write_task(tasks_dir, "task-x")
|
|
154
|
+
|
|
155
|
+
def _missing():
|
|
156
|
+
raise KernelCliNotFound("Kernel CLI not found")
|
|
157
|
+
|
|
158
|
+
monkeypatch.setattr(kernel_command_mod, "kernel_cli_argv", _missing)
|
|
159
|
+
rc = cmd_set_branch(argparse.Namespace(dir="task-x", branch="feat/demo"))
|
|
160
|
+
assert rc == 1
|
|
161
|
+
data = _read(task_dir)
|
|
162
|
+
assert "branch" not in data or data.get("branch") in (None, "")
|
|
163
|
+
assert not (task_dir / "kernel.json").is_file()
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
"""
|
|
4
4
|
Workflow Phase Extraction.
|
|
5
5
|
|
|
6
|
+
Convenience reader for the human-overview copy of `.cstl/workflow.md`.
|
|
7
|
+
That file is not the runtime SSOT — Kernel extras and `task.json` are.
|
|
8
|
+
|
|
6
9
|
Extracts step-level content from .cstl/workflow.md and optionally filters
|
|
7
10
|
platform-specific blocks.
|
|
8
11
|
|
|
@@ -85,7 +85,7 @@ Task: Call the fast-context semantic search with the query:
|
|
|
85
85
|
Report:
|
|
86
86
|
1. Whether the tool returned any results.
|
|
87
87
|
2. If so, the top file path (expected to contain something under
|
|
88
|
-
`.cstl/local/cursor2plus/` or `.cstl/
|
|
88
|
+
`.cstl/local/cursor2plus/` or `.cstl/framework/cursor-subagent-policy.md`).
|
|
89
89
|
3. The exact tool name you invoked.
|
|
90
90
|
|
|
91
91
|
Reply in this exact format:
|
|
@@ -155,8 +155,7 @@ Semantic question:
|
|
|
155
155
|
Expected answer (for verification, do NOT reveal this to the solver path):
|
|
156
156
|
the relevant logic lives in `.cstl/local/cursor2plus/patch_wpelc8.py` (the
|
|
157
157
|
`WPeLc8` function patch) and is documented in
|
|
158
|
-
`.cstl/
|
|
159
|
-
`.cstl/spec/guides/cursor-subagent-reverse-engineering-report.md`.
|
|
158
|
+
`.cstl/framework/cursor-subagent-policy.md`.
|
|
160
159
|
|
|
161
160
|
Reply in this exact format:
|
|
162
161
|
|
|
@@ -193,7 +192,7 @@ Semantic question (same as P-08 — no literal file/symbol/path clues in your qu
|
|
|
193
192
|
|
|
194
193
|
Expected (for verification only — do not paste paths into fast_context_search query):
|
|
195
194
|
Top hits should include `.cstl/local/cursor2plus/patch_wpelc8.py` and/or
|
|
196
|
-
`.cstl/
|
|
195
|
+
`.cstl/framework/cursor-subagent-policy.md`.
|
|
197
196
|
|
|
198
197
|
Reply in this exact format:
|
|
199
198
|
|
|
@@ -231,7 +230,7 @@ Semantic question (no literal clues):
|
|
|
231
230
|
Expected (for verification only): the answer should weave together
|
|
232
231
|
`.cursor/hooks/inject-retrieval-plan.py` (beforeSubmitPrompt injection),
|
|
233
232
|
`.cursor/rules/retrieval-routing.mdc` (alwaysApply policy), and the
|
|
234
|
-
`sessionStart` bug #158452 noted in `.cstl/
|
|
233
|
+
`sessionStart` bug #158452 noted in `.cstl/framework/cursor-context-injection-guide.md`.
|
|
235
234
|
|
|
236
235
|
Reply in this exact format:
|
|
237
236
|
|
|
@@ -5,6 +5,7 @@ Get Session Context for AI Agent.
|
|
|
5
5
|
Usage:
|
|
6
6
|
python3 get_context.py Output context in text format
|
|
7
7
|
python3 get_context.py --json Output context in JSON format
|
|
8
|
+
python3 get_context.py --mode lite --json Personal Lite budgeted pack
|
|
8
9
|
python3 get_context.py --mode retrieval-pack --json Output scored retrieval pack JSON
|
|
9
10
|
"""
|
|
10
11
|
|
|
@@ -101,6 +101,11 @@ def cmd_show(args: argparse.Namespace) -> int:
|
|
|
101
101
|
print(f"title: {item.title or '<missing>'}")
|
|
102
102
|
print(f"status: {item.status or '<missing>'}")
|
|
103
103
|
print(f"type: {item.type or '<missing>'}")
|
|
104
|
+
priority = item.frontmatter.get("priority")
|
|
105
|
+
if isinstance(priority, str) and priority.strip():
|
|
106
|
+
print(f"priority: {priority.strip()}")
|
|
107
|
+
else:
|
|
108
|
+
print("priority: <unlabeled>")
|
|
104
109
|
print(f"path: {item.path}")
|
|
105
110
|
if not item.linked_tasks:
|
|
106
111
|
print("linked_tasks: []")
|