specweave 2.1.0 → 2.2.1

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 (73) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/README.md +7 -6
  3. package/bin/specweave.js +28 -0
  4. package/dist/src/cli/commands/jev-helpers.d.ts +148 -0
  5. package/dist/src/cli/commands/jev-helpers.d.ts.map +1 -0
  6. package/dist/src/cli/commands/jev-helpers.js +582 -0
  7. package/dist/src/cli/commands/jev-helpers.js.map +1 -0
  8. package/dist/src/cli/commands/jev.d.ts +21 -0
  9. package/dist/src/cli/commands/jev.d.ts.map +1 -0
  10. package/dist/src/cli/commands/jev.js +350 -0
  11. package/dist/src/cli/commands/jev.js.map +1 -0
  12. package/dist/src/cli/helpers/init/instruction-file-writer.d.ts +4 -0
  13. package/dist/src/cli/helpers/init/instruction-file-writer.d.ts.map +1 -1
  14. package/dist/src/cli/helpers/init/instruction-file-writer.js +11 -6
  15. package/dist/src/cli/helpers/init/instruction-file-writer.js.map +1 -1
  16. package/dist/src/core/auto/completion-evaluator.d.ts +22 -1
  17. package/dist/src/core/auto/completion-evaluator.d.ts.map +1 -1
  18. package/dist/src/core/auto/completion-evaluator.js +99 -9
  19. package/dist/src/core/auto/completion-evaluator.js.map +1 -1
  20. package/dist/src/core/config/types.d.ts +39 -1
  21. package/dist/src/core/config/types.d.ts.map +1 -1
  22. package/dist/src/core/config/types.js +1 -0
  23. package/dist/src/core/config/types.js.map +1 -1
  24. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +28 -5
  25. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -1
  26. package/dist/src/core/hooks/handlers/pre-tool-use.js +162 -7
  27. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -1
  28. package/dist/src/core/jev/browse.d.ts +56 -0
  29. package/dist/src/core/jev/browse.d.ts.map +1 -0
  30. package/dist/src/core/jev/browse.js +721 -0
  31. package/dist/src/core/jev/browse.js.map +1 -0
  32. package/dist/src/core/jev/client.d.ts +134 -0
  33. package/dist/src/core/jev/client.d.ts.map +1 -0
  34. package/dist/src/core/jev/client.js +329 -0
  35. package/dist/src/core/jev/client.js.map +1 -0
  36. package/dist/src/core/jev/config.d.ts +69 -0
  37. package/dist/src/core/jev/config.d.ts.map +1 -0
  38. package/dist/src/core/jev/config.js +181 -0
  39. package/dist/src/core/jev/config.js.map +1 -0
  40. package/dist/src/core/jev/decide.d.ts +162 -0
  41. package/dist/src/core/jev/decide.d.ts.map +1 -0
  42. package/dist/src/core/jev/decide.js +333 -0
  43. package/dist/src/core/jev/decide.js.map +1 -0
  44. package/dist/src/core/jev/index.d.ts +20 -0
  45. package/dist/src/core/jev/index.d.ts.map +1 -0
  46. package/dist/src/core/jev/index.js +20 -0
  47. package/dist/src/core/jev/index.js.map +1 -0
  48. package/dist/src/core/jev/questions.d.ts +56 -0
  49. package/dist/src/core/jev/questions.d.ts.map +1 -0
  50. package/dist/src/core/jev/questions.js +159 -0
  51. package/dist/src/core/jev/questions.js.map +1 -0
  52. package/dist/src/core/jev/redact.d.ts +44 -0
  53. package/dist/src/core/jev/redact.d.ts.map +1 -0
  54. package/dist/src/core/jev/redact.js +102 -0
  55. package/dist/src/core/jev/redact.js.map +1 -0
  56. package/dist/src/core/jev/usage.d.ts +38 -0
  57. package/dist/src/core/jev/usage.d.ts.map +1 -0
  58. package/dist/src/core/jev/usage.js +70 -0
  59. package/dist/src/core/jev/usage.js.map +1 -0
  60. package/dist/src/utils/model-selection.d.ts +49 -0
  61. package/dist/src/utils/model-selection.d.ts.map +1 -1
  62. package/dist/src/utils/model-selection.js +70 -0
  63. package/dist/src/utils/model-selection.js.map +1 -1
  64. package/package.json +1 -1
  65. package/plugins/PLUGINS-INDEX.md +14 -4
  66. package/plugins/specweave/.claude-plugin/plugin.json +5 -3
  67. package/plugins/specweave/PLUGIN.md +16 -4
  68. package/plugins/specweave/hooks/run-worker.mjs +37 -2
  69. package/plugins/specweave/hooks/run.mjs +30 -0
  70. package/plugins/specweave/marketplace.json +6 -0
  71. package/plugins/specweave/skills/jev/SKILL.md +203 -0
  72. package/src/templates/AGENTS.md.template +22 -0
  73. package/src/templates/CLAUDE.md.template +22 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Jev — the single redaction choke point.
3
+ *
4
+ * Every byte that leaves this machine for the System One endpoint goes through
5
+ * {@link redactSecrets} first: the client scrubs the serialized state before any
6
+ * request, and the PreToolUse Bash guard scrubs the command text it scores.
7
+ * One function, one set of patterns, one set of markers — a second copy is how a
8
+ * key eventually ships.
9
+ *
10
+ * Layers, in order:
11
+ * 1. the shared handoff scrubber (`sk-…`, `sk-or-…`, `ghp_`/`gho_`/`ghs_`,
12
+ * `vsk_`, `xox[abp]-`, `AKIA…`/`ASIA…`, `Bearer …`, PEM headers,
13
+ * `password=`, `api_key=`);
14
+ * 2. key shapes it does not carry (`github_pat_…`, JWT-looking `eyJ….….…`);
15
+ * 3. command-shaped secrets (`scheme:// USER : PASS @host`, `--otp=`/`--token …`,
16
+ * `SOMETHING_TOKEN=value`).
17
+ *
18
+ * Later layers carry a `(?!\[REDACTED)` guard so an already-masked span is never
19
+ * masked twice. Markers are normalised to `<REDACTED-…>` at the end: masking
20
+ * removes text, and removed text could otherwise turn a command the guard's
21
+ * prefilter calls 'check' into one it calls 'skip' (`echo PASSWORD="x; rm -rf ~"`
22
+ * → `echo PASSWORD=<…>`). `<` is in the prefilter's shell-power set, so a
23
+ * redacted command always still reaches Jev.
24
+ *
25
+ * HEURISTIC, never a guarantee: zero redactions does not mean the text is clean.
26
+ * That is why every Jev integration is opt-in and the docs state the export.
27
+ *
28
+ * @module core/jev/redact
29
+ */
30
+ /**
31
+ * Mask secret-shaped values before text leaves this machine.
32
+ *
33
+ * The markers keep the text's shape, so a command still scores the same way for
34
+ * scope and destructiveness and a state object still reads the same way.
35
+ *
36
+ * @param text - anything about to be sent to the System One endpoint
37
+ * @returns the redacted text and how many spans were masked (0 = nothing matched,
38
+ * which is not the same as "clean")
39
+ */
40
+ export declare function redactSecrets(text: string): {
41
+ text: string;
42
+ redactions: number;
43
+ };
44
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../../../src/core/jev/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA4DH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAiBhF"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Jev — the single redaction choke point.
3
+ *
4
+ * Every byte that leaves this machine for the System One endpoint goes through
5
+ * {@link redactSecrets} first: the client scrubs the serialized state before any
6
+ * request, and the PreToolUse Bash guard scrubs the command text it scores.
7
+ * One function, one set of patterns, one set of markers — a second copy is how a
8
+ * key eventually ships.
9
+ *
10
+ * Layers, in order:
11
+ * 1. the shared handoff scrubber (`sk-…`, `sk-or-…`, `ghp_`/`gho_`/`ghs_`,
12
+ * `vsk_`, `xox[abp]-`, `AKIA…`/`ASIA…`, `Bearer …`, PEM headers,
13
+ * `password=`, `api_key=`);
14
+ * 2. key shapes it does not carry (`github_pat_…`, JWT-looking `eyJ….….…`);
15
+ * 3. command-shaped secrets (`scheme:// USER : PASS @host`, `--otp=`/`--token …`,
16
+ * `SOMETHING_TOKEN=value`).
17
+ *
18
+ * Later layers carry a `(?!\[REDACTED)` guard so an already-masked span is never
19
+ * masked twice. Markers are normalised to `<REDACTED-…>` at the end: masking
20
+ * removes text, and removed text could otherwise turn a command the guard's
21
+ * prefilter calls 'check' into one it calls 'skip' (`echo PASSWORD="x; rm -rf ~"`
22
+ * → `echo PASSWORD=<…>`). `<` is in the prefilter's shell-power set, so a
23
+ * redacted command always still reaches Jev.
24
+ *
25
+ * HEURISTIC, never a guarantee: zero redactions does not mean the text is clean.
26
+ * That is why every Jev integration is opt-in and the docs state the export.
27
+ *
28
+ * @module core/jev/redact
29
+ */
30
+ import { scrubSecrets, totalRedactions } from '../session/handoff-secret-scrub.js';
31
+ /**
32
+ * Key shapes the shared scrubber does not carry.
33
+ *
34
+ * Fixed-literal prefixes, so they can never match inside a `[REDACTED-…]` marker.
35
+ */
36
+ const KEY_SHAPE_PATTERNS = [
37
+ {
38
+ // GitHub fine-grained PAT: `github_pat_11ABCDEF0…`
39
+ type: 'github-pat',
40
+ regex: /github_pat_[A-Za-z0-9_]{20,}/g,
41
+ replace: '[REDACTED-github-pat]',
42
+ },
43
+ {
44
+ // JWT-looking: `eyJhbGciOi….eyJzdWIi….<signature>` (the signature is optional).
45
+ type: 'jwt',
46
+ regex: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?:\.[A-Za-z0-9_-]+)?/g,
47
+ replace: '[REDACTED-jwt]',
48
+ },
49
+ ];
50
+ /**
51
+ * Command-shaped secrets: the value is identified by the flag or variable in
52
+ * front of it rather than by its own shape.
53
+ */
54
+ const COMMAND_SECRET_PATTERNS = [
55
+ {
56
+ // `psql postgres:// USER : PASS @host/db`, `git clone https:// U : TOK @github.com/...`
57
+ type: 'url-credentials',
58
+ regex: /([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]*@/gi,
59
+ replace: '$1[REDACTED-url-credentials]@',
60
+ },
61
+ {
62
+ // `npm publish --otp=123456`, `--token <value>`, `--password=…`
63
+ type: 'secret-flag',
64
+ regex: /(?<![\w-])(--?(?:otp|tokens?|passwords?|passwd|secrets?|api[-_]?keys?|access[-_]?tokens?|credentials?)[=\s])(?!\[REDACTED)("[^"]*"|'[^']*'|\S+)/gi,
65
+ replace: '$1[REDACTED-secret-flag]',
66
+ },
67
+ {
68
+ // `GITHUB_TOKEN=ghp_… cmd`, `MY_API_KEY="…"`, `DB_PASSWORD=…`
69
+ type: 'env-secret',
70
+ regex: /(^|[\s;&|(])([A-Za-z_][A-Za-z0-9_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|KEY|CREDENTIALS?)[A-Za-z0-9_]*=)(?!\[REDACTED)("[^"]*"|'[^']*'|\S*)/gi,
71
+ replace: '$1$2[REDACTED-env-secret]',
72
+ },
73
+ ];
74
+ const EXTRA_PATTERNS = [...KEY_SHAPE_PATTERNS, ...COMMAND_SECRET_PATTERNS];
75
+ /**
76
+ * Mask secret-shaped values before text leaves this machine.
77
+ *
78
+ * The markers keep the text's shape, so a command still scores the same way for
79
+ * scope and destructiveness and a state object still reads the same way.
80
+ *
81
+ * @param text - anything about to be sent to the System One endpoint
82
+ * @returns the redacted text and how many spans were masked (0 = nothing matched,
83
+ * which is not the same as "clean")
84
+ */
85
+ export function redactSecrets(text) {
86
+ const base = scrubSecrets(text ?? '');
87
+ let redacted = base.scrubbed;
88
+ let redactions = totalRedactions(base.counts);
89
+ for (const { regex, replace } of EXTRA_PATTERNS) {
90
+ regex.lastIndex = 0;
91
+ const hits = redacted.match(regex);
92
+ if (!hits)
93
+ continue;
94
+ redactions += hits.length;
95
+ regex.lastIndex = 0;
96
+ redacted = redacted.replace(regex, replace);
97
+ }
98
+ if (redactions > 0)
99
+ redacted = redacted.replace(/\[REDACTED-([A-Za-z-]+)\]/g, '<REDACTED-$1>');
100
+ return { text: redacted, redactions };
101
+ }
102
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../../../src/core/jev/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AASnF;;;;GAIG;AACH,MAAM,kBAAkB,GAAiC;IACvD;QACE,mDAAmD;QACnD,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,+BAA+B;QACtC,OAAO,EAAE,uBAAuB;KACjC;IACD;QACE,gFAAgF;QAChF,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,mEAAmE;QAC1E,OAAO,EAAE,gBAAgB;KAC1B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,uBAAuB,GAAiC;IAC5D;QACE,wFAAwF;QACxF,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,+CAA+C;QACtD,OAAO,EAAE,+BAA+B;KACzC;IACD;QACE,gEAAgE;QAChE,IAAI,EAAE,aAAa;QACnB,KAAK,EACH,mJAAmJ;QACrJ,OAAO,EAAE,0BAA0B;KACpC;IACD;QACE,8DAA8D;QAC9D,IAAI,EAAE,YAAY;QAClB,KAAK,EACH,0IAA0I;QAC5I,OAAO,EAAE,2BAA2B;KACrC;CACF,CAAC;AAEF,MAAM,cAAc,GAAiC,CAAC,GAAG,kBAAkB,EAAE,GAAG,uBAAuB,CAAC,CAAC;AAEzG;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACtC,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC7B,IAAI,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE9C,KAAK,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,cAAc,EAAE,CAAC;QAChD,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC;QAC1B,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACpB,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,UAAU,GAAG,CAAC;QAAE,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;IAE/F,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Jev usage ledger — append-only JSONL at `.specweave/state/jev-usage.jsonl`
3
+ *
4
+ * Every Jev call writes one line (tokens, cost, latency, ok). Reading is tolerant:
5
+ * a truncated or corrupt line is skipped, never thrown. Nothing here stores a key.
6
+ *
7
+ * @module core/jev/usage
8
+ */
9
+ export interface JevUsageRecord {
10
+ at: string;
11
+ kind: string;
12
+ provider: string;
13
+ model: string;
14
+ input_tokens: number;
15
+ output_tokens: number;
16
+ cost?: number;
17
+ latencyMs: number;
18
+ /** Secret-shaped spans masked out of the request state before it was sent. */
19
+ redactions?: number;
20
+ ok: boolean;
21
+ }
22
+ export interface JevUsageSummary {
23
+ calls: number;
24
+ input_tokens: number;
25
+ cost: number;
26
+ byKind: Record<string, number>;
27
+ since?: string;
28
+ }
29
+ /** Absolute path of the ledger for a project root. */
30
+ export declare function usageLogPath(projectRoot: string): string;
31
+ /**
32
+ * Append one record. Best-effort: never throws (the caller is mid-decision).
33
+ * O_APPEND keeps concurrent agents from interleaving partial lines.
34
+ */
35
+ export declare function appendUsage(projectRoot: string, rec: JevUsageRecord): void;
36
+ /** Totals over the whole ledger. Missing file → zeroes. Bad lines → skipped. */
37
+ export declare function readUsageSummary(projectRoot: string): JevUsageSummary;
38
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/core/jev/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAQ1E;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAuCrE"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Jev usage ledger — append-only JSONL at `.specweave/state/jev-usage.jsonl`
3
+ *
4
+ * Every Jev call writes one line (tokens, cost, latency, ok). Reading is tolerant:
5
+ * a truncated or corrupt line is skipped, never thrown. Nothing here stores a key.
6
+ *
7
+ * @module core/jev/usage
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ /** Absolute path of the ledger for a project root. */
12
+ export function usageLogPath(projectRoot) {
13
+ return path.join(projectRoot, '.specweave', 'state', 'jev-usage.jsonl');
14
+ }
15
+ /**
16
+ * Append one record. Best-effort: never throws (the caller is mid-decision).
17
+ * O_APPEND keeps concurrent agents from interleaving partial lines.
18
+ */
19
+ export function appendUsage(projectRoot, rec) {
20
+ try {
21
+ const filePath = usageLogPath(projectRoot);
22
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
23
+ fs.appendFileSync(filePath, JSON.stringify(rec) + '\n', { flag: 'a' });
24
+ }
25
+ catch {
26
+ // Ledger writes are advisory; a full disk must not break a Jev decision.
27
+ }
28
+ }
29
+ /** Totals over the whole ledger. Missing file → zeroes. Bad lines → skipped. */
30
+ export function readUsageSummary(projectRoot) {
31
+ const summary = { calls: 0, input_tokens: 0, cost: 0, byKind: {} };
32
+ let raw;
33
+ try {
34
+ const filePath = usageLogPath(projectRoot);
35
+ if (!fs.existsSync(filePath))
36
+ return summary;
37
+ raw = fs.readFileSync(filePath, 'utf-8');
38
+ }
39
+ catch {
40
+ return summary;
41
+ }
42
+ for (const line of raw.split('\n')) {
43
+ const trimmed = line.trim();
44
+ if (!trimmed)
45
+ continue;
46
+ let rec;
47
+ try {
48
+ rec = JSON.parse(trimmed);
49
+ }
50
+ catch {
51
+ continue;
52
+ }
53
+ if (!rec || typeof rec !== 'object')
54
+ continue;
55
+ summary.calls += 1;
56
+ if (typeof rec.input_tokens === 'number' && Number.isFinite(rec.input_tokens)) {
57
+ summary.input_tokens += rec.input_tokens;
58
+ }
59
+ if (typeof rec.cost === 'number' && Number.isFinite(rec.cost)) {
60
+ summary.cost += rec.cost;
61
+ }
62
+ const kind = typeof rec.kind === 'string' && rec.kind ? rec.kind : 'unknown';
63
+ summary.byKind[kind] = (summary.byKind[kind] ?? 0) + 1;
64
+ if (typeof rec.at === 'string' && rec.at && (!summary.since || rec.at < summary.since)) {
65
+ summary.since = rec.at;
66
+ }
67
+ }
68
+ return summary;
69
+ }
70
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../../src/core/jev/usage.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,8 @@
8
8
  * - Haiku: Simple/cheap operations, translations, mechanical work
9
9
  * - Opus: Default for all complex work, architecture, creative problem-solving
10
10
  */
11
+ import type { JevClient } from '../core/jev/client.js';
12
+ import type { classifyTask } from '../core/jev/decide.js';
11
13
  export type ModelTier = 'haiku' | 'sonnet' | 'opus';
12
14
  export interface Task {
13
15
  id: string;
@@ -71,4 +73,51 @@ export declare function calculateCostSavings(tasksWithModels: Map<string, ModelT
71
73
  savings: number;
72
74
  savingsPercent: number;
73
75
  };
76
+ /**
77
+ * Where a tier recommendation came from.
78
+ * - `jev` — TypeSafe System One classified the task
79
+ * - `heuristic` — the keyword scorer in {@link detectModelForTask}
80
+ */
81
+ export type ModelTierSource = 'jev' | 'heuristic';
82
+ /** {@link DetectionResult} plus the decision's provenance. */
83
+ export interface TierSelection extends DetectionResult {
84
+ source: ModelTierSource;
85
+ /** Latency of the Jev call, when one happened. */
86
+ latencyMs?: number;
87
+ /** Cost of the Jev call in USD, when reported. */
88
+ cost?: number;
89
+ }
90
+ /**
91
+ * Injection points for tests and callers that already hold a client/config.
92
+ * Nothing here is required: the defaults read the project config.
93
+ */
94
+ export interface SelectModelTierDeps {
95
+ /** Project root used to load `.specweave/config.json`. */
96
+ projectRoot?: string;
97
+ /** Force the Jev path on/off (skips config loading when provided). */
98
+ enabled?: boolean;
99
+ /** Force modelRouting on/off (skips config loading when provided). */
100
+ modelRouting?: boolean;
101
+ /** Confidence floor below which the tier falls back to opus. */
102
+ routeThreshold?: number;
103
+ /** A ready client. `null` means "no client available" (heuristic path). */
104
+ client?: JevClient | null;
105
+ /** Override the classifier (tests). */
106
+ classify?: typeof classifyTask;
107
+ }
108
+ /**
109
+ * Pick a model tier for a task, preferring Jev when the project opted in.
110
+ *
111
+ * Behaviour (AC-07):
112
+ * - Jev off, no key, error, timeout → the keyword heuristic, `source: 'heuristic'`
113
+ * - Jev on → `{ model: tier, reasoning: 'jev:<complexity>', source: 'jev' }`
114
+ * - Jev on but confidence < `thresholds.route` → opus, `reasoning: 'jev:low-confidence'`
115
+ *
116
+ * Never throws: every failure path degrades to the heuristic.
117
+ */
118
+ export declare function selectModelTierForTask(task: Task, options?: {
119
+ specDetailLevel?: number;
120
+ hasDetailedPlan?: boolean;
121
+ isArchitectural?: boolean;
122
+ }, deps?: SelectModelTierDeps): Promise<TierSelection>;
74
123
  //# sourceMappingURL=model-selection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../../src/utils/model-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AA4BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;CACtB,GACL,eAAe,CA6GjB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;CACtB,GACL,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAS9B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAQxD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAU7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAChB,eAAe,GAAE,MAAa,GAC7B,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EACvC,oBAAoB,GAAE,MAAa,GAClC;IACD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB,CAkBA"}
1
+ {"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../../src/utils/model-selection.ts"],"names":[],"mappings":"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"}
@@ -205,4 +205,74 @@ export function calculateCostSavings(tasksWithModels, averageTokensPerTask = 200
205
205
  savingsPercent
206
206
  };
207
207
  }
208
+ /**
209
+ * Pick a model tier for a task, preferring Jev when the project opted in.
210
+ *
211
+ * Behaviour (AC-07):
212
+ * - Jev off, no key, error, timeout → the keyword heuristic, `source: 'heuristic'`
213
+ * - Jev on → `{ model: tier, reasoning: 'jev:<complexity>', source: 'jev' }`
214
+ * - Jev on but confidence < `thresholds.route` → opus, `reasoning: 'jev:low-confidence'`
215
+ *
216
+ * Never throws: every failure path degrades to the heuristic.
217
+ */
218
+ export async function selectModelTierForTask(task, options = {}, deps = {}) {
219
+ const heuristic = () => ({
220
+ ...detectModelForTask(task, options),
221
+ source: 'heuristic',
222
+ });
223
+ try {
224
+ const [cfgMod, clientMod, decideMod] = await Promise.all([
225
+ import('../core/jev/config.js'),
226
+ import('../core/jev/client.js'),
227
+ import('../core/jev/decide.js'),
228
+ ]);
229
+ let enabled = deps.enabled;
230
+ let modelRouting = deps.modelRouting;
231
+ let routeThreshold = deps.routeThreshold;
232
+ if (enabled === undefined || modelRouting === undefined || routeThreshold === undefined) {
233
+ const cfg = cfgMod.loadJevConfig(deps.projectRoot);
234
+ if (enabled === undefined)
235
+ enabled = cfg.enabled;
236
+ if (modelRouting === undefined)
237
+ modelRouting = cfg.modelRouting;
238
+ if (routeThreshold === undefined)
239
+ routeThreshold = cfg.thresholds.route;
240
+ }
241
+ if (!enabled || !modelRouting)
242
+ return heuristic();
243
+ const client = deps.client !== undefined ? deps.client : clientMod.createJevClient(deps.projectRoot);
244
+ if (!client)
245
+ return heuristic();
246
+ const classify = deps.classify ?? decideMod.classifyTask;
247
+ const decision = await classify(client, {
248
+ id: task.id,
249
+ title: task.content,
250
+ body: task.description ?? '',
251
+ acs: task.acceptanceCriteria ?? [],
252
+ });
253
+ if (!decision.available)
254
+ return heuristic();
255
+ if (decision.confidence < routeThreshold) {
256
+ return {
257
+ model: 'opus',
258
+ confidence: decision.confidence,
259
+ reasoning: 'jev:low-confidence',
260
+ source: 'jev',
261
+ latencyMs: decision.latencyMs,
262
+ cost: decision.cost,
263
+ };
264
+ }
265
+ return {
266
+ model: decision.tier,
267
+ confidence: decision.confidence,
268
+ reasoning: `jev:${decision.complexity}`,
269
+ source: 'jev',
270
+ latencyMs: decision.latencyMs,
271
+ cost: decision.cost,
272
+ };
273
+ }
274
+ catch {
275
+ return heuristic();
276
+ }
277
+ }
208
278
  //# sourceMappingURL=model-selection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../../src/utils/model-selection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../../src/utils/model-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwBH;;GAEG;AACH,MAAM,gBAAgB,GAAG;IACvB,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ;IACrE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU;IACnE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ;CACnE,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS;IACjE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO;IAC/D,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM;CAC1D,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc;IACvE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS;CAC3D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAU,EACV,UAII,EAAE;IAEN,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3E,wBAAwB;IACxB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,sBAAsB;IACtB,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QACjC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,WAAW,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAChC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,UAAU,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAClC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,WAAW,IAAI,CAAC,CAAC;YACjB,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,kCAAkC;IAClC,IAAI,IAAI,CAAC,aAAa,IAAI,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC;QACnF,UAAU,IAAI,CAAC,CAAC,CAAC,8BAA8B;IACjD,CAAC;IAED,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,UAAU,IAAI,CAAC,CAAC,CAAC,0CAA0C;IAC7D,CAAC;IAED,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,WAAW,IAAI,CAAC,CAAC,CAAC,wCAAwC;QAC1D,SAAS,IAAI,CAAC,CAAC;IACjB,CAAC;IAED,kCAAkC;IAClC,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACnE,UAAU,IAAI,CAAC,CAAC,CAAC,2CAA2C;IAC9D,CAAC;IAED,8DAA8D;IAC9D,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QACvD,WAAW,IAAI,CAAC,CAAC,CAAC,6CAA6C;IACjE,CAAC;IAED,gCAAgC;IAChC,MAAM,gBAAgB,GAAG,qDAAqD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9F,IAAI,gBAAgB,EAAE,CAAC;QACrB,UAAU,IAAI,CAAC,CAAC,CAAC,8CAA8C;IACjE,CAAC;IAED,MAAM,gBAAgB,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7D,IAAI,gBAAgB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAChD,UAAU,IAAI,CAAC,CAAC,CAAC,kDAAkD;IACrE,CAAC;IAED,6CAA6C;IAC7C,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;IAExD,mCAAmC;IACnC,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;YACL,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,GAAG;YACf,SAAS,EAAE,gDAAgD;SAC5D,CAAC;IACJ,CAAC;IAED,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC;IAClD,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;IAE9C,mFAAmF;IACnF,IAAI,SAAS,GAAG,CAAC,IAAI,cAAc,GAAG,GAAG,EAAE,CAAC;QAC1C,OAAO;YACL,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,cAAc;YAC1B,SAAS,EAAE,0DAA0D;SACtE,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,GAAG,WAAW,IAAI,eAAe,GAAG,GAAG,EAAE,CAAC;QACtD,OAAO;YACL,KAAK,EAAE,OAAO;YACd,UAAU,EAAE,eAAe;YAC3B,SAAS,EAAE,0EAA0E;SACtF,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,GAAG,UAAU,IAAI,gBAAgB,GAAG,GAAG,EAAE,CAAC;QACvD,OAAO;YACL,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,gBAAgB;YAC5B,SAAS,EAAE,oDAAoD;SAChE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,GAAG;QACf,SAAS,EAAE,gDAAgD;KAC5D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,UAGI,EAAE;IAEN,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEnD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACnB,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgB;IAC9C,MAAM,KAAK,GAAG;QACZ,KAAK,EAAE,GAAG,EAAI,OAAO;QACrB,MAAM,EAAE,IAAI,EAAG,WAAW;QAC1B,IAAI,EAAE,IAAI,CAAK,UAAU;KAC1B,CAAC;IAEF,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,UAAU,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAExD,IAAI,UAAU;QAAE,OAAO,OAAO,CAAC;IAC/B,IAAI,WAAW;QAAE,OAAO,QAAQ,CAAC;IACjC,IAAI,SAAS;QAAE,OAAO,MAAM,CAAC;IAE7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAgB,EAChB,kBAA0B,IAAI;IAE9B,2DAA2D;IAC3D,MAAM,SAAS,GAAG;QAChB,KAAK,EAAE,IAAI,EAAI,8CAA8C;QAC7D,MAAM,EAAE,KAAK,EAAE,uCAAuC;QACtD,IAAI,EAAE,KAAK,CAAI,uCAAuC;KACvD,CAAC;IAEF,OAAO,CAAC,eAAe,GAAG,OAAS,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,eAAuC,EACvC,uBAA+B,IAAI;IAOnC,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,eAAe,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAChC,aAAa,IAAI,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;QAC/D,aAAa,IAAI,gBAAgB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC;IAC9C,MAAM,cAAc,GAAG,CAAC,OAAO,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;IAEvD,OAAO;QACL,aAAa;QACb,aAAa;QACb,OAAO;QACP,cAAc;KACf,CAAC;AACJ,CAAC;AAyCD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAU,EACV,UAII,EAAE,EACN,OAA4B,EAAE;IAE9B,MAAM,SAAS,GAAG,GAAkB,EAAE,CAAC,CAAC;QACtC,GAAG,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC;QACpC,MAAM,EAAE,WAAW;KACpB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACvD,MAAM,CAAC,uBAAuB,CAAC;YAC/B,MAAM,CAAC,uBAAuB,CAAC;YAC/B,MAAM,CAAC,uBAAuB,CAAC;SAChC,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC3B,IAAI,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACrC,IAAI,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAEzC,IAAI,OAAO,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACxF,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACnD,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YACjD,IAAI,YAAY,KAAK,SAAS;gBAAE,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;YAChE,IAAI,cAAc,KAAK,SAAS;gBAAE,cAAc,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;QAC1E,CAAC;QAED,IAAI,CAAC,OAAO,IAAI,CAAC,YAAY;YAAE,OAAO,SAAS,EAAE,CAAC;QAElD,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxF,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,EAAE,CAAC;QAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,YAAY,CAAC;QACzD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE;YACtC,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,OAAO;YACnB,IAAI,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;YAC5B,GAAG,EAAE,IAAI,CAAC,kBAAkB,IAAI,EAAE;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,OAAO,SAAS,EAAE,CAAC;QAE5C,IAAI,QAAQ,CAAC,UAAU,GAAG,cAAc,EAAE,CAAC;YACzC,OAAO;gBACL,KAAK,EAAE,MAAM;gBACb,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,SAAS,EAAE,oBAAoB;gBAC/B,MAAM,EAAE,KAAK;gBACb,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC;QACJ,CAAC;QAED,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,IAAI;YACpB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,SAAS,EAAE,OAAO,QAAQ,CAAC,UAAU,EAAE;YACvC,MAAM,EAAE,KAAK;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,EAAE,CAAC;IACrB,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specweave",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "Keep intent, specifications, and verified progress portable across AI coding tools. A local live work board, append-only task evidence, explicit handoffs, and optional GitHub/Jira/Azure DevOps integrations.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,13 +1,13 @@
1
1
  # SpecWeave plugins index
2
2
 
3
- **Plugins**: 1 (`sw`) · **Skills**: 10 · **Commands**: 0 · **Hooks**: 4
3
+ **Plugins**: 1 (`sw`) · **Skills**: 11 · **Commands**: 0 · **Hooks**: 2 default
4
4
 
5
5
  The 1.x `commands/` namespace is gone: anything deterministic is a `specweave`
6
- CLI subcommand, and the model-judgement procedures are the 10 skills below.
6
+ CLI subcommand, and the model-judgement procedures are the 11 skills below.
7
7
 
8
8
  | Plugin | Triggers | Description |
9
9
  |---|---|---|
10
- | **specweave** (`sw`) | increment, spec, tasks, plan, implement, close, review, team, handoff, sync, GitHub, Jira, ADO, auto, brainstorm, qa | Increment lifecycle: plan → work the ledger → verify → review → complete, with cross-tool handoff and tracker sync |
10
+ | **specweave** (`sw`) | increment, spec, tasks, plan, implement, close, review, team, handoff, sync, GitHub, Jira, ADO, auto, brainstorm, qa, jev, system one | Increment lifecycle: plan → work the ledger → verify → review → complete, with cross-tool handoff, tracker sync and closed-set decisions delegated to Jev |
11
11
 
12
12
  ## Quick lookup
13
13
 
@@ -23,6 +23,16 @@ CLI subcommand, and the model-judgement procedures are the 10 skills below.
23
23
  | "Run until done" | `sw:auto` |
24
24
  | "What are our options" | `sw:brainstorm` |
25
25
  | "Quality check" / "risk assessment" | `sw:qa` |
26
+ | "Jev" / "system one" / a decision whose answers can all be enumerated first | `sw:jev` |
27
+
28
+ ## Hooks
29
+
30
+ Two by default, registered in `specweave/hooks/hooks.json` as exec-form
31
+ `node hooks/run.mjs <event>`: `SessionStart` and `Stop`. Each one fails open.
32
+ `PreToolUse` is not a default hook — the Jev Bash guard is turned on per project by
33
+ `specweave jev setup --guard-bash`, which writes `jev.guards.bash`, the marker
34
+ `.specweave/state/jev-guard.enabled`, and a `PreToolUse` entry (matcher `Bash`) in that
35
+ project's `.claude/settings.json`. `--no-guard-bash` removes all three.
26
36
 
27
37
  ## Not in the plugin
28
38
 
@@ -30,4 +40,4 @@ CLI subcommand, and the model-judgement procedures are the 10 skills below.
30
40
  and install per-project with vskill. See `skills-optional/README.md`.
31
41
 
32
42
  Deterministic operations are CLI: `specweave status | task | verify | complete | qa |
33
- handoff | sync | docs | doctor | gc`.
43
+ handoff | sync | docs | doctor | gc | jev`.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sw",
3
- "description": "Portable intent and verified progress across coding tools. Ten focused workflow skills, two default lifecycle hooks, and a deterministic CLI and live local dashboard.",
4
- "version": "2.1.0",
3
+ "description": "Portable intent and verified progress across coding tools. Eleven focused workflow skills, two default lifecycle hooks, and a deterministic CLI and live local dashboard.",
4
+ "version": "2.2.1",
5
5
  "author": {
6
6
  "name": "SpecWeave Team",
7
7
  "url": "https://spec-weave.com"
@@ -20,6 +20,8 @@
20
20
  "handoff",
21
21
  "github",
22
22
  "jira",
23
- "azure-devops"
23
+ "azure-devops",
24
+ "jev",
25
+ "system-one"
24
26
  ]
25
27
  }
@@ -1,6 +1,6 @@
1
1
  # SpecWeave plugin (`sw`)
2
2
 
3
- The Claude Code surface for SpecWeave: **10 skills, 4 hooks, 1 closer agent**.
3
+ The Claude Code surface for SpecWeave: **11 skills, 2 default hooks, 1 closer agent**.
4
4
  Everything deterministic lives in the `specweave` CLI; a skill exists only where a
5
5
  procedure needs model judgement. There is no `commands/` namespace in 2.0.
6
6
 
@@ -18,6 +18,7 @@ procedure needs model judgement. There is no `commands/` namespace in 2.0.
18
18
  | `sw:auto` | Unattended loop driven by the Stop hook |
19
19
  | `sw:brainstorm` | Expand the option space before committing to one |
20
20
  | `sw:qa` | Risk-scored quality assessment (`specweave qa`) |
21
+ | `sw:jev` | Delegate closed-set decisions to Jev (TypeSafe System One): routing, command safety, screening |
21
22
 
22
23
  Optional procedures (tdd-cycle, e2e, debug, diagrams, release-expert) are **not** in the
23
24
  plugin — they ship from `skills-optional/` via
@@ -25,14 +26,25 @@ plugin — they ship from `skills-optional/` via
25
26
 
26
27
  ## Hooks
27
28
 
28
- Four, all exec-form `node hooks/run.mjs <event>` (no shell, Windows-safe):
29
+ Two by default, both exec-form `node hooks/run.mjs <event>` (no shell, Windows-safe):
29
30
 
30
31
  | Hook | Job |
31
32
  |---|---|
32
33
  | `SessionStart` | Inject the active increment + next task as context |
33
- | `PreToolUse` (Write\|Edit) | Guard writes under `.specweave/increments/` |
34
34
  | `Stop` | Drive the `sw:auto` loop; `{}` for every ordinary session |
35
- | `PreCompact` | Write a handoff doc before context is compacted |
35
+
36
+ `PreToolUse` is **not** registered by default — `hooks.json` ships `SessionStart` and
37
+ `Stop` only, exactly as in 2.1.0. `PreToolUse` and `PreCompact` stay callable
38
+ compatibility handlers.
39
+
40
+ The Jev Bash guard is opted into **one project at a time**:
41
+ `specweave jev setup --guard-bash` sets `jev.guards.bash` in `.specweave/config.json`,
42
+ writes the marker `.specweave/state/jev-guard.enabled`, and registers a project-level
43
+ hook in that project's `.claude/settings.json` (`hooks.PreToolUse`, matcher `Bash`,
44
+ command `node "<installed specweave>/plugins/specweave/hooks/run.mjs" pre-tool-use`).
45
+ `specweave jev setup --no-guard-bash` removes all three, and `specweave jev doctor` shows
46
+ the marker and the project hook. This is a Claude Code surface only; other tools call
47
+ `specweave jev guard "<command>"` explicitly before running anything unattended.
36
48
 
37
49
  ## Agents
38
50
 
@@ -19,7 +19,9 @@
19
19
  * 4. `npm root -g` (result cached in a per-user private file under ~/.specweave)
20
20
  *
21
21
  * Fast path: PreToolUse for a file outside `.specweave/increments/` prints `{}`
22
- * without loading the CLI at all (the guards only concern increment files).
22
+ * without loading the CLI at all (the guards only concern increment files), and
23
+ * PreToolUse for Bash prints `{}` unless the project opted into the Jev command
24
+ * guard with a `.specweave/state/jev-guard.enabled` marker.
23
25
  */
24
26
  import { createRequire } from 'node:module';
25
27
  import { spawnSync } from 'node:child_process';
@@ -62,6 +64,34 @@ function isPrivateOwnedFile(file) {
62
64
 
63
65
  const event = process.argv[2] ?? '';
64
66
 
67
+ /** Opt-in marker for the Jev Bash guard, searched upward from cwd / project dir. */
68
+ const JEV_GUARD_MARKER = path.join('.specweave', 'state', 'jev-guard.enabled');
69
+ const JEV_GUARD_MAX_DEPTH = 8;
70
+
71
+ function hasJevGuardMarker(input) {
72
+ const starts = [typeof input.cwd === 'string' ? input.cwd : process.cwd(), process.env.CLAUDE_PROJECT_DIR];
73
+ for (const start of starts) {
74
+ if (!start) continue;
75
+ let current;
76
+ try {
77
+ current = path.resolve(start);
78
+ } catch {
79
+ continue;
80
+ }
81
+ for (let depth = 0; depth < JEV_GUARD_MAX_DEPTH; depth++) {
82
+ try {
83
+ if (existsSync(path.join(current, JEV_GUARD_MARKER))) return true;
84
+ } catch {
85
+ break;
86
+ }
87
+ const parent = path.dirname(current);
88
+ if (parent === current) break;
89
+ current = parent;
90
+ }
91
+ }
92
+ return false;
93
+ }
94
+
65
95
  function inactiveOutput() {
66
96
  if (event === 'session-start') {
67
97
  return {
@@ -123,7 +153,12 @@ function normalizeInput(raw) {
123
153
  filePath = ti.file_path;
124
154
  }
125
155
  if (typeof input.cwd === 'string') input.cwd = input.cwd.replace(/\\/g, '/');
126
- const skip = event === 'pre-tool-use' && !filePath.includes('.specweave/increments/');
156
+ const tool = typeof input.tool_name === 'string' ? input.tool_name : '';
157
+ const skip =
158
+ event === 'pre-tool-use' &&
159
+ (tool === 'Bash'
160
+ ? !hasJevGuardMarker(input)
161
+ : !filePath.includes('.specweave/increments/'));
127
162
  return { raw: JSON.stringify(input), skip };
128
163
  }
129
164
  } catch {