kenaz 0.3.21 → 0.3.23

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.
Files changed (481) hide show
  1. package/core/.claude/commands/Ansuz.md +2 -0
  2. package/core/.claude/hooks/__tests__/peer-session-fill.test.js +37 -0
  3. package/core/.claude/hooks/_ansuz-conversation.js +32 -1
  4. package/core/.claude/hooks/_user-scope.js +1 -1
  5. package/core/.claude/hooks/core-resolve.js +1 -1
  6. package/core/.claude/hooks/peer-optin.test.js +74 -0
  7. package/core/.claude/hooks/peer-session-fill.js +38 -0
  8. package/core/.claude/hooks/turn-context.js +5 -4
  9. package/core/.claude/hooks/worktree-create.js +6 -6
  10. package/core/.claude/hooks/worktree-remove.js +4 -4
  11. package/core/.claude/settings.json +9 -0
  12. package/core/.collaboration/core/reconcile.js +16 -1
  13. package/core/.collaboration/core/task-2467-lifecycle.test.js +63 -0
  14. package/core/.collaboration/core/task-api.js +37 -7
  15. package/core/.formation/bifrost/launch.js +1 -1
  16. package/core/.formation/bifrost/openai/codex-hook-shim.js +21 -4
  17. package/core/.formation/bifrost/openai/codex-peer-pull.test.js +42 -0
  18. package/core/.formation/bifrost/provider-launch.js +2 -1
  19. package/core/.formation/tools/kenaz-stats.js +1 -1
  20. package/core/.formation/tools/post-complete/git-merge.js +1 -1
  21. package/core/.formation/tools/prompt.js +1 -1
  22. package/core/.kenaz/specialist/ansuz_rules.yaml +7 -51
  23. package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +2 -6
  24. package/core/.rule/general/project-self-containment.yaml +2 -2
  25. package/core/.specialist/Amelia/README.md +1 -1
  26. package/core/.specialist/Amelia/rule.yaml +1 -1
  27. package/core/.specialist/Ansuz/RULES.md +1 -1
  28. package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +1 -1
  29. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +1 -1
  30. package/core/.specialist/Ansuz/knowledge.yaml +1 -3
  31. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +10 -0
  32. package/core/.specialist/tools/__tests__/task-2427-harvest.test.js +25 -0
  33. package/core/.specialist/tools/ansuz-boot-fast.js +1 -1
  34. package/core/.specialist/tools/failure-detector.js +4 -4
  35. package/core/.specialist/tools/handoff-doc.js +1 -1
  36. package/core/.specialist/tools/lessons.js +2 -2
  37. package/core/CLAUDE.md +5 -5
  38. package/core/KENAZ_CORE_VERSION +1 -1
  39. package/core/dashboard/scripts/install-kenaz-cli.js +471 -0
  40. package/core/dev/scripts/check-file-size.js +1 -1
  41. package/core/dev/scripts/ci-feedback.js +1 -1
  42. package/core/dev/scripts/gc-agent-worktrees.js +11 -11
  43. package/core/dev/scripts/kenaz-session.js +3 -3
  44. package/core/dev/scripts/peer-identity-e2e.js +3 -3
  45. package/core/dev/scripts/run-rust-tests.js +2 -2
  46. package/core/dev/scripts/skill-routing-replay.js +3 -3
  47. package/core/dev/scripts/task1961/selftest.js +2 -2
  48. package/core/dev/scripts/windows-hide-guard.test.js +97 -0
  49. package/core/plugins/kenaz/commands/Ansuz.md +2 -0
  50. package/core/plugins/kenaz/guidance.md +2 -0
  51. package/core/plugins/kenaz/hooks/core-resolve.js +1 -1
  52. package/core/plugins/kenaz/hooks/hooks.json +9 -0
  53. package/core/plugins/kenaz/hooks/kenaz-hook.js +53 -4
  54. package/core/plugins/kenaz/scripts/kenaz.test.js +72 -5
  55. package/core/plugins/kenaz/scripts/ygg.js +40 -4
  56. package/core/plugins/kenaz/scripts/ygg.test.js +63 -3
  57. package/core/plugins/kenaz-peer/hooks/register.test.ts +59 -2
  58. package/core/plugins/kenaz-peer/hooks/register.ts +24 -1
  59. package/lib/cli.js +9 -5
  60. package/package.json +6 -6
  61. package/vendor/install-kenaz-cli.js +21 -6
  62. package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +0 -537
  63. package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +0 -501
  64. package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +0 -426
  65. package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +0 -103
  66. package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +0 -97
  67. package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +0 -154
  68. package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +0 -159
  69. package/core/.kenaz/designs/metaplasticity_simulation_results.json +0 -696
  70. package/core/.kenaz/main-memory/README.md +0 -230
  71. package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +0 -168
  72. package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +0 -30
  73. package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +0 -361
  74. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +0 -117
  75. package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +0 -154
  76. package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +0 -51
  77. package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +0 -46
  78. package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +0 -108
  79. package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +0 -121
  80. package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
  81. package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +0 -48
  82. package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +0 -197
  83. package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +0 -78
  84. package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
  85. package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +0 -115
  86. package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +0 -223
  87. package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +0 -242
  88. package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +0 -111
  89. package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +0 -274
  90. package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +0 -28
  91. package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +0 -137
  92. package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
  93. package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
  94. package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +0 -239
  95. package/core/.kenaz/main-memory/registry.json +0 -326
  96. package/core/.kenaz/main-memory/version.yaml +0 -58
  97. package/core/.kenaz/specialist/memory_guard_fired.json +0 -1
  98. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +0 -1
  99. package/core/.kenaz/specialist/memory_source_priority.yaml +0 -260
  100. package/core/.kenaz/specialist/prompt_1775.txt +0 -317
  101. package/core/.kenaz/specialist/prompt_1776.txt +0 -326
  102. package/core/.kenaz/specialist/prompt_1791.txt +0 -320
  103. package/core/.kenaz/specialist/prompt_1792.txt +0 -320
  104. package/core/.kenaz/specialist/prompt_1795.txt +0 -281
  105. package/core/.kenaz/specialist/prompt_1813.txt +0 -332
  106. package/core/.kenaz/specialist/prompt_1814.txt +0 -401
  107. package/core/.kenaz/specialist/prompt_1815.txt +0 -394
  108. package/core/.kenaz/specialist/prompt_1816.txt +0 -437
  109. package/core/.kenaz/specialist/prompt_1818.txt +0 -361
  110. package/core/.kenaz/specialist/prompt_1819.txt +0 -421
  111. package/core/.kenaz/specialist/prompt_1821.txt +0 -345
  112. package/core/.kenaz/specialist/prompt_1822.txt +0 -313
  113. package/core/.kenaz/specialist/prompt_1824.txt +0 -348
  114. package/core/.kenaz/specialist/prompt_1826.txt +0 -388
  115. package/core/.kenaz/specialist/rune_efe_salience_gap.md +0 -21
  116. package/core/.kenaz/specialist/task1825_update.json +0 -43
  117. package/core/.kenaz/specialist/taskgen/consolidation_i.json +0 -38
  118. package/core/.kenaz/specialist/taskgen/csharp_a.json +0 -44
  119. package/core/.kenaz/specialist/taskgen/csharp_b.json +0 -40
  120. package/core/.kenaz/specialist/taskgen/embedding_e.json +0 -34
  121. package/core/.kenaz/specialist/taskgen/hygiene_fg.json +0 -39
  122. package/core/.kenaz/specialist/taskgen/pathology_h.json +0 -36
  123. package/core/.kenaz/specialist/taskgen/unity_noise_d.json +0 -38
  124. package/core/.kenaz/specialist/taskgen/visibility_c.json +0 -38
  125. package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +0 -390
  126. package/core/.specialist/Ansuz/self_model_seed.backup.json +0 -100
  127. package/core/.specialist/ansuz_session_handoff.json +0 -96
  128. package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +0 -126
  129. package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +0 -231
  130. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +0 -355
  131. package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +0 -143
  132. package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +0 -99
  133. package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +0 -44
  134. package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +0 -263
  135. package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +0 -180
  136. package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +0 -271
  137. package/core/dev/HOOK_DIET_2026-09-21.md +0 -126
  138. package/core/dev/JEV_INTEGRATION_PLAN.md +0 -189
  139. package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +0 -139
  140. package/core/dev/MOBILE_DESIGN_SPEC.md +0 -569
  141. package/core/dev/MULTI_ANSUZ_SPEC.md +0 -136
  142. package/core/dev/MUNINN_RETIREMENT.md +0 -115
  143. package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +0 -211
  144. package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +0 -83
  145. package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +0 -83
  146. package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +0 -231
  147. package/core/dev/PREDICTION_GROUNDING_DESIGN.md +0 -376
  148. package/core/dev/PRODUCT_SPEC.md +0 -317
  149. package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +0 -86
  150. package/core/dev/STARTUP_TIMELINE_TASK_1995.md +0 -181
  151. package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +0 -881
  152. package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +0 -96
  153. package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +0 -170
  154. package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +0 -171
  155. package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +0 -262
  156. package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +0 -207
  157. package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +0 -146
  158. package/core/dev/ansuz-eval/README.md +0 -38
  159. package/core/dev/ansuz-eval/build-fixtures.js +0 -87
  160. package/core/dev/ansuz-eval/grade.js +0 -96
  161. package/core/dev/ansuz-eval/grader.test.js +0 -117
  162. package/core/dev/ansuz-eval/tasks.md +0 -32
  163. package/core/dev/archive/ansuz/BOOT_FULL.md +0 -141
  164. package/core/dev/archive/ansuz/agents/ansuz-boot.md +0 -176
  165. package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +0 -84
  166. package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +0 -307
  167. package/core/dev/archive/ansuz/designs/check_guard.md +0 -322
  168. package/core/dev/archive/ansuz/designs/consequence_loop.md +0 -227
  169. package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +0 -312
  170. package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +0 -278
  171. package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +0 -490
  172. package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +0 -167
  173. package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +0 -193
  174. package/core/dev/archive/ansuz/designs/thought_stack.md +0 -286
  175. package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +0 -330
  176. package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +0 -352
  177. package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +0 -48
  178. package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +0 -170
  179. package/core/dev/archive/ansuz/legacy/kernel.yaml +0 -399
  180. package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +0 -418
  181. package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +0 -376
  182. package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +0 -35
  183. package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +0 -582
  184. package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +0 -94
  185. package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +0 -274
  186. package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +0 -67
  187. package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +0 -32
  188. package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +0 -91
  189. package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +0 -58
  190. package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +0 -146
  191. package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +0 -424
  192. package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +0 -92
  193. package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +0 -453
  194. package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +0 -191
  195. package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +0 -250
  196. package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +0 -301
  197. package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +0 -272
  198. package/core/dev/archive/skills/feature_agent/SKILL.md +0 -289
  199. package/core/dev/design/PHASE4_DESIGN.md +0 -559
  200. package/core/dev/design/dashboard_docs_integration_PLAN.md +0 -388
  201. package/core/dev/design/matrix_format_ABBREVIATIONS.md +0 -655
  202. package/core/dev/design/matrix_format_DESIGN_SPEC.md +0 -601
  203. package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +0 -484
  204. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +0 -13
  205. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +0 -9
  206. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +0 -14
  207. package/core/dev/design/matrix_format_SYNTAX_BNF.md +0 -754
  208. package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +0 -484
  209. package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +0 -503
  210. package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +0 -414
  211. package/core/dev/design/matrix_v2_EXAMPLE.matrix +0 -67
  212. package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +0 -509
  213. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +0 -52
  214. package/core/dev/jev-eval/ANNOTATION_GUIDE.md +0 -68
  215. package/core/dev/jev-eval/BASELINE_COMPARISON.md +0 -45
  216. package/core/dev/jev-eval/CONTEXT_REVIEW.md +0 -31
  217. package/core/dev/jev-eval/EVALUATION_STATUS.md +0 -39
  218. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +0 -33
  219. package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +0 -42
  220. package/core/dev/jev-eval/README.md +0 -101
  221. package/core/dev/jev-eval/THALAMUS_RANKING.md +0 -58
  222. package/core/dev/jev-eval/VALIDATION_PROGRESS.md +0 -54
  223. package/core/dev/jev-eval/cli.mjs +0 -50
  224. package/core/dev/jev-eval/context.mjs +0 -183
  225. package/core/dev/jev-eval/corpus.mjs +0 -186
  226. package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +0 -6
  227. package/core/dev/jev-eval/fixtures/synthetic.jsonl +0 -11
  228. package/core/dev/jev-eval/metrics.mjs +0 -67
  229. package/core/dev/jev-eval/muninn-baseline.mjs +0 -119
  230. package/core/dev/jev-eval/providers.mjs +0 -95
  231. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +0 -32
  232. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +0 -48
  233. package/core/dev/jev-eval/reports/conversation-review.pending.json +0 -151
  234. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +0 -52
  235. package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +0 -133
  236. package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +0 -616
  237. package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +0 -52
  238. package/core/dev/jev-eval/reports/resilience-2026-09-20.json +0 -520
  239. package/core/dev/jev-eval/reports/rules-baseline.json +0 -197
  240. package/core/dev/jev-eval/reports/synthetic-review.pending.json +0 -357
  241. package/core/dev/jev-eval/resilience.mjs +0 -71
  242. package/core/dev/jev-eval/review.mjs +0 -78
  243. package/core/dev/jev-eval/schema.mjs +0 -87
  244. package/core/dev/jev-eval/test/context.test.mjs +0 -95
  245. package/core/dev/jev-eval/test/corpus.test.mjs +0 -102
  246. package/core/dev/jev-eval/test/eval.test.mjs +0 -146
  247. package/core/dev/jev-eval/test/muninn-baseline.test.mjs +0 -71
  248. package/core/dev/jev-eval/test/resilience.test.mjs +0 -72
  249. package/core/dev/jev-eval/test/review.test.mjs +0 -61
  250. package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +0 -338
  251. package/core/dev/pipeline/PROGRESS.md +0 -113
  252. package/core/dev/pipeline/PROGRESS_template.md +0 -860
  253. package/core/dev/pipeline/QA_REPORT_F008.md +0 -431
  254. package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +0 -583
  255. package/core/dev/pipeline/README.md +0 -210
  256. package/core/dev/pipeline/WORKFLOW_GUIDE.md +0 -824
  257. package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +0 -53
  258. package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +0 -54
  259. package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +0 -54
  260. package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +0 -53
  261. package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +0 -56
  262. package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +0 -54
  263. package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +0 -55
  264. package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +0 -65
  265. package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +0 -86
  266. package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +0 -51
  267. package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +0 -66
  268. package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +0 -56
  269. package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +0 -60
  270. package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +0 -60
  271. package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +0 -62
  272. package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +0 -54
  273. package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +0 -56
  274. package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +0 -54
  275. package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +0 -53
  276. package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +0 -57
  277. package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +0 -85
  278. package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +0 -54
  279. package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +0 -60
  280. package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +0 -55
  281. package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +0 -92
  282. package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +0 -58
  283. package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +0 -56
  284. package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +0 -53
  285. package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +0 -58
  286. package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +0 -54
  287. package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +0 -76
  288. package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +0 -64
  289. package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +0 -62
  290. package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +0 -54
  291. package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +0 -51
  292. package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +0 -51
  293. package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +0 -51
  294. package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +0 -53
  295. package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +0 -56
  296. package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +0 -56
  297. package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +0 -57
  298. package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +0 -56
  299. package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +0 -60
  300. package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +0 -53
  301. package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +0 -65
  302. package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +0 -46
  303. package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +0 -61
  304. package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +0 -46
  305. package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +0 -62
  306. package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +0 -62
  307. package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +0 -57
  308. package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +0 -98
  309. package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +0 -57
  310. package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +0 -71
  311. package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +0 -57
  312. package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +0 -68
  313. package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +0 -64
  314. package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +0 -71
  315. package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +0 -56
  316. package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +0 -69
  317. package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +0 -75
  318. package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +0 -70
  319. package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +0 -65
  320. package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +0 -51
  321. package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +0 -59
  322. package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +0 -53
  323. package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +0 -74
  324. package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +0 -63
  325. package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +0 -56
  326. package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +0 -56
  327. package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +0 -55
  328. package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +0 -57
  329. package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +0 -62
  330. package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +0 -51
  331. package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +0 -60
  332. package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +0 -48
  333. package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +0 -67
  334. package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +0 -66
  335. package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +0 -68
  336. package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +0 -46
  337. package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +0 -98
  338. package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +0 -161
  339. package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +0 -62
  340. package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +0 -163
  341. package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +0 -68
  342. package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +0 -63
  343. package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +0 -121
  344. package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +0 -60
  345. package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +0 -58
  346. package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +0 -61
  347. package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +0 -63
  348. package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +0 -56
  349. package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +0 -65
  350. package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +0 -60
  351. package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +0 -84
  352. package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +0 -57
  353. package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +0 -84
  354. package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +0 -115
  355. package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +0 -55
  356. package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +0 -129
  357. package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +0 -60
  358. package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +0 -163
  359. package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +0 -60
  360. package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +0 -59
  361. package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +0 -59
  362. package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +0 -60
  363. package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +0 -58
  364. package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +0 -258
  365. package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +0 -61
  366. package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +0 -403
  367. package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +0 -90
  368. package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +0 -86
  369. package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +0 -83
  370. package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +0 -65
  371. package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +0 -96
  372. package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +0 -63
  373. package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +0 -69
  374. package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +0 -67
  375. package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +0 -93
  376. package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +0 -68
  377. package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +0 -61
  378. package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +0 -65
  379. package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +0 -141
  380. package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +0 -76
  381. package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +0 -77
  382. package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +0 -63
  383. package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +0 -77
  384. package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +0 -82
  385. package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +0 -49
  386. package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +0 -53
  387. package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +0 -48
  388. package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +0 -55
  389. package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +0 -51
  390. package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +0 -52
  391. package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +0 -95
  392. package/core/dev/pipeline/docs/multi-agent-coordination.md +0 -446
  393. package/core/dev/pipeline/docs/overview.md +0 -406
  394. package/core/dev/pipeline/docs/task-management.md +0 -412
  395. package/core/dev/pipeline/docs/workflows.md +0 -32
  396. package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +0 -58
  397. package/core/dev/pipeline/orchestrator/schemas/task_schema.json +0 -139
  398. package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +0 -281
  399. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +0 -27
  400. package/core/dev/plans/ANSUZ_SLIM_PLAN.md +0 -68
  401. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +0 -120
  402. package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +0 -313
  403. package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +0 -126
  404. package/core/dev/scripts/CRASH_DIAGNOSIS.md +0 -47
  405. package/core/dev/scripts/README.md +0 -142
  406. package/core/dev/scripts/RUN_ONCE.bat +0 -40
  407. package/core/dev/scripts/START_DEV_AGENT.bat +0 -63
  408. package/core/dev/scripts/START_MULTI_AGENT.bat +0 -80
  409. package/core/dev/scripts/dev_agent_scheduler.ps1 +0 -536
  410. package/core/dev/scripts/init_git.ps1 +0 -396
  411. package/core/dev/scripts/init_git.sh +0 -337
  412. package/core/dev/scripts/init_project.ps1 +0 -851
  413. package/core/dev/scripts/init_project.sh +0 -477
  414. package/core/dev/scripts/multi_agent_scheduler.ps1 +0 -2021
  415. package/core/dev/scripts/multi_agent_scheduler.sh +0 -1344
  416. package/core/dev/scripts/run_once.sh +0 -47
  417. package/core/dev/scripts/setup_rag.ps1 +0 -304
  418. package/core/dev/scripts/setup_rag.sh +0 -230
  419. package/core/dev/scripts/start_dev_agent.sh +0 -137
  420. package/core/dev/scripts/start_multi_agent.sh +0 -41
  421. package/core/dev/scripts/sync_task_queue.ps1 +0 -505
  422. package/core/dev/scripts/sync_task_queue.sh +0 -392
  423. package/core/dev/specs/agent-connect/PROTOCOL.md +0 -177
  424. package/core/dev/specs/agent-connect/SDK_GUIDE.md +0 -915
  425. package/core/dev/specs/agent-connect/examples/minimal-site/README.md +0 -137
  426. package/core/dev/specs/agent-connect/examples/minimal-site/package.json +0 -12
  427. package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +0 -116
  428. package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +0 -73
  429. package/core/dev/specs/agent-connect/examples/minimal-site/server.js +0 -516
  430. package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +0 -263
  431. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-empty-prompt-no-first-turn.md +0 -77
  432. package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +0 -90
  433. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +0 -61
  434. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +0 -76
  435. package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +0 -87
  436. package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +0 -68
  437. package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +0 -642
  438. package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +0 -244
  439. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +0 -77
  440. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +0 -44
  441. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +0 -37
  442. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +0 -56
  443. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +0 -44
  444. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +0 -56
  445. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +0 -48
  446. package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +0 -57
  447. package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +0 -379
  448. package/core/dev/specs/agent-connect/history/README.md +0 -47
  449. package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +0 -65
  450. package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +0 -54
  451. package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +0 -54
  452. package/core/dev/specs/peer/MODS_SPIKE.md +0 -133
  453. package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +0 -143
  454. package/core/dev/specs/peer/SWARM_PROTOCOLS.md +0 -256
  455. package/core/dev/specs/peer/codex-hook-shim-peer.test.js +0 -113
  456. package/core/dev/specs/peer/codex-push-launcher.test.js +0 -142
  457. package/core/dev/specs/peer/setup-codex-hooks.test.js +0 -60
  458. package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +0 -397
  459. package/core/dev/specs/peer-ansuz/DESIGN.md +0 -109
  460. package/core/dev/specs/peer-ansuz/spike/claude_poke.js +0 -129
  461. package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +0 -37
  462. package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +0 -14
  463. package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +0 -105
  464. package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +0 -29
  465. package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +0 -26
  466. package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +0 -305
  467. package/core/dev/spikes/A4-cypher-varlen.md +0 -176
  468. package/core/dev/spikes/bloat-rounds.sh +0 -25
  469. package/core/dev/spikes/mods/clean-claude.js +0 -9
  470. package/core/dev/spikes/mods/drive-probe.js +0 -29
  471. package/core/dev/spikes/mods/e2e-peer.js +0 -71
  472. package/core/dev/spikes/mods/evidence/e2e-peer-control.json +0 -17
  473. package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +0 -17
  474. package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +0 -4
  475. package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +0 -12
  476. package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +0 -11
  477. package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +0 -18
  478. package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +0 -1
  479. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +0 -1
  480. package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +0 -65
  481. package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +0 -3
@@ -1,915 +0,0 @@
1
- # Kenaz Agent Connect — SDK 開發指南 (SDK_GUIDE.md)
2
-
3
- 給生態系網站開發者的接入文件。讀完本檔 + 跑過 `examples/minimal-site/`,你
4
- 應該能在 30 分鐘內讓自己的網站完成一次「連接 Kenaz → 審批 → 終端分頁 →
5
- 你的網站收到 `kenaz_hello`」的完整流程。
6
-
7
- - 協定權威規格:`./PROTOCOL.md`(v0.4)——本檔每一個參數、錯誤訊息、行為都
8
- 對照該檔與 Kenaz 目前 main 上的實作,不臆測未實作的功能。
9
- - 可跑範例:`./examples/minimal-site/`(零 npm 依賴的 Node 專案,`node
10
- server.js` 三行指令起來)。
11
- - 適用範圍:**Kenaz 自家生態系網站**(目前是 app.kenazai.com、FlowPix),
12
- 不對外公開推廣。
13
-
14
- 你不需要知道 Kenaz 內部怎麼運作——只需要知道深連結長什麼樣、你的 MCP 端點
15
- 要滿足什麼約定,以及使用者會看到什麼畫面。
16
-
17
- ---
18
-
19
- ## 0. 心智模型
20
-
21
- ```
22
- 你的網站(瀏覽器) 使用者本機的 Kenaz 你的網站(後端 MCP)
23
- │ │ │
24
- │ 1. 按「連接」 │ │
25
- │──── kenaz://connect?... ─────>│ │
26
- │ (OS 開啟 Kenaz) │ │
27
- │ │ 2. 顯示審批卡(第 3 節) │
28
- │ │ 使用者按下「允許」 │
29
- │ │ 3. 開一個終端分頁, │
30
- │ │ agent 掛著你的 MCP │
31
- │ │────── kenaz_hello ──────────>│
32
- │ │ │ 4. 記錄「已連線」
33
- │<─────────(你自己的通道,例如輪詢/SSE)───────────────────────│
34
- │ 5. UI 顯示「已連線」 │
35
- ```
36
-
37
- 三個事實決定了整份文件的形狀:
38
-
39
- 1. **深連結本身就是完整的請求。** 沒有事先的配對步驟,沒有 relay,沒有
40
- WebSocket。使用者按下「連接」那一下(同意深連結)就是 launch 本身。
41
- 2. **Kenaz 沒有回程通道。** 你的網站完全靠 agent 呼叫你自己 MCP 的
42
- `kenaz_hello` 工具才知道「連上了」。深連結送出去之後,Kenaz 不會再告訴
43
- 你任何事——不管是審批被拒絕、使用者沒裝 Kenaz、還是 agent 執行失敗。
44
- 3. **Bearer 驗證是你的責任,不是 Kenaz 的。** Kenaz 只是把深連結裡的
45
- `token` 原樣轉交給 agent 當 `Authorization: Bearer <token>`。誰簽發、
46
- 誰驗證、TTL 多長、怎麼撤銷,全部由你決定。
47
-
48
- ---
49
-
50
- ## 1. 10 分鐘接入
51
-
52
- ### 步驟一:簽 token
53
-
54
- 你的後端在使用者按下「連接」時,簽發一個一次性 bearer token(不要重複使用
55
- 上一次連接時發過的 token),綁定你自己的用戶 session:
56
-
57
- ```js
58
- import crypto from 'node:crypto';
59
- const token = crypto.randomBytes(24).toString('base64url'); // 或任何你熟悉的簽發方式
60
- // 存起來:token -> { userId, createdAt, ttl },用你自己的 session 系統
61
- ```
62
-
63
- Token 的唯一硬性限制(deep_link.rs 會驗證,見第 2 節):長度 ≤ 512 字元,
64
- 字元集限 `[A-Za-z0-9._-]`。除此之外由你自己決定形狀——JWT、隨機字串、資料
65
- 庫查得到的 opaque ID 都可以,只要你自己的 MCP 端點認得它。
66
-
67
- ### 步驟二:組深連結
68
-
69
- ```js
70
- const params = new URLSearchParams({
71
- site: 'https://your-site.example', // 你的網站 origin
72
- mcp: 'https://your-site.example/mcp', // 你的 MCP 端點(完整 URL)
73
- token,
74
- });
75
- const deepLink = `kenaz://connect?${params.toString()}`;
76
- ```
77
-
78
- 前端拿到這個 URL 後直接導覽過去(`window.location.href = deepLink` 或一個
79
- `<a href>`):瀏覽器會把 `kenaz://` 交給 OS,OS 交給 Kenaz(若已安裝)。
80
-
81
- ### 步驟三:MCP 加 bearer 驗證與 `kenaz_hello`
82
-
83
- 你的 MCP 端點(任何符合 MCP Streamable HTTP 的伺服器都可以)必須:
84
-
85
- ```js
86
- // 偽代碼——完整可跑版本見 examples/minimal-site/server.js
87
- function handleMcpRequest(req, res) {
88
- const auth = req.headers['authorization']; // "Bearer <token>"
89
- if (!isValidToken(auth)) { res.writeHead(401); res.end(); return; }
90
- // ...JSON-RPC dispatch,至少要有 kenaz_hello 工具(見第 3 節)
91
- }
92
- ```
93
-
94
- 做完這三步,你的網站就符合 Kenaz Agent Connect 的最小約定了。完整範例見
95
- `examples/minimal-site/`。
96
-
97
- ---
98
-
99
- ## 2. 深連結
100
-
101
- ### 格式
102
-
103
- ```
104
- kenaz://connect?site=<url-encoded https origin>&mcp=<url-encoded https MCP url>&token=<one-time token>[&prompt=<url-encoded text>][&agent=claude|codex][&v=1]
105
- ```
106
-
107
- ### 參數表
108
-
109
- | 參數 | 必填 | 說明 |
110
- |---|---|---|
111
- | `site` | 是 | 你的網站 origin。正式環境必須是 `https://...`。開發模式(見第 5 節)允許 `http://localhost` / `http://127.0.0.1` / `http://[::1]`。Kenaz 用 `Url::origin()` 正規化,去掉 path/query/fragment。 |
112
- | `mcp` | 是 | 你的 MCP 端點,**完整 URL(含 path)**。scheme 規則與 `site` 相同。**審批卡上顯示的主要識別是這個 URL 的 host**,不是 `site`——沒有 relay 驗證過的 origin,`mcp` 是 agent 真正會連的對象。 |
113
- | `token` | 是 | 一次性 bearer,≤512 字元,字元集限 `[A-Za-z0-9._-]`。Kenaz 不解讀、不落盤——只在這次啟動期間以環境變數形式交給 agent 當 MCP 的 `Authorization: Bearer` 值。 |
114
- | `prompt` | 否 | 起始 prompt,交給 agent 當第一則訊息。**省略時由 Kenaz 保證仍有第一個 turn**——Kenaz 自己補一句開場訊息觸發它,你不必也不應該為了讓 agent 動起來而塞 `prompt=`(見第 9 節)。 |
115
- | `agent` | 否 | 指定 CLI,`"claude"` 或 `"codex"`。省略時依使用者自己的預設設定;顯式指定但使用者沒裝該 CLI 時 launch 直接失敗,**不會靜默退回別的 CLI**。 |
116
- | `v` | 否 | 協定版本,缺省 `"1"`。目前只有 `"1"` 是合法值;其他值一律 toast 拒絕,不出審批卡。 |
117
-
118
- 任何其他未知參數一律靜默忽略,不拒絕;只有格式不合法(scheme 錯、`token`
119
- 過長、`v` 不支援等)才拒絕。
120
-
121
- ### URL 編碼規則
122
-
123
- 每個參數值都要 `encodeURIComponent`(JS 的 `URLSearchParams` 會自動做這件
124
- 事——見第 1 節範例)。`site`/`mcp` 是完整 URL,所以本身就含有會被
125
- percent-encode 的字元(`:`、`/`),這是預期行為,不是 bug。
126
-
127
- ### 長度限制與「大內容放哪裡」
128
-
129
- 深連結整體長度在 Windows 上約有 **2 KB** 限制(作業系統層級,不是 Kenaz 定
130
- 的)。這代表:
131
-
132
- - `prompt` 只放**簡短**的起始指示。
133
- - 任何長內容(畫布狀態、文件全文、使用者的完整輸入)**不要塞進
134
- `prompt=`**——讓 agent 呼叫你自己 MCP 的其他工具去讀取,你的工具回傳內容
135
- 或一個可再次 fetch 的 URL 即可。這也是第 3 節「大檔案走 URL」的同一個
136
- 原則:深連結和 MCP 工具的回應都不是傳大檔案的地方,讓 agent 自己再發一
137
- 次請求去拿。
138
- - `prompt` 支援任意 UTF-8(含 CJK),你只要照正常的
139
- `encodeURIComponent` percent-encode 即可;Windows 上把內嵌 prompt 正確
140
- 解碼(不會被系統 ANSI codepage 亂碼化)是 Kenaz 這一側的責任,不需要你
141
- 額外處理。
142
-
143
- ### `v` 版本
144
-
145
- 省略時視為 `"1"`。目前整個協定只有版本 `"1"`;`v=999` 這種未來/錯誤的版本
146
- 號會被**明確拒絕**(toast「protocol version unsupported: 999」),不會被
147
- 當成 `"1"` 靜默處理,也不會出審批卡。這是刻意設計:深連結本身就是唯一的請
148
- 求,沒有線上協商步驟能事後補救版本不合的情況,所以必須在這裡就失敗大聲。
149
-
150
- ### `agent` 的語意
151
-
152
- - 省略:用使用者自己在 Kenaz 裡設定的預設 CLI/model。
153
- - 指定 `"claude"` 或 `"codex"`:**只有這兩個字面值**合法(但注意:`agent=`
154
- 不合法值目前不會被 deep_link.rs 拒絕——它會原樣往後傳,直到
155
- `launch::execute` 內部解析 CLI 時才會因為「這個 CLI 不存在/未安裝」而
156
- 失敗,見第 6 節疑難排解表)。
157
- - 指定了但使用者沒裝該 CLI:**launch 直接失敗**,不會退回使用者的預設
158
- CLI——設計上你的 `agent=` 指定要不就完全生效,要不就明確失敗,不會有「我
159
- 以為在跑 codex 結果其實在跑 claude」這種混淆。
160
-
161
- ---
162
-
163
- ## 3. 網站 MCP 最小約定
164
-
165
- 任何網站只要提供一個符合下列約定的 MCP 端點,就能被 Kenaz 的深連結串接。
166
- Kenaz **不列舉、不審核、不限制**你的 MCP 提供什麼工具——這一節只講「必須
167
- 有」和「建議有」的最小子集。
168
-
169
- ### 3.1 Bearer 驗證:簽發、TTL、撤銷建議
170
-
171
- - 每個請求的 `Authorization: Bearer <token>` 必須被你的伺服器驗證是**自己
172
- 簽發、未過期、未撤銷**的。Kenaz 完全不驗證這個 token——它只是深連結裡
173
- 那串字元的原樣轉交者。這是你的網站唯一需要信任的邊界。
174
- - **簽發**:每次使用者按下「連接」都簽一個新的 token,不要重複使用上一次
175
- 的。把 token 綁定到你自己的登入 session,這樣即使 token 外洩,攻擊者能
176
- 做的事也被限制在那個使用者的權限範圍內。
177
- - **TTL**:建議短——這個 token 只需要活到這次終端分頁的session 期間。過期
178
- 就讓後續的 MCP 呼叫全部 401。
179
- - **撤銷**:如果你的網站有「登出」或「撤銷授權」功能,記得同時讓對應的
180
- token 立刻失效,不要只靠 TTL 到期。
181
-
182
- ### 3.1b `X-Kenaz-Session` header(選讀)與工具權限(TASK_1947)
183
-
184
- - 除了 `Authorization: Bearer <token>`,Kenaz 對每個請求還會**一律**多送一
185
- 個 `X-Kenaz-Session: <launch_id>` header。`<launch_id>` 是 Kenaz 在這次
186
- 啟動一開始就產生的 uuid v4,同一次深連結啟動的存續期間固定不變。
187
- - 這個 header 是**選讀**的——bearer 仍是唯一你必須驗證的邊界(見 3.1)。
188
- 它存在的用途:如果你想分辨「這次 MCP 呼叫屬於哪一次連接」,`launch_id`
189
- 比單純用 token 對應更直接——同一個 token 理論上可能被同一使用者的多個
190
- 分頁/連接重用,但 `launch_id` 保證每次啟動獨一無二。
191
- - 範例(claude 分支預配的 MCP config JSON,見
192
- `dev/specs/agent-connect/PROTOCOL.md` §2 fixture
193
- `mcp.config_with_session_header`):
194
-
195
- ```json
196
- {"mcpServers": {"flowpix": {"type": "http", "url": "https://flowpix.app/mcp", "headers": {"Authorization": "Bearer a1b2c3d4e5f60718293a4b5c6d7e8f90", "X-Kenaz-Session": "1b0d6b9a-8f2a-4c56-8abc-9f9e9c9d9e9f"}}}}
197
- ```
198
-
199
- - **本機除錯**:使用者自己在本機呼叫 `GET /api/agent-hub/status` 時,每個
200
- origin 底下會列出 `sessions[]`(`session_id` 就是這個 `launch_id`、還有
201
- `agent`/`model`/`cwd`/`started_at`/`alive`)——這是給使用者自己排查
202
- 「Kenaz 現在覺得有幾個連線活著」用的本機端點,不是你的網站能呼叫的(僅
203
- 限 `127.0.0.1`,見第 4 節「被封鎖後怎麼辦」)。
204
- - **工具權限**:使用者在審批卡按下允許,等於同意了這個 session 使用你的
205
- MCP 工具——claude 分支因此會在啟動前對你的 MCP 做一次 `tools/list` 探
206
- 測,把**依 tool annotations 判定為安全**的工具加進
207
- `--allowedTools`,讓 agent 呼叫那些工具時不用再跳一次終端機權限詢問;
208
- 沒被判定為安全的工具維持逐次詢問。這個允許清單**只**涵蓋你這個 MCP
209
- server 的工具,不會放寬到別的工具。判定規則、探測失敗時的退回行為見
210
- 3.1c。codex 分支目前沒有等效的「只允許某個 MCP」設定可加、也不套用
211
- annotations 分級(查證結論見 PROTOCOL.md「codex 限制」一節)——如果使
212
- 用者用 codex 跑你的網站,第一次工具呼叫是否會跳審批目前未完全驗證。
213
-
214
- ### 3.1c `--allowedTools` 依 tool annotations 分級(TASK_1949,Agent Connect C-1b)
215
-
216
- - **這是什麼**:3.1b 提到 claude 分支會預先允許部分工具跳過終端機權限詢
217
- 問——這一節說明「部分」是怎麼判定的。MCP 規格的 tool `annotations`
218
- (`readOnlyHint`、`destructiveHint`、`idempotentHint`、`openWorldHint`)
219
- 讓你不用發明新協定就能告訴 Kenaz「這個工具有沒有後果」。
220
- - **判定規則**:你的 `tools/list` 回應裡,一個工具的
221
- `annotations.readOnlyHint == true` **或** `annotations.destructiveHint ==
222
- false` 時,會被加進 `--allowedTools`。**沒有 `annotations` 物件、或有
223
- `annotations` 但沒寫 `destructiveHint`,一律不會被預先允許**——MCP 規
224
- 格對 `destructiveHint` 的預設值就是 `true`,Kenaz 沿用這個保守預設,不
225
- 是自創規則。範例(見 PROTOCOL.md §2 fixture
226
- `mcp.tools_list_with_annotations`):
227
-
228
- ```json
229
- {"jsonrpc": "2.0", "id": 1, "result": {"tools": [{"name": "kenaz_hello", "annotations": {"destructiveHint": false, "idempotentHint": true}}, {"name": "kenaz_wait_for_message", "annotations": {"readOnlyHint": true}}, {"name": "echo", "annotations": {"readOnlyHint": true}}, {"name": "delete_all_data", "annotations": {"destructiveHint": true}}]}}
230
- ```
231
-
232
- 這個範例裡只有前三個工具會被預先允許;`delete_all_data`
233
- (`destructiveHint: true`)維持每次呼叫都跳終端機詢問。
234
- - **探測時機與逾時**:Kenaz 在組出啟動腳本前,對你的 `mcp=` 端點送一次
235
- `tools/list` JSON-RPC 請求(header 與其他 MCP 呼叫相同:`Authorization:
236
- Bearer <token>` + `X-Kenaz-Session`),**逾時 3 秒**。
237
- - **探測失敗時的退回**:逾時、HTTP 非 2xx、回應不是合法 JSON、或回應裡
238
- 沒有 `result.tools` 陣列——**任何一種都不會預先允許任何工具**(不是退
239
- 回舊版的全部允許,也不代表你的 MCP 整個不能用),並且會在啟動的終端
240
- 分頁第一行印出失敗原因,方便你自己的使用者(或你自己除錯時)看到
241
- 「為什麼每次工具呼叫都要按一下」。探測成功時同樣會印一行摘要(例如
242
- `pre-allowed 2/4 MCP tools by annotations`)。
243
- - **你不需要做任何事才能運作**——不標 annotations 完全不影響功能,你的
244
- 工具照樣能被呼叫,唯一差別是每次呼叫都會在終端機多跳一次確認。標了
245
- annotations 純粹是幫使用者少按幾次。
246
-
247
- ### 3.2 `kenaz_hello`:回應形狀與逾時處理
248
-
249
- - **建議**(不是強制,但沒有它你的網站永遠不知道有沒有連上)提供一個
250
- `kenaz_hello` 工具:**無參數**,成功回:
251
-
252
- ```json
253
- {"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "{\"ok\":true}"}], "isError": false}}
254
- ```
255
-
256
- 對應的呼叫長這樣:
257
-
258
- ```json
259
- {"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "kenaz_hello", "arguments": {}}}
260
- ```
261
-
262
- - Kenaz 注入給 agent 的人格會在處理 `prompt` **之前**呼叫這個工具一次
263
- ——這是你的網站得知「Kenaz 真的連上了」的**唯一方式**(沒有回程通道,
264
- 見第 0 節)。
265
- - **逾時處理**:建議設 **60 秒**。深連結送出去之後,如果 60 秒內沒有收到
266
- `kenaz_hello` 呼叫,就把前端 UI 從「連線中」切到「請安裝 Kenaz」之類的
267
- 安裝指引(第 4 節有完整的偵測/fallback 邏輯)。60 秒逾時涵蓋了「使用者
268
- 沒裝 Kenaz」「使用者拒絕了審批卡」「使用者封鎖了你的網站」這幾種你**分
269
- 辨不出來**的情況——見第 6 節疑難排解。
270
-
271
- ### 3.3 工具命名:`mcp__<name>__` 前綴由 Kenaz 決定
272
-
273
- Kenaz 把你的 MCP 掛給 agent 時,會用一個從你的 **`mcp=` URL 的 hostname**
274
- 衍生出來的名字當作 MCP server 名稱,agent 看到的完整工具名稱因此是
275
- `mcp__<name>__<你的工具名>`:
276
-
277
- - `mcp=https://flowpix.app/mcp` → `<name>` = `flowpix` → agent 呼叫的是
278
- `mcp__flowpix__kenaz_hello`
279
- - `mcp=https://sub.example.com/mcp` → `<name>` = `sub`(取 hostname 第一個
280
- `.` 之前的 label)
281
- - 衍生規則:hostname 的第一個 label,非英數字元一律換成 `_`;解析失敗或
282
- 結果是空字串則用 `site` 當預設名。
283
-
284
- **你完全不用自己決定或宣告這個前綴**——你只要決定你自己的工具名(例如
285
- `kenaz_hello`、`echo`),Kenaz 會自動加上從你的 MCP hostname 衍生的
286
- server 名稱前綴。這代表:你的 `mcp=` hostname 最好是穩定、看起來像正常英
287
- 數字元的網域名稱,不要依賴前綴本身帶有特殊語意。
288
-
289
- ### 3.4 其餘工具完全自訂
290
-
291
- 你的產品邏輯(生圖、寫回、查詢……)全部經由自訂的 MCP 工具與 agent 互動,
292
- Kenaz 對這段流量完全不可見。設計這些工具時記得:
293
-
294
- - **大檔案走 URL**:工具的回應不要塞入大量二進位或超長文字——回傳一個
295
- 你自己網站可以再次驗證 bearer 後提供內容的 URL,讓 agent 用你的其他機
296
- 制(例如你自己網站上的一個已認證下載端點)去取,而不是塞進單一次
297
- JSON-RPC 回應裡。這與深連結 `prompt=` 的 2 KB 限制是同一個設計原則的兩
298
- 處體現。
299
- - **沒有結束通知**:agent 的終端分頁何時關閉,你的網站不會被告知。用
300
- token 撤銷或閒置逾時回收狀態,不要假設有「已結束」事件。
301
-
302
- ---
303
-
304
- ## 4. 使用者體驗
305
-
306
- ### 審批卡上會顯示什麼
307
-
308
- 使用者按下深連結、Kenaz 判斷這個 origin 不是 `always`/`blocked` 狀態時,
309
- 會跳出一張審批卡,內容固定是:
310
-
311
- ```
312
- {site} → MCP {mcp_host} → {agent}/{model} · cwd {絕對路徑} · {prompt 前 120 字}
313
- ```
314
-
315
- - **site**:深連結 `site=` 的 origin(你的網站自稱,未經第三方驗證)。
316
- - **MCP host**:`mcp=` URL 的 hostname——**這是主要識別**,因為沒有 relay
317
- 驗證過的 origin,這個 host 才是 agent 真正會連上的對象。
318
- - **agent/model**:實際會用的 CLI 與 model(沒指定 `agent=` 就是使用者的
319
- 預設值)。
320
- - **cwd**:agent 會在哪個資料夾執行——**永遠是 Kenaz Dashboard 目前開啟的
321
- 專案,你的網站不能指定**。這一項刻意不可省略:使用者按允許前必須知道
322
- 這次操作會發生在哪個資料夾。
323
- - **prompt 前 120 字**:你的 `prompt=`(若有)截斷到 120 個字元。
324
-
325
- ### 一次/永遠允許/拒絕/封鎖是什麼意思
326
-
327
- Per-origin 四態,鍵值是你的 `site=` origin(不是 `mcp=`):
328
-
329
- | 狀態 | 意義 | 下一次同一 origin 的深連結會發生什麼 |
330
- |---|---|---|
331
- | `unauthorized`(初次) | 從沒授權過 | 出審批卡 |
332
- | `once`(使用者按「允許」) | 這次允許,下次再問 | 出審批卡 |
333
- | `always`(使用者按「永遠允許」) | 跳過審批卡 | **直接執行**(仍會在本機記一筆事件) |
334
- | `blocked`(使用者按「封鎖」,或手動編輯設定檔) | 完全不信任這個 origin | **直接拒絕,連 toast 都只在 Kenaz 本機顯示,你的網站完全看不到** |
335
-
336
- 一個被使用者暫停的 Agent Hub(tray「Pause Agent Hub」)會擋下**所有**深連
337
- 結,包含 `always` 狀態的 origin,而且同樣不出審批卡。
338
-
339
- ### 被封鎖後怎麼辦
340
-
341
- **你的網站完全無法得知自己被封鎖了**——沒有回程通道,被封鎖的請求和「使
342
- 用者根本沒裝 Kenaz」在你的網站端看起來一模一樣(都是 `kenaz_hello`
343
- 逾時,見第 3.2 節與第 6 節)。能解除封鎖的只有使用者自己,在自己的機器
344
- 上,透過下面任一方式:
345
-
346
- - Kenaz 本機的狀態 API(`http://127.0.0.1:18080`,僅限本機呼叫):
347
- - `GET /api/agent-hub/status` 列出所有 origin 目前的狀態。
348
- - `POST /api/agent-hub/revoke {"origin": "https://your-site.example"}`
349
- 會**整筆刪除**這個 origin 的紀錄(含 `blocked` 狀態),下一次深連結
350
- 會重新從 `unauthorized` 出審批卡。
351
- - 或直接編輯 `~/.kenaz/agent_hub/sites.json`,把該 origin 的 `state` 改掉
352
- (Kenaz 每次請求都重新讀檔,不吃記憶體快取,改完立即生效)。
353
-
354
- **你的網站文件應該教使用者**:如果「連接」按了很久都沒反應,除了「還沒安
355
- 裝 Kenaz」之外,也可能是之前不小心按過「封鎖」——請使用者自己去確認。
356
-
357
- ### 「請安裝 Kenaz」的偵測與 fallback
358
-
359
- 因為沒有回程通道,偵測「使用者沒裝 Kenaz」的**唯一**方法是逾時:
360
-
361
- 1. 導覽到 `kenaz://connect?...`。
362
- 2. 同時開始輪詢(或用你自己的推播通道)等待 `kenaz_hello` 被呼叫。
363
- 3. 一段時間(建議跟 `kenaz_hello` 的 60 秒逾時對齊)內沒有收到,就顯示
364
- 「請安裝 Kenaz」的安裝指引頁面 / 下載連結。
365
-
366
- `examples/minimal-site/public/index.html` 有這個邏輯的完整實作
367
- (`pollStatus` + `HELLO_TIMEOUT_MS`),可以直接參考或複製。注意:瀏覽器對
368
- 未註冊的自訂 scheme 導覽通常是靜默失敗(頁面不會跳轉、不會拋錯),所以
369
- **不要**指望用 `catch` 或 `beforeunload` 之類的事件偵測「有沒有裝」——用
370
- 逾時輪詢才是唯一可靠的做法。
371
-
372
- ---
373
-
374
- ## 5. 開發模式
375
-
376
- 正式環境的 `site=`/`mcp=` 必須是 `https://`。要在本機用
377
- `http://localhost` / `http://127.0.0.1` / `http://[::1]` 測試(例如你的
378
- 開發伺服器還沒有 HTTPS),需要 Kenaz 端也進入開發模式:
379
-
380
- - **`KENAZ_AGENT_HUB_DEV=1`**:設這個環境變數啟動 Kenaz,或者
381
- - Kenaz 本身是 **debug build**(`cfg!(debug_assertions)`)——本機 `cargo
382
- tauri dev` 跑起來的版本預設就滿足這個條件,不需要額外設環境變數。
383
-
384
- **環境變數只在行程啟動當下讀取一次**。這代表:
385
-
386
- - 如果 Kenaz 已經在背景執行(含縮到 tray),**改環境變數不會讓正在跑的那
387
- 個行程生效**——必須先從 tray 選單選「Quit」讓 Kenaz **完整退出**(不是
388
- 關視窗,關視窗通常只是縮到 tray),再重新啟動一次帶著
389
- `KENAZ_AGENT_HUB_DEV=1` 的行程。
390
- - 這是最常見的「明明設了環境變數,dev 深連結還是被拒絕」的原因——見第 6
391
- 節疑難排解表。
392
-
393
- **Dev 深連結指向 `target\debug` 的行為**:Debug build 在啟動時(`.setup()`
394
- 內)會呼叫 `register_all()`,把 OS 的 `kenaz://` scheme 註冊指向**這次啟
395
- 動的那個執行檔**(通常是 `target\debug\kenaz-dashboard.exe`)。這代表:
396
-
397
- - 如果你的機器上同時有「一般安裝的 Kenaz」和「本機 build 的 dev
398
- Kenaz」,dev build 一啟動就會把 `kenaz://` 的 OS 註冊**改指向自己**,
399
- 之後所有 `kenaz://connect` 深連結(包含正式網站點出來的)都會打開 dev
400
- 版本,直到你重新安裝/啟動正式版覆蓋回去。開發時如果發現深連結打開了不
401
- 預期的 Kenaz 視窗,先檢查是不是這個原因。
402
-
403
- ---
404
-
405
- ## 6. 測試
406
-
407
- ### 對自己的 MCP 端點做煙霧測試(不需要 Kenaz)
408
-
409
- 你不需要真的裝 Kenaz 才能驗證你的 MCP 端點符不符合第 3 節的約定——因為
410
- Kenaz 對你的 MCP 來說就是「一個會帶著正確 bearer 呼叫 `kenaz_hello`、以及
411
- 帶著錯誤/缺失 bearer 呼叫任何工具」的 HTTP client,這兩件事你可以直接用
412
- `curl` 或任何 HTTP client 模擬:
413
-
414
- ```bash
415
- # 1. 錯誤 bearer 必須 401
416
- curl -i -X POST https://your-site.example/mcp \
417
- -H 'content-type: application/json' \
418
- -H 'authorization: Bearer wrong-token' \
419
- -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"kenaz_hello","arguments":{}}}'
420
-
421
- # 2. 正確 bearer 呼叫 kenaz_hello 必須回 {"ok":true}
422
- curl -i -X POST https://your-site.example/mcp \
423
- -H 'content-type: application/json' \
424
- -H 'authorization: Bearer <一個你自己簽發的合法 token>' \
425
- -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"kenaz_hello","arguments":{}}}'
426
- ```
427
-
428
- `examples/minimal-site/test/smoke.test.mjs` 是這個模式的完整
429
- `node --test` 版本(起一個真的 HTTP server、真的送請求、結束時關閉伺
430
- 服器),可以直接拿來當你自己 MCP 端點測試的樣板——把 `createServer()` 換
431
- 成你自己的伺服器啟動函式即可。
432
-
433
- **目前沒有一個「假 Kenaz」npm 套件**能自動幫你送出 `kenaz://connect` 並模
434
- 擬 agent 呼叫 `kenaz_hello`(SDK 規格 §2.4 把它列為 C 期產出,尚未發佈)
435
- ——上面的 curl / smoke test 手法就是目前**唯一已驗證可行**的「不裝 Kenaz
436
- 也能測」方式:既然 Kenaz 對你的 MCP 來說只是「一個會呼叫工具的 HTTP
437
- client」,直接模擬那個 client 的行為,比等一個尚未存在的模擬器更直接。
438
-
439
- ### Conformance suite(Kenaz 這一側的測試)
440
-
441
- `dashboard/scripts/agent-connect-conformance/run.mjs` 是 Kenaz 專案自己
442
- 的 conformance suite,驗證兩件事:
443
-
444
- 1. `PROTOCOL.md` 裡的 `#### Fixture: deep_link.*` / `mcp.*` 區塊都是合法
445
- JSON,且深連結 fixture 的形狀符合第 2 節的參數表。
446
- 2. Kenaz 自己的假 MCP(`dashboard/scripts/agent-hub-fake-mcp.mjs`)確實會
447
- 對錯誤 bearer 回 401、對 `kenaz_hello` 回 `{"ok":true}` 並記錄呼叫。
448
-
449
- 這個 suite **目前測的是 Kenaz 自己的假 MCP,不是可以指向任意第三方 MCP
450
- URL 的通用工具**——它不是你驗證自己網站 MCP 端點的方式;你的驗證方式是上
451
- 面的 curl / smoke test。它們驗證的是同一件事(bearer 401 + `kenaz_hello`
452
- 形狀),只是分別跑在 Kenaz 這一側與你這一側。跑法:
453
-
454
- ```bash
455
- node --test dashboard/scripts/agent-connect-conformance/run.mjs
456
- ```
457
-
458
- ### 對真 Kenaz 做一次端到端連接(需要安裝或本機跑 Kenaz)
459
-
460
- 1. 依第 5 節設定開發模式並完整重啟 Kenaz。
461
- 2. 跑起 `examples/minimal-site/`(`node server.js`)。
462
- 3. 瀏覽器打開範例頁面,按「連接 Kenaz」。
463
- 4. 預期看到:審批卡(site/MCP host/agent/model/cwd/prompt 都符合第 4 節格
464
- 式)→ 按「允許」→ Dashboard 開一個新的終端分頁 → agent 在處理 prompt
465
- 之前呼叫 `mcp__<name>__kenaz_hello` → 範例頁面的輪詢偵測到「已連線」。
466
-
467
- ---
468
-
469
- ## 7. 疑難排解
470
-
471
- ### Toast 訊息對照表
472
-
473
- Kenaz 拒絕深連結時,只會在**自己本機**顯示一個 toast(你的網站看不到,
474
- 沒有回程通道)。下表逐字對照 Kenaz 目前 main 上
475
- `dashboard/src-tauri/src/features/agent_hub/deep_link.rs` 的
476
- `DeepLinkError` Display 實作與 `mod.rs::handle_incoming_url` 組出的完整
477
- toast 文字:
478
-
479
- | 情況 | 完整 toast 文字 | 你該怎麼修 |
480
- |---|---|---|
481
- | URL 完全無法解析 | `Rejected deep link: not a parseable URL` | 檢查有沒有漏編碼、字串是不是完整的 URL |
482
- | scheme 不是 `kenaz` | `Rejected deep link: unsupported scheme: <scheme>` | 確認開頭是 `kenaz://` |
483
- | host 不是 `connect` | `Rejected deep link: not a connect action` | 確認是 `kenaz://connect?...`,不是別的 action |
484
- | 缺少必填欄位 | `Rejected deep link: missing field: site` / `mcp` / `token` | 檢查第 2 節參數表——`site`/`mcp`/`token` 三個都必填 |
485
- | `site` 不是合法 URL | `Rejected deep link: site is not a parseable URL` | 確認 `site=` 是一個完整、可解析的 URL |
486
- | `site` scheme 不允許 | `Rejected deep link: site scheme not allowed: http` | 正式環境用 `https://`;本機測試需要開發模式(第 5 節)且 host 必須是 `localhost`/`127.0.0.1`/`[::1]` 其中之一(bracket 形式的 `[::1]`,其他 IPv6 位址不算) |
487
- | `mcp` 不是合法 URL | `Rejected deep link: mcp is not a parseable URL` | 確認 `mcp=` 是一個完整、可解析的 URL |
488
- | `mcp` scheme 不允許 | `Rejected deep link: mcp scheme not allowed: http` | 同上,`mcp=` 適用一模一樣的 https/開發模式規則 |
489
- | `token` 是空字串 | `Rejected deep link: token is empty` | `token=` 不能是空值 |
490
- | `token` 超過 512 bytes | `Rejected deep link: token too long: <n> bytes` | 縮短你的 token;大內容走第 3.4 節「大檔案走 URL」 |
491
- | `token` 含不合法字元 | `Rejected deep link: token has invalid characters` | 字元集只能是 `[A-Za-z0-9._-]` |
492
- | `v` 不是 Kenaz 支援的版本 | `Rejected deep link: protocol version unsupported: <v>` | 目前只支援 `v=1`(或省略);不要自己編一個版本號 |
493
- | Agent Hub 被使用者暫停(tray「Pause Agent Hub」) | `Agent Hub is paused` | 這是使用者自己的選擇,你的網站無法繞過;只能等使用者自己恢復 |
494
- | origin 是 `blocked` 狀態 | `<你的 site origin> is blocked` | 見第 4 節「被封鎖後怎麼辦」——只有使用者自己能解除 |
495
- | 使用者在審批卡按了「拒絕」 | (不會 toast——只是安靜地不執行;`Decision::Deny`) | 這是正常拒絕流程,不是錯誤;你的網站一樣只能靠逾時偵測 |
496
- | Launch 本身失敗(審批通過**之後**) | `[<error_code>] <錯誤訊息>`,例如 `[agent_unavailable] requested agent "codex" is not installed (probed \`codex --version\`)` 或 `[not_logged_in] codex is not logged in — run \`codex login\` before this site can generate anything` | 通常是使用者本機環境問題(CLI 沒裝、沒登入),不是你網站端能修的;`agent=` 若指定了不存在的 CLI 會落在這裡,不是落在深連結驗證階段 |
497
-
498
- **重要**:以上全部只在 Kenaz 本機顯示,你的網站永遠看不到。你能做的只有
499
- 第 4 節講的逾時偵測 + fallback 頁面,以及在你自己的文件裡引導使用者去看
500
- Kenaz 視窗的 toast。
501
-
502
- ### 常見錯誤
503
-
504
- - **「按了連接沒反應」**:先確認瀏覽器有沒有跳出「要不要用 Kenaz 開啟這個
505
- 連結」的系統對話框——大部分瀏覽器對未安裝的自訂 scheme 是完全靜默的,
506
- 不會有任何視覺回饋。用第 4 節的逾時偵測,不要假設「沒反應」等於使用者
507
- 看到了什麼。
508
- - **「dev 模式設了環境變數還是被拒絕 `site scheme not allowed: http`」**
509
- :Kenaz 沒有完整重啟過(見第 5 節——環境變數只在行程啟動當下讀一次,
510
- 必須先 tray Quit 再重開)。
511
- - **「MCP 一直收不到 `kenaz_hello`,但審批卡有出現而且我按了允許」**:先
512
- 用第 6 節的 curl 手法確認你的 MCP 端點本身沒問題(bearer 對得上、
513
- `kenaz_hello` 回應形狀正確)。如果 MCP 端點本身沒問題,通常是 agent
514
- 端啟動失敗(見上面「Launch 本身失敗」那一列的 toast),跟你的網站/MCP
515
- 無關。
516
- - **「同一個 origin 明明按過永遠允許,這次又跳審批卡」**:檢查是不是換了
517
- `mcp=` 的 hostname 或整個換了瀏覽器/使用者 profile——四態權限的 key 是
518
- `site=` 的 origin,不是 `mcp=`,正常情況下換 `mcp=` 不會重置狀態,但如
519
- 果連 `site=` 都變了(例如從 `https://your-site.example` 換成
520
- `https://www.your-site.example`)就是不同 origin,會重新從
521
- `unauthorized` 開始。
522
-
523
- ---
524
-
525
- ## 8. 安全
526
-
527
- - **Token 不可重用**:每次「連接」都簽一個新的一次性 token,不要把同一個
528
- 值發給下一次連接請求——重用會讓你失去「這個 token 對應哪一次連接」的可
529
- 追蹤性,也讓撤銷變得沒有意義。
530
- - **不要把長期憑證放進深連結**:深連結的 `token=` 只應該是一個短命、限定
531
- 用途的 bearer,绑定這一次連接。不要把使用者的長期 API key、OAuth
532
- refresh token 之類的東西直接塞進 `token=`——深連結會經過 OS 的 URL
533
- handler,也可能被瀏覽器歷史記錄或系統日誌留下痕跡。
534
- - **MCP 只信 bearer,不要信任何其他隱含的信任來源**:Kenaz 不會替你驗證
535
- `token`;你的 MCP 端點收到的每一個請求都要自己驗證
536
- `Authorization: Bearer <token>`,不要假設「請求是從 Kenaz 打來的所以一
537
- 定合法」——任何知道你 MCP URL 的人都可以直接對它送 HTTP 請求,繞過整個
538
- 深連結流程。
539
-
540
- ---
541
-
542
- ## 9. 持續對話:`kenaz_wait_for_message`(TASK_1948,FlowPix S2)
543
-
544
- 第 3 節的 `kenaz_hello` 只解決「連上了沒」——如果你的網站想在那之後**繼續
545
- 跟 agent 對話**(例如你自己的聊天 UI 使用者又打了一行字,或畫布又產生了新
546
- 的狀態要交給 agent 處理),過去唯一的做法是自己在 `prompt=` 或某個工具的
547
- 回應裡塞一堆「請持續呼叫我」的 prompt 工程指令,效果不穩定也不可測試。
548
- v0.4 把這件事收斂成一個**可選的**約定工具,讓「agent 會不會一直聽」這件事
549
- 從你的 prompt 措辭搬進 Kenaz 人格本身。
550
-
551
- ### 這是什麼
552
-
553
- 你的 MCP 若在 `tools/list` 多提供一個無參數工具 `kenaz_wait_for_message`,
554
- Kenaz 注入的 Ansuz 人格會在呼叫過 `kenaz_hello`、處理完 `prompt` 之後,
555
- **自動反覆呼叫它**,不需要你在 prompt 裡寫任何「請持續輪詢」之類的指
556
- 令——完全不提供這個工具的網站,行為與現在完全一樣(agent 只呼叫一次
557
- `kenaz_hello`,之後就照 prompt 跟你其餘的工具互動,不會提起、也不會呼叫
558
- 一個不存在的工具)。
559
-
560
- **`prompt` 省略時由 Kenaz 保證**(TASK_1956):CLI 的第一個位置參數就是互
561
- 動式會話的第一則使用者訊息,省略/空字串在機制上等於「沒有第一個
562
- turn」——連 Kenaz 注入的人格本身都不會被 agent 讀到,`kenaz_hello`/
563
- `kenaz_wait_for_message` 這整套約定自然也就永遠不會發生。Kenaz 因此在
564
- `prompt` 為空/空白時,自己補一句純 ASCII 的開場訊息(帶你的 `site`
565
- origin)當作這第一則訊息,讓上面這段流程照樣跑起來。**這代表你完全不需
566
- 要、也不應該**為了讓 agent「動起來」而自己塞一句 `prompt=` 當觸發
567
- 器——那正是這個約定原本要讓你省掉的 prompt 工程。
568
-
569
- ### 回應形狀
570
-
571
- ```json
572
- {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "kenaz_wait_for_message", "arguments": {}}}
573
- ```
574
-
575
- ```json
576
- {"jsonrpc": "2.0", "id": 2, "result": {"content": [{"type": "text", "text": "{\"message\":\"add a red circle to the canvas\",\"message_id\":\"m_1\",\"end\":false}"}], "isError": false}}
577
- ```
578
-
579
- - `message` 非 `null`:agent 把它當成使用者的下一則指令執行,執行完再呼叫
580
- 一次。
581
- - `message` 為 `null`:目前沒有新訊息,不是錯誤——agent 直接再呼叫一次
582
- (這是**預期的常態**,不是逾時或失敗)。
583
- - `end` 為 `true`(可省略,預設 `false`):agent 停止呼叫,告知使用者對話
584
- 已結束。
585
- - agent 連續呼叫這個工具失敗(逾時、拋錯、連線失敗)達 **3 次**,也會停
586
- 止並告知使用者——你不需要自己實作「停止」邏輯之外的任何額外信號。
587
-
588
- 完整的權威規格見 `./PROTOCOL.md` 第 2 節第 5 點;`examples/minimal-site/
589
- server.js` 有一份可跑的參考實作(記憶體信箱:`POST /message` 投遞,
590
- `kenaz_wait_for_message` 長輪詢拉取,見該範例的 README「持續對話」一節)。
591
-
592
- ### 用長輪詢實作,不是短輪詢——這個成本算在使用者頭上
593
-
594
- **這是本節唯一的強制條款**:`kenaz_wait_for_message` 的每一次呼叫都是一次
595
- 真實的 agent turn,成本由**呼叫它的 Kenaz 使用者自己的訂閱額度**承擔,不
596
- 是你網站的成本。這代表:
597
-
598
- - 你的伺服器端實作**必須**用長輪詢——收到請求後,如果暫時沒有新訊息,先
599
- 阻塞著(建議 **20-25 秒**)等新訊息進來,逾時了才回 `message: null`;
600
- 不要立刻回應。
601
- - **不得**用短輪詢(例如每 1 秒就回一次 `null`,靠 agent 自己在 1 秒後再
602
- 呼叫一次)——這會讓 agent 為了等你的下一則訊息,高頻率地消耗使用者的
603
- 訂閱額度,而這個消耗對你的網站完全免費、對使用者卻是真金白銀。把長輪
604
- 詢窗口拉長,是你對使用者訂閱額度的責任,不是效能優化的選項。
605
-
606
- ### 跟 FlowPix 自己的信箱模式的對照
607
-
608
- 如果你已經有一套「使用者訊息 → 佇列 → worker 拉取處理」的信箱/佇列架
609
- 構(FlowPix 內部原本就是這樣:畫布事件先進一個佇列,worker 再消費),
610
- `kenaz_wait_for_message` 幾乎是直接把你信箱的**消費端**換成「agent 呼叫
611
- 的 MCP 工具」而已:
612
-
613
- | FlowPix 原有信箱模式 | `kenaz_wait_for_message` |
614
- |---|---|
615
- | worker 對佇列做長輪詢 / blocking pop | agent 對你的 MCP 工具做長輪詢式呼叫 |
616
- | 佇列裡的一筆訊息 | 回應裡的 `message` 欄位 |
617
- | 訊息的唯一 ID(供去重/確認) | `message_id` 欄位 |
618
- | worker 收到「關閉佇列」信號就停止消費 | 回應裡的 `end: true` |
619
- | 佇列基礎設施掛了,worker 重試幾次後放棄 | 連續呼叫失敗 3 次,agent 放棄並告知使用者 |
620
-
621
- 差異只在於:你的信箱現在多了一個**消費者是 Kenaz 使用者本人的 agent
622
- turn**,每次消費都有真實成本(見上一節)——這也是為什麼即使你已經有一套
623
- 成熟的信箱架構,也不建議把它原本對內部 worker 用的短輪詢頻率原封不動套
624
- 用到這個工具上。
625
-
626
- ### 這節不涵蓋什麼
627
-
628
- - **不涵蓋 agent 輸出串流回你的網站**(S3,未分期)——`kenaz_wait_for_
629
- message` 只是「網站 → agent」單向的訊息投遞,agent 執行過程或結果不會
630
- 透過這個機制串流回你的網站;如果你需要看到執行進度,一樣得靠你自己另
631
- 外設計的工具(例如 agent 主動呼叫的一個「回報進度」工具)。
632
- - **不涵蓋 agent 主動通知「我結束了」**(S4,未分期)——`end: true` 只是
633
- 你告訴 agent「別再問了」,不是 agent 告訴你「我做完了」;agent 結束一
634
- 段對話(不管是你送了 `end: true`,還是使用者自己叫它停)之後,終端分頁
635
- 何時關閉、agent 進程是否還活著,你的網站依然無從得知(第 3.4 節「沒有
636
- 結束通知」的限制在這裡同樣成立)。
637
- - **不改變審批卡文案**——目前的審批卡(第 4 節)不會因為你的 MCP 有沒有
638
- `kenaz_wait_for_message` 而顯示任何額外內容。
639
-
640
- ---
641
-
642
- ## 10. 未安裝流程:偵測 + 導向安裝頁(TASK_1950)
643
-
644
- 第 4 節「請安裝 Kenaz 的偵測與 fallback」講的是**一般性**的逾時
645
- fallback——60 秒沒收到 `kenaz_hello` 就顯示一段安裝指引文字,而且刻意把
646
- 「沒裝」「使用者拒絕審批」「使用者封鎖了你的網站」三種情況混在一起,因為
647
- 網站真的分辨不出來(第 0 節「沒有回程通道」)。
648
-
649
- 這一節加的是一個**更快、專門針對「可能沒裝」的獨立偵測層**,用途不是取
650
- 代第 4 節的 60 秒一般性 fallback,而是在它之前先做一次快速判斷、**主動導
651
- 覽**到安裝頁(不只是顯示一段文字),並把原始深連結透過 `return=` 帶過
652
- 去,讓使用者裝完 Kenaz 之後不用再按一次「連接」。`@kenaz/connect` 這個
653
- SDK npm 套件本身**尚未實作**(C 期產出,見 §6「目前沒有一個『假
654
- Kenaz』npm 套件」段落同樣的分期狀態)——這一節記錄的是它的目標行為,
655
- `examples/minimal-site/` 用零依賴的原生 JS 先示範同一套邏輯,供現在就要
656
- 接入的網站參考。
657
-
658
- ### 流程圖
659
-
660
- ```
661
- 使用者按「連接」
662
- │
663
- ▼
664
- 組深連結 kenaz://connect?...(第 2 節)→ 記下 startedAt
665
- │
666
- ▼
667
- window.location.href = 深連結(同一分頁導覽,OS 靜默失敗或開啟 Kenaz)
668
- │
669
- ▼
670
- 開始輪詢自己後端的連線狀態(例如 GET /api/status/:token)──┐
671
- │ │
672
- │ 每次輪詢檢查: │ 每 1 秒
673
- ▼ │
674
- 已收到 kenaz_hello?──是──> 顯示「已連線」,結束 │
675
- │否 │
676
- ▼ │
677
- now - startedAt >= NOT_INSTALLED_TIMEOUT_MS(預設 8 秒)?──否─┘
678
- │是
679
- ▼
680
- 導覽到安裝頁:installUrl + "?return=" + encodeURIComponent(原始深連結)
681
- │
682
- ▼
683
- (使用者在安裝頁下載、安裝、Kenaz 完成 scheme 註冊)
684
- │
685
- ▼
686
- 安裝頁重新觸發 return= 裡的那條深連結
687
- │
688
- ▼
689
- 回到第 2 節的深連結流程(審批卡 → 終端分頁 → kenaz_hello)
690
- ```
691
-
692
- ### 逾時判定:8 秒預設,backend 沒收到 `kenaz_hello` 為準
693
-
694
- - **預設 8 秒**(`examples/minimal-site` 裡的 `NOT_INSTALLED_TIMEOUT_MS`,
695
- 可調——見下方「minimal-site 怎麼示範」)。比第 4 節的 60 秒短得多,因
696
- 為這裡的目的是快速把「大概率沒裝」的使用者送去安裝頁,不是給審批卡的
697
- 使用者充分反應時間。
698
- - **判定依據**:網站自己的後端在這個時間窗內有沒有收到 agent 呼叫
699
- `kenaz_hello`(第 3.2 節)——輪詢自己後端的連線狀態端點,跟第 4 節同一
700
- 個機制,只是時間窗更短。
701
- - **瀏覽器 blur/visibilitychange 不是主要依據**:導覽到 `kenaz://` 這類
702
- 自訂 scheme 時,部分瀏覽器/OS 組合會短暫觸發分頁失焦(跳出「要不要用
703
- Kenaz 開啟」的系統對話框,或 OS 真的切到 Kenaz 視窗),可以拿來當一個
704
- **加速捷徑**(例如「分頁在 1 秒內重新拿到焦點」,八成是系統對話框被使
705
- 用者選了「取消」,可以提早判定沒裝)——但這個訊號在不同瀏覽器、不同
706
- OS 上是否觸發、觸發時機都不一致,**不能當成唯一或主要判定依據**,`kenaz_hello`
707
- 逾時仍然是唯一可靠的來源。
708
- - **已知的取捨(未解決,如實記錄)**:8 秒對於「已經裝了 Kenaz,但使用
709
- 者還沒看到/還沒按審批卡」的使用者是會誤判的——審批卡跳出、使用者切
710
- 去讀別的視窗、8 秒內沒按「允許」,一樣會被導去安裝頁。這是這個設計故
711
- 意接受的假陽性,換取「真的沒裝」的使用者不用等到 60 秒才知道要去哪
712
- 裡。如果你的網站場景使用者反應通常較慢,把
713
- `NOT_INSTALLED_TIMEOUT_MS`/`KENAZ_INSTALL_TIMEOUT_MS` 調大一些即可——這
714
- 就是它必須是可調參數、不能寫死的原因。
715
-
716
- ### 安裝頁 URL 從哪裡來——這是一個可設定參數,不是臆造的路由
717
-
718
- **目前沒有已知的 `app.kenazai.com` 安裝頁路由**,本檔不臆造一個。查證
719
- `dashboard/scripts/publish-release.js` 得到的實際事實:
720
-
721
- - Kenaz 的正式安裝檔上傳到 Supabase Storage 的 `kenaz-release` bucket
722
- (`publish-release.js` 第 19 行 `const BUCKET = 'kenaz-release'`)。
723
- - 下載 URL 形狀:
724
- `{SUPABASE_URL}/storage/v1/object/public/kenaz-release/{version}/{encodeURIComponent(nsisZip檔名)}`
725
- (第 113-115 行)。
726
- - `latest.json` 上傳到同一個 bucket 的根目錄(`{SUPABASE_URL}/storage/v1/
727
- object/public/kenaz-release/latest.json`),內容形狀是
728
- `{version, notes, pub_date, platforms: {"windows-x86_64": {url,
729
- signature}}}`(第 117-127 行)——這是 Tauri updater 消費的格式,不是給
730
- 瀏覽器直接開的人類可讀安裝頁。
731
- - `SUPABASE_URL` 本身**不在本 repo 裡**(`publish-release.js` 從
732
- gitignored 的 `.env.local` 讀取,第 21-35 行)——因此本檔**無法引用**
733
- 正式環境的實際 bucket URL,只能引用上面這個結構事實。
734
-
735
- **結論**:在 Kenaz 提供一個正式的人類可讀安裝頁之前,`installUrl` 是
736
- SDK/範例的一個**必填設定參數**,不是硬編碼常數:
737
-
738
- - `examples/minimal-site/server.js` 讀取環境變數 `KENAZ_INSTALL_URL`
739
- (沒設時退回一個明顯是佔位符的預設值
740
- `https://kenaz-install.example/placeholder`,`.example` TLD 保證不會意
741
- 外解析成真的網域),伺服器端把它注入 `public/index.html` 連接按鈕的
742
- `data-install-url` 屬性。
743
- - 在 Kenaz 提供正式安裝頁之前,網站可以自行把這個參數指向:**(a)** 自
744
- 家的下載頁(自己寫「請安裝 Kenaz」+ 下載連結 + 裝完後手動再按一次「連
745
- 接」),或 **(b)** 一個會去讀 `latest.json`、解析出
746
- `platforms['windows-x86_64'].url` 再自動觸發下載的輕量頁面。無論哪
747
- 種,`return=` 參數(下一節)都應該由網站自己的頁面在裝完之後負責重新
748
- 觸發,而不是假設 Kenaz 的安裝程式本身會處理 `return=`——目前的 NSIS 安
749
- 裝程式沒有讀取/處理任何啟動參數的已知邏輯(未在本任務驗證範圍內找到相
750
- 反證據,也未逐行查證安裝程式腳本;如果之後要做到「安裝完自動觸發
751
- `return=`」,需要另外驗證/修改安裝程式,這不在本任務 scope 內)。
752
-
753
- ### `return=`:帶原始深連結,以及一個目前沒有協定層數字保證的 TTL 風險
754
-
755
- `return=` 的值是**原始的 `kenaz://connect?...` 深連結**,整個字串經
756
- `URLSearchParams.set('return', deepLink)` 處理(等同
757
- `encodeURIComponent`,見 `examples/minimal-site/public/install-redirect.js`
758
- 的 `buildInstallRedirectUrl()`)。
759
-
760
- **查證 TTL 數字的結果(更正一個容易望文生義的假設)**:`PROTOCOL.md` §2
761
- 點 1 與本檔 §3.1 都只寫「TTL:建議短——這個 token 只需要活到這次終端分
762
- 頁的 session 期間」,**沒有任何具體秒數**——Kenaz 完全不驗證、不落盤這個
763
- token(第 0 節「沒有回程通道」的同一個事實:Kenaz 只是原樣轉交),TTL
764
- 純粹是網站自己的決定,協定層沒有規定任何數字。
765
-
766
- 這對「未安裝流程」有一個實際後果:使用者從按下「連接」到裝完 Kenaz、
767
- `return=` 裡的深連結被重新觸發,中間可能經過**任意長**的時間(下載、安
768
- 裝、可能還要重開機)——遠超過「一個終端分頁 session 的存續期間」這個一
769
- 般性 TTL 假設所預期的量級。如果網站的 token 依照 §3.1 的一般建議設得很
770
- 短,`return=` 重新觸發時很可能已經過期,導致裝完 Kenaz 後审批卡看起來
771
- 正常跳出、agent 也啟動了,但呼叫 `kenaz_hello` 時網站的 bearer 驗證卻
772
- 401——使用者會卡在「裝都裝了怎麼還是連不上」。
773
-
774
- **建議(本檔的建議,不是協定規定)**:網站在替「未安裝流程」產生 token
775
- 時,要嘛(a)給這個特定用途的 token 一個明顯更寬容的 TTL(例如以「分
776
- 鐘」而非「這一個 session」為單位),要嘛(b)更穩妥的做法——`return=`
777
- 不要直接指向裸的 `kenaz://` 深連結,而是指回網站自己的一個頁面
778
- (例如 `https://your-site.example/connect?resume=1`),讓那個頁面重新
779
- 執行第 1 節「步驟一:簽 token」+「步驟二:組深連結」重新簽發一個全新
780
- token,再導覽到新組出的深連結——這樣就完全不用假設任何 TTL 撐得過使用
781
- 者離開網站的這段時間。`examples/minimal-site` 目前示範的是最直接的
782
- (a) 類做法的簡化版(沿用原深連結字面值),選 (b) 的網站需要自己加一個
783
- resume 路由,這不在本任務 scope 內、範例沒有實作。
784
-
785
- ### minimal-site 怎麼示範
786
-
787
- `examples/minimal-site/public/install-redirect.js` 是這段邏輯的**純函
788
- 數**實作(刻意抽成獨立檔案而不是塞進 `index.html` 的 inline script,因
789
- 為同一份邏輯要同時被瀏覽器跟 `node --test` 匯入,見該檔案的檔頭註解):
790
-
791
- - `hasInstallTimedOut({ startedAt, timeoutMs, now })`:逾時判定,`now`
792
- 可外部注入方便測試。
793
- - `buildInstallRedirectUrl(installUrl, deepLink)`:組出帶 `return=` 的安
794
- 裝頁 URL。
795
- - `resolveInstallRedirect({ connected, startedAt, timeoutMs, installUrl,
796
- deepLink, now })`:單一決策入口——`connected` 為真或還沒逾時都回
797
- `null`(`connected` 的檢查優先於逾時檢查,逾時後才收到的「已連線」回
798
- 應不應該還被導去安裝頁),逾時且未連線才回傳導向 URL。
799
-
800
- `public/index.html` 的連接按鈕透過 `data-install-url` /
801
- `data-not-installed-timeout-ms` 兩個屬性讀取設定(`server.js` 的
802
- `renderIndexHtml()` 從 `KENAZ_INSTALL_URL` / `KENAZ_INSTALL_TIMEOUT_MS`
803
- 環境變數注入,見該檔案),輪詢迴圈每次都呼叫
804
- `resolveInstallRedirect()`,拿到非 `null` 就直接
805
- `window.location.href = redirectUrl` 導覽過去。
806
-
807
- `test/smoke.test.mjs` 用 200ms 的短逾時(而不是真的 8 秒)驗證這條路徑
808
- (TASK_1950 AC1):
809
-
810
- - 逾時前呼叫 `resolveInstallRedirect` 必須回 `null`。
811
- - 逾時後(且 `connected: false`)必須回傳一個 URL,其 `return=` 參數解
812
- 碼後**等於原始深連結字串**。
813
- - 對照組:`connected: true` 時,就算已經遠遠超過逾時,也絕不能回傳導向
814
- URL(`feedback_probe_needs_control_group` 這條記憶——沒有對照組的通過
815
- 證明不了邏輯是對的,只證明程式碼跑起來沒拋錯)。
816
- - 額外驗證 `GET /` 真的把設定值注入進 HTML、`GET /install-redirect.js`
817
- 把同一份模組當真的靜態檔案提供(不是另外複製一份給瀏覽器用)。
818
-
819
- 跑法:
820
-
821
- ```bash
822
- node --test dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs
823
- ```
824
-
825
- ### 冷啟動:Windows 上的深連結能不能被剛啟動的 Kenaz 接住?
826
-
827
- 這是本節最需要如實記錄的部分——**已修復(TASK_1953):Kenaz 啟動時讀取
828
- `get_current` 補處理;待實機冷啟動驗證**,不是「已驗證可行」:
829
-
830
- 1. `tauri-plugin-deep-link` 2.4.10(`Cargo.lock` 釘的版本)在**它自己的
831
- plugin `.setup()` 階段**(`init_deep_link()`,套件原始碼
832
- `src/lib.rs` 第 68-79 行)就會呼叫
833
- `handle_cli_arguments(std::env::args())`(第 196-220 行):Windows/
834
- Linux 上,如果啟動參數只有一個且能解析成一個符合設定 scheme 的 URL,
835
- 會把它存進 `self.current`(供 `get_current()` 讀取)**並且**立刻
836
- `self.app.emit("deep-link://new-url", vec![url])`。
837
- 2. `on_open_url()`(同檔案第 514-524 行)的實作就是
838
- `app.listen("deep-link://new-url", ...)`——一個標準的 Tauri event
839
- listener,**不會**補送監聽之前就發生過的事件。
840
- 3. Tauri 2.10.2 的 `Builder::build()`(`tauri` crate `src/app.rs` 第
841
- 2094 行起)會呼叫 `app.manager.initialize_plugins(handle)`(第 2286
842
- 行附近),這一步會跑過每個 plugin 自己的 `.setup()`——包含上面第 1 點
843
- 的 `handle_cli_arguments` 呼叫與事件 emit。這整個 `build()` 呼叫,發
844
- 生在 KenazAI 自己那個 app 層級的 `.setup(|app| {...})` 閉包(`lib.rs`
845
- 第 1331 行起)**執行之前**——後者是被 `src/app.rs` 裡另一個自由函式
846
- `setup<R>()`(第 2371 行 `app.ran_setup = true`)呼叫的,而那個自由函
847
- 式是在 `App::run()` 的事件迴圈裡才觸發,時間點晚於 `build()`。
848
- 4. KenazAI 自己的
849
- `dashboard/src-tauri/src/features/agent_hub/mod.rs`
850
- `install_deep_link_handler()`(第 111-139 行)是在上述第 3 點「較晚」
851
- 的那個 `.setup()` 閉包裡才呼叫(`lib.rs` 第 1400 行),而且**只**呼叫
852
- `on_open_url()`——通篇 `dashboard/src-tauri/src/` 搜尋 `get_current()`
853
- 在 deep-link 這個 extension 上的呼叫,結果是**零筆**。
854
-
855
- 四點合起來:**在 Windows 上,一個真正的「Kenaz 完全沒在跑,直接靠雙擊
856
- `kenaz://connect?...` 冷啟動」的情境下,`handle_cli_arguments` 在 plugin
857
- setup 階段 emit 的那個事件,此時還沒有任何 listener 訂閱它(`on_open_
858
- url` 要等到後面的 app-level `.setup()` 才註冊)——這個事件因此被靜靜地
859
- 丟掉。這是 TASK_1950 查證當下(沒有任何地方呼叫 `get_current()`)的實際
860
- 狀態,會導致不出審批卡、不出 toast、什麼都不會發生——跟「使用者根本沒
861
- 看到任何反應」的現象一模一樣。
862
-
863
- **已修復(TASK_1953)**:`install_deep_link_handler()`
864
- (`dashboard/src-tauri/src/features/agent_hub/mod.rs`)在註冊完
865
- `on_open_url` 之後,補一次 `app.deep_link().get_current()`——若冷啟動時
866
- plugin setup 階段已經捕獲但尚未被任何 listener 處理的 URL 存在,會逐一
867
- 餵進與 `on_open_url` 完全相同的 `handle_incoming_url()` 路徑(兩者共用
868
- 同一個 `spawn_handle_url` helper,不重複解析邏輯);`get_current()` 回
869
- `Err`/`None` 時只 `tracing::debug!` 靜默記錄,不影響啟動。已在執行時的
870
- 第二次啟動(single-instance 轉發)走的是另一條路徑(見下段),不會與
871
- `get_current()` 重複處理同一個 URL。
872
-
873
- 這個修復連同上面 1-4 點的查證,完全基於閱讀 `tauri-plugin-deep-link`
874
- 2.4.10 與 `tauri` 2.10.2 的原始碼(本機 cargo registry cache)加上
875
- KenazAI 自己的原始碼——**尚未做過真的冷啟動實機測試**(TASK_1953 同樣
876
- 在 worktree 中完成,worktree 規則禁止對正在跑的 live tauri dev 動任何
877
- 東西,也不能啟動一個新的 Kenaz 行程)。單實例轉發(已在執行時的第二次
878
- 啟動)走 `tauri-plugin-single-instance` 的 `deep-link` feature,
879
- TASK_1928 已實測正常,不受本次修復影響、也不在待驗證範圍內。
880
-
881
- **實機冷啟動驗證步驟**(待主線程或有桌面環境的人執行):
882
-
883
- 1. 完整關閉所有 Kenaz 行程(含 tray 常駐;dev 模式下也要停掉 `tauri
884
- dev`,因為 dev 模式的 `register_all()` 會把 `kenaz://` 指到
885
- `target/debug` 的 exe,需要重新啟動一次乾淨的行程來吃到冷啟動路徑)。
886
- 2. 在瀏覽器網址列直接開啟一個合法的 `kenaz://connect?...` 深連結
887
- (帶上 `origin`/`mcp`/`token`/`prompt` 等必要參數,見本檔第 2/3 節)。
888
- 3. 預期:OS 拉起 Kenaz 主行程後,視窗前景顯示審批卡(而不是靜默無反應、
889
- 也不是網站端 `kenaz_hello` 逾時後被 TASK_1950 的未安裝流程誤判成
890
- 「未安裝」)。
891
- 4. 按下「允許」後應正常走完 §0 心智模型的第 3-5 步(開終端分頁、agent
892
- 掛上網站的 MCP、網站收到 `kenaz_hello`)。
893
-
894
- **AC3 判定**:程式碼修復已完成並可 code review 驗證(見上),但「實機冷
895
- 啟動時 OS 真的會如描述般拉起行程並吃到這條路徑」仍是**待驗證**——這裡
896
- 誠實記錄為「已修復,待實機驗證」,不是「已驗證沒問題」。
897
-
898
- ---
899
-
900
- ## 參考
901
-
902
- - `./PROTOCOL.md`(v0.4,本檔每個行為的權威來源)
903
- - `./examples/minimal-site/`(可跑範例 + `node --test` 煙霧測試,含
904
- `kenaz_wait_for_message` 信箱參考實作、§10「未安裝流程」的
905
- `install-redirect.js` 參考實作)
906
- - `dev/KENAZ_AGENT_CONNECT_v1_SPEC.md`(規格總覽,含分期與已決定事項)
907
- - Kenaz 側實作(僅供對照,你不需要讀這些就能接入):
908
- `dashboard/src-tauri/src/features/agent_hub/{deep_link,mod,launch,permissions,approval}.rs`
909
- - 假 MCP(Kenaz 自己的 conformance 用,不是你要跑的東西):
910
- `dashboard/scripts/agent-hub-fake-mcp.mjs`
911
- - 安裝檔發布腳本(§10「安裝頁 URL 從哪裡來」的事實來源):
912
- `dashboard/scripts/publish-release.js`
913
- - deep-link 冷啟動查證(§10 最後一節)的原始碼來源:
914
- `tauri-plugin-deep-link` 2.4.10(cargo registry cache)、`tauri` 2.10.2
915
- `src/app.rs`