@wazir-dev/cli 1.1.0 → 1.2.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 (124) hide show
  1. package/CHANGELOG.md +73 -4
  2. package/README.md +6 -6
  3. package/docs/concepts/architecture.md +1 -1
  4. package/docs/concepts/roles-and-workflows.md +2 -0
  5. package/docs/concepts/why-wazir.md +59 -0
  6. package/docs/decisions/2026-03-19-deferred-items.md +564 -0
  7. package/docs/decisions/2026-03-19-enhancement-decisions.md +300 -0
  8. package/docs/readmes/INDEX.md +21 -5
  9. package/docs/readmes/features/expertise/README.md +2 -2
  10. package/docs/readmes/features/exports/README.md +2 -2
  11. package/docs/readmes/features/schemas/README.md +3 -0
  12. package/docs/readmes/features/skills/README.md +17 -0
  13. package/docs/readmes/features/skills/clarifier.md +5 -0
  14. package/docs/readmes/features/skills/claude-cli.md +5 -0
  15. package/docs/readmes/features/skills/codex-cli.md +5 -0
  16. package/docs/readmes/features/skills/dispatching-parallel-agents.md +5 -0
  17. package/docs/readmes/features/skills/executing-plans.md +5 -0
  18. package/docs/readmes/features/skills/executor.md +5 -0
  19. package/docs/readmes/features/skills/finishing-a-development-branch.md +5 -0
  20. package/docs/readmes/features/skills/gemini-cli.md +5 -0
  21. package/docs/readmes/features/skills/humanize.md +5 -0
  22. package/docs/readmes/features/skills/init-pipeline.md +5 -0
  23. package/docs/readmes/features/skills/receiving-code-review.md +5 -0
  24. package/docs/readmes/features/skills/requesting-code-review.md +5 -0
  25. package/docs/readmes/features/skills/reviewer.md +5 -0
  26. package/docs/readmes/features/skills/subagent-driven-development.md +5 -0
  27. package/docs/readmes/features/skills/using-git-worktrees.md +5 -0
  28. package/docs/readmes/features/skills/wazir.md +5 -0
  29. package/docs/readmes/features/skills/writing-skills.md +5 -0
  30. package/docs/readmes/features/workflows/prepare-next.md +1 -1
  31. package/docs/reference/configuration-reference.md +47 -6
  32. package/docs/reference/launch-checklist.md +4 -4
  33. package/docs/reference/review-loop-pattern.md +117 -8
  34. package/docs/reference/roles-reference.md +1 -0
  35. package/docs/reference/skill-tiers.md +147 -0
  36. package/docs/reference/tooling-cli.md +3 -1
  37. package/docs/truth-claims.yaml +12 -0
  38. package/expertise/antipatterns/process/ai-coding-antipatterns.md +97 -1
  39. package/exports/hosts/claude/.claude/settings.json +9 -0
  40. package/exports/hosts/claude/CLAUDE.md +1 -1
  41. package/exports/hosts/claude/export.manifest.json +4 -2
  42. package/exports/hosts/claude/host-package.json +3 -1
  43. package/exports/hosts/codex/AGENTS.md +1 -1
  44. package/exports/hosts/codex/export.manifest.json +4 -2
  45. package/exports/hosts/codex/host-package.json +3 -1
  46. package/exports/hosts/cursor/.cursor/hooks.json +4 -0
  47. package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +1 -1
  48. package/exports/hosts/cursor/export.manifest.json +4 -2
  49. package/exports/hosts/cursor/host-package.json +3 -1
  50. package/exports/hosts/gemini/GEMINI.md +1 -1
  51. package/exports/hosts/gemini/export.manifest.json +4 -2
  52. package/exports/hosts/gemini/host-package.json +3 -1
  53. package/hooks/context-mode-router +191 -0
  54. package/hooks/definitions/context_mode_router.yaml +19 -0
  55. package/hooks/hooks.json +31 -6
  56. package/hooks/protected-path-write-guard +8 -0
  57. package/hooks/routing-matrix.json +45 -0
  58. package/hooks/session-start +62 -1
  59. package/llms-full.txt +905 -132
  60. package/package.json +2 -3
  61. package/schemas/hook.schema.json +2 -1
  62. package/schemas/phase-report.schema.json +80 -0
  63. package/schemas/usage.schema.json +25 -1
  64. package/schemas/wazir-manifest.schema.json +19 -0
  65. package/skills/brainstorming/SKILL.md +18 -155
  66. package/skills/clarifier/SKILL.md +122 -98
  67. package/skills/claude-cli/SKILL.md +320 -0
  68. package/skills/codex-cli/SKILL.md +260 -0
  69. package/skills/debugging/SKILL.md +13 -0
  70. package/skills/design/SKILL.md +13 -0
  71. package/skills/dispatching-parallel-agents/SKILL.md +13 -0
  72. package/skills/executing-plans/SKILL.md +13 -0
  73. package/skills/executor/SKILL.md +72 -19
  74. package/skills/finishing-a-development-branch/SKILL.md +13 -0
  75. package/skills/gemini-cli/SKILL.md +260 -0
  76. package/skills/humanize/SKILL.md +13 -0
  77. package/skills/init-pipeline/SKILL.md +73 -164
  78. package/skills/prepare-next/SKILL.md +81 -10
  79. package/skills/receiving-code-review/SKILL.md +13 -0
  80. package/skills/requesting-code-review/SKILL.md +13 -0
  81. package/skills/reviewer/SKILL.md +287 -15
  82. package/skills/run-audit/SKILL.md +13 -0
  83. package/skills/scan-project/SKILL.md +13 -0
  84. package/skills/self-audit/SKILL.md +197 -16
  85. package/skills/subagent-driven-development/SKILL.md +13 -0
  86. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +2 -0
  87. package/skills/subagent-driven-development/implementer-prompt.md +8 -0
  88. package/skills/subagent-driven-development/spec-reviewer-prompt.md +7 -0
  89. package/skills/tdd/SKILL.md +13 -0
  90. package/skills/using-git-worktrees/SKILL.md +13 -0
  91. package/skills/using-skills/SKILL.md +13 -0
  92. package/skills/verification/SKILL.md +13 -0
  93. package/skills/wazir/SKILL.md +194 -377
  94. package/skills/writing-plans/SKILL.md +14 -1
  95. package/skills/writing-skills/SKILL.md +13 -0
  96. package/templates/artifacts/implementation-plan.md +3 -0
  97. package/templates/artifacts/tasks-template.md +133 -0
  98. package/templates/examples/phase-report.example.json +48 -0
  99. package/tooling/src/adapters/composition-engine.js +256 -0
  100. package/tooling/src/adapters/model-router.js +84 -0
  101. package/tooling/src/capture/command.js +24 -1
  102. package/tooling/src/capture/run-config.js +3 -1
  103. package/tooling/src/capture/store.js +24 -0
  104. package/tooling/src/capture/usage.js +106 -0
  105. package/tooling/src/checks/ac-matrix.js +256 -0
  106. package/tooling/src/checks/command-registry.js +12 -0
  107. package/tooling/src/checks/docs-truth.js +1 -1
  108. package/tooling/src/checks/skills.js +111 -0
  109. package/tooling/src/cli.js +9 -0
  110. package/tooling/src/commands/stats.js +161 -0
  111. package/tooling/src/commands/validate.js +5 -1
  112. package/tooling/src/export/compiler.js +33 -37
  113. package/tooling/src/gating/agent.js +145 -0
  114. package/tooling/src/guards/phase-prerequisite-guard.js +127 -0
  115. package/tooling/src/hooks/routing-logic.js +69 -0
  116. package/tooling/src/init/auto-detect.js +260 -0
  117. package/tooling/src/init/command.js +95 -135
  118. package/tooling/src/input/scanner.js +46 -0
  119. package/tooling/src/reports/command.js +103 -0
  120. package/tooling/src/reports/phase-report.js +323 -0
  121. package/tooling/src/state/command.js +160 -0
  122. package/tooling/src/state/db.js +287 -0
  123. package/tooling/src/status/command.js +53 -1
  124. package/wazir.manifest.yaml +26 -14
@@ -0,0 +1,287 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { DatabaseSync } from 'node:sqlite';
5
+
6
+ function getStateDatabasePath(stateRoot) {
7
+ return path.join(stateRoot, 'state', 'state.sqlite');
8
+ }
9
+
10
+ function hashDescription(description) {
11
+ return crypto.createHash('sha256').update(description).digest('hex');
12
+ }
13
+
14
+ function ensureStateSchema(db) {
15
+ db.exec(`
16
+ CREATE TABLE IF NOT EXISTS learnings (
17
+ id TEXT PRIMARY KEY,
18
+ source_run TEXT NOT NULL,
19
+ category TEXT NOT NULL,
20
+ scope_roles TEXT DEFAULT '',
21
+ scope_stacks TEXT DEFAULT '',
22
+ scope_concerns TEXT DEFAULT '',
23
+ confidence TEXT DEFAULT 'medium' CHECK(confidence IN ('low','medium','high')),
24
+ recurrence_count INTEGER DEFAULT 1,
25
+ content TEXT NOT NULL,
26
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
27
+ last_applied TEXT,
28
+ expires_at TEXT
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS findings (
32
+ id TEXT PRIMARY KEY,
33
+ run_id TEXT NOT NULL,
34
+ phase TEXT NOT NULL,
35
+ source TEXT NOT NULL CHECK(source IN ('internal','codex','self-audit','gemini')),
36
+ severity TEXT NOT NULL CHECK(severity IN ('critical','high','medium','low')),
37
+ description TEXT NOT NULL,
38
+ resolved INTEGER DEFAULT 0,
39
+ finding_hash TEXT NOT NULL,
40
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS audit_history (
44
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
45
+ run_id TEXT NOT NULL,
46
+ date TEXT NOT NULL DEFAULT (date('now')),
47
+ finding_count INTEGER DEFAULT 0,
48
+ fix_count INTEGER DEFAULT 0,
49
+ manual_count INTEGER DEFAULT 0,
50
+ quality_score_before REAL,
51
+ quality_score_after REAL
52
+ );
53
+
54
+ CREATE TABLE IF NOT EXISTS usage_aggregate (
55
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
56
+ run_id TEXT NOT NULL,
57
+ date TEXT NOT NULL DEFAULT (date('now')),
58
+ tokens_saved INTEGER DEFAULT 0,
59
+ bytes_avoided INTEGER DEFAULT 0,
60
+ savings_ratio REAL DEFAULT 0.0,
61
+ index_queries INTEGER DEFAULT 0,
62
+ routing_decisions INTEGER DEFAULT 0
63
+ );
64
+
65
+ CREATE INDEX IF NOT EXISTS idx_learnings_category ON learnings(category);
66
+ CREATE INDEX IF NOT EXISTS idx_findings_run_id ON findings(run_id);
67
+ CREATE INDEX IF NOT EXISTS idx_findings_finding_hash ON findings(finding_hash);
68
+ CREATE INDEX IF NOT EXISTS idx_audit_history_run_id ON audit_history(run_id);
69
+ CREATE INDEX IF NOT EXISTS idx_usage_aggregate_run_id ON usage_aggregate(run_id);
70
+ `);
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Database lifecycle
75
+ // ---------------------------------------------------------------------------
76
+
77
+ export function openStateDb(stateRoot) {
78
+ const databasePath = getStateDatabasePath(stateRoot);
79
+ fs.mkdirSync(path.dirname(databasePath), { recursive: true });
80
+ const db = new DatabaseSync(databasePath, { timeout: 5000 });
81
+ ensureStateSchema(db);
82
+ return db;
83
+ }
84
+
85
+ export function closeStateDb(db) {
86
+ db.close();
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // Learnings CRUD
91
+ // ---------------------------------------------------------------------------
92
+
93
+ export function insertLearning(db, record) {
94
+ const id = crypto.randomUUID();
95
+ const createdAt = new Date().toISOString();
96
+
97
+ db.prepare(`
98
+ INSERT INTO learnings (id, source_run, category, scope_roles, scope_stacks, scope_concerns, confidence, content, created_at)
99
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
100
+ `).run(
101
+ id,
102
+ record.source_run,
103
+ record.category,
104
+ record.scope_roles ?? '',
105
+ record.scope_stacks ?? '',
106
+ record.scope_concerns ?? '',
107
+ record.confidence ?? 'medium',
108
+ record.content,
109
+ createdAt,
110
+ );
111
+
112
+ return id;
113
+ }
114
+
115
+ export function getLearningsByScope(db, filters = {}) {
116
+ const conditions = [];
117
+ const params = [];
118
+
119
+ if (filters.roles) {
120
+ conditions.push("scope_roles LIKE ?");
121
+ params.push(`%${filters.roles}%`);
122
+ }
123
+
124
+ if (filters.stacks) {
125
+ conditions.push("scope_stacks LIKE ?");
126
+ params.push(`%${filters.stacks}%`);
127
+ }
128
+
129
+ if (filters.concerns) {
130
+ conditions.push("scope_concerns LIKE ?");
131
+ params.push(`%${filters.concerns}%`);
132
+ }
133
+
134
+ if (filters.confidence) {
135
+ conditions.push("confidence = ?");
136
+ params.push(filters.confidence);
137
+ }
138
+
139
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
140
+ const limit = filters.limit ? `LIMIT ${Number(filters.limit)}` : '';
141
+
142
+ return db.prepare(`
143
+ SELECT * FROM learnings ${where} ORDER BY created_at DESC ${limit}
144
+ `).all(...params);
145
+ }
146
+
147
+ export function updateLearningRecurrence(db, id) {
148
+ const now = new Date().toISOString();
149
+
150
+ db.prepare(`
151
+ UPDATE learnings
152
+ SET recurrence_count = recurrence_count + 1,
153
+ last_applied = ?
154
+ WHERE id = ?
155
+ `).run(now, id);
156
+ }
157
+
158
+ export function getRecurringLearnings(db, minCount) {
159
+ return db.prepare(`
160
+ SELECT * FROM learnings
161
+ WHERE recurrence_count >= ?
162
+ ORDER BY recurrence_count DESC
163
+ `).all(minCount);
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // Findings CRUD
168
+ // ---------------------------------------------------------------------------
169
+
170
+ export function insertFinding(db, record) {
171
+ const id = crypto.randomUUID();
172
+ const findingHash = record.finding_hash ?? hashDescription(record.description);
173
+ const createdAt = new Date().toISOString();
174
+
175
+ db.prepare(`
176
+ INSERT INTO findings (id, run_id, phase, source, severity, description, finding_hash, created_at)
177
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
178
+ `).run(
179
+ id,
180
+ record.run_id,
181
+ record.phase,
182
+ record.source,
183
+ record.severity,
184
+ record.description,
185
+ findingHash,
186
+ createdAt,
187
+ );
188
+
189
+ return id;
190
+ }
191
+
192
+ export function getFindingsByRun(db, runId) {
193
+ return db.prepare(`
194
+ SELECT * FROM findings
195
+ WHERE run_id = ?
196
+ ORDER BY created_at ASC
197
+ `).all(runId);
198
+ }
199
+
200
+ export function getRecurringFindingHashes(db, minOccurrences) {
201
+ return db.prepare(`
202
+ SELECT finding_hash, COUNT(*) AS count
203
+ FROM findings
204
+ GROUP BY finding_hash
205
+ HAVING COUNT(*) >= ?
206
+ ORDER BY count DESC
207
+ `).all(minOccurrences);
208
+ }
209
+
210
+ export function resolveFinding(db, id) {
211
+ db.prepare(`
212
+ UPDATE findings SET resolved = 1 WHERE id = ?
213
+ `).run(id);
214
+ }
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // Audit history
218
+ // ---------------------------------------------------------------------------
219
+
220
+ export function insertAuditRecord(db, record) {
221
+ db.prepare(`
222
+ INSERT INTO audit_history (run_id, finding_count, fix_count, manual_count, quality_score_before, quality_score_after)
223
+ VALUES (?, ?, ?, ?, ?, ?)
224
+ `).run(
225
+ record.run_id,
226
+ record.finding_count ?? 0,
227
+ record.fix_count ?? 0,
228
+ record.manual_count ?? 0,
229
+ record.quality_score_before ?? null,
230
+ record.quality_score_after ?? null,
231
+ );
232
+ }
233
+
234
+ export function getAuditTrend(db, limit) {
235
+ const limitClause = limit ? `LIMIT ${Number(limit)}` : '';
236
+
237
+ return db.prepare(`
238
+ SELECT * FROM audit_history
239
+ ORDER BY date DESC, id DESC
240
+ ${limitClause}
241
+ `).all();
242
+ }
243
+
244
+ // ---------------------------------------------------------------------------
245
+ // Usage
246
+ // ---------------------------------------------------------------------------
247
+
248
+ export function insertUsageRecord(db, record) {
249
+ db.prepare(`
250
+ INSERT INTO usage_aggregate (run_id, tokens_saved, bytes_avoided, savings_ratio, index_queries, routing_decisions)
251
+ VALUES (?, ?, ?, ?, ?, ?)
252
+ `).run(
253
+ record.run_id,
254
+ record.tokens_saved ?? 0,
255
+ record.bytes_avoided ?? 0,
256
+ record.savings_ratio ?? 0.0,
257
+ record.index_queries ?? 0,
258
+ record.routing_decisions ?? 0,
259
+ );
260
+ }
261
+
262
+ export function getUsageSummary(db) {
263
+ const row = db.prepare(`
264
+ SELECT
265
+ COALESCE(SUM(tokens_saved), 0) AS total_tokens_saved,
266
+ COALESCE(SUM(bytes_avoided), 0) AS total_bytes_avoided,
267
+ CASE WHEN COUNT(*) > 0 THEN AVG(savings_ratio) ELSE 0.0 END AS avg_savings_ratio,
268
+ COALESCE(SUM(index_queries), 0) AS total_index_queries,
269
+ COUNT(*) AS run_count
270
+ FROM usage_aggregate
271
+ `).get();
272
+
273
+ return row;
274
+ }
275
+
276
+ // ---------------------------------------------------------------------------
277
+ // Stats (for CLI)
278
+ // ---------------------------------------------------------------------------
279
+
280
+ export function getStateCounts(db) {
281
+ return {
282
+ learning_count: db.prepare('SELECT COUNT(*) AS count FROM learnings').get().count,
283
+ finding_count: db.prepare('SELECT COUNT(*) AS count FROM findings').get().count,
284
+ audit_count: db.prepare('SELECT COUNT(*) AS count FROM audit_history').get().count,
285
+ usage_count: db.prepare('SELECT COUNT(*) AS count FROM usage_aggregate').get().count,
286
+ };
287
+ }
@@ -5,6 +5,46 @@ import { parseCommandOptions } from '../command-options.js';
5
5
  import { readYamlFile } from '../loaders.js';
6
6
  import { findProjectRoot } from '../project-root.js';
7
7
  import { resolveStateRoot } from '../state-root.js';
8
+ import { estimateTokens } from '../capture/usage.js';
9
+
10
+ function readUsageSavingsSummary(stateRoot, runId) {
11
+ const usagePath = path.join(stateRoot, 'runs', runId, 'usage.json');
12
+
13
+ if (!fs.existsSync(usagePath)) {
14
+ return null;
15
+ }
16
+
17
+ try {
18
+ const usage = JSON.parse(fs.readFileSync(usagePath, 'utf8'));
19
+ const cr = usage.savings?.capture_routing ?? {};
20
+ const cm = usage.savings?.context_mode ?? {};
21
+ const co = usage.savings?.compaction ?? {};
22
+ const iq = usage.savings?.index_queries ?? {};
23
+
24
+ const crTokensSaved = cr.estimated_tokens_avoided ?? 0;
25
+ const cmRawTokens = estimateTokens(Math.round((cm.raw_kb ?? 0) * 1024));
26
+ const cmAfterTokens = estimateTokens(Math.round((cm.context_kb ?? 0) * 1024));
27
+ const cmTokensSaved = cmRawTokens - cmAfterTokens;
28
+ const coTokensSaved = (co.pre_compaction_tokens_est ?? 0) - (co.post_compaction_tokens_est ?? 0);
29
+ const iqTokensSaved = iq.estimated_tokens_saved ?? 0;
30
+
31
+ const totalSaved = crTokensSaved + cmTokensSaved + coTokensSaved + iqTokensSaved;
32
+
33
+ if (totalSaved === 0) {
34
+ return null;
35
+ }
36
+
37
+ const crRawTokens = crTokensSaved + estimateTokens(cr.summary_bytes ?? 0);
38
+ const withoutSavings = crRawTokens + cmRawTokens + (co.pre_compaction_tokens_est ?? 0);
39
+ const pct = withoutSavings > 0
40
+ ? `${((totalSaved / withoutSavings) * 100).toFixed(0)}%`
41
+ : '0%';
42
+
43
+ return `Context savings: ~${totalSaved.toLocaleString('en-US')} tokens saved (${pct} reduction)`;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
8
48
 
9
49
  function success(payload, options = {}) {
10
50
  if (options.json) {
@@ -14,9 +54,15 @@ function success(payload, options = {}) {
14
54
  };
15
55
  }
16
56
 
57
+ let output = `${payload.run_id} ${payload.phase} ${payload.status}\n`;
58
+
59
+ if (payload.savings_summary) {
60
+ output += `${payload.savings_summary}\n`;
61
+ }
62
+
17
63
  return {
18
64
  exitCode: 0,
19
- stdout: `${payload.run_id} ${payload.phase} ${payload.status}\n`,
65
+ stdout: output,
20
66
  };
21
67
  }
22
68
 
@@ -61,6 +107,12 @@ export function runStatusCommand(parsed, context = {}) {
61
107
  status_path: statusPath,
62
108
  };
63
109
 
110
+ const savingsSummary = readUsageSavingsSummary(stateRoot, options.run);
111
+
112
+ if (savingsSummary) {
113
+ payload.savings_summary = savingsSummary;
114
+ }
115
+
64
116
  return success(payload, { json: options.json });
65
117
  } catch (error) {
66
118
  return {
@@ -47,20 +47,31 @@ workflows:
47
47
  - prepare_next
48
48
  - run_audit
49
49
  phases:
50
- - clarify
51
- - discover
52
- - specify
53
- - spec_challenge
54
- - author
55
- - design
56
- - design_review
57
- - plan
58
- - plan_review
59
- - execute
60
- - verify
61
- - review
62
- - learn
63
- - prepare_next
50
+ - init
51
+ - clarifier
52
+ - executor
53
+ - final_review
54
+ phase_prerequisites:
55
+ init: {}
56
+ clarifier: {}
57
+ executor:
58
+ required_artifacts:
59
+ - clarified/clarification.md
60
+ - clarified/spec-hardened.md
61
+ - clarified/design.md
62
+ - clarified/execution-plan.md
63
+ required_phase_exits:
64
+ - clarifier
65
+ final_review:
66
+ required_artifacts:
67
+ - clarified/clarification.md
68
+ - clarified/spec-hardened.md
69
+ - clarified/design.md
70
+ - clarified/execution-plan.md
71
+ - artifacts/verification-proof.md
72
+ required_phase_exits:
73
+ - clarifier
74
+ - executor
64
75
  roles:
65
76
  - clarifier
66
77
  - researcher
@@ -85,6 +96,7 @@ required_hooks:
85
96
  - stop_handoff_harvest
86
97
  - protected_path_write_guard
87
98
  - loop_cap_guard
99
+ - context_mode_router
88
100
  protected_paths:
89
101
  - input
90
102
  - roles