@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.
- package/CHANGELOG.md +73 -4
- package/README.md +6 -6
- package/docs/concepts/architecture.md +1 -1
- package/docs/concepts/roles-and-workflows.md +2 -0
- package/docs/concepts/why-wazir.md +59 -0
- package/docs/decisions/2026-03-19-deferred-items.md +564 -0
- package/docs/decisions/2026-03-19-enhancement-decisions.md +300 -0
- package/docs/readmes/INDEX.md +21 -5
- package/docs/readmes/features/expertise/README.md +2 -2
- package/docs/readmes/features/exports/README.md +2 -2
- package/docs/readmes/features/schemas/README.md +3 -0
- package/docs/readmes/features/skills/README.md +17 -0
- package/docs/readmes/features/skills/clarifier.md +5 -0
- package/docs/readmes/features/skills/claude-cli.md +5 -0
- package/docs/readmes/features/skills/codex-cli.md +5 -0
- package/docs/readmes/features/skills/dispatching-parallel-agents.md +5 -0
- package/docs/readmes/features/skills/executing-plans.md +5 -0
- package/docs/readmes/features/skills/executor.md +5 -0
- package/docs/readmes/features/skills/finishing-a-development-branch.md +5 -0
- package/docs/readmes/features/skills/gemini-cli.md +5 -0
- package/docs/readmes/features/skills/humanize.md +5 -0
- package/docs/readmes/features/skills/init-pipeline.md +5 -0
- package/docs/readmes/features/skills/receiving-code-review.md +5 -0
- package/docs/readmes/features/skills/requesting-code-review.md +5 -0
- package/docs/readmes/features/skills/reviewer.md +5 -0
- package/docs/readmes/features/skills/subagent-driven-development.md +5 -0
- package/docs/readmes/features/skills/using-git-worktrees.md +5 -0
- package/docs/readmes/features/skills/wazir.md +5 -0
- package/docs/readmes/features/skills/writing-skills.md +5 -0
- package/docs/readmes/features/workflows/prepare-next.md +1 -1
- package/docs/reference/configuration-reference.md +47 -6
- package/docs/reference/launch-checklist.md +4 -4
- package/docs/reference/review-loop-pattern.md +117 -8
- package/docs/reference/roles-reference.md +1 -0
- package/docs/reference/skill-tiers.md +147 -0
- package/docs/reference/tooling-cli.md +3 -1
- package/docs/truth-claims.yaml +12 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +97 -1
- package/exports/hosts/claude/.claude/settings.json +9 -0
- package/exports/hosts/claude/CLAUDE.md +1 -1
- package/exports/hosts/claude/export.manifest.json +4 -2
- package/exports/hosts/claude/host-package.json +3 -1
- package/exports/hosts/codex/AGENTS.md +1 -1
- package/exports/hosts/codex/export.manifest.json +4 -2
- package/exports/hosts/codex/host-package.json +3 -1
- package/exports/hosts/cursor/.cursor/hooks.json +4 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +1 -1
- package/exports/hosts/cursor/export.manifest.json +4 -2
- package/exports/hosts/cursor/host-package.json +3 -1
- package/exports/hosts/gemini/GEMINI.md +1 -1
- package/exports/hosts/gemini/export.manifest.json +4 -2
- package/exports/hosts/gemini/host-package.json +3 -1
- package/hooks/context-mode-router +191 -0
- package/hooks/definitions/context_mode_router.yaml +19 -0
- package/hooks/hooks.json +31 -6
- package/hooks/protected-path-write-guard +8 -0
- package/hooks/routing-matrix.json +45 -0
- package/hooks/session-start +62 -1
- package/llms-full.txt +905 -132
- package/package.json +2 -3
- package/schemas/hook.schema.json +2 -1
- package/schemas/phase-report.schema.json +80 -0
- package/schemas/usage.schema.json +25 -1
- package/schemas/wazir-manifest.schema.json +19 -0
- package/skills/brainstorming/SKILL.md +18 -155
- package/skills/clarifier/SKILL.md +122 -98
- package/skills/claude-cli/SKILL.md +320 -0
- package/skills/codex-cli/SKILL.md +260 -0
- package/skills/debugging/SKILL.md +13 -0
- package/skills/design/SKILL.md +13 -0
- package/skills/dispatching-parallel-agents/SKILL.md +13 -0
- package/skills/executing-plans/SKILL.md +13 -0
- package/skills/executor/SKILL.md +72 -19
- package/skills/finishing-a-development-branch/SKILL.md +13 -0
- package/skills/gemini-cli/SKILL.md +260 -0
- package/skills/humanize/SKILL.md +13 -0
- package/skills/init-pipeline/SKILL.md +73 -164
- package/skills/prepare-next/SKILL.md +81 -10
- package/skills/receiving-code-review/SKILL.md +13 -0
- package/skills/requesting-code-review/SKILL.md +13 -0
- package/skills/reviewer/SKILL.md +287 -15
- package/skills/run-audit/SKILL.md +13 -0
- package/skills/scan-project/SKILL.md +13 -0
- package/skills/self-audit/SKILL.md +197 -16
- package/skills/subagent-driven-development/SKILL.md +13 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +2 -0
- package/skills/subagent-driven-development/implementer-prompt.md +8 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +7 -0
- package/skills/tdd/SKILL.md +13 -0
- package/skills/using-git-worktrees/SKILL.md +13 -0
- package/skills/using-skills/SKILL.md +13 -0
- package/skills/verification/SKILL.md +13 -0
- package/skills/wazir/SKILL.md +194 -377
- package/skills/writing-plans/SKILL.md +14 -1
- package/skills/writing-skills/SKILL.md +13 -0
- package/templates/artifacts/implementation-plan.md +3 -0
- package/templates/artifacts/tasks-template.md +133 -0
- package/templates/examples/phase-report.example.json +48 -0
- package/tooling/src/adapters/composition-engine.js +256 -0
- package/tooling/src/adapters/model-router.js +84 -0
- package/tooling/src/capture/command.js +24 -1
- package/tooling/src/capture/run-config.js +3 -1
- package/tooling/src/capture/store.js +24 -0
- package/tooling/src/capture/usage.js +106 -0
- package/tooling/src/checks/ac-matrix.js +256 -0
- package/tooling/src/checks/command-registry.js +12 -0
- package/tooling/src/checks/docs-truth.js +1 -1
- package/tooling/src/checks/skills.js +111 -0
- package/tooling/src/cli.js +9 -0
- package/tooling/src/commands/stats.js +161 -0
- package/tooling/src/commands/validate.js +5 -1
- package/tooling/src/export/compiler.js +33 -37
- package/tooling/src/gating/agent.js +145 -0
- package/tooling/src/guards/phase-prerequisite-guard.js +127 -0
- package/tooling/src/hooks/routing-logic.js +69 -0
- package/tooling/src/init/auto-detect.js +260 -0
- package/tooling/src/init/command.js +95 -135
- package/tooling/src/input/scanner.js +46 -0
- package/tooling/src/reports/command.js +103 -0
- package/tooling/src/reports/phase-report.js +323 -0
- package/tooling/src/state/command.js +160 -0
- package/tooling/src/state/db.js +287 -0
- package/tooling/src/status/command.js +53 -1
- 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:
|
|
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 {
|
package/wazir.manifest.yaml
CHANGED
|
@@ -47,20 +47,31 @@ workflows:
|
|
|
47
47
|
- prepare_next
|
|
48
48
|
- run_audit
|
|
49
49
|
phases:
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|