kenaz 0.3.17 → 0.3.19
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/core/.claude/commands/agent-worker.md +1 -1
- package/core/.claude/commands/architect.md +1 -2
- package/core/.claude/commands/spec.md +1 -1
- package/core/.claude/commands//347/224/242/345/223/201.md +1 -1
- package/core/.claude/hooks/__tests__/task-1977-dedupe-guard.test.js +8 -8
- package/core/.claude/hooks/synapse-first-investigation.js +15 -0
- package/core/.claude/skills/architect_agent/SKILL.md +11 -92
- package/core/.claude/skills/assessment_agent/SKILL.md +0 -1
- package/core/.claude/skills/backend_engineer/SKILL.md +3 -6
- package/core/.claude/skills/code_reviewer/SKILL.md +1 -1
- package/core/.claude/skills/code_reviewer/patterns.yaml +1 -1
- package/core/.claude/skills/designer/SKILL.md +3 -6
- package/core/.claude/skills/dev_agent/SKILL.md +30 -491
- package/core/.claude/skills/developer/SKILL.md +3 -6
- package/core/.claude/skills/feature_agent/SKILL.md +3 -17
- package/core/.claude/skills/product_manager/SKILL.md +29 -1064
- package/core/.claude/skills/qa_engineer/SKILL.md +12 -17
- package/core/.claude/skills/spec_optimizer/SKILL.md +25 -275
- package/core/.claude/skills/sre_agent/SKILL.md +3 -6
- package/core/.collaboration/README.md +2 -3
- package/core/.collaboration/core/task-api.js +5 -138
- package/core/.collaboration/docs/CLI.md +0 -2
- package/core/.failure/INDEX.yaml +6 -40
- package/core/.failure/agent-execution/FAIL-013-search-cwd-drift-and-case-mismatch.yaml +1 -1
- package/core/.failure/tools/README.md +9 -227
- package/core/.formation/bifrost/exec.js +29 -4
- package/core/.formation/bifrost/launch.js +1 -6
- package/core/.formation/bifrost/launch.test.js +1 -1
- package/core/.formation/bifrost/provider-launch.js +18 -11
- package/core/.formation/bifrost/provider-launch.test.js +26 -2
- package/core/.formation/bifrost/shared/ansuz-boot-policy.js +3 -3
- package/core/.formation/bifrost/shared/ansuz-boot-policy.test.js +1 -2
- package/core/.formation/tools/__tests__/dispatch-cwd-project.test.js +42 -0
- package/core/.formation/tools/__tests__/m1-hmap-convid.test.js +1 -124
- package/core/.formation/tools/__tests__/subagent-executor.test.js +3 -2
- package/core/.formation/tools/dispatch.js +15 -2
- package/core/.formation/tools/loader.js +17 -140
- package/core/.formation/tools/post-complete.js +0 -31
- package/core/.rule/INDEX.yaml +0 -18
- package/core/.rule/general/agent-workflow.yaml +14 -164
- package/core/.rule/general/project-self-containment.yaml +8 -19
- package/core/.rule/general/rust-verify-target.yaml +6 -5
- package/core/.rule/general/synapse-code-intelligence.yaml +3 -3
- package/core/.specialist/Amelia/capability.yaml +12 -12
- package/core/.specialist/Amelia/workflow.yaml +2 -2
- package/core/.specialist/Ansuz/SYSTEM_DOC.md +20 -578
- package/core/.specialist/Ansuz/cognitive_principles.yaml +2 -3
- package/core/.specialist/Ansuz/concepts/boot_rules_summary.yaml +0 -1
- package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +1 -2
- package/core/.specialist/Ansuz/core.yaml +6 -108
- package/core/.specialist/Ansuz/guards/lesson_guards.yaml +0 -3
- package/core/.specialist/Ansuz/identity_contract.yaml +0 -1
- package/core/.specialist/Ansuz/knowledge.yaml +0 -4
- package/core/.specialist/Ansuz/rule.yaml +0 -1
- package/core/.specialist/Ansuz/tools/handoff-session-identity.test.js +6 -150
- package/core/.specialist/tests/runtime-discovery/README.md +1 -1
- package/core/.specialist/tools/__tests__/task-2374-usage-counter.test.js +1 -12
- package/core/.specialist/tools/prompt-files.test.js +1 -0
- package/core/.specialist/tools/task-bridge.js +1 -66
- package/core/.system/README.md +11 -552
- package/core/.system/collaboration/README.md +10 -174
- package/core/CLAUDE.md +1 -6
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dev/scripts/js-yaml-resolution.test.js +1 -1
- package/core/dev/scripts/run-rust-tests.js +30 -46
- package/core/dev/scripts/run-rust-tests.test.js +17 -0
- package/core/dev/scripts/rust-verify-worktree.js +4 -4
- package/core/dev/scripts/verify-target-dir.js +6 -6
- package/core/plugins/kenaz/INVENTORY.md +8 -8
- package/core/plugins/kenaz/commands/architect.md +1 -2
- package/core/plugins/kenaz/commands/spec.md +1 -1
- package/core/plugins/kenaz/commands//347/224/242/345/223/201.md +1 -1
- package/core/plugins/kenaz/guidance.md +1 -1
- package/core/plugins/kenaz/scripts/sync.js +1 -1
- package/core/plugins/kenaz/scripts/ygg.js +6 -0
- package/core/plugins/kenaz/skills/architect_agent/SKILL.md +11 -92
- package/core/plugins/kenaz/skills/assessment_agent/SKILL.md +0 -1
- package/core/plugins/kenaz/skills/backend_engineer/SKILL.md +3 -6
- package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +1 -1
- package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +1 -1
- package/core/plugins/kenaz/skills/designer/SKILL.md +3 -6
- package/core/plugins/kenaz/skills/dev_agent/SKILL.md +30 -491
- package/core/plugins/kenaz/skills/developer/SKILL.md +3 -6
- package/core/plugins/kenaz/skills/feature_agent/SKILL.md +3 -17
- package/core/plugins/kenaz/skills/product_manager/SKILL.md +29 -1064
- package/core/plugins/kenaz/skills/qa_engineer/SKILL.md +12 -17
- package/core/plugins/kenaz/skills/spec_optimizer/SKILL.md +25 -275
- package/core/plugins/kenaz/skills/sre_agent/SKILL.md +3 -6
- package/package.json +6 -6
- package/core/.claude/commands/archive.md +0 -24
- package/core/.claude/commands/init.md +0 -112
- package/core/.claude/commands/legacy_dev.md +0 -18
- package/core/.claude/commands/product-review.md +0 -131
- package/core/.claude/commands/strategy.md +0 -141
- package/core/.claude/commands/sunny.md +0 -1
- package/core/.claude/commands//347/224/242/345/223/201/346/252/242/350/246/226.md +0 -129
- package/core/.claude/commands//351/200/262/345/272/246.md +0 -15
- package/core/.claude/hooks/__tests__/substrate.test.js +0 -122
- package/core/.claude/hooks/_substrate-paths.js +0 -95
- package/core/.claude/hooks/context-check.js +0 -51
- package/core/.claude/hooks/fatigue-check.js +0 -52
- package/core/.claude/hooks/handoff-snapshot-on-commit.js +0 -154
- package/core/.claude/hooks/handoff-snapshot-on-question.js +0 -158
- package/core/.claude/hooks/handoff-staleness.js +0 -197
- package/core/.claude/hooks/jev-thalamus-context.js +0 -17
- package/core/.claude/hooks/jev-thalamus-context.test.js +0 -41
- package/core/.claude/hooks/lease-release.js +0 -119
- package/core/.claude/hooks/lease-touch.js +0 -96
- package/core/.claude/hooks/reflex-feedback.js +0 -5
- package/core/.claude/hooks/session-init.ps1 +0 -49
- package/core/.claude/hooks/sound-event.js +0 -70
- package/core/.claude/hooks/sound-event.sh +0 -37
- package/core/.claude/hooks/stream-delta.js +0 -169
- package/core/.claude/no-hooks.settings.json +0 -3
- package/core/.claude/skills/legacy_dev/SKILL.md +0 -202
- package/core/.claude/skills/sunny/SKILL.md +0 -74
- package/core/.collaboration/cli/commands/assign.js +0 -39
- package/core/.collaboration/cli/commands/claim.js +0 -33
- package/core/.collaboration/cli/commands/complete.js +0 -44
- package/core/.collaboration/cli/commands/create.js +0 -110
- package/core/.collaboration/cli/commands/get.js +0 -83
- package/core/.collaboration/cli/commands/index.js +0 -52
- package/core/.collaboration/cli/commands/list.js +0 -51
- package/core/.collaboration/cli/commands/lock.js +0 -45
- package/core/.collaboration/cli/commands/rebuild.js +0 -39
- package/core/.collaboration/cli/commands/search.js +0 -61
- package/core/.collaboration/cli/commands/stats.js +0 -61
- package/core/.collaboration/cli/commands/transfer.js +0 -41
- package/core/.collaboration/cli/commands/unlock.js +0 -48
- package/core/.collaboration/cli/formatters/help-formatter.js +0 -70
- package/core/.collaboration/cli/formatters/index.js +0 -7
- package/core/.collaboration/cli/task-cli.js +0 -46
- package/core/.collaboration/cli/utils/arg-parser.js +0 -74
- package/core/.collaboration/cli/utils/git-user.js +0 -25
- package/core/.collaboration/cli/utils/index.js +0 -9
- package/core/.collaboration/cli/utils/output.js +0 -10
- package/core/.collaboration/config/default.yaml +0 -189
- package/core/.collaboration/core/conflict-resolver.js +0 -461
- package/core/.collaboration/core/conflict-resolver.test.js +0 -389
- package/core/.collaboration/core/migrate-legacy.js +0 -260
- package/core/.collaboration/docs/API.md +0 -787
- package/core/.collaboration/docs/ARCHITECTURE.md +0 -596
- package/core/.collaboration/docs/FAQ.md +0 -695
- package/core/.collaboration/docs/MIGRATION.md +0 -804
- package/core/.collaboration/docs/examples/README.md +0 -320
- package/core/.collaboration/docs/examples/advanced-queries.js +0 -261
- package/core/.collaboration/docs/examples/basic-usage.js +0 -184
- package/core/.collaboration/docs/examples/team-workflow.js +0 -352
- package/core/.failure/agent-execution/FAIL-001-agent-no-output.yaml +0 -391
- package/core/.failure/agent-execution/FAIL-007-pm-lead-wrong-team-invocation.yaml +0 -0
- package/core/.failure/agent-execution/FAIL-010-phase0-poem-format-skipped.yaml +0 -28
- package/core/.failure/agent-execution/FAIL-010-skipping-cognitive-checkpoint-after-verification.yaml +0 -59
- package/core/.failure/agent-execution/FAIL-012-grep-shortcut-during-investigation.yaml +0 -85
- package/core/.failure/architecture/FAIL-006-python-version-compatibility.yaml +0 -445
- package/core/.failure/pipeline/FAIL-003-queue-pollution.yaml +0 -335
- package/core/.failure/pipeline/README.md +0 -95
- package/core/.failure/retired/FAIL-009-skipping-synapse-pulse-before-code-change.yaml +0 -49
- package/core/.failure/tools/USAGE_GUIDE.md +0 -323
- package/core/.failure/tools/check_failures.ps1 +0 -387
- package/core/.failure/tools/log_failure.ps1 +0 -474
- package/core/.formation/.episode-input.json +0 -10
- package/core/.formation/.merge-lock +0 -1
- package/core/.formation/lead.yaml +0 -118
- package/core/.formation/legacy.bak/designer.yaml +0 -57
- package/core/.formation/legacy.bak/pm.yaml +0 -57
- package/core/.formation/legacy.bak/qa.yaml +0 -57
- package/core/.formation/legacy.bak/review.yaml +0 -62
- package/core/.formation/legacy.bak/scheduler.yaml +0 -129
- package/core/.formation/legacy.bak/sre.yaml +0 -57
- package/core/.formation/role-map.yaml +0 -274
- package/core/.formation/roles/_shared/modules/code_review.yaml +0 -98
- package/core/.formation/roles/_shared/modules/security.yaml +0 -103
- package/core/.formation/roles/_shared/modules/testing.yaml +0 -14
- package/core/.formation/roles/backend/role.yaml +0 -93
- package/core/.formation/roles/code_reviewer/role.yaml +0 -102
- package/core/.formation/roles/database_optimizer/role.yaml +0 -107
- package/core/.formation/roles/designer/role.yaml +0 -66
- package/core/.formation/roles/developer/role.yaml +0 -75
- package/core/.formation/roles/frontend/role.yaml +0 -134
- package/core/.formation/roles/incident_response/role.yaml +0 -89
- package/core/.formation/roles/qa/role.yaml +0 -89
- package/core/.formation/roles/security/role.yaml +0 -87
- package/core/.formation/roles/sre/role.yaml +0 -66
- package/core/.formation/skills/coordinator.yaml +0 -52
- package/core/.formation/solo/diagnosis.yaml +0 -78
- package/core/.formation/solo/strategy.yaml +0 -121
- package/core/.formation/tests/hello.txt +0 -2
- package/core/.formation/tools/coordinator.js +0 -350
- package/core/.formation/tools/jev-correction.js +0 -214
- package/core/.formation/tools/jev-correction.test.js +0 -178
- package/core/.formation/tools/log-reader.js +0 -232
- package/core/.formation/tools/revert-daemon-state.js +0 -162
- package/core/.formation/tools/test-drift.js +0 -148
- package/core/.formation/unit/heimdall.yaml +0 -96
- package/core/.formation/unit/plan.yaml +0 -67
- package/core/.formation/unit/think.yaml +0 -58
- package/core/.kenaz/MUNINN_SNAPSHOT9_EPISODE.json +0 -32
- package/core/.kenaz/MUNINN_SNAPSHOT9_RUNE.json +0 -23
- package/core/.kenaz/MUNINN_SNAPSHOT9_SUMMARY.md +0 -89
- package/core/.kenaz/ash_TASK_1428-20260507.json +0 -14
- package/core/.kenaz/muninn_episode_write.ps1 +0 -17
- package/core/.kenaz/muninn_snapshot11_rune_candidates.md +0 -63
- package/core/.kenaz/muninn_snapshot1_rune_candidates.md +0 -49
- package/core/.kenaz/runes_TASK_1428.json +0 -57
- package/core/.kenaz/tmp_heimdall_proposal_8d3e392.json +0 -13
- package/core/.kenaz/tmp_props.json +0 -1
- package/core/.kenaz/tmp_sounddrop_t1_prompt.txt +0 -371
- package/core/.rule/MECHANIZED.md +0 -61
- package/core/.rule/general/cortex-memory-recall.yaml +0 -446
- package/core/.rule/general/pipeline.yaml +0 -246
- package/core/.rule/general/sunny-access-control.yaml +0 -60
- package/core/.rule/general/system-invariants.yaml +0 -231
- package/core/.rule/pipeline/PPL-002-completed-task-archival.yaml +0 -528
- package/core/.rule/pipeline/auto-update.yaml +0 -282
- package/core/.rule/pipeline/task-execution.yaml +0 -365
- package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +0 -65
- package/core/.specialist/Ansuz/experiments/boot_ablation_replay.js +0 -197
- package/core/.specialist/Ansuz/tools/bootstrap-anchors.js +0 -289
- package/core/.specialist/Ansuz/workflow.yaml +0 -1225
- package/core/.specialist/experiments/rg_benchmark.js +0 -523
- package/core/.specialist/experiments/rg_benchmark_results.json +0 -27
- package/core/.specialist/tools/jev-optional-context.js +0 -107
- package/core/.specialist/tools/jev-optional-context.test.js +0 -152
- package/core/.specialist/tools/memory-action-log.js +0 -839
- package/core/.specialist/tools/phase-gate.js +0 -3534
- package/core/.specialist/tools/phase-gate.test.js +0 -85
- package/core/.specialist/tools/precompute-runner.js +0 -444
- package/core/.specialist/tools/rule-engine.js +0 -621
- package/core/.specialist/tools/task-bridge-jev.test.js +0 -170
- package/core/.synapse/memory-shared.json.sync +0 -1
- package/core/.system/agent-skills/README.md +0 -724
- package/core/.system/cli-tools/README.md +0 -724
- package/core/.system/cortex/MODULES.md +0 -1046
- package/core/.system/dashboard/FRONTEND.md +0 -812
- package/core/.system/dashboard/README.md +0 -737
- package/core/.system/failure/README.md +0 -723
- package/core/.system/formation/LEGACY_SKILLS.md +0 -974
- package/core/.system/formation/POST_COMPLETE.md +0 -602
- package/core/.system/formation/README.md +0 -1094
- package/core/.system/formation/TOOLS_REFERENCE.md +0 -1145
- package/core/.system/kenaz/README.md +0 -787
- package/core/.system/memory/README.md +0 -719
- package/core/.system/pipeline/README.md +0 -712
- package/core/.system/rule/README.md +0 -794
- package/core/.system/sunny/README.md +0 -476
- package/core/.system/sunny/RULES.json +0 -89
- package/core/.system/sunny/knowledge/INDEX.md +0 -37
- package/core/.system/sunny/knowledge/agent-teams-api.md +0 -0
- package/core/.system/sunny/knowledge/ansuz-specialist.md +0 -500
- package/core/.system/sunny/knowledge/claude-cli-spawn.md +0 -177
- package/core/.system/sunny/knowledge/collaboration-api.md +0 -925
- package/core/.system/sunny/teammates/README.md +0 -107
- package/core/.system/sunny/teammates/how_to_use.yaml +0 -101
- package/core/.system/sunny/teammates/tools/headless/launcher.js +0 -318
- package/core/.system/sunny/teammates/tools/powershell/launcher.js +0 -241
- package/core/.system/sunny/teammates/tools/powershell/start.bat +0 -50
- package/core/.system/sunny/teammates/tools/utils/env.js +0 -96
- package/core/.system/sunny/teammates/tools/utils/format-output.js +0 -329
- package/core/.system/sunny/tools.json +0 -101
- package/core/dev/scripts/cleanup-queue.js +0 -184
- package/core/dev/scripts/cleanup_queue.js +0 -86
- package/core/dev/scripts/legacy/README.md +0 -39
- package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +0 -536
- package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +0 -1978
- package/core/dev/scripts/matrix/CLI_README.md +0 -214
- package/core/dev/scripts/matrix/README.md +0 -310
- package/core/dev/scripts/matrix/package-lock.json +0 -4266
- package/core/dev/scripts/matrix/package.json +0 -55
- package/core/dev/scripts/matrix/src/abbreviations.ts +0 -295
- package/core/dev/scripts/matrix/src/cli/commands/convert.ts +0 -211
- package/core/dev/scripts/matrix/src/cli/commands/create.ts +0 -95
- package/core/dev/scripts/matrix/src/cli/commands/delete.ts +0 -102
- package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +0 -140
- package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +0 -173
- package/core/dev/scripts/matrix/src/cli/commands/query.ts +0 -261
- package/core/dev/scripts/matrix/src/cli/commands/read.ts +0 -77
- package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +0 -168
- package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +0 -126
- package/core/dev/scripts/matrix/src/cli/commands/update.ts +0 -147
- package/core/dev/scripts/matrix/src/cli/commands/validate.ts +0 -275
- package/core/dev/scripts/matrix/src/cli/index.ts +0 -350
- package/core/dev/scripts/matrix/src/cli/utils/file-handler.ts +0 -72
- package/core/dev/scripts/matrix/src/cli/utils/logger.ts +0 -65
- package/core/dev/scripts/matrix/src/index.ts +0 -62
- package/core/dev/scripts/matrix/src/indexer/tag-indexer.ts +0 -165
- package/core/dev/scripts/matrix/src/parser.ts +0 -281
- package/core/dev/scripts/matrix/src/serializer.ts +0 -151
- package/core/dev/scripts/matrix/src/validator.ts +0 -301
- package/core/dev/scripts/matrix/tests/abbreviations.test.ts +0 -122
- package/core/dev/scripts/matrix/tests/cli.test.ts +0 -177
- package/core/dev/scripts/matrix/tests/convert.test.ts +0 -143
- package/core/dev/scripts/matrix/tests/parser.test.ts +0 -203
- package/core/dev/scripts/matrix/tests/query.test.ts +0 -85
- package/core/dev/scripts/matrix/tests/serializer.test.ts +0 -197
- package/core/dev/scripts/matrix/tests/validate.test.ts +0 -141
- package/core/dev/scripts/matrix/tests/validator.test.ts +0 -167
- package/core/dev/scripts/matrix/tsconfig.json +0 -20
- package/core/dev/scripts/matrix/types/index.d.ts +0 -111
- package/core/dev/scripts/matrix/types/index.d.ts.map +0 -1
- package/core/dev/scripts/matrix/types/index.js +0 -8
- package/core/dev/scripts/matrix/types/index.js.map +0 -1
- package/core/dev/scripts/matrix/types/index.ts +0 -124
- package/core/dev/scripts/memory-usage-report.js +0 -152
- package/core/dev/scripts/probe/ansuz-scaffold-ablation.js +0 -579
- package/core/dev/scripts/probe/ansuz-scaffold-ablation.test.js +0 -244
- package/core/dev/scripts/probe/hook-latency-probe.js +0 -315
- package/core/dev/scripts/probe/hook-latency-probe.test.js +0 -105
- package/core/dev/scripts/probe/prediction-signal-auc.js +0 -483
- package/core/dev/scripts/probe/prediction-signal-auc.test.js +0 -200
- package/core/dev/scripts/test-pty-ws-tunnel.js +0 -229
- package/core/dev/scripts/validate_pipeline.js +0 -197
- package/core/dev/spikes/task2145-evidence-20261004/backend-log-excerpt.txt +0 -56
- package/core/dev/spikes/task2145-evidence-20261004/graph.shadow +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph.wal +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph_corrupt_suspect.marker +0 -1
- package/core/plugins/kenaz/commands/strategy.md +0 -141
package/core/.failure/INDEX.yaml
CHANGED
|
@@ -41,11 +41,6 @@ categories:
|
|
|
41
41
|
description: "架構決策失敗(設計缺陷、技術選型錯誤)"
|
|
42
42
|
icon: "🏗️"
|
|
43
43
|
|
|
44
|
-
pipeline:
|
|
45
|
-
path: "pipeline/"
|
|
46
|
-
description: "Pipeline 系統失敗(任務管理、佇列、統計)"
|
|
47
|
-
icon: "⚙️"
|
|
48
|
-
|
|
49
44
|
data_integrity:
|
|
50
45
|
path: "data-integrity/"
|
|
51
46
|
description: "數據完整性問題(JSON 損壞、編碼錯誤)"
|
|
@@ -83,7 +78,7 @@ failure_template: |
|
|
|
83
78
|
|
|
84
79
|
_meta:
|
|
85
80
|
id: "FAIL-XXX"
|
|
86
|
-
category: "agent_execution | code_quality | architecture |
|
|
81
|
+
category: "agent_execution | code_quality | architecture | data_integrity"
|
|
87
82
|
severity: "critical | high | medium | low"
|
|
88
83
|
date: "YYYY-MM-DD"
|
|
89
84
|
related_tasks: ["TASK_XXX"]
|
|
@@ -118,7 +113,7 @@ failure_template: |
|
|
|
118
113
|
- [ ] 檢查項目 1
|
|
119
114
|
- [ ] 檢查項目 2
|
|
120
115
|
|
|
121
|
-
###
|
|
116
|
+
### 三級預防
|
|
122
117
|
prevention:
|
|
123
118
|
primary: "防止再發 — 架構加固、測試覆蓋、代碼重構"
|
|
124
119
|
secondary: "早期偵測 — 監控指標、日誌告警、健康檢查"
|
|
@@ -137,18 +132,10 @@ failure_template: |
|
|
|
137
132
|
# 載入順序(按嚴重程度)
|
|
138
133
|
# ============================================================
|
|
139
134
|
load_order:
|
|
140
|
-
- path: "agent-execution/FAIL-001-agent-no-output.yaml"
|
|
141
|
-
title: "Agent 執行無輸出問題"
|
|
142
|
-
severity: "critical"
|
|
143
|
-
|
|
144
135
|
- path: "data-integrity/FAIL-002-json-bom.yaml"
|
|
145
136
|
title: "JSON BOM 編碼問題"
|
|
146
137
|
severity: "high"
|
|
147
138
|
|
|
148
|
-
- path: "pipeline/FAIL-003-queue-pollution.yaml"
|
|
149
|
-
title: "TASK_QUEUE 污染問題"
|
|
150
|
-
severity: "high"
|
|
151
|
-
|
|
152
139
|
- path: "agent-execution/FAIL-004_agent_platform_specific_commands.md"
|
|
153
140
|
title: "Agent 使用平台特定命令導致失敗"
|
|
154
141
|
severity: "high"
|
|
@@ -157,18 +144,10 @@ load_order:
|
|
|
157
144
|
title: "背景 Agent 無寫入權限"
|
|
158
145
|
severity: "critical"
|
|
159
146
|
|
|
160
|
-
- path: "architecture/FAIL-006-python-version-compatibility.yaml"
|
|
161
|
-
title: "Python 3.14 依賴兼容性問題"
|
|
162
|
-
severity: "high"
|
|
163
|
-
|
|
164
147
|
- path: "agent-execution/FAIL-008-bypass-api-direct-yaml-write.yaml"
|
|
165
148
|
title: "Agent 繞過 API 直接寫 YAML 任務檔案"
|
|
166
149
|
severity: "high"
|
|
167
150
|
|
|
168
|
-
- path: "agent-execution/FAIL-010-phase0-poem-format-skipped.yaml"
|
|
169
|
-
title: "Phase 0 記憶之烏鴉歸巢段落持續缺失"
|
|
170
|
-
severity: "medium"
|
|
171
|
-
|
|
172
151
|
- path: "agent-execution/FAIL-014-shared-worktree-premature-death-verdict.yaml"
|
|
173
152
|
title: "並發 Agent worktree 共用路徑被提前清理 + 沉默誤判死亡 → 重複派工"
|
|
174
153
|
severity: "high"
|
|
@@ -178,19 +157,11 @@ load_order:
|
|
|
178
157
|
# 統計數據
|
|
179
158
|
# ============================================================
|
|
180
159
|
statistics:
|
|
181
|
-
total_failures:
|
|
160
|
+
total_failures: 5
|
|
182
161
|
by_category:
|
|
183
|
-
agent_execution:
|
|
162
|
+
agent_execution: 4
|
|
184
163
|
data_integrity: 1
|
|
185
|
-
|
|
186
|
-
architecture: 1
|
|
187
|
-
by_severity:
|
|
188
|
-
critical: 2
|
|
189
|
-
high: 5
|
|
190
|
-
medium: 1
|
|
191
|
-
low: 0
|
|
192
|
-
resolved: 7
|
|
193
|
-
converted_to_rules: 2 # 已轉化為 .rule/ 規則
|
|
164
|
+
resolved: 5
|
|
194
165
|
|
|
195
166
|
# ============================================================
|
|
196
167
|
# Agent 使用指南
|
|
@@ -220,12 +191,7 @@ system_integration:
|
|
|
220
191
|
priority_order: |
|
|
221
192
|
1. .rule/ (最高優先級 - 必須遵守的規則)
|
|
222
193
|
2. .failure/ (失敗經驗 - 應避免的模式)
|
|
223
|
-
3. .
|
|
224
|
-
4. CLAUDE.md (專案指導)
|
|
194
|
+
3. CLAUDE.md (專案指導)
|
|
225
195
|
|
|
226
196
|
workflow: |
|
|
227
197
|
失敗 → 記錄到 .failure/ → 分析根因 → 如重複發生 → 提升為 .rule/
|
|
228
|
-
|
|
229
|
-
example:
|
|
230
|
-
failure: "FAIL-003: TASK_QUEUE 被 completed 任務污染"
|
|
231
|
-
rule: "PPL-002: 已完成任務必須封存到 .memory/"
|
|
@@ -1,230 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# .failure/tools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Small Node helpers for the JSON/BOM failure pattern (`data-integrity/FAIL-002-json-bom.yaml`). All take a file or directory path.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
| Tool | Use |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `check_bom.js <file\|dir> [--recursive]` | Report files that start with a UTF-8 BOM |
|
|
8
|
+
| `remove_bom.js <file>` | Strip the BOM |
|
|
9
|
+
| `fix_json.js <file>` | Strip the BOM, validate, and reformat a JSON file |
|
|
10
|
+
| `validate_json.js <file>` | Exit non-zero if the file is not valid JSON |
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### 1. log_failure.ps1
|
|
10
|
-
自動化建立失敗記錄文件的 PowerShell 腳本。
|
|
11
|
-
|
|
12
|
-
#### 使用方式
|
|
13
|
-
```powershell
|
|
14
|
-
# 互動式建立失敗記錄
|
|
15
|
-
.\.failure\tools\log_failure.ps1
|
|
16
|
-
|
|
17
|
-
# 指定參數建立
|
|
18
|
-
.\.failure\tools\log_failure.ps1 `
|
|
19
|
-
-Category "pipeline" `
|
|
20
|
-
-Title "TASK_QUEUE 污染問題" `
|
|
21
|
-
-Severity "high" `
|
|
22
|
-
-TaskID "TASK_088"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
#### 功能
|
|
26
|
-
- 自動生成 FAIL-XXX ID(根據 INDEX.yaml 中的最大 ID)
|
|
27
|
-
- 根據分類選擇正確的目錄
|
|
28
|
-
- 使用標準模板建立 YAML 文件
|
|
29
|
-
- 自動更新 INDEX.yaml 的 load_order 和統計數據
|
|
30
|
-
- 支援互動式和參數化兩種模式
|
|
31
|
-
|
|
32
|
-
### 2. check_failures.ps1
|
|
33
|
-
檢查當前任務是否匹配已知失敗模式的腳本。
|
|
34
|
-
|
|
35
|
-
#### 使用方式
|
|
36
|
-
```powershell
|
|
37
|
-
# 檢查特定任務的失敗模式
|
|
38
|
-
.\.failure\tools\check_failures.ps1 -TaskID "TASK_077"
|
|
39
|
-
|
|
40
|
-
# 檢查特定類型的任務
|
|
41
|
-
.\.failure\tools\check_failures.ps1 -AgentType "developer"
|
|
42
|
-
|
|
43
|
-
# 檢查特定路徑的失敗模式
|
|
44
|
-
.\.failure\tools\check_failures.ps1 -ScopePath "dev/pipeline/"
|
|
45
|
-
|
|
46
|
-
# 使用關鍵詞搜尋
|
|
47
|
-
.\.failure\tools\check_failures.ps1 -Keywords "JSON,BOM,encoding"
|
|
48
|
-
|
|
49
|
-
# 過濾特定分類和嚴重程度
|
|
50
|
-
.\.failure\tools\check_failures.ps1 -Category "pipeline" -Severity "critical"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
#### 功能
|
|
54
|
-
- 根據任務 ID 自動載入 TASK_QUEUE.json 詳情
|
|
55
|
-
- 根據 agent_type 匹配相關失敗記錄
|
|
56
|
-
- 根據 scope_paths 匹配相關失敗記錄
|
|
57
|
-
- 支援關鍵詞模糊搜尋
|
|
58
|
-
- 輸出預防檢查清單和解決方案參考
|
|
59
|
-
- 按嚴重程度排序顯示結果
|
|
60
|
-
|
|
61
|
-
### 3. validate_json.js
|
|
62
|
-
驗證 JSON 文件完整性的 Node.js 腳本。
|
|
63
|
-
|
|
64
|
-
#### 使用方式
|
|
65
|
-
```bash
|
|
66
|
-
# 驗證單個文件
|
|
67
|
-
node .failure/tools/validate_json.js dev/pipeline/TASK_QUEUE.json
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
#### 功能
|
|
71
|
-
- 驗證 JSON 語法正確性
|
|
72
|
-
- 檢測 BOM (Byte Order Mark)
|
|
73
|
-
- 提供錯誤診斷提示
|
|
74
|
-
|
|
75
|
-
### 3.1 remove_bom.js
|
|
76
|
-
移除 UTF-8 文件開頭的 BOM (Byte Order Mark)。
|
|
77
|
-
|
|
78
|
-
#### 使用方式
|
|
79
|
-
```bash
|
|
80
|
-
# 移除 BOM
|
|
81
|
-
node .failure/tools/remove_bom.js dev/pipeline/TASK_QUEUE.json
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
#### 功能
|
|
85
|
-
- 檢測並移除 BOM (0xFEFF)
|
|
86
|
-
- 不修改其他內容
|
|
87
|
-
- 無 BOM 時不做任何操作
|
|
88
|
-
|
|
89
|
-
### 3.2 fix_json.js
|
|
90
|
-
一鍵修復 JSON 文件(移除 BOM + 驗證 + 重新格式化)。
|
|
91
|
-
|
|
92
|
-
#### 使用方式
|
|
93
|
-
```bash
|
|
94
|
-
# 修復 JSON 文件
|
|
95
|
-
node .failure/tools/fix_json.js dev/pipeline/TASK_QUEUE.json
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
#### 功能
|
|
99
|
-
- 自動移除 BOM
|
|
100
|
-
- 驗證 JSON 語法
|
|
101
|
-
- 重新格式化(統一縮排 2 空格)
|
|
102
|
-
- 寫回無 BOM 的 UTF-8 文件
|
|
103
|
-
|
|
104
|
-
### 3.3 check_bom.js
|
|
105
|
-
批量檢查 JSON 文件是否有 BOM(用於 CI/CD 或 pre-commit hook)。
|
|
106
|
-
|
|
107
|
-
#### 使用方式
|
|
108
|
-
```bash
|
|
109
|
-
# 檢查單個文件
|
|
110
|
-
node .failure/tools/check_bom.js dev/pipeline/TASK_QUEUE.json
|
|
111
|
-
|
|
112
|
-
# 遞迴檢查目錄中所有 JSON 文件
|
|
113
|
-
node .failure/tools/check_bom.js dev/pipeline --recursive
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
#### 功能
|
|
117
|
-
- 批量檢查 JSON 文件
|
|
118
|
-
- 遞迴掃描目錄(使用 --recursive)
|
|
119
|
-
- 列出所有有 BOM 的文件
|
|
120
|
-
- 退出碼:0(無 BOM)或 1(檢測到 BOM)
|
|
121
|
-
|
|
122
|
-
#### Pre-commit Hook 整合
|
|
123
|
-
```bash
|
|
124
|
-
#!/bin/bash
|
|
125
|
-
# .git/hooks/pre-commit
|
|
126
|
-
node .failure/tools/check_bom.js dev/pipeline --recursive || exit 1
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### 4. failure-report.ps1 (計劃中)
|
|
130
|
-
生成失敗經驗報告的腳本。
|
|
131
|
-
|
|
132
|
-
#### 使用方式
|
|
133
|
-
```powershell
|
|
134
|
-
# 生成完整報告
|
|
135
|
-
.\.failure\tools\failure-report.ps1
|
|
136
|
-
|
|
137
|
-
# 只生成特定分類的報告
|
|
138
|
-
.\.failure\tools\failure-report.ps1 -Category "pipeline"
|
|
139
|
-
|
|
140
|
-
# 只生成特定嚴重程度的報告
|
|
141
|
-
.\.failure\tools\failure-report.ps1 -Severity "critical,high"
|
|
142
|
-
|
|
143
|
-
# 輸出為 Markdown 格式
|
|
144
|
-
.\.failure\tools\failure-report.ps1 -Format "markdown" -Output "failure-report.md"
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
#### 功能(計劃中)
|
|
148
|
-
- 統計失敗記錄數量
|
|
149
|
-
- 按分類和嚴重程度分組
|
|
150
|
-
- 列出已轉化為規則的失敗
|
|
151
|
-
- 生成 Markdown 報告
|
|
152
|
-
|
|
153
|
-
### 5. failure-to-rule.ps1 (計劃中)
|
|
154
|
-
將重複發生的失敗轉化為規則的輔助工具。
|
|
155
|
-
|
|
156
|
-
#### 使用方式
|
|
157
|
-
```powershell
|
|
158
|
-
# 檢查哪些失敗應該轉化為規則
|
|
159
|
-
.\.failure\tools\failure-to-rule.ps1 -Analyze
|
|
160
|
-
|
|
161
|
-
# 將特定失敗轉化為規則
|
|
162
|
-
.\.failure\tools\failure-to-rule.ps1 -FailureID "FAIL-003" -RuleID "PPL-002"
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
#### 功能(計劃中)
|
|
166
|
-
- 分析失敗記錄,建議哪些應該轉化為規則
|
|
167
|
-
- 自動生成規則文件草稿
|
|
168
|
-
- 更新失敗記錄的 `converted_to_rules` 狀態
|
|
169
|
-
- 更新 INDEX.yaml 統計數據
|
|
170
|
-
|
|
171
|
-
## 開發新工具
|
|
172
|
-
|
|
173
|
-
如果需要開發新的失敗學習工具,請遵循以下指南:
|
|
174
|
-
|
|
175
|
-
### 1. 工具命名規範
|
|
176
|
-
- PowerShell 腳本:`action-noun.ps1`(如 `check-failure-patterns.ps1`)
|
|
177
|
-
- Node.js 腳本:`action-noun.js`(如 `validate-json.js`)
|
|
178
|
-
- Python 腳本:`action_noun.py`(如 `analyze_failures.py`)
|
|
179
|
-
|
|
180
|
-
### 2. 必須包含的功能
|
|
181
|
-
- **幫助訊息**:`-Help` 或 `--help` 參數
|
|
182
|
-
- **錯誤處理**:優雅處理錯誤,提供清晰的錯誤訊息
|
|
183
|
-
- **日誌輸出**:使用一致的日誌格式
|
|
184
|
-
- **返回碼**:成功返回 0,失敗返回非 0
|
|
185
|
-
|
|
186
|
-
### 3. 文檔要求
|
|
187
|
-
- 在此 README.md 中添加工具說明
|
|
188
|
-
- 在腳本開頭添加註解說明用途和使用方式
|
|
189
|
-
- 提供使用範例
|
|
190
|
-
|
|
191
|
-
### 4. 測試要求
|
|
192
|
-
- 提供測試用例
|
|
193
|
-
- 在 `.failure/tools/tests/` 目錄中
|
|
194
|
-
|
|
195
|
-
## 工具使用最佳實踐
|
|
196
|
-
|
|
197
|
-
### Agent 使用場景
|
|
198
|
-
|
|
199
|
-
#### 任務開始前
|
|
200
|
-
```powershell
|
|
201
|
-
# 檢查相關失敗模式
|
|
202
|
-
.\.failure\tools\check_failures.ps1 -TaskID $TASK_ID
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
#### 任務執行中
|
|
206
|
-
```bash
|
|
207
|
-
# 驗證 JSON 文件
|
|
208
|
-
node .failure/tools/validate_json.js dev/pipeline/TASK_QUEUE.json
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
#### 任務失敗後
|
|
212
|
-
```powershell
|
|
213
|
-
# 建立失敗記錄
|
|
214
|
-
.\.failure\tools\log_failure.ps1 -Interactive
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### 定期維護
|
|
218
|
-
```powershell
|
|
219
|
-
# 每週生成失敗報告
|
|
220
|
-
.\failure\tools\failure-report.ps1 -Output "weekly-failure-report.md"
|
|
221
|
-
|
|
222
|
-
# 分析哪些失敗應該轉化為規則
|
|
223
|
-
.\failure\tools\failure-to-rule.ps1 -Analyze
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## 相關資源
|
|
227
|
-
|
|
228
|
-
- **失敗記錄索引**:`.failure/INDEX.yaml`
|
|
229
|
-
- **規則系統**:`.rule/INDEX.yaml`
|
|
230
|
-
- **Agent 工作流程**:`.rule/general/agent-workflow.yaml`
|
|
12
|
+
Looking up known failures: read `.failure/INDEX.yaml`, then Grep `.failure/` for the task's scope or error text. Record a new failure by adding a YAML file from the template in INDEX.yaml and listing it in `load_order`; lessons that are not reproducible failure patterns go to `kenaz learn add`.
|
|
@@ -19,7 +19,7 @@ const { spawn, spawnSync } = require('child_process');
|
|
|
19
19
|
|
|
20
20
|
// First = default. From GET https://api.deepseek.com/models on 2026-10-11 (V4 ids, 1M context); the V3 ids still
|
|
21
21
|
// answer but are no longer listed. `kenaz launch` re-reads the context window from that endpoint at start.
|
|
22
|
-
const DEEPSEEK_MODELS = ['deepseek-
|
|
22
|
+
const DEEPSEEK_MODELS = ['deepseek-flash', 'deepseek-v4-pro', 'deepseek-chat', 'deepseek-reasoner']; // flash = default (user decision 2026-10-12)
|
|
23
23
|
const DEEPSEEK_BASE_URL = 'https://api.deepseek.com/anthropic';
|
|
24
24
|
const DEEPSEEK_CONTEXT_TOKENS = { 'deepseek-v4-pro': 1048576, 'deepseek-flash': 1048576, 'deepseek-chat': 128000, 'deepseek-reasoner': 128000 };
|
|
25
25
|
const DEEPSEEK_FAST = 'deepseek-flash'; // Claude Code's small/fast slot (titles, summaries): the cheap model
|
|
@@ -38,12 +38,37 @@ function parseExecutorModel(raw) {
|
|
|
38
38
|
return { adapter, id };
|
|
39
39
|
}
|
|
40
40
|
if (adapter === 'deepseek') {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
// Any id the vendor may add later is accepted (no release needed); `deepseek:` alone = the user's saved default.
|
|
42
|
+
const model = id || providerDefault('deepseek') || DEEPSEEK_MODELS[0];
|
|
43
|
+
if (!MODEL_ID.test(model)) throw new Error(`invalid deepseek model id '${id}' (letters, digits, . _ - only); known: ${DEEPSEEK_MODELS.map((i) => 'deepseek:' + i).join(', ')}`);
|
|
44
|
+
return { adapter, id: model };
|
|
43
45
|
}
|
|
44
46
|
throw new Error(`unknown executor prefix '${m[1]}:'; valid prefixes: codex:<id>, deepseek:<model>`);
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
const MODEL_ID = /^[A-Za-z0-9][\w.-]{0,63}$/;
|
|
50
|
+
const configFile = (home) => path.join(home, '.kenaz', 'config.json');
|
|
51
|
+
|
|
52
|
+
/** The user's own default model for a provider: KENAZ_<PROVIDER>_MODEL, else ~/.kenaz/config.json
|
|
53
|
+
* providers.<provider>.model (written by `kenaz launch --provider p --model m --save-default`); null when unset. */
|
|
54
|
+
function providerDefault(provider, env = process.env, home = os.homedir()) {
|
|
55
|
+
const e = env['KENAZ_' + provider.toUpperCase() + '_MODEL'];
|
|
56
|
+
if (e && e.trim()) return e.trim();
|
|
57
|
+
try { const m = JSON.parse(fs.readFileSync(configFile(home), 'utf8')).providers[provider].model; return typeof m === 'string' && m.trim() ? m.trim() : null; } catch { return null; }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Save the default (other keys in config.json are kept; atomic write). */
|
|
61
|
+
function saveProviderDefault(provider, model, home = os.homedir()) {
|
|
62
|
+
let cfg = {};
|
|
63
|
+
try { cfg = JSON.parse(fs.readFileSync(configFile(home), 'utf8')) || {}; } catch { /* new file */ }
|
|
64
|
+
cfg.providers = { ...(cfg.providers || {}), [provider]: { ...((cfg.providers || {})[provider] || {}), model } };
|
|
65
|
+
fs.mkdirSync(path.dirname(configFile(home)), { recursive: true });
|
|
66
|
+
const tmp = configFile(home) + '.tmp';
|
|
67
|
+
fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2) + '\n');
|
|
68
|
+
fs.renameSync(tmp, configFile(home));
|
|
69
|
+
return configFile(home);
|
|
70
|
+
}
|
|
71
|
+
|
|
47
72
|
/** DEEPSEEK_API_KEY, else deepseek_api_key in ~/.kenaz/credentials.yaml; null when neither. */
|
|
48
73
|
function deepseekKey(env = process.env, home = os.homedir()) {
|
|
49
74
|
if (env.DEEPSEEK_API_KEY && env.DEEPSEEK_API_KEY.trim()) return env.DEEPSEEK_API_KEY.trim();
|
|
@@ -175,4 +200,4 @@ async function main(argv) {
|
|
|
175
200
|
}
|
|
176
201
|
|
|
177
202
|
if (require.main === module) main(process.argv.slice(2)).then((c) => { process.exitCode = c; });
|
|
178
|
-
module.exports = { otherVendorSession, parseExecutorModel, deepseekKey, deepseekEnv, deepseekModels, DEEPSEEK_UNSET, winQuote, buildChild, run, main, DEEPSEEK_MODELS };
|
|
203
|
+
module.exports = { otherVendorSession, providerDefault, saveProviderDefault, MODEL_ID, parseExecutorModel, deepseekKey, deepseekEnv, deepseekModels, DEEPSEEK_UNSET, winQuote, buildChild, run, main, DEEPSEEK_MODELS };
|
|
@@ -286,12 +286,7 @@ function renderOverride(prompt, bootContext, { policy = BOOT_POLICY, projectPath
|
|
|
286
286
|
const content = `${projectInstruction}${bootContext}${memoryStartupDoc}${codexDdxInjection}You have been activated as ${policy.specialist} via Bifröst.
|
|
287
287
|
|
|
288
288
|
IMPORTANT — Shell compatibility (you are running under Codex which uses PowerShell on Windows):
|
|
289
|
-
-
|
|
290
|
-
- Instead: write JSON to a temp file, then use --data-file=path. Example:
|
|
291
|
-
1. Write: Set-Content -Path _phase_data.json -Value '{"ash_loaded":true,"poem_displayed":true,"session_handoff_loaded":false}'
|
|
292
|
-
2. Run: node .specialist/tools/phase-gate.js exit --phase=0 --data-file=_phase_data.json
|
|
293
|
-
3. Cleanup: Remove-Item _phase_data.json
|
|
294
|
-
- This applies to ALL phase-gate.js exit calls, not just Phase 0.
|
|
289
|
+
- Do not pass inline JSON on the command line; PowerShell mangles JSON quotes. Write it to a temp file and pass the path instead.
|
|
295
290
|
|
|
296
291
|
${prompt}
|
|
297
292
|
|
|
@@ -104,7 +104,7 @@ test('override ends with fast precedence and retains full project pin', () => {
|
|
|
104
104
|
assert.equal((fast.match(/## Codex Bootstrap Policy/g) || []).length, 1);
|
|
105
105
|
assert.ok(fast.includes(`projectPath="${projectPath}"`));
|
|
106
106
|
const full = api.renderOverride('fixture', '', { projectPath, policy: resolveBootPolicy({ depth: 'kernel' }) });
|
|
107
|
-
assert.ok(full.includes(
|
|
107
|
+
assert.ok(full.includes(`projectPath="${projectPath}"`));
|
|
108
108
|
assert.match(full, /HALT and emit recovery/);
|
|
109
109
|
assert.doesNotMatch(full, /Ansuz fast boot/);
|
|
110
110
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
/**
|
|
4
|
-
* `kenaz launch --provider deepseek [--model deepseek-v4-pro
|
|
4
|
+
* `kenaz launch --provider deepseek [--model deepseek-flash (default)|deepseek-v4-pro|...] [claude args...]`
|
|
5
5
|
* Starts Claude Code with every model request sent to another vendor's Anthropic-compatible endpoint, so
|
|
6
6
|
* Ansuz (/kenaz:Ansuz), its subagents and background requests run on that vendor and use no Claude quota.
|
|
7
7
|
* The key is read from the env or ~/.kenaz/credentials.yaml and set only in the claude child's env: never in
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
const os = require('os');
|
|
11
11
|
const { spawn } = require('child_process');
|
|
12
|
-
const { deepseekKey, deepseekEnv, deepseekModels, DEEPSEEK_UNSET, DEEPSEEK_MODELS, winQuote } = require('./exec');
|
|
12
|
+
const { deepseekKey, deepseekEnv, deepseekModels, DEEPSEEK_UNSET, DEEPSEEK_MODELS, winQuote, providerDefault, saveProviderDefault, MODEL_ID } = require('./exec');
|
|
13
13
|
|
|
14
14
|
const PROVIDERS = {
|
|
15
15
|
deepseek: {
|
|
@@ -17,29 +17,31 @@ const PROVIDERS = {
|
|
|
17
17
|
keyHelp: 'set DEEPSEEK_API_KEY, or add `deepseek_api_key: <key>` to ~/.kenaz/credentials.yaml',
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
|
-
const USAGE = 'usage: kenaz launch --provider <' + Object.keys(PROVIDERS).join('|') + '> [--model <id>] [claude args...]';
|
|
20
|
+
const USAGE = 'usage: kenaz launch --provider <' + Object.keys(PROVIDERS).join('|') + '> [--model <id> [--save-default]] [claude args...]';
|
|
21
21
|
|
|
22
22
|
function parse(argv) {
|
|
23
|
-
const rest = []; let provider = null; let model = null;
|
|
23
|
+
const rest = []; let provider = null; let model = null; let save = false;
|
|
24
24
|
for (let i = 0; i < argv.length; i++) {
|
|
25
|
+
if (argv[i] === '--save-default') { save = true; continue; }
|
|
25
26
|
const m = /^--(provider|model)(?:=(.*))?$/.exec(argv[i]);
|
|
26
27
|
if (!m) { rest.push(argv[i]); continue; }
|
|
27
28
|
const v = m[2] !== undefined ? m[2] : argv[++i];
|
|
28
29
|
if (m[1] === 'provider') provider = v; else model = v;
|
|
29
30
|
}
|
|
30
|
-
return { rest, provider, model };
|
|
31
|
+
return { rest, provider, model, save };
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
/** Child process plan: { bin, args, env }.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
34
|
+
/** Child process plan: { bin, args, env }. Model = --model, else the user's own default (KENAZ_<P>_MODEL or
|
|
35
|
+
* ~/.kenaz/config.json, see providerDefault), else the built-in default. live = {id: context_window} from the
|
|
36
|
+
* vendor's model list (or null): when known it is the only validation (new vendor models work without a Kenaz
|
|
37
|
+
* release); when unreachable any well-formed id is accepted. Throws with a user-facing message. */
|
|
36
38
|
function plan(argv, env = process.env, home = os.homedir(), live = null) {
|
|
37
39
|
const { rest, provider, model } = parse(argv);
|
|
38
40
|
const p = PROVIDERS[provider];
|
|
39
41
|
if (!p) throw new Error((provider ? `unknown provider '${provider}'. ` : '') + USAGE);
|
|
40
|
-
const id = model || p.models[0];
|
|
41
|
-
|
|
42
|
-
if (!
|
|
42
|
+
const id = model || providerDefault(provider, env, home) || p.models[0];
|
|
43
|
+
if (!MODEL_ID.test(id)) throw new Error(`invalid ${provider} model id '${id}'`);
|
|
44
|
+
if (live && !(id in live)) throw new Error(`unknown ${provider} model '${id}'; the vendor currently lists: ${Object.keys(live).join(', ')}`);
|
|
43
45
|
const key = p.key(env, home);
|
|
44
46
|
if (!key) throw new Error(`${provider}: no API key (${p.keyHelp})`);
|
|
45
47
|
const childEnv = { ...env, ...p.env(id, key, live && live[id]), CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
|
|
@@ -56,6 +58,11 @@ async function main(argv, out = console.log, deps = {}) {
|
|
|
56
58
|
const live = key ? await (deps.live || p.live)(key) : null;
|
|
57
59
|
let pl;
|
|
58
60
|
try { pl = plan(argv, env, home, live); } catch (e) { out(e.message); return 2; }
|
|
61
|
+
const { model: asked, save } = parse(argv);
|
|
62
|
+
if (save) {
|
|
63
|
+
if (!asked) { out('--save-default needs --model <id>'); return 2; }
|
|
64
|
+
out(`kenaz launch: ${pl.provider} default model saved: ${pl.model} (${saveProviderDefault(pl.provider, pl.model, home)})`);
|
|
65
|
+
}
|
|
59
66
|
out(`kenaz launch: Claude Code on ${pl.provider} (${pl.model}, context ${pl.context} tokens); no Claude quota is used in this session`);
|
|
60
67
|
const win = (deps.platform || process.platform) === 'win32'; // claude is a .cmd shim on npm installs
|
|
61
68
|
const child = (deps.spawn || spawn)(win ? [pl.bin, ...pl.args].map(winQuote).join(' ') : pl.bin, win ? [] : pl.args,
|
|
@@ -25,7 +25,7 @@ test('deepseek: every model slot points at DeepSeek, key only in the child env,
|
|
|
25
25
|
assert.strictEqual(e.ANTHROPIC_BASE_URL, 'https://api.deepseek.com/anthropic');
|
|
26
26
|
assert.strictEqual(e.ANTHROPIC_AUTH_TOKEN, KEY);
|
|
27
27
|
for (const k of ['ANTHROPIC_MODEL', 'ANTHROPIC_DEFAULT_SONNET_MODEL', 'ANTHROPIC_DEFAULT_OPUS_MODEL', 'CLAUDE_CODE_SUBAGENT_MODEL']) {
|
|
28
|
-
assert.strictEqual(e[k], 'deepseek-
|
|
28
|
+
assert.strictEqual(e[k], 'deepseek-flash', k);
|
|
29
29
|
}
|
|
30
30
|
assert.strictEqual(e.ANTHROPIC_SMALL_FAST_MODEL, 'deepseek-flash'); assert.strictEqual(e.ANTHROPIC_DEFAULT_HAIKU_MODEL, 'deepseek-flash');
|
|
31
31
|
assert.strictEqual(e.CLAUDE_CODE_MAX_CONTEXT_TOKENS, '1048576', 'V4 window from the built-in table when the live list is unavailable');
|
|
@@ -54,7 +54,7 @@ test('control: no key, unknown provider or model -> exit 2 and claude is never s
|
|
|
54
54
|
[['--provider', 'deepseek'], {}, /no API key/],
|
|
55
55
|
[['--provider', 'nope'], { DEEPSEEK_API_KEY: KEY }, /unknown provider 'nope'/],
|
|
56
56
|
[[], { DEEPSEEK_API_KEY: KEY }, /usage: kenaz launch --provider <deepseek>/],
|
|
57
|
-
[['--provider', 'deepseek', '--model', '
|
|
57
|
+
[['--provider', 'deepseek', '--model', 'bad id'], { DEEPSEEK_API_KEY: KEY }, /invalid deepseek model id/],
|
|
58
58
|
]) {
|
|
59
59
|
const calls = [], lines = [];
|
|
60
60
|
const rc = await main(argv, (l) => lines.push(l), { spawn: fakeSpawn(calls), live: async () => null, env, home: home(), platform: 'linux' });
|
|
@@ -74,3 +74,27 @@ test('live model list: a newer listed id is accepted and its context window driv
|
|
|
74
74
|
assert.strictEqual(calls[0].opts.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS, '2097152');
|
|
75
75
|
assert.match(lines[0], /context 2097152 tokens/);
|
|
76
76
|
});
|
|
77
|
+
|
|
78
|
+
test('model not in the vendor list is refused only when the list is known; unknown list = accepted (no release needed)', async () => {
|
|
79
|
+
const calls = [], lines = [];
|
|
80
|
+
const rc = await main(['--provider', 'deepseek', '--model', 'gpt-x'], (l) => lines.push(l), { spawn: fakeSpawn(calls), live: async () => ({ 'deepseek-flash': 1048576 }), env: { DEEPSEEK_API_KEY: KEY }, home: home(), platform: 'linux' });
|
|
81
|
+
assert.strictEqual(rc, 2); assert.strictEqual(calls.length, 0); assert.match(lines.join(String.fromCharCode(10)), /the vendor currently lists: deepseek-flash/);
|
|
82
|
+
const calls2 = [];
|
|
83
|
+
assert.strictEqual(await main(['--provider', 'deepseek', '--model', 'deepseek-v9'], () => {}, { spawn: fakeSpawn(calls2), live: async () => null, env: { DEEPSEEK_API_KEY: KEY }, home: home(), platform: 'linux' }), 0);
|
|
84
|
+
assert.strictEqual(calls2[0].opts.env.ANTHROPIC_MODEL, 'deepseek-v9');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('the user picks the default: --save-default writes ~/.kenaz/config.json (other keys kept), env overrides it, --model overrides both', async () => {
|
|
88
|
+
const h = home(); fs.mkdirSync(path.join(h, '.kenaz'));
|
|
89
|
+
fs.writeFileSync(path.join(h, '.kenaz', 'config.json'), JSON.stringify({ setupCompleted: true }));
|
|
90
|
+
const run = async (argv, env = {}) => { const calls = [], lines = []; const rc = await main(argv, (l) => lines.push(l), { spawn: fakeSpawn(calls), live: async () => null, env: { DEEPSEEK_API_KEY: KEY, ...env }, home: h, platform: 'linux' }); return { rc, model: calls[0] && calls[0].opts.env.ANTHROPIC_MODEL, lines }; };
|
|
91
|
+
assert.strictEqual((await run(['--provider', 'deepseek'])).model, 'deepseek-flash', 'built-in default');
|
|
92
|
+
const saved = await run(['--provider', 'deepseek', '--model', 'deepseek-v4-pro', '--save-default']);
|
|
93
|
+
assert.strictEqual(saved.model, 'deepseek-v4-pro'); assert.match(saved.lines.join(String.fromCharCode(10)), /default model saved: deepseek-v4-pro/);
|
|
94
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(h, '.kenaz', 'config.json'), 'utf8'));
|
|
95
|
+
assert.strictEqual(cfg.setupCompleted, true); assert.strictEqual(cfg.providers.deepseek.model, 'deepseek-v4-pro');
|
|
96
|
+
assert.strictEqual((await run(['--provider', 'deepseek'])).model, 'deepseek-v4-pro', 'saved default used');
|
|
97
|
+
assert.strictEqual((await run(['--provider', 'deepseek'], { KENAZ_DEEPSEEK_MODEL: 'deepseek-chat' })).model, 'deepseek-chat', 'env overrides saved');
|
|
98
|
+
assert.strictEqual((await run(['--provider', 'deepseek', '--model', 'deepseek-flash'])).model, 'deepseek-flash', '--model overrides');
|
|
99
|
+
assert.strictEqual((await run(['--provider', 'deepseek', '--save-default'])).rc, 2, '--save-default without --model');
|
|
100
|
+
});
|
|
@@ -19,11 +19,11 @@ function renderBootstrap({ policy, projectPath, port = '18080', contextual = fal
|
|
|
19
19
|
const fast = [
|
|
20
20
|
'Ansuz fast boot (elixir) is the default. This bootstrap policy supersedes any older instruction to run Phase 0, including the Phase 0 sentence inside elixir.',
|
|
21
21
|
'Check kenaz_ping with the active projectPath when available. If unavailable, report that the Kenaz server is unavailable and continue only read-only inspection and analysis using local evidence.',
|
|
22
|
-
'Lightweight Phase 0 uses the supplied boot context and local project evidence; do not run
|
|
22
|
+
'Lightweight Phase 0 uses the supplied boot context and local project evidence; do not run Phase 0 boot rituals in fast mode. This also supersedes legacy handoff instructions that promise Phase 0 archival. When offline, defer state-changing execution and memory-dependent work until the required service is restored.',
|
|
23
23
|
'Existing authorization, scope, verification, task tracking, and merge restrictions remain in force.',
|
|
24
24
|
].join('\n');
|
|
25
|
-
const
|
|
26
|
-
|
|
25
|
+
const full = `Before starting Phase 0, call kenaz_ping with the active projectPath${projectPath ? ` ("${projectPath}")` : ''}. If it errors or times out, HALT and emit recovery: confirm the Kenaz server on port ${port}, re-run setup-codex, and restart the Codex session.
|
|
26
|
+
Execute Phase 0 initialization now using the supplied boot context and local project evidence.`;
|
|
27
27
|
if (contextual) return `## Codex Bootstrap Policy\n\nFor Ansuz without an explicit full boot or legacy depth:\n${fast}\n\nFor explicit --full / --boot-mode full or kernel depth, and for other specialists: retain the full bootstrap guard; call kenaz_ping before Phase 0 and HALT with recovery instructions if it is unavailable. Use the active specialist and project-path for Phase 0.\n`;
|
|
28
28
|
return `## Codex Bootstrap Policy (${policy.mode})\n\n${policy.mode === 'fast' ? fast : full}\n`;
|
|
29
29
|
}
|
|
@@ -28,8 +28,7 @@ test('renderer preserves full project pin and limits fast offline work without r
|
|
|
28
28
|
const projectPath = 'C:\\example project\\quotation';
|
|
29
29
|
const full = renderBootstrap({ policy: resolveBootPolicy({ full: true }), projectPath });
|
|
30
30
|
assert.match(full, /HALT/);
|
|
31
|
-
assert.ok(full.includes(
|
|
32
|
-
assert.match(full, /--specialist=ansuz/);
|
|
31
|
+
assert.ok(full.includes(`"${projectPath}"`));
|
|
33
32
|
const fast = renderBootstrap({ policy: resolveBootPolicy() });
|
|
34
33
|
assert.match(fast, /Lightweight Phase 0/);
|
|
35
34
|
assert.match(fast, /supersedes any older instruction/);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// dispatch.js without --project-path, run from a user's project through the plugin (cwd = that project, ROOT = core):
|
|
2
|
+
// the card and the worktree belong to the cwd project, not the core (repro 2026-10-12: '任務不存在' and a worktree
|
|
3
|
+
// created inside the core repo, leaving Ansuz waiting on a subagent that had no card).
|
|
4
|
+
const test = require('node:test');
|
|
5
|
+
const assert = require('node:assert');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { spawnSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
12
|
+
const DISPATCH = path.join(ROOT, '.formation', 'tools', 'dispatch.js');
|
|
13
|
+
const git = (cwd, args) => spawnSync('git', ['-c', 'user.name=t', '-c', 'user.email=t@t', ...args], { cwd, encoding: 'utf8' });
|
|
14
|
+
|
|
15
|
+
function project() {
|
|
16
|
+
const p = fs.mkdtempSync(path.join(os.tmpdir(), 'dcp-'));
|
|
17
|
+
git(p, ['init', '-q']); fs.writeFileSync(path.join(p, 'README.md'), 'x'); git(p, ['add', '-A']); git(p, ['commit', '-q', '-m', 'init']);
|
|
18
|
+
for (const d of ['backlog', 'active', 'done', 'blocked', 'cancel']) fs.mkdirSync(path.join(p, '.kenaz', 'tasks', d), { recursive: true });
|
|
19
|
+
fs.writeFileSync(path.join(p, '.kenaz', 'project.yaml'), 'name: dcp\n');
|
|
20
|
+
fs.writeFileSync(path.join(p, '.kenaz', 'tasks', 'backlog', 'TASK_7201_x.yaml'),
|
|
21
|
+
'id: TASK_7201\ntitle: "Unique card title 7201"\nstatus: backlog\npriority: low\nrigor: low\nrequirements: ["r"]\nacceptance_criteria: ["a"]\nscope_paths: [x.txt]\n');
|
|
22
|
+
return p;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const env = () => { const e = { ...process.env }; for (const k of ['CLAUDE_PROJECT_DIR', 'KENAZ_PROVIDER', 'ANTHROPIC_BASE_URL', 'CODEX_SESSION_ID', 'CODEX_THREAD_ID']) delete e[k]; return e; };
|
|
26
|
+
|
|
27
|
+
test('from a user project without --project-path: the card is found and isolation targets that project', () => {
|
|
28
|
+
const p = project();
|
|
29
|
+
const r = spawnSync(process.execPath, [DISPATCH, '--skill=do', '--task=TASK_7201', '--dispatch-mode=subagent', '--dry-run'], { cwd: p, env: env(), encoding: 'utf8' });
|
|
30
|
+
assert.strictEqual(r.status, 0, r.stderr);
|
|
31
|
+
assert.doesNotMatch(r.stderr, /任務不存在/);
|
|
32
|
+
const j = JSON.parse(r.stdout);
|
|
33
|
+
assert.match(j.promptText, /Unique card title 7201/);
|
|
34
|
+
assert.match(r.stderr, new RegExp('cross-project detected .*' + path.basename(p)));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('control: in the core repo itself nothing changes (same-project Agent worktree)', () => {
|
|
38
|
+
const r = spawnSync(process.execPath, [DISPATCH, '--skill=do', '--task=TASK_2376', '--dispatch-mode=subagent', '--dry-run'], { cwd: ROOT, env: env(), encoding: 'utf8' });
|
|
39
|
+
assert.strictEqual(r.status, 0, r.stderr);
|
|
40
|
+
const j = JSON.parse(r.stdout);
|
|
41
|
+
assert.strictEqual(j.isolation.mode, 'agent_tool_worktree');
|
|
42
|
+
});
|