@blxzer/cursor-trellis 0.4.2 → 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 +24 -0
- package/README.md +23 -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 +137 -40
- 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 +2 -4
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +9 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +13 -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-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 +5 -4
- 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/cursor/agents/cstl-research.md +1 -1
- 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 +15 -10
- package/dist/templates/markdown/framework/cursor-native-modes-guide.md.txt +12 -9
- package/dist/templates/markdown/framework/cursor-subagent-policy.md.txt +62 -126
- package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +4 -6
- package/dist/templates/markdown/framework/execution-strategy.md.txt +2 -0
- package/dist/templates/markdown/framework/index.md.txt +4 -0
- package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +4 -3
- 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/release-boundary.md.txt +30 -0
- package/dist/templates/markdown/framework/retrieval-daily-guide.md.txt +1 -1
- package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
- package/dist/templates/markdown/index.d.ts +4 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +17 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/guides/index.md.txt +0 -6
- 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 +18 -1
- package/dist/templates/trellis/CONTEXT.md +63 -3
- 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 +286 -56
- 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_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/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 +100 -18
- 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/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/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
|
@@ -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,
|
|
@@ -345,6 +357,35 @@ def _default_prd_content(
|
|
|
345
357
|
return default_prd_content(title, description, locale, root)
|
|
346
358
|
|
|
347
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
|
+
|
|
348
389
|
# =============================================================================
|
|
349
390
|
# Command: create
|
|
350
391
|
# =============================================================================
|
|
@@ -445,7 +486,33 @@ def cmd_create(args: argparse.Namespace) -> int:
|
|
|
445
486
|
"meta": {},
|
|
446
487
|
}
|
|
447
488
|
|
|
448
|
-
|
|
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
|
|
449
516
|
|
|
450
517
|
prd_path = task_dir / "prd.md"
|
|
451
518
|
if not prd_path.exists():
|
|
@@ -473,39 +540,35 @@ def cmd_create(args: argparse.Namespace) -> int:
|
|
|
473
540
|
_write_seed_jsonl(jsonl_path, repo_root, task_dir, task_data)
|
|
474
541
|
seeded_jsonl = True
|
|
475
542
|
|
|
476
|
-
# Handle --parent:
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if not
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
list(parent_data.get("children", [])),
|
|
499
|
-
f"Linked Child `{dir_name}`.",
|
|
500
|
-
)
|
|
501
|
-
|
|
502
|
-
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)
|
|
503
565
|
|
|
504
566
|
print(colored(f"Created task: {dir_name}", Colors.GREEN), file=sys.stderr)
|
|
505
567
|
print("", file=sys.stderr)
|
|
506
568
|
print(colored("Next steps:", Colors.BLUE), file=sys.stderr)
|
|
507
569
|
print(" - Fill prd.md with requirements and acceptance criteria", file=sys.stderr)
|
|
508
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)
|
|
509
572
|
print(" - Lightweight task: PRD-only is valid", file=sys.stderr)
|
|
510
573
|
print(" - Complex task: add design.md and implement.md before task.py start-execution --check", file=sys.stderr)
|
|
511
574
|
if seeded_jsonl:
|
|
@@ -636,7 +699,21 @@ def _archive_one_task(
|
|
|
636
699
|
write_gate_record(data, "full-task-complete", BASELINE_GATE, guard.baseline_record)
|
|
637
700
|
data["status"] = "completed"
|
|
638
701
|
data["completedAt"] = today
|
|
639
|
-
|
|
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
|
|
640
717
|
|
|
641
718
|
task_children = data.get("children", [])
|
|
642
719
|
if task_children:
|
|
@@ -648,14 +725,32 @@ def _archive_one_task(
|
|
|
648
725
|
child_data = read_json(child_json)
|
|
649
726
|
if child_data:
|
|
650
727
|
child_data["parent"] = None
|
|
651
|
-
|
|
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
|
|
652
736
|
modified_children.append(child_dir_path.name)
|
|
653
737
|
|
|
654
738
|
from .active_task import clear_task_from_sessions
|
|
655
739
|
|
|
740
|
+
profile = task_closeout_profile(task_dir, task_data) if task_data else "lite"
|
|
656
741
|
clear_task_from_sessions(str(task_dir), repo_root)
|
|
657
742
|
result = archive_task_complete(task_dir, repo_root)
|
|
658
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}"
|
|
659
754
|
return False, modified_children, None
|
|
660
755
|
|
|
661
756
|
archive_dest = Path(result["archived_to"])
|
|
@@ -667,15 +762,25 @@ def _archive_one_task(
|
|
|
667
762
|
|
|
668
763
|
if not no_commit:
|
|
669
764
|
if not _auto_commit_archive(dir_name, repo_root, modified_children):
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
|
679
784
|
|
|
680
785
|
rel = f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}/{year_month}/{dir_name}"
|
|
681
786
|
archived_json = archive_dest / FILE_TASK_JSON
|
|
@@ -858,6 +963,14 @@ def _auto_commit_archive(
|
|
|
858
963
|
set to ``false``, this function returns immediately without
|
|
859
964
|
touching git (the archive directory move on disk is unaffected).
|
|
860
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
|
+
|
|
861
974
|
if not get_session_auto_commit(repo_root):
|
|
862
975
|
print(
|
|
863
976
|
"[OK] session_auto_commit: false — skipping git stage/commit.",
|
|
@@ -967,9 +1080,49 @@ def cmd_add_subtask(args: argparse.Namespace) -> int:
|
|
|
967
1080
|
# Set parent in child's task.json
|
|
968
1081
|
child_data["parent"] = parent_dir.name
|
|
969
1082
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
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
|
|
973
1126
|
ensure_task_map(
|
|
974
1127
|
parent_dir,
|
|
975
1128
|
parent_data,
|
|
@@ -1020,9 +1173,41 @@ def cmd_remove_subtask(args: argparse.Namespace) -> int:
|
|
|
1020
1173
|
# Clear parent in child's task.json
|
|
1021
1174
|
child_data["parent"] = None
|
|
1022
1175
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
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
|
|
1026
1211
|
remove_child_from_task_map(parent_dir, parent_data, child_dir_name)
|
|
1027
1212
|
|
|
1028
1213
|
print(colored(f"Unlinked: {child_dir.name} from {parent_dir.name}", Colors.GREEN), file=sys.stderr)
|
|
@@ -1108,7 +1293,14 @@ def cmd_prepare_child_worktree(args: argparse.Namespace) -> int:
|
|
|
1108
1293
|
|
|
1109
1294
|
child_data["branch"] = branch
|
|
1110
1295
|
child_data["worktree_path"] = worktree_rel
|
|
1111
|
-
|
|
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
|
|
1112
1304
|
|
|
1113
1305
|
ok, map_errors = record_child_worktree(
|
|
1114
1306
|
parent_dir,
|
|
@@ -1147,7 +1339,7 @@ def append_depends_ignore_event(
|
|
|
1147
1339
|
"""Append a depends-ignore audit event to meta.depends_ignore_events.
|
|
1148
1340
|
|
|
1149
1341
|
Mutates task_data in memory; the caller persists it in the SAME
|
|
1150
|
-
|
|
1342
|
+
Kernel patch as the mutation it accompanies (execution approval / child
|
|
1151
1343
|
state), so the event can never dangle as a separate stale write. The
|
|
1152
1344
|
list is capped at MAX_IGNORE_EVENTS (FIFO drops the oldest entry).
|
|
1153
1345
|
"""
|
|
@@ -1236,8 +1428,13 @@ def _guard_child_working_deps(
|
|
|
1236
1428
|
evidence=args.evidence,
|
|
1237
1429
|
reason=getattr(args, "reason", None),
|
|
1238
1430
|
)
|
|
1239
|
-
|
|
1240
|
-
|
|
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
|
+
):
|
|
1241
1438
|
print(
|
|
1242
1439
|
colored("Error: failed to write task.json (ignore event)", Colors.RED),
|
|
1243
1440
|
file=sys.stderr,
|
|
@@ -1772,7 +1969,14 @@ def cmd_set_branch(args: argparse.Namespace) -> int:
|
|
|
1772
1969
|
return 1
|
|
1773
1970
|
|
|
1774
1971
|
data["branch"] = branch
|
|
1775
|
-
|
|
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
|
|
1776
1980
|
|
|
1777
1981
|
print(colored(f"✓ Branch set to: {branch}", Colors.GREEN))
|
|
1778
1982
|
return 0
|
|
@@ -1806,7 +2010,14 @@ def cmd_set_base_branch(args: argparse.Namespace) -> int:
|
|
|
1806
2010
|
return 1
|
|
1807
2011
|
|
|
1808
2012
|
data["base_branch"] = base_branch
|
|
1809
|
-
|
|
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
|
|
1810
2021
|
|
|
1811
2022
|
print(colored(f"✓ Base branch set to: {base_branch}", Colors.GREEN))
|
|
1812
2023
|
print(f" PR will target: {base_branch}")
|
|
@@ -1838,7 +2049,14 @@ def cmd_set_scope(args: argparse.Namespace) -> int:
|
|
|
1838
2049
|
return 1
|
|
1839
2050
|
|
|
1840
2051
|
data["scope"] = scope
|
|
1841
|
-
|
|
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
|
|
1842
2060
|
|
|
1843
2061
|
print(colored(f"✓ Scope set to: {scope}", Colors.GREEN))
|
|
1844
2062
|
return 0
|
|
@@ -1880,7 +2098,13 @@ def cmd_set_deps(args: argparse.Namespace) -> int:
|
|
|
1880
2098
|
if resolve_dep_ref(ref, repo_root=repo_root).kind == KIND_MISSING
|
|
1881
2099
|
]
|
|
1882
2100
|
|
|
1883
|
-
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
|
+
):
|
|
1884
2108
|
print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
|
|
1885
2109
|
return 1
|
|
1886
2110
|
|
|
@@ -1950,7 +2174,13 @@ def cmd_set_depends_mode(args: argparse.Namespace) -> int:
|
|
|
1950
2174
|
data["meta"] = meta
|
|
1951
2175
|
meta["depends_mode"] = args.mode
|
|
1952
2176
|
|
|
1953
|
-
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
|
+
):
|
|
1954
2184
|
print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
|
|
1955
2185
|
return 1
|
|
1956
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
|
|