mister-wolf 2.11.0 → 2.12.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 (63) hide show
  1. package/dist/adapters/cli/cli-entry.d.ts.map +1 -1
  2. package/dist/adapters/cli/cli-entry.js +337 -94
  3. package/dist/adapters/cli/cli-entry.js.map +1 -1
  4. package/dist/adapters/cli/commands/analytics.d.ts +1 -1
  5. package/dist/adapters/cli/commands/analytics.d.ts.map +1 -1
  6. package/dist/adapters/cli/commands/analytics.js +30 -1
  7. package/dist/adapters/cli/commands/analytics.js.map +1 -1
  8. package/dist/adapters/cli/commands/memory-brief.d.ts.map +1 -1
  9. package/dist/adapters/cli/commands/memory-brief.js +13 -3
  10. package/dist/adapters/cli/commands/memory-brief.js.map +1 -1
  11. package/dist/adapters/cli/commands/memory-call.d.ts.map +1 -1
  12. package/dist/adapters/cli/commands/memory-call.js +54 -3
  13. package/dist/adapters/cli/commands/memory-call.js.map +1 -1
  14. package/dist/adapters/cli/commands/memory-recap.d.ts.map +1 -1
  15. package/dist/adapters/cli/commands/memory-recap.js +16 -1
  16. package/dist/adapters/cli/commands/memory-recap.js.map +1 -1
  17. package/dist/adapters/fs/config-file.d.ts +8 -0
  18. package/dist/adapters/fs/config-file.d.ts.map +1 -1
  19. package/dist/adapters/fs/config-file.js +57 -2
  20. package/dist/adapters/fs/config-file.js.map +1 -1
  21. package/dist/adapters/fs/scan-snapshot-cache.d.ts +23 -0
  22. package/dist/adapters/fs/scan-snapshot-cache.d.ts.map +1 -0
  23. package/dist/adapters/fs/scan-snapshot-cache.js +36 -0
  24. package/dist/adapters/fs/scan-snapshot-cache.js.map +1 -0
  25. package/dist/adapters/fs/session-delivery-registry.d.ts +31 -0
  26. package/dist/adapters/fs/session-delivery-registry.d.ts.map +1 -0
  27. package/dist/adapters/fs/session-delivery-registry.js +104 -0
  28. package/dist/adapters/fs/session-delivery-registry.js.map +1 -0
  29. package/dist/adapters/fs/session-metrics-log.d.ts +15 -3
  30. package/dist/adapters/fs/session-metrics-log.d.ts.map +1 -1
  31. package/dist/adapters/fs/session-metrics-log.js +150 -29
  32. package/dist/adapters/fs/session-metrics-log.js.map +1 -1
  33. package/dist/adapters/mcp/mcp-schemas.d.ts +1 -1
  34. package/dist/adapters/mcp/mcp-tools.d.ts.map +1 -1
  35. package/dist/adapters/mcp/mcp-tools.js +5 -3
  36. package/dist/adapters/mcp/mcp-tools.js.map +1 -1
  37. package/dist/adapters/sqlite/sqlite-search-index.d.ts +6 -1
  38. package/dist/adapters/sqlite/sqlite-search-index.d.ts.map +1 -1
  39. package/dist/adapters/sqlite/sqlite-search-index.js +47 -25
  40. package/dist/adapters/sqlite/sqlite-search-index.js.map +1 -1
  41. package/dist/app/use-cases/build-analytics.d.ts +64 -1
  42. package/dist/app/use-cases/build-analytics.d.ts.map +1 -1
  43. package/dist/app/use-cases/build-analytics.js +157 -0
  44. package/dist/app/use-cases/build-analytics.js.map +1 -1
  45. package/dist/app/use-cases/generate-recap.d.ts +14 -0
  46. package/dist/app/use-cases/generate-recap.d.ts.map +1 -1
  47. package/dist/app/use-cases/generate-recap.js +37 -0
  48. package/dist/app/use-cases/generate-recap.js.map +1 -1
  49. package/dist/app/use-cases/get-call-injections.d.ts +6 -0
  50. package/dist/app/use-cases/get-call-injections.d.ts.map +1 -1
  51. package/dist/app/use-cases/get-call-injections.js +26 -8
  52. package/dist/app/use-cases/get-call-injections.js.map +1 -1
  53. package/dist/app/use-cases/scan-project.d.ts +26 -1
  54. package/dist/app/use-cases/scan-project.d.ts.map +1 -1
  55. package/dist/app/use-cases/scan-project.js +80 -49
  56. package/dist/app/use-cases/scan-project.js.map +1 -1
  57. package/dist/domain/router-log.d.ts +8 -2
  58. package/dist/domain/router-log.d.ts.map +1 -1
  59. package/dist/domain/router-log.js +14 -2
  60. package/dist/domain/router-log.js.map +1 -1
  61. package/dist/domain/schemas/relation-schema.d.ts +1 -1
  62. package/package.json +1 -1
  63. package/templates/opencode/plugins/wolf-router.ts +80 -42
@@ -1 +1 @@
1
- {"version":3,"file":"scan-project.d.ts","sourceRoot":"","sources":["../../../src/app/use-cases/scan-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAI9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAeD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE;IACJ,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD,EACD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAQ5B;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE;IACJ,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,EACD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAiED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQhE"}
1
+ {"version":3,"file":"scan-project.d.ts","sourceRoot":"","sources":["../../../src/app/use-cases/scan-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAI9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC1C,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE;IACJ,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,iBAAiB,CAAC;CACnC,EACD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE;IACJ,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,EACD,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACvD,OAAO,CAAC,iBAAiB,CAAC,CAc5B;AAwID,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQhE"}
@@ -1,72 +1,93 @@
1
1
  import { governanceDefaults } from '../../domain/governance.js';
2
2
  import { documentRefId, withTieBreak } from '../../adapters/fs/document-id.js';
3
3
  /**
4
- * Кэш скана по сигнатуре дерева (T013): sig совпал → кэшированный результат
5
- * без обхода/побочных эффектов; не совпал → полный scanProject (со всеми
6
- * эффектами — запись project-scan-latest, регистрация document-ref'ов) и
7
- * обновление кэша. treeSignature отсутствует → всегда полный скан
8
- * (обратная совместимость портов в тестах).
4
+ * Кэш скана по сигнатуре дерева (T013 → P105: кэш персистный). sig совпал →
5
+ * результат из кэша без обхода дерева и побочных эффектов; не совпал →
6
+ * полный scanProject (diff-before-save внутри) и перезапись кэша.
7
+ * treeSignature отсутствует → всегда полный скан (обратная совместимость портов
8
+ * в тестах); snapshotCache отсутствует → скан без кэширования.
9
9
  * Инвалидация — см. projectTreeSignature в heuristic-project-scanner.ts:
10
10
  * dir mtime (добавление/удаление/переименование файлов), package.json, .git/HEAD;
11
11
  * контентные правки существующих файлов НЕ инвалидируют (brief не зависит от
12
12
  * содержимого файлов).
13
13
  */
14
- const scanCache = new Map();
15
14
  export async function scanProjectCached(deps, root) {
16
15
  if (!deps.treeSignature)
17
16
  return scanProject(deps, root);
18
17
  const sig = await deps.treeSignature(root);
19
- const cached = scanCache.get(root);
20
- if (cached && cached.sig === sig)
21
- return cached.result;
22
- const result = await scanProject(deps, root);
23
- scanCache.set(root, { sig, result });
24
- return result;
18
+ const cache = deps.snapshotCache;
19
+ if (cache) {
20
+ const hit = await cache.read();
21
+ if (hit && hit.sig === sig)
22
+ return { object: hit.object, snapshot: hit.snapshot, documents: hit.documents };
23
+ }
24
+ // P105: запись кэша — под lock скана (хук выполняется внутри run)
25
+ const persist = cache
26
+ ? async (result) => cache.write({ ...result, sig })
27
+ : undefined;
28
+ return scanProject(deps, root, persist);
25
29
  }
26
- export async function scanProject(deps, root) {
30
+ export async function scanProject(deps, root, afterScan) {
27
31
  const run = async () => {
28
32
  const snapshot = await deps.scanner.scan(root);
29
33
  const now = deps.clock.now();
30
34
  const actor = 'agent:mr-wolf';
31
- const defaults = governanceDefaults(actor);
32
- const object = {
33
- id: 'project-scan-latest',
34
- type: 'context',
35
- title: `Project scan for ${snapshot.projectName}`,
36
- body: renderScanBody(snapshot),
37
- status: 'active',
38
- review_state: 'accepted',
39
- confidence: 'high',
40
- importance: 0.7,
41
- created_at: now.toISOString(),
42
- updated_at: now.toISOString(),
43
- created_by: actor,
44
- schema_version: 1,
45
- source: { kind: 'scan', path: snapshot.root },
46
- related: { files: [], docs: [], decisions: [] },
47
- tags: ['scan'],
48
- superseded_by: null,
49
- memory_class: defaults.memory_class,
50
- truth_role: defaults.truth_role,
51
- lifetime: defaults.lifetime,
52
- };
53
- const existingScan = await deps.store.get(object.id);
54
- await deps.store.save(object);
55
- await deps.log.append({
56
- id: deps.idGen.generateEventId(now),
57
- type: existingScan ? 'memory.scan.updated' : 'memory.added',
58
- timestamp: now.toISOString(),
59
- actor,
60
- payload: { memory_id: object.id, type: object.type },
61
- });
62
- if (deps.index) {
63
- await deps.index.indexObject(object);
64
- }
35
+ const object = await upsertScanObject(deps, snapshot, now, actor);
65
36
  const documents = await registerDocuments(deps, snapshot, now, actor);
66
- return { object, snapshot, documents };
37
+ const result = { object, snapshot, documents };
38
+ if (afterScan)
39
+ await afterScan(result);
40
+ return result;
67
41
  };
68
42
  return deps.lock ? deps.lock.withLock(run) : run();
69
43
  }
44
+ const SCAN_OBJECT_ID = 'project-scan-latest';
45
+ /**
46
+ * Scan-объект project-scan-latest с diff-before-save (P105): title+body
47
+ * (renderScanBody детерминирован) не изменились → ни save, ни event, ни index;
48
+ * возвращается existing, updated_at не тикает.
49
+ */
50
+ async function upsertScanObject(deps, snapshot, now, actor) {
51
+ const title = `Project scan for ${snapshot.projectName}`;
52
+ const body = renderScanBody(snapshot);
53
+ const existing = await deps.store.get(SCAN_OBJECT_ID);
54
+ if (existing && existing.title === title && existing.body === body)
55
+ return existing;
56
+ const defaults = governanceDefaults(actor);
57
+ const object = {
58
+ id: SCAN_OBJECT_ID,
59
+ type: 'context',
60
+ title,
61
+ body,
62
+ status: 'active',
63
+ review_state: 'accepted',
64
+ confidence: 'high',
65
+ importance: 0.7,
66
+ created_at: existing?.created_at ?? now.toISOString(),
67
+ updated_at: now.toISOString(),
68
+ created_by: actor,
69
+ schema_version: 1,
70
+ source: { kind: 'scan', path: snapshot.root },
71
+ related: { files: [], docs: [], decisions: [] },
72
+ tags: ['scan'],
73
+ superseded_by: null,
74
+ memory_class: defaults.memory_class,
75
+ truth_role: defaults.truth_role,
76
+ lifetime: defaults.lifetime,
77
+ };
78
+ await deps.store.save(object);
79
+ await deps.log.append({
80
+ id: deps.idGen.generateEventId(now),
81
+ type: existing ? 'memory.scan.updated' : 'memory.added',
82
+ timestamp: now.toISOString(),
83
+ actor,
84
+ payload: { memory_id: object.id, type: object.type },
85
+ });
86
+ if (deps.index) {
87
+ await deps.index.indexObject(object);
88
+ }
89
+ return object;
90
+ }
70
91
  async function registerDocuments(deps, snapshot, now, actor) {
71
92
  const results = [];
72
93
  const defaults = governanceDefaults(actor);
@@ -80,6 +101,16 @@ async function registerDocuments(deps, snapshot, now, actor) {
80
101
  const takenIds = new Set((await deps.store.list()).map((o) => o.id));
81
102
  for (const doc of snapshot.docs) {
82
103
  const existing = existingByPath.get(doc.path);
104
+ const createdAt = existing?.created_at ?? now.toISOString();
105
+ // P105 diff-before-save: title/path/created_at не изменились → ни save, ни
106
+ // event, ни index; возвращается existing, updated_at не тикает.
107
+ if (existing &&
108
+ existing.title === doc.title &&
109
+ existing.source?.path === doc.path &&
110
+ existing.created_at === createdAt) {
111
+ results.push(existing);
112
+ continue;
113
+ }
83
114
  // Скан не мигрирует (§2.1): у существующего объекта id сохраняется как есть
84
115
  // (даже легаси doc_*); канонический id — только для новых объектов.
85
116
  const id = existing ? existing.id : withTieBreak(documentRefId(doc.path, now.toISOString()), takenIds);
@@ -93,7 +124,7 @@ async function registerDocuments(deps, snapshot, now, actor) {
93
124
  review_state: 'accepted',
94
125
  confidence: 'high',
95
126
  importance: 0.6,
96
- created_at: existing?.created_at ?? now.toISOString(),
127
+ created_at: createdAt,
97
128
  updated_at: now.toISOString(),
98
129
  created_by: existing?.created_by ?? actor,
99
130
  schema_version: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"scan-project.js","sourceRoot":"","sources":["../../../src/app/use-cases/scan-project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scan-project.js","sourceRoot":"","sources":["../../../src/app/use-cases/scan-project.ts"],"names":[],"mappings":"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"}
@@ -3,8 +3,10 @@
3
3
  * Пишет плагин wolf-router (templates/opencode/plugins/wolf-router.ts):
4
4
  * `<ISO> agent-id=<id> playbook=hit name=<mem-id> variant=canonical injected=yes`
5
5
  * `<ISO> agent-id=<id> playbook=miss injected=no`
6
- * Старые файлы могут не иметь name/variant. Парсинг k=v парами (не позиционно),
7
- * чтобы пережить будущие поля; строка валидна ⇔ есть agent-id И playbook=hit|miss.
6
+ * P106 (волна 2.12): строка дополняется `ms=<resolve>` и `bytes=<playbook bytes>`
7
+ * (nullable — старые строки полей не имеют). Старые файлы могут не иметь
8
+ * name/variant. Парсинг k=v парами (не позиционно), чтобы пережить будущие
9
+ * поля; строка валидна ⇔ есть agent-id И playbook=hit|miss.
8
10
  * Битая строка не роняет аналитику — только malformedLines (прецедент readJsonl).
9
11
  */
10
12
  export interface RouterLogRow {
@@ -13,6 +15,10 @@ export interface RouterLogRow {
13
15
  hit: boolean;
14
16
  playbookId: string | null;
15
17
  variant: string | null;
18
+ /** P106: длительность resolve, мс (нет в старых строках). */
19
+ ms: number | null;
20
+ /** P106: размер инъекции playbook, байты (нет в старых строках). */
21
+ bytes: number | null;
16
22
  }
17
23
  export declare function parseRouterLog(text: string): {
18
24
  rows: RouterLogRow[];
@@ -1 +1 @@
1
- {"version":3,"file":"router-log.d.ts","sourceRoot":"","sources":["../../src/domain/router-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAW7F"}
1
+ {"version":3,"file":"router-log.d.ts","sourceRoot":"","sources":["../../src/domain/router-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAW7F"}
@@ -3,8 +3,10 @@
3
3
  * Пишет плагин wolf-router (templates/opencode/plugins/wolf-router.ts):
4
4
  * `<ISO> agent-id=<id> playbook=hit name=<mem-id> variant=canonical injected=yes`
5
5
  * `<ISO> agent-id=<id> playbook=miss injected=no`
6
- * Старые файлы могут не иметь name/variant. Парсинг k=v парами (не позиционно),
7
- * чтобы пережить будущие поля; строка валидна ⇔ есть agent-id И playbook=hit|miss.
6
+ * P106 (волна 2.12): строка дополняется `ms=<resolve>` и `bytes=<playbook bytes>`
7
+ * (nullable — старые строки полей не имеют). Старые файлы могут не иметь
8
+ * name/variant. Парсинг k=v парами (не позиционно), чтобы пережить будущие
9
+ * поля; строка валидна ⇔ есть agent-id И playbook=hit|miss.
8
10
  * Битая строка не роняет аналитику — только malformedLines (прецедент readJsonl).
9
11
  */
10
12
  export function parseRouterLog(text) {
@@ -40,12 +42,22 @@ function parseLine(line) {
40
42
  return null;
41
43
  const name = kv.get('name');
42
44
  const variant = kv.get('variant');
45
+ // P106: ms/bytes — целые числа; нечисловое/отсутствующее → null (толерантность)
46
+ const num = (key) => {
47
+ const v = kv.get(key);
48
+ if (v === undefined || !/^\d+$/.test(v))
49
+ return null;
50
+ const n = Number(v);
51
+ return Number.isSafeInteger(n) ? n : null;
52
+ };
43
53
  return {
44
54
  ts,
45
55
  agentId,
46
56
  hit: playbook === 'hit',
47
57
  playbookId: name !== undefined && name !== '' ? name : null,
48
58
  variant: variant !== undefined && variant !== '' ? variant : null,
59
+ ms: num('ms'),
60
+ bytes: num('bytes'),
49
61
  };
50
62
  }
51
63
  //# sourceMappingURL=router-log.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"router-log.js","sourceRoot":"","sources":["../../src/domain/router-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,IAAI,GAAmB,EAAE,CAAC;IAChC,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,EAAE;YAAE,SAAS;QAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,IAAI;YAAE,cAAc,IAAI,CAAC,CAAC;;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AAClC,CAAC;AAED,gGAAgG;AAChG,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,EAAE,GAAG,CAAC;YAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,IAAI,CAAC,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxG,MAAM,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO;QACL,EAAE;QACF,OAAO;QACP,GAAG,EAAE,QAAQ,KAAK,KAAK;QACvB,UAAU,EAAE,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAC3D,OAAO,EAAE,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;KAClE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"router-log.js","sourceRoot":"","sources":["../../src/domain/router-log.ts"],"names":[],"mappings":"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"}
@@ -4,10 +4,10 @@ export declare const RelationSchema: z.ZodObject<{
4
4
  id: z.ZodString;
5
5
  subject: z.ZodString;
6
6
  predicate: z.ZodEnum<{
7
+ superseded_by: "superseded_by";
7
8
  answers: "answers";
8
9
  supports: "supports";
9
10
  owner_skill: "owner_skill";
10
- superseded_by: "superseded_by";
11
11
  answered_by: "answered_by";
12
12
  supported_by: "supported_by";
13
13
  based_on: "based_on";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mister-wolf",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Local-first project memory for AI coding agents: decisions, lessons, tools and processes that outlive the session",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -5,8 +5,9 @@
5
5
  * доставка вместо вероятностного wolf search агентом. Маркер
6
6
  * `agent-id: <id>` В ТЕЛЕ рамки агента (frontmatter в system-промпт не
7
7
  * попадает — известная грабля) → wolf search --type playbook → get +
8
- * гвард owner_skill === agentId | `skill:${agentId}` (legacy) → максимальная
9
- * version → инжект в system-промпт на каждое сообщение.
8
+ * гвард owner_skill === agentId | `skill:${agentId}` (legacy) → первый
9
+ * прошедший гвард кандидат (ранний стоп, A2-б) → инжект в system-промпт
10
+ * на каждое сообщение.
10
11
  *
11
12
  * Fallback (T012, волна 1.1): канон приоритетен; при miss для ЛЮБОГО
12
13
  * agent-id инъецируется встроенный универсальный FALLBACK_PLAYBOOK —
@@ -16,8 +17,8 @@
16
17
  *
17
18
  * Ноль зависимостей (Node stdlib; ai-sdk НЕ используется). Fail-safe: всё в
18
19
  * try/catch — плагин не имеет права уронить сессию (лог: .wolf/router.log —
19
- * agent-id, name, variant, injected). Через этот файл при рендере проходят
20
- * подстановка {{tool.*}} и штамп `// wolf:rendered` (ставит рендерер).
20
+ * agent-id, name, variant, injected, ms, bytes). Через этот файл при рендере
21
+ * проходят подстановка {{tool.*}} и штамп `// wolf:rendered` (ставит рендерер).
21
22
  */
22
23
 
23
24
  import path from 'path';
@@ -52,19 +53,22 @@ const FALLBACK_PLAYBOOK = `# Универсальный playbook (fallback)
52
53
  причина; обошёл через <что сработало>\`), не молча и не ретраи в стол.`;
53
54
  // [ \t] вместо \s: \s съедает переводы строк и вытаскивает id с чужой строки.
54
55
  const AGENT_ID_RE = /^agent-id:[ \t]*([\w-]+)[ \t]*$/m;
55
- const CACHE_TTL_MS = 2500;
56
+ // Спека A2: playbook — canonical-память, Стюард мутирует редко → TTL 5 минут.
57
+ // Негативный кэш (null) живёт тем же TTL — повторный miss не спавнит CLI.
58
+ const CACHE_TTL_MS = 300_000;
59
+
60
+ // agent-id последней рамки, пропущенной через system.transform (для skill-метрики B3)
61
+ let lastAgentId: string | null = null;
56
62
 
57
63
  const run = promisify(execFile);
58
64
  // execFile: args array, no shell. Целевой проект — глобальный `wolf`;
59
65
  // догфуд в репо Wolf — локальный dist. Ошибка обоих → исключение наверх (fail-safe).
60
- // Волна 0 (0.2): свежий WOLF_SESSION на каждый spawn — унаследованный из long-lived
61
- // opencode-процесса env дал бы одну фальшивую сессию на все доставки.
66
+ // WOLF_SESSION (4.C): ключ ставится фабрикой ОДИН раз на процесс opencode —
67
+ // спавны и bash-вызовы волка наследуют его из process.env (execFile без
68
+ // env-поля наследует сам). Известный потолок: несколько чатов одного процесса
69
+ // opencode шарят ключ — консервативная недо-дедупликация, не ошибка.
62
70
  const runWolf = (args: string[]): Promise<{ stdout: string }> => {
63
- const opts = {
64
- cwd: PROJECT_ROOT,
65
- timeout: 5000,
66
- env: { ...process.env, WOLF_SESSION: 'opc-' + randomUUID() },
67
- };
71
+ const opts = { cwd: PROJECT_ROOT, timeout: 5000 };
68
72
  return run('wolf', args, opts).catch(() => run('node', [LOCAL_CLI, ...args], opts));
69
73
  };
70
74
 
@@ -77,7 +81,8 @@ function logRoute(line: string): void {
77
81
  }
78
82
  }
79
83
 
80
- // ponytail: per-agent кэш 2.5с — свежесть между сообщениями, без CLI-спавна на каждый чих.
84
+ // ponytail: per-agent кэш на TTL 5 мин — canonical-память мутируется редко,
85
+ // CLI-спавн не на каждое сообщение.
81
86
  const cache = new Map<string, { value: { id: string; body: string } | null; at: number }>();
82
87
 
83
88
  async function resolvePlaybook(agentId: string): Promise<{ id: string; body: string } | null> {
@@ -87,20 +92,17 @@ async function resolvePlaybook(agentId: string): Promise<{ id: string; body: str
87
92
  try {
88
93
  const { stdout } = await runWolf(['search', agentId, '--type', 'playbook', '--hide-superseded']);
89
94
  const ids = [...stdout.matchAll(/^([\w-]+) \[playbook\]/gm)].map((m) => m[1]);
90
- let best: { id?: string; body?: string } | null = null;
91
- let bestVersion = -1;
95
+ // Ранний стоп (спека A2-б): релевантность поиска уже отсортировала,
96
+ // --hide-superseded отсекает старые версии — первый кандидат, прошедший
97
+ // гвард владельца, и есть результат (один get при miss вместо K подряд).
92
98
  for (const id of ids) {
93
99
  const { stdout: json } = await runWolf(['get', id]);
94
100
  const obj = JSON.parse(json);
95
101
  const owner = obj.owner_skill ?? obj.extra?.owner_skill;
96
102
  if (owner !== agentId && owner !== `skill:${agentId}`) continue; // гвард владельца
97
- const version = Number(String(obj.version ?? '').match(/\d+/)?.[0] ?? 0);
98
- if (version > bestVersion) {
99
- bestVersion = version;
100
- best = obj;
101
- }
103
+ if (obj.body) found = { id: String(obj.id ?? id), body: obj.body };
104
+ break;
102
105
  }
103
- found = best?.body ? { id: String(best.id ?? ''), body: best.body } : null;
104
106
  } catch {
105
107
  /* fail-safe: без playbook — рамка работает через wolf search */
106
108
  }
@@ -108,25 +110,61 @@ async function resolvePlaybook(agentId: string): Promise<{ id: string; body: str
108
110
  return found;
109
111
  }
110
112
 
111
- export const WolfPlaybookPlugin = async () => ({
112
- 'experimental.chat.system.transform': async (_input, output) => {
113
- try {
114
- const joined = output.system.join('\n');
115
- const m = joined.match(AGENT_ID_RE);
116
- if (!m) return; // рамка без маркера — не наша забота
117
- if (joined.includes(INJECT_HEADER)) return; // идемпотентность: не вставляем дважды
118
- const agentId = m[1];
119
- const resolved = await resolvePlaybook(agentId);
120
- if (resolved) {
121
- output.system.push(`\n\n${INJECT_HEADER}\n\n${resolved.body}`);
122
- logRoute(`agent-id=${agentId} playbook=hit name=${resolved.id} variant=canonical injected=yes`);
123
- } else {
124
- // T012: miss канона → универсальный fallback; инъекция для любого agent-id
125
- output.system.push(`\n\n${INJECT_HEADER}\n\n${FALLBACK_PLAYBOOK}`);
126
- logRoute(`agent-id=${agentId} playbook=hit name=fallback variant=fallback injected=yes`);
113
+ export const WolfPlaybookPlugin = async () => {
114
+ // 4.C: один WOLF_SESSION на процесс opencode — спавны волка и bash-вызовы
115
+ // наследуют ключ. Известный потолок: несколько чатов одного процесса
116
+ // opencode шарят ключ — консервативная недо-дедупликация.
117
+ if (!process.env.WOLF_SESSION) process.env.WOLF_SESSION = 'opc-' + randomUUID();
118
+ return {
119
+ 'experimental.chat.system.transform': async (_input, output) => {
120
+ try {
121
+ const joined = output.system.join('\n');
122
+ const m = joined.match(AGENT_ID_RE);
123
+ if (!m) return; // рамка без маркера — не наша забота
124
+ if (joined.includes(INJECT_HEADER)) return; // идемпотентность: не вставляем дважды
125
+ const agentId = m[1];
126
+ lastAgentId = agentId; // агент известен хуку skill-метрики (B3)
127
+ const startedAt = Date.now();
128
+ const resolved = await resolvePlaybook(agentId);
129
+ const ms = Date.now() - startedAt;
130
+ if (resolved) {
131
+ output.system.push(`\n\n${INJECT_HEADER}\n\n${resolved.body}`);
132
+ logRoute(
133
+ `agent-id=${agentId} playbook=hit name=${resolved.id} variant=canonical injected=yes` +
134
+ ` ms=${ms} bytes=${Buffer.byteLength(resolved.body)}`
135
+ );
136
+ } else {
137
+ // T012: miss канона → универсальный fallback; инъекция для любого agent-id
138
+ output.system.push(`\n\n${INJECT_HEADER}\n\n${FALLBACK_PLAYBOOK}`);
139
+ logRoute(
140
+ `agent-id=${agentId} playbook=hit name=fallback variant=fallback injected=yes` +
141
+ ` ms=${ms} bytes=${Buffer.byteLength(FALLBACK_PLAYBOOK)}`
142
+ );
143
+ }
144
+ } catch {
145
+ /* fail-safe: не роняем сессию */
127
146
  }
128
- } catch {
129
- /* fail-safe: не роняем сессию */
130
- }
131
- },
132
- });
147
+ },
148
+ // B3: метрика вызовов скиллов. Форма входа по докам opencode: input.tool —
149
+ // имя тула, output.args — объект аргументов (name | skill — фолбэк).
150
+ // Отдельный JSONL-файл — инвариант: enum событий SignalEventSchema закрытый,
151
+ // в общий router.log эти события класть нельзя. WOLF_SKILL_LOG — тест-шов
152
+ // (читается на каждый вызов: env ставится тестами уже после импорта модуля).
153
+ 'tool.execute.before': async (input: unknown, output: unknown) => {
154
+ try {
155
+ if ((input as { tool?: string } | null)?.tool !== 'skill') return;
156
+ const args = (output as { args?: { name?: string; skill?: string } } | null)?.args;
157
+ const skill = args?.name ?? args?.skill;
158
+ if (!skill) return;
159
+ const file =
160
+ process.env.WOLF_SKILL_LOG ?? path.join(PROJECT_ROOT, '.wolf', 'metrics', 'skill-invocations.jsonl');
161
+ fs.mkdirSync(path.dirname(file), { recursive: true });
162
+ const entry: { ts: string; skill: string; agent?: string } = { ts: new Date().toISOString(), skill };
163
+ if (lastAgentId) entry.agent = lastAgentId;
164
+ fs.appendFileSync(file, `${JSON.stringify(entry)}\n`);
165
+ } catch {
166
+ /* fail-safe: падение метрики не роняет сессию */
167
+ }
168
+ },
169
+ };
170
+ };