aiwcli 0.9.7 → 0.10.0

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 (119) hide show
  1. package/bin/run.js +5 -2
  2. package/dist/lib/claude-settings-types.d.ts +2 -0
  3. package/dist/templates/CLAUDE.md +49 -18
  4. package/dist/templates/_shared/.claude/settings.json +4 -0
  5. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  6. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  7. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  8. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  9. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  10. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  11. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  12. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  13. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  14. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  15. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  16. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  17. package/dist/templates/_shared/hooks/archive_plan.py +87 -178
  18. package/dist/templates/_shared/hooks/context_monitor.py +128 -194
  19. package/dist/templates/_shared/hooks/file-suggestion.py +26 -23
  20. package/dist/templates/_shared/hooks/pre_compact.py +104 -0
  21. package/dist/templates/_shared/hooks/session_end.py +154 -0
  22. package/dist/templates/_shared/hooks/session_start.py +145 -59
  23. package/dist/templates/_shared/hooks/task_create_capture.py +26 -49
  24. package/dist/templates/_shared/hooks/task_update_capture.py +42 -100
  25. package/dist/templates/_shared/hooks/user_prompt_submit.py +63 -77
  26. package/dist/templates/_shared/lib/base/__init__.py +16 -0
  27. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  28. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  29. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  30. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  31. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  32. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  33. package/dist/templates/_shared/lib/base/constants.py +18 -4
  34. package/dist/templates/_shared/lib/base/hook_utils.py +199 -11
  35. package/dist/templates/_shared/lib/base/inference.py +121 -0
  36. package/dist/templates/_shared/lib/base/logger.py +291 -0
  37. package/dist/templates/_shared/lib/base/utils.py +49 -11
  38. package/dist/templates/_shared/lib/context/__init__.py +72 -80
  39. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  40. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  41. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  42. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  43. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  44. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  45. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  46. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  47. package/dist/templates/_shared/lib/context/context_formatter.py +316 -0
  48. package/dist/templates/_shared/lib/context/context_selector.py +491 -0
  49. package/dist/templates/_shared/lib/context/context_store.py +636 -0
  50. package/dist/templates/_shared/lib/context/plan_manager.py +204 -0
  51. package/dist/templates/_shared/lib/context/task_tracker.py +188 -0
  52. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  53. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  54. package/dist/templates/_shared/lib/handoff/document_generator.py +14 -40
  55. package/dist/templates/_shared/lib/templates/README.md +5 -13
  56. package/dist/templates/_shared/lib/templates/__init__.py +2 -6
  57. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  58. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  59. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  60. package/dist/templates/_shared/lib/templates/plan_context.py +25 -79
  61. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  62. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  63. package/dist/templates/_shared/scripts/save_handoff.py +39 -19
  64. package/dist/templates/_shared/scripts/status_line.py +701 -0
  65. package/dist/templates/_shared/workflows/handoff.md +9 -3
  66. package/dist/templates/cc-native/.claude/settings.json +64 -9
  67. package/dist/templates/cc-native/CC-NATIVE-README.md +25 -28
  68. package/dist/templates/cc-native/MIGRATION.md +1 -1
  69. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +14 -39
  70. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +1 -1
  71. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +57 -22
  72. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  73. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  74. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  75. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  76. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  77. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  78. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +57 -57
  79. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +208 -158
  80. package/dist/templates/cc-native/_cc-native/hooks/plan_accepted.py +127 -0
  81. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +81 -0
  82. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +26 -25
  83. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +35 -10
  84. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  85. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  86. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  87. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  88. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  89. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  90. package/dist/templates/cc-native/_cc-native/lib/debug.py +37 -22
  91. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +103 -42
  92. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  93. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  94. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  95. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  96. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  97. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +26 -21
  98. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +12 -7
  99. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +12 -7
  100. package/dist/templates/cc-native/_cc-native/lib/state.py +31 -16
  101. package/dist/templates/cc-native/_cc-native/lib/utils.py +210 -43
  102. package/dist/templates/cc-native/_cc-native/plan-review.config.json +1 -2
  103. package/oclif.manifest.json +1 -1
  104. package/package.json +1 -1
  105. package/dist/templates/_shared/hooks/context_enforcer.py +0 -625
  106. package/dist/templates/_shared/hooks/task_create_atomicity.py +0 -205
  107. package/dist/templates/_shared/lib/context/cache.py +0 -444
  108. package/dist/templates/_shared/lib/context/context_extractor.py +0 -115
  109. package/dist/templates/_shared/lib/context/context_manager.py +0 -1054
  110. package/dist/templates/_shared/lib/context/discovery.py +0 -444
  111. package/dist/templates/_shared/lib/context/event_log.py +0 -308
  112. package/dist/templates/_shared/lib/context/plan_archive.py +0 -101
  113. package/dist/templates/_shared/lib/context/task_sync.py +0 -290
  114. package/dist/templates/_shared/lib/templates/persona_questions.py +0 -113
  115. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  116. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
  117. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
  118. package/dist/templates/cc-native/_cc-native/lib/async_archive.py +0 -68
  119. package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +0 -98
@@ -19,7 +19,7 @@ Generate a handoff document summarizing the current session's work, decisions, a
19
19
 
20
20
  ### Step 1: Get Context ID
21
21
 
22
- Extract the `context_id` from the system reminder injected by the context enforcer hook.
22
+ Extract the `context_id` from the system reminder injected by the user_prompt_submit hook.
23
23
 
24
24
  Look for the pattern in the system reminder:
25
25
  ```
@@ -160,8 +160,14 @@ This script:
160
160
  2. Parses sections and writes sharded files (index.md, completed-work.md, dead-ends.md, etc.)
161
161
  3. Copies the current plan (if any) to plan.md
162
162
  4. Records the event in the context's event log (informational only)
163
-
164
- Use the handoff folder for context in the next session.
163
+ 5. Sets the context to dormant (`mode="idle"`) so it won't auto-select in new sessions
164
+
165
+ **After handoff is saved, the context becomes dormant:**
166
+ - It will **not** auto-select when starting new sessions — new work gets a fresh context
167
+ - It remains visible in the context picker (`^`) with a `[Handoff Ready]` label
168
+ - To resume, use `^N` (where N is the context number) to explicitly select it
169
+ - When selected via `^N`, the handoff content is automatically injected into the session
170
+ - The `handoff_path` is cleared after injection to prevent re-injection
165
171
 
166
172
  ## Dead Ends Section Guidelines
167
173
 
@@ -1,4 +1,8 @@
1
1
  {
2
+ "statusLine": {
3
+ "type": "command",
4
+ "command": "python .aiwcli/_shared/scripts/status_line.py"
5
+ },
2
6
  "permissions": {
3
7
  "allow": [],
4
8
  "deny": []
@@ -14,7 +18,7 @@
14
18
  "ides": [
15
19
  "claude"
16
20
  ],
17
- "installedAt": "{{INSTALLED_AT}}"
21
+ "installedAt": "2026-01-29T01:59:02.558Z"
18
22
  }
19
23
  },
20
24
  "hooks": {
@@ -29,13 +33,44 @@
29
33
  ]
30
34
  }
31
35
  ],
36
+ "SessionEnd": [
37
+ {
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "python .aiwcli/_shared/hooks/session_end.py",
42
+ "timeout": 5000
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "PreCompact": [
48
+ {
49
+ "hooks": [
50
+ {
51
+ "type": "command",
52
+ "command": "python .aiwcli/_shared/hooks/pre_compact.py",
53
+ "timeout": 5000
54
+ }
55
+ ]
56
+ }
57
+ ],
32
58
  "UserPromptSubmit": [
33
59
  {
34
60
  "hooks": [
35
61
  {
36
62
  "type": "command",
37
63
  "command": "python .aiwcli/_shared/hooks/user_prompt_submit.py",
38
- "timeout": 5000
64
+ "timeout": 10000
65
+ }
66
+ ]
67
+ },
68
+ {
69
+ "hooks": [
70
+ {
71
+ "type": "command",
72
+ "command": "python .aiwcli/_cc-native/hooks/plan_questions_early.py",
73
+ "timeout": 3000
39
74
  }
40
75
  ]
41
76
  }
@@ -57,7 +92,8 @@
57
92
  {
58
93
  "type": "command",
59
94
  "command": "python .aiwcli/_shared/hooks/task_create_capture.py",
60
- "timeout": 3000
95
+ "timeout": 3000,
96
+ "async": true
61
97
  }
62
98
  ]
63
99
  },
@@ -67,7 +103,8 @@
67
103
  {
68
104
  "type": "command",
69
105
  "command": "python .aiwcli/_shared/hooks/task_update_capture.py",
70
- "timeout": 3000
106
+ "timeout": 3000,
107
+ "async": true
71
108
  }
72
109
  ]
73
110
  },
@@ -76,7 +113,7 @@
76
113
  "hooks": [
77
114
  {
78
115
  "type": "command",
79
- "command": "python .aiwcli/_shared/hooks/archive_plan.py",
116
+ "command": "python .aiwcli/_cc-native/hooks/plan_accepted.py",
80
117
  "timeout": 5000
81
118
  }
82
119
  ]
@@ -90,6 +127,16 @@
90
127
  "timeout": 5000
91
128
  }
92
129
  ]
130
+ },
131
+ {
132
+ "matcher": "AskUserQuestion",
133
+ "hooks": [
134
+ {
135
+ "type": "command",
136
+ "command": "python .aiwcli/_cc-native/hooks/add_plan_context.py",
137
+ "timeout": 3000
138
+ }
139
+ ]
93
140
  }
94
141
  ],
95
142
  "PermissionRequest": [
@@ -106,12 +153,20 @@
106
153
  ],
107
154
  "PreToolUse": [
108
155
  {
109
- "matcher": "TaskCreate",
156
+ "matcher": "^TaskCreate$",
110
157
  "hooks": [
111
158
  {
112
- "type": "command",
113
- "command": "python .aiwcli/_shared/hooks/task_create_atomicity.py",
114
- "timeout": 15000
159
+ "type": "prompt",
160
+ "prompt": "Evaluate this TaskCreate call for atomicity. Tasks become ISC criteria checked during verification — vague criteria cannot be verified, so precision matters. A well-specified task includes: (1) Explicit file paths like 'src/lib/auth.py' instead of 'the file above' or 'as discussed', (2) Specific function or component names instead of pronouns like 'it' or 'the function', (3) Clear expected state or behavior that is binary-testable in 2 seconds, (4) Concrete scope — one concern per task, not compound goals. If all four criteria are met and an agent with zero conversation history could verify the task was completed, return ok:true. If any criterion is missing, return ok:false with a response like: 'Missing context: [list each gap — e.g., no file path specified for the auth module, expected behavior is vague: what does fix the bug mean specifically, compound task should be split into separate criteria]'. When returning ok:false, end your response with: 'Retry: Re-invoke TaskCreate with a revised subject and description that address the gaps above.' This directive ensures the calling agent corrects and retries rather than abandoning the task."
161
+ }
162
+ ]
163
+ },
164
+ {
165
+ "matcher": "^Task$",
166
+ "hooks": [
167
+ {
168
+ "type": "prompt",
169
+ "prompt": "The sub-agent receives ONLY the prompt text — no conversation history, no prior context.\n\nCheck 1 — Dangling References: Does the prompt use pronouns or demonstratives that ONLY make sense with prior conversation? Violations: 'the file we looked at', 'as discussed above', 'that approach we chose', 'the error from earlier', 'fix the issue mentioned above'. NOT violations: relative paths ('_output/', 'src/lib/'), search terms ('context-manager', 'auth module'), directory exploration ('find files matching X'), tool names, or any concrete noun — even if imprecise. Only flag references that are truly UNRESOLVABLE without conversation history.\n\nCheck 2 — Implicit Contract: Does the prompt have ANY discernible goal? 'Explore the _output directory and find context files' IS a clear goal. 'Search for hooks that handle Task events' IS a clear goal. 'Read and summarize all files in X' IS a clear goal. Only flag if the prompt is truly goalless — e.g., a sentence fragment with no verb, or pure context with no request.\n\nIf both checks pass, return ok:true. When in doubt, pass — false negatives (letting a vague prompt through) are far less costly than false positives (blocking legitimate work).\n\nWhen returning ok:false, end your response with: 'Retry: Re-invoke the Task tool with a revised prompt that resolves the issues above.'"
115
170
  }
116
171
  ]
117
172
  },
@@ -92,29 +92,26 @@ The brackets indicate optional steps. Research only needs Clarify → Explore
92
92
 
93
93
  ---
94
94
 
95
- ## Context Management (Phase 1 - Shared Infrastructure)
95
+ ## Context Management (Phase 2 - Shared Infrastructure)
96
96
 
97
- CC-Native uses **event-sourced context management** via shared infrastructure in `_shared/`:
97
+ CC-Native uses **direct-state context management** via shared infrastructure in `_shared/`:
98
98
 
99
99
  ```
100
100
  _output/contexts/
101
101
  ├── feature-auth/ # Context folder (method-agnostic)
102
- │ ├── context.json # Derived cache with current state
103
- │ ├── events.jsonl # SOURCE OF TRUTH (append-only)
102
+ │ ├── state.json # SOURCE OF TRUTH (direct read/write)
104
103
  │ └── plans/ # Archived plans for this context
105
104
  │ └── 2026-01-25-auth-plan.md
106
105
  └── another-context/
107
- ├── context.json
108
- └── events.jsonl
106
+ └── state.json
109
107
  ```
110
108
 
111
109
  ### Data Hierarchy
112
110
 
113
111
  | File | Role | Notes |
114
112
  |------|------|-------|
115
- | `events.jsonl` | **Source of truth** | Append-only, never modified |
116
- | `context.json` | Derived cache | Rebuilt from events if corrupted |
117
- | `_output/index.json` | Global cache | Aggregates all contexts |
113
+ | `state.json` | **Source of truth** | Direct read/write per context |
114
+ | `_output/index.json` | Global cache | Fast session-to-context lookup |
118
115
 
119
116
  ### Context Schema
120
117
 
@@ -124,27 +121,25 @@ _output/contexts/
124
121
  "status": "active",
125
122
  "summary": "JWT authentication system",
126
123
  "method": "cc-native",
127
- "in_flight": {
128
- "mode": "implementing",
129
- "artifact_path": "_output/contexts/feature-auth/plans/2026-01-25-auth.md",
130
- "artifact_hash": "a1b2c3d4"
131
- }
124
+ "mode": "active",
125
+ "plan_path": "_output/contexts/feature-auth/plans/2026-01-25-auth.md",
126
+ "plan_hash": "a1b2c3d4",
127
+ "plan_signature": "approved"
132
128
  }
133
129
  ```
134
130
 
135
- ### In-Flight Modes
131
+ ### Context Modes
136
132
 
137
133
  | Mode | Meaning |
138
134
  |------|---------|
139
- | `none` | Normal context, no special handling |
140
- | `planning` | Currently in plan mode |
141
- | `pending_implementation` | Plan approved, awaiting implementation |
142
- | `implementing` | Implementation in progress |
135
+ | `idle` | No active plan or work in progress |
136
+ | `has_plan` | Plan exists but not yet being implemented |
137
+ | `active` | Implementation in progress |
143
138
 
144
- ### Why Event Sourcing?
139
+ ### Why 2-Layer Architecture?
145
140
 
146
- - **Crash recovery**: Replay events to rebuild state
147
- - **Audit trail**: Full history of all actions
141
+ - **Simple reads**: `state.json` is read directly, no event replay needed
142
+ - **Fast lookup**: `index.json` provides global session-to-context mapping without scanning directories
148
143
  - **No orphan state**: Contexts always visible (no "in_progress" limbo)
149
144
  - **Cross-session**: State persists across `/clear` and session restarts
150
145
 
@@ -158,7 +153,7 @@ _output/contexts/
158
153
 
159
154
  **Check:**
160
155
  1. Context exists: `ls _output/contexts/`
161
- 2. Events logged: `cat _output/contexts/{id}/events.jsonl`
156
+ 2. State file exists: `cat _output/contexts/{id}/state.json`
162
157
  3. Hook logs in terminal output
163
158
 
164
159
  **Solutions:**
@@ -167,13 +162,15 @@ _output/contexts/
167
162
 
168
163
  ### Context Recovery
169
164
 
170
- **Symptom:** `context.json` appears corrupted
165
+ **Symptom:** `state.json` appears corrupted
171
166
 
172
- **Fix:** Context can be rebuilt from events:
167
+ **WARNING:** Do NOT delete `state.json` -- it IS the source of truth and cannot be rebuilt.
168
+
169
+ **Fix:** Edit `state.json` directly to correct invalid fields, or restore from a backup:
173
170
  ```bash
174
- # Events are the source of truth - context.json is derived
175
- # Delete context.json and it will be rebuilt on next access
176
- rm _output/contexts/{id}/context.json
171
+ # state.json is the source of truth - do NOT delete it
172
+ # Instead, inspect and fix the JSON manually
173
+ cat _output/contexts/{id}/state.json
177
174
  ```
178
175
 
179
176
  ### Notification Issues
@@ -41,7 +41,7 @@ mv config.json plan-review.config.json
41
41
  ### Context-Integrated Reviews (v1.5.0)
42
42
  - Reviews written to `_output/contexts/{context_id}/reviews/`
43
43
  - Iteration state persists across sessions in context folder
44
- - Automatic context discovery via session_id or single in-flight context
44
+ - Automatic context selection via session_id or single active context
45
45
 
46
46
  ### Atomic Writes
47
47
  - Cross-platform atomic file writes (Windows + POSIX)
@@ -10,18 +10,6 @@ CC-Native uses Claude Code's native tools with minimal workflow overhead. Plan r
10
10
 
11
11
  ```
12
12
  packages/cli/src/templates/cc-native/
13
- ├── _shared/ # SHARED: Cross-method infrastructure (Phase 1)
14
- │ ├── lib/
15
- │ │ ├── base/ # Base utilities
16
- │ │ │ ├── atomic_write.py # Cross-platform atomic file writes
17
- │ │ │ ├── constants.py # Security and configuration constants
18
- │ │ │ └── utils.py # Common functions
19
- │ │ └── context/ # Context management
20
- │ │ ├── context_manager.py # Context CRUD operations
21
- │ │ ├── event_log.py # JSONL append/read utilities
22
- │ │ └── cache.py # Cache rebuild utilities
23
- │ └── hooks/
24
- │ └── session_start.py # SessionStart hook (context discovery)
25
13
  ├── _cc-native/ # METHOD-SPECIFIC: CC-Native template code
26
14
  │ ├── workflows/*.md # Workflow definitions
27
15
  │ ├── hooks/ # Hook scripts
@@ -77,8 +65,7 @@ _output/
77
65
  ├── index.json # Global context cache
78
66
  ├── contexts/ # Context folders (method-agnostic)
79
67
  │ └── {context-id}/
80
- │ ├── context.json # Context state cache
81
- │ ├── events.jsonl # Event log (source of truth)
68
+ │ ├── state.json # Context state (source of truth)
82
69
  │ └── plans/ # Archived plans for this context
83
70
  │ └── YYYY-MM-DD-{slug}.md
84
71
  ├── cc-native/ # CC-Native specific outputs
@@ -159,7 +146,7 @@ CC-Native settings are stored in `_cc-native/plan-review.config.json`:
159
146
 
160
147
  ---
161
148
 
162
- ## Context Management (Phase 1 - Event Sourced)
149
+ ## Context Management (Phase 1 - State Based)
163
150
 
164
151
  CC-Native uses **shared infrastructure** for cross-session context persistence:
165
152
 
@@ -168,22 +155,19 @@ _output/
168
155
  ├── index.json # CACHE: Aggregates all contexts
169
156
  └── contexts/ # All contexts (method-agnostic)
170
157
  ├── feature-auth/
171
- │ ├── context.json # CACHE: Derived from events
172
- │ ├── events.jsonl # SOURCE OF TRUTH (append-only)
158
+ │ ├── state.json # SOURCE OF TRUTH: Context state
173
159
  │ └── plans/ # Archived plans for this context
174
160
  │ └── 2026-01-25-auth.md
175
161
  └── another-context/
176
- ├── context.json
177
- └── events.jsonl
162
+ └── state.json
178
163
  ```
179
164
 
180
165
  ### Data Hierarchy
181
166
 
182
167
  | Level | File | Role | Recovery |
183
168
  |-------|------|------|----------|
184
- | 1 (Truth) | `events.jsonl` | Append-only event log | Cannot be rebuilt |
185
- | 2 (Cache) | `context.json` | Current state snapshot | Rebuild from events |
186
- | 3 (Cache) | `index.json` | Global context index | Rebuild from context files |
169
+ | 1 (Truth) | `state.json` | Context state (source of truth) | Cannot be rebuilt |
170
+ | 2 (Cache) | `index.json` | Global context index | Rebuild from state files |
187
171
 
188
172
  ### Context Schema
189
173
 
@@ -213,16 +197,6 @@ _output/
213
197
  | `pending_implementation` | Plan approved | Auto-continue implementation |
214
198
  | `implementing` | Implementation active | Continue implementation |
215
199
 
216
- ### Event Types
217
-
218
- ```jsonl
219
- {"event":"context_created","timestamp":"2026-01-20T10:00:00Z","summary":"JWT auth","method":"cc-native"}
220
- {"event":"task_added","task_id":"aiw-1","subject":"Add JWT middleware","timestamp":"..."}
221
- {"event":"task_completed","task_id":"aiw-1","evidence":"tests pass","timestamp":"..."}
222
- {"event":"plan_created","path":"_output/contexts/.../plans/...","hash":"a1b2c3","timestamp":"..."}
223
- {"event":"context_completed","timestamp":"..."}
224
- ```
225
-
226
200
  ### Robust Writes
227
201
 
228
202
  When `CC_NATIVE_ROBUST_WRITES=true` (default):
@@ -255,12 +229,14 @@ Hook scripts live in `_cc-native/hooks/`. IDE-specific wiring in `.claude/settin
255
229
  }
256
230
  ```
257
231
 
258
- **Hook order matters:** Reviews run first; archive runs on Edit/Write/Bash. If a review blocks, the plan is not archived. Only plans that pass all reviews get archived.
232
+ **Hook order matters:** Archive runs on PermissionRequest:ExitPlanMode before reviews. If a review blocks, the archived plan is available for reference. Only plans that pass all reviews proceed to implementation.
259
233
 
260
234
  | Hook | Trigger | Purpose |
261
235
  |------|---------|---------|
262
236
  | `cc-native-plan-review.py` | ExitPlanMode | Unified review: CLI + orchestrator + agents |
263
- | `archive_plan.py` | Edit/Write/Bash | Archives approved plans when implementation starts |
237
+ | `archive_plan.py` | PermissionRequest:ExitPlanMode | Archives plan content and stores hash/signature before user acceptance |
238
+ | `plan_accepted.py` | PostToolUse:ExitPlanMode | Sets context mode to has_plan |
239
+ | `plan_questions_early.py` | UserPromptSubmit | Injects Phase A clarification in plan mode |
264
240
 
265
241
  ### Claude Feedback Mechanism
266
242
 
@@ -269,11 +245,10 @@ The unified review hook returns structured JSON to Claude Code:
269
245
  ```json
270
246
  {
271
247
  "hookSpecificOutput": {
272
- "hookEventName": "PreToolUse",
273
- "additionalContext": "Review results and recommendations..."
274
- },
275
- "decision": "block", // Optional: blocks Claude if review fails
276
- "reason": "Reason for blocking..."
248
+ "additionalContext": "Review results and recommendations...",
249
+ "permissionDecision": "deny",
250
+ "permissionDecisionReason": "Reason for blocking..."
251
+ }
277
252
  }
278
253
  ```
279
254
 
@@ -21,7 +21,7 @@ Each agent file has:
21
21
  - **Frontmatter (YAML):** name, model, focus, categories, enabled
22
22
  - **Body (Markdown):** Full persona content → becomes `system_prompt` for `--system-prompt` flag
23
23
 
24
- The `aggregate_agents.py` script extracts both parts. The body becomes `AgentConfig.system_prompt`.
24
+ The `aggregate_agents.py` script (`_cc-native/scripts/aggregate_agents.py`) extracts both parts. The body becomes `AgentConfig.system_prompt`.
25
25
 
26
26
  ## --setting-sources "" Requirement
27
27
 
@@ -9,7 +9,7 @@
9
9
  | Hook | Trigger | Purpose |
10
10
  |------|---------|---------|
11
11
  | `cc-native-plan-review.py` | PreToolUse: ExitPlanMode | Review plans before user approval |
12
- | `add_plan_context.py` | PostToolUse: EnterPlanMode | Add context when entering plan mode |
12
+ | `add_plan_context.py` | PostToolUse: AskUserQuestion, PreToolUse: Write | Mark questions asked; add context when writing plan files |
13
13
  | `suggest-fresh-perspective.py` | PostToolUse | Suggest fresh perspective workflow |
14
14
 
15
15
  ---
@@ -32,6 +32,7 @@ sys.path.insert(0, str(_shared))
32
32
 
33
33
  from utils import eprint, ReviewerResult
34
34
  from lib.base.subprocess_utils import is_internal_call
35
+ from debug import log_debug # Context-folder debug logging
35
36
  ```
36
37
 
37
38
  ```python
@@ -70,7 +71,6 @@ import json
70
71
 
71
72
  out = {
72
73
  "hookSpecificOutput": {
73
- "hookEventName": "PreToolUse",
74
74
  "additionalContext": "Information for Claude to see...",
75
75
  }
76
76
  }
@@ -90,25 +90,52 @@ print(json.dumps(out, ensure_ascii=False))
90
90
 
91
91
  **Key insight:** The old `decision`/`reason` format fails silently. If your hook isn't affecting Claude's behavior, check the output format first.
92
92
 
93
+ ### Using Hook Utilities (Preferred)
94
+
95
+ Instead of manually constructing hookSpecificOutput dicts, use the shared utilities from `base.hook_utils`:
96
+
97
+ ```python
98
+ from base.hook_utils import emit_context, emit_context_and_block
99
+
100
+ # Inject context without blocking:
101
+ emit_context("Information for Claude to see...")
102
+
103
+ # Block the tool call with context and reason:
104
+ emit_context_and_block(
105
+ "Review feedback for Claude to see...",
106
+ "Reason shown to Claude for the denial"
107
+ )
108
+ ```
109
+
110
+ These handle the JSON serialization and stdout printing. `emit_context` defaults to `ensure_ascii=False`; `emit_context_and_block` defaults to `ensure_ascii=True` (safe for Windows cp1252).
111
+
93
112
  ---
94
113
 
95
114
  ## Debugging Output
96
115
 
97
- Hooks communicate via stdout (JSON) and stderr (logs). Use them correctly:
116
+ Hooks communicate via stdout (JSON) and stderr (logs). Use the unified logger for all diagnostic output:
98
117
 
99
118
  ```python
100
- # CORRECT - logs go to stderr, visible in terminal
101
- def eprint(*args):
102
- print(*args, file=sys.stderr)
119
+ from base.hook_utils import log_debug, log_info, log_warn, log_error
120
+
121
+ # CORRECT - unified logger: writes to stderr AND _output/hook-log.jsonl
122
+ log_debug("hook-name", f"Found {len(items)} items")
123
+ log_info("hook-name", "Starting hook...")
124
+ log_warn("hook-name", f"Fallback used: {reason}")
125
+ log_error("hook-name", f"Failed: {e}", traceback_str=tb)
126
+ ```
103
127
 
104
- eprint("[hook-name] Starting hook...")
105
- eprint(f"[hook-name] Found {len(items)} items")
128
+ ```python
129
+ # ACCEPTABLE - eprint() for terminal-only UX (usage help, progress)
130
+ eprint("Usage: python hook.py <args>")
106
131
  ```
107
132
 
108
133
  ```python
109
134
  # WRONG - print() goes to stdout, corrupts JSON output
110
135
  print("Debug info") # Breaks JSON parsing
111
- print(json.dumps(output)) # Now invalid because of previous print
136
+
137
+ # WRONG - raw print to stderr instead of logger
138
+ print(f"Error: {e}", file=sys.stderr) # Use log_error() instead
112
139
  ```
113
140
 
114
141
  ---
@@ -140,9 +167,9 @@ reviews_dir = get_context_reviews_dir(context.id, project_root)
140
167
  If context isn't found, add diagnostic logging:
141
168
 
142
169
  ```python
143
- eprint(f"[hook] Session ID: {session_id}")
144
- eprint(f"[hook] In-flight contexts: {len(in_flight)}")
145
- eprint(f"[hook] Modes: {[c.in_flight.mode for c in in_flight]}")
170
+ log_debug("hook", f"Session ID: {session_id}")
171
+ log_debug("hook", f"In-flight contexts: {len(in_flight)}")
172
+ log_debug("hook", f"Modes: {[c.in_flight.mode for c in in_flight]}")
146
173
  ```
147
174
 
148
175
  ---
@@ -152,27 +179,24 @@ eprint(f"[hook] Modes: {[c.in_flight.mode for c in in_flight]}")
152
179
  Hooks should fail gracefully - a broken hook shouldn't break the user's workflow:
153
180
 
154
181
  ```python
182
+ from base.hook_utils import log_error, run_hook
183
+
155
184
  def main() -> int:
156
185
  try:
157
186
  # Hook logic...
158
187
  return 0
159
188
  except Exception as e:
160
- eprint(f"[hook-name] Error: {e}")
189
+ import traceback
190
+ tb = traceback.format_exc()
191
+ log_error("hook-name", str(e), traceback_str=tb)
161
192
  # Return 0 to not block the user
162
193
  return 0
163
194
 
164
195
  if __name__ == "__main__":
165
- try:
166
- raise SystemExit(main())
167
- except Exception as e:
168
- import traceback
169
- eprint(f"[hook-name] FATAL: {e}")
170
- traceback.print_exc(file=sys.stderr)
171
- # Still exit 0 to not block - or exit 1 if blocking is intentional
172
- raise SystemExit(0)
196
+ run_hook(main, "hook-name")
173
197
  ```
174
198
 
175
- Use `sys.exit(1)` only for intentional blocking (e.g., `blockOnFail: true` configured).
199
+ Use `sys.exit(1)` only for intentional blocking (e.g., two-stage review decision denies the plan).
176
200
 
177
201
  ---
178
202
 
@@ -195,7 +219,14 @@ These are reminders based on past issues. Not enforcement rules.
195
219
  Always validate Python syntax after editing hooks:
196
220
 
197
221
  ```bash
222
+ # Validate working copy
223
+ python -m py_compile .aiwcli/_cc-native/hooks/cc-native-plan-review.py
224
+
225
+ # Validate template copy (after sync)
198
226
  python -m py_compile packages/cli/src/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py
227
+
228
+ # Validate all shared hooks (loop required — py_compile doesn't accept globs)
229
+ for f in .aiwcli/_shared/hooks/*.py; do python -m py_compile "$f"; done
199
230
  ```
200
231
 
201
232
  Hooks fail silently on syntax errors - this catches them before they reach production.
@@ -208,4 +239,8 @@ Hooks fail silently on syntax errors - this catches them before they reach produ
208
239
 
209
240
  | Date | Change |
210
241
  |------|--------|
242
+ | 2026-02-07 | Hook lifecycle diagnostics: all hooks now use `run_hook(main, "hook_name")` entry point. Logs HOOK_START/HOOK_END with template origin, event type, duration_ms, and status. Millisecond timestamps in logger. |
243
+ | 2026-02-07 | Unified logger: all diagnostic logging uses `log_debug/log_info/log_warn/log_error` from `_shared/lib/base/logger.py` instead of eprint/print-to-stderr. Updated debugging and error handling docs. |
244
+ | 2026-02-06 | Merged mark_questions_asked.py into add_plan_context.py. Hook now handles both PostToolUse:AskUserQuestion and PreToolUse:Write. Deleted standalone mark_questions_asked.py. |
245
+ | 2026-02-06 | Fixed add_plan_context.py trigger docs (was PostToolUse: EnterPlanMode, is PreToolUse: Write). Added emit_context/emit_context_and_block utility docs. |
211
246
  | 2026-02-03 | Initial creation |