promptkaizen-agent 0.3.7 → 0.4.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 (48) hide show
  1. package/dist/analyze/analyzer.d.ts +29 -0
  2. package/dist/analyze/analyzer.d.ts.map +1 -0
  3. package/dist/analyze/analyzer.js +107 -0
  4. package/dist/analyze/analyzer.js.map +1 -0
  5. package/dist/analyze/failure-mode-sender.d.ts +18 -0
  6. package/dist/analyze/failure-mode-sender.d.ts.map +1 -0
  7. package/dist/analyze/failure-mode-sender.js +72 -0
  8. package/dist/analyze/failure-mode-sender.js.map +1 -0
  9. package/dist/analyze/failure-modes.d.ts +36 -0
  10. package/dist/analyze/failure-modes.d.ts.map +1 -0
  11. package/dist/analyze/failure-modes.js +130 -0
  12. package/dist/analyze/failure-modes.js.map +1 -0
  13. package/dist/analyze/index.d.ts +20 -0
  14. package/dist/analyze/index.d.ts.map +1 -0
  15. package/dist/analyze/index.js +107 -0
  16. package/dist/analyze/index.js.map +1 -0
  17. package/dist/analyze/ollama-client.d.ts +33 -0
  18. package/dist/analyze/ollama-client.d.ts.map +1 -0
  19. package/dist/analyze/ollama-client.js +118 -0
  20. package/dist/analyze/ollama-client.js.map +1 -0
  21. package/dist/cli/analyze.d.ts +2 -0
  22. package/dist/cli/analyze.d.ts.map +1 -0
  23. package/dist/cli/analyze.js +66 -0
  24. package/dist/cli/analyze.js.map +1 -0
  25. package/dist/cli/start.d.ts.map +1 -1
  26. package/dist/cli/start.js +17 -2
  27. package/dist/cli/start.js.map +1 -1
  28. package/dist/config.d.ts +58 -0
  29. package/dist/config.d.ts.map +1 -1
  30. package/dist/config.js +43 -0
  31. package/dist/config.js.map +1 -1
  32. package/dist/index.js +4 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/store/local-store.d.ts +74 -0
  35. package/dist/store/local-store.d.ts.map +1 -1
  36. package/dist/store/local-store.js +132 -0
  37. package/dist/store/local-store.js.map +1 -1
  38. package/dist/store/schema.d.ts +25 -1
  39. package/dist/store/schema.d.ts.map +1 -1
  40. package/dist/store/schema.js +45 -2
  41. package/dist/store/schema.js.map +1 -1
  42. package/dist/suppress-sea-warning.d.ts +2 -0
  43. package/dist/suppress-sea-warning.d.ts.map +1 -0
  44. package/dist/suppress-sea-warning.js +21 -0
  45. package/dist/suppress-sea-warning.js.map +1 -0
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ import type { EventRow, LocalStore } from '../store/local-store';
2
+ import { OllamaClient } from './ollama-client';
3
+ export interface AnalyzeOptions {
4
+ maxSessionsPerRun: number;
5
+ minEventsPerSession: number;
6
+ model: string;
7
+ /** 直近 N ms のセッションのみ対象 (既定 14 日)。 */
8
+ sinceMs?: number;
9
+ }
10
+ export interface AnalyzeCycleResult {
11
+ sessionsConsidered: number;
12
+ sessionsAnalyzed: number;
13
+ failuresFound: number;
14
+ skippedAlreadyAnalyzed: number;
15
+ errors: number;
16
+ }
17
+ /**
18
+ * マスク済みイベント列を解析用 transcript に整形する。
19
+ * body は events の不変条件によりマスク済み (生機密を含まない)。
20
+ */
21
+ export declare function renderSessionTranscript(events: EventRow[]): string;
22
+ /** マスク済み transcript の sha256 (dedupe キー。生本文は再構成不能)。 */
23
+ export declare function transcriptHash(transcript: string): string;
24
+ /**
25
+ * 1 解析サイクル: 直近セッションを集めて分類し、失敗モードメタを保存する。
26
+ * 例外は 1 セッション単位で握りつぶし、サイクル全体は止めない (常駐の堅牢性)。
27
+ */
28
+ export declare function runAnalysisCycle(store: LocalStore, client: OllamaClient, opts: AnalyzeOptions): Promise<AnalyzeCycleResult>;
29
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/analyze/analyzer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEhE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAO9C,MAAM,WAAW,cAAc;IAC7B,iBAAiB,EAAE,MAAM,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAWlE;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,kBAAkB,CAAC,CA0D7B"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ // =============================================
3
+ // 失敗モード解析オーケストレータ (Issue #208 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // ローカル SQLite の **マスク済み** イベントをセッション単位で集め、
7
+ // ローカル Ollama に分類させ、失敗モードの構造化メタを保存する。
8
+ //
9
+ // 不変条件:
10
+ // - 入力はマスク済み body のみ (生機密は解析にも回さない)。
11
+ // - 出力は pattern_id/label/severity/confidence/ハッシュのみ (生本文を保持しない)。
12
+ // - 推論先はループバック Ollama のみ (ollama-client が構築時に強制)。
13
+ // - **バックグラウンド専用**。送信経路 (watcher fileChange / hook) からは呼ばない。
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.renderSessionTranscript = renderSessionTranscript;
16
+ exports.transcriptHash = transcriptHash;
17
+ exports.runAnalysisCycle = runAnalysisCycle;
18
+ const crypto_1 = require("crypto");
19
+ const logger_1 = require("../logger");
20
+ const failure_modes_1 = require("./failure-modes");
21
+ /** transcript 1 件あたりの最大文字数 (num_ctx を食い潰さないよう頭打ち)。 */
22
+ const MAX_TRANSCRIPT_CHARS = 6000;
23
+ /** 1 イベント本文の最大文字数 (1 件が長大でも全体が膨らまないように)。 */
24
+ const MAX_EVENT_CHARS = 600;
25
+ /**
26
+ * マスク済みイベント列を解析用 transcript に整形する。
27
+ * body は events の不変条件によりマスク済み (生機密を含まない)。
28
+ */
29
+ function renderSessionTranscript(events) {
30
+ const lines = [];
31
+ for (const e of events) {
32
+ const body = (e.body ?? '').trim();
33
+ if (!body)
34
+ continue;
35
+ const who = e.toolName ? `tool:${e.toolName}` : e.type || e.source;
36
+ const snippet = body.length > MAX_EVENT_CHARS ? `${body.slice(0, MAX_EVENT_CHARS)}…` : body;
37
+ lines.push(`[${who}] ${snippet}`);
38
+ }
39
+ const joined = lines.join('\n');
40
+ return joined.length > MAX_TRANSCRIPT_CHARS ? joined.slice(-MAX_TRANSCRIPT_CHARS) : joined;
41
+ }
42
+ /** マスク済み transcript の sha256 (dedupe キー。生本文は再構成不能)。 */
43
+ function transcriptHash(transcript) {
44
+ return (0, crypto_1.createHash)('sha256').update(transcript).digest('hex');
45
+ }
46
+ /**
47
+ * 1 解析サイクル: 直近セッションを集めて分類し、失敗モードメタを保存する。
48
+ * 例外は 1 セッション単位で握りつぶし、サイクル全体は止めない (常駐の堅牢性)。
49
+ */
50
+ async function runAnalysisCycle(store, client, opts) {
51
+ const result = {
52
+ sessionsConsidered: 0,
53
+ sessionsAnalyzed: 0,
54
+ failuresFound: 0,
55
+ skippedAlreadyAnalyzed: 0,
56
+ errors: 0,
57
+ };
58
+ const sessions = store.recentSessions({
59
+ limit: opts.maxSessionsPerRun,
60
+ minEvents: opts.minEventsPerSession,
61
+ sinceMs: opts.sinceMs ?? 14 * 24 * 3600 * 1000,
62
+ });
63
+ result.sessionsConsidered = sessions.length;
64
+ for (const s of sessions) {
65
+ try {
66
+ const events = store.eventsBySessionAsc(s.sessionId);
67
+ const transcript = renderSessionTranscript(events);
68
+ if (!transcript.trim())
69
+ continue;
70
+ const exampleHash = transcriptHash(transcript);
71
+ // 冪等: 同一セッション×同一内容は再解析しない。
72
+ if (store.hasFailureMode(s.sessionId, exampleHash)) {
73
+ result.skippedAlreadyAnalyzed++;
74
+ continue;
75
+ }
76
+ const out = await client.generate((0, failure_modes_1.buildAnalyzePrompt)(transcript));
77
+ const parsed = (0, failure_modes_1.parseFailureMode)(out.text);
78
+ result.sessionsAnalyzed++;
79
+ if (!parsed) {
80
+ logger_1.logger.warn('analyze: unparseable model output', { sessionId: s.sessionId });
81
+ continue;
82
+ }
83
+ // 'none' (失敗なし) も dedupe のために記録する (= 健全と判定済みの印)。
84
+ const inserted = store.recordFailureMode({
85
+ detectedAt: new Date().toISOString(),
86
+ sessionId: s.sessionId,
87
+ cwd: s.cwd,
88
+ patternId: parsed.patternId,
89
+ label: parsed.label,
90
+ severity: parsed.severity,
91
+ confidence: parsed.confidence,
92
+ signal: parsed.signal,
93
+ exampleHash,
94
+ model: opts.model,
95
+ });
96
+ if (inserted && (0, failure_modes_1.isRealFailure)(parsed.patternId))
97
+ result.failuresFound++;
98
+ }
99
+ catch (e) {
100
+ result.errors++;
101
+ logger_1.logger.warn('analyze: session failed', { sessionId: s.sessionId, error: e.message });
102
+ }
103
+ }
104
+ logger_1.logger.info('analyze cycle complete', { ...result });
105
+ return result;
106
+ }
107
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/analyze/analyzer.ts"],"names":[],"mappings":";AAAA,gDAAgD;AAChD,mDAAmD;AACnD,gDAAgD;AAChD,EAAE;AACF,2CAA2C;AAC3C,sCAAsC;AACtC,EAAE;AACF,QAAQ;AACR,uCAAuC;AACvC,mEAAmE;AACnE,oDAAoD;AACpD,+DAA+D;;AAiC/D,0DAWC;AAGD,wCAEC;AAMD,4CA8DC;AAnHD,mCAAmC;AACnC,sCAAkC;AAElC,mDAAqF;AAGrF,sDAAsD;AACtD,MAAM,oBAAoB,GAAG,IAAI,CAAA;AACjC,4CAA4C;AAC5C,MAAM,eAAe,GAAG,GAAG,CAAA;AAkB3B;;;GAGG;AACH,SAAgB,uBAAuB,CAAC,MAAkB;IACxD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAClC,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAA;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;QAC3F,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC,CAAA;IACnC,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/B,OAAO,MAAM,CAAC,MAAM,GAAG,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;AAC5F,CAAC;AAED,uDAAuD;AACvD,SAAgB,cAAc,CAAC,UAAkB;IAC/C,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC9D,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,gBAAgB,CACpC,KAAiB,EACjB,MAAoB,EACpB,IAAoB;IAEpB,MAAM,MAAM,GAAuB;QACjC,kBAAkB,EAAE,CAAC;QACrB,gBAAgB,EAAE,CAAC;QACnB,aAAa,EAAE,CAAC;QAChB,sBAAsB,EAAE,CAAC;QACzB,MAAM,EAAE,CAAC;KACV,CAAA;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC;QACpC,KAAK,EAAE,IAAI,CAAC,iBAAiB;QAC7B,SAAS,EAAE,IAAI,CAAC,mBAAmB;QACnC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;KAC/C,CAAC,CAAA;IACF,MAAM,CAAC,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAA;IAE3C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YACpD,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAA;YAClD,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE;gBAAE,SAAQ;YAChC,MAAM,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;YAE9C,2BAA2B;YAC3B,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;gBACnD,MAAM,CAAC,sBAAsB,EAAE,CAAA;gBAC/B,SAAQ;YACV,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAA,kCAAkB,EAAC,UAAU,CAAC,CAAC,CAAA;YACjE,MAAM,MAAM,GAAG,IAAA,gCAAgB,EAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACzC,MAAM,CAAC,gBAAgB,EAAE,CAAA;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,eAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAA;gBAC5E,SAAQ;YACV,CAAC;YAED,iDAAiD;YACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,iBAAiB,CAAC;gBACvC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACpC,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,WAAW;gBACX,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAA;YACF,IAAI,QAAQ,IAAI,IAAA,6BAAa,EAAC,MAAM,CAAC,SAAS,CAAC;gBAAE,MAAM,CAAC,aAAa,EAAE,CAAA;QACzE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,MAAM,EAAE,CAAA;YACf,eAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;QACjG,CAAC;IACH,CAAC;IAED,eAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;IACpD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { LocalStore } from '../store/local-store';
2
+ /** receiveObservations と同じ apiKey/endpoint pattern で /receiveFailureModes を導出。 */
3
+ export declare function failureModesUrl(apiEndpoint: string): string;
4
+ export interface FlushFailureModesOptions {
5
+ apiEndpoint: string;
6
+ apiKey: string;
7
+ fetchImpl?: typeof fetch;
8
+ /** 1 回の送信件数上限。 */
9
+ limit?: number;
10
+ }
11
+ /**
12
+ * 未送信の失敗モードメタをクラウドへ送る。成功時は sent=1 を立てる。
13
+ * - 'none' (健全) は送らない (失敗の集計のみ可視化する)。
14
+ * - 送信失敗時は sent を立てず次回再送 (warn のみ、解析は止めない)。
15
+ * 戻り値は送信した件数。
16
+ */
17
+ export declare function flushFailureModes(store: LocalStore, opts: FlushFailureModesOptions): Promise<number>;
18
+ //# sourceMappingURL=failure-mode-sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-mode-sender.d.ts","sourceRoot":"","sources":["../../src/analyze/failure-mode-sender.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAItD,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA4CjB"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // =============================================
3
+ // 失敗モードメタのクラウド送信 (Issue #209 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // オンライン時のみ、ローカル解析 (#208) が抽出した失敗モードの **メタ** を
7
+ // 専用エンドポイント receiveFailureModes に送り、dashboard で集計表示する。
8
+ //
9
+ // 送信ゼロの徹底: 送るのは pattern_id/label/severity/confidence/日付のみ。
10
+ // signal(根拠文)・transcript・プロンプト本文・session_id は **一切送らない**。
11
+ // (dashboard 可視化に必要なのは「どの失敗モードが何件か」だけ)
12
+ // 認証は receiveObservations / getAgentMaskRules と同じ Bearer apiKey。
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.failureModesUrl = failureModesUrl;
15
+ exports.flushFailureModes = flushFailureModes;
16
+ const logger_1 = require("../logger");
17
+ const version_1 = require("../version");
18
+ const failure_modes_1 = require("./failure-modes");
19
+ /** receiveObservations と同じ apiKey/endpoint pattern で /receiveFailureModes を導出。 */
20
+ function failureModesUrl(apiEndpoint) {
21
+ return apiEndpoint.replace(/\/receiveObservations\/?$/, '/receiveFailureModes');
22
+ }
23
+ /**
24
+ * 未送信の失敗モードメタをクラウドへ送る。成功時は sent=1 を立てる。
25
+ * - 'none' (健全) は送らない (失敗の集計のみ可視化する)。
26
+ * - 送信失敗時は sent を立てず次回再送 (warn のみ、解析は止めない)。
27
+ * 戻り値は送信した件数。
28
+ */
29
+ async function flushFailureModes(store, opts) {
30
+ const rows = store.unsentFailureModes(opts.limit ?? 200);
31
+ if (rows.length === 0)
32
+ return 0;
33
+ // 'none' は dedupe 用にローカル記録されるが送信対象外。送らない行も sent=1 にして
34
+ // 再評価のたびに溜まり続けないようにする。
35
+ const sendable = rows.filter((r) => (0, failure_modes_1.isRealFailure)(r.patternId));
36
+ const skipIds = rows.filter((r) => !(0, failure_modes_1.isRealFailure)(r.patternId)).map((r) => r.id);
37
+ if (sendable.length === 0) {
38
+ store.markFailureModesSent(skipIds);
39
+ return 0;
40
+ }
41
+ const doFetch = opts.fetchImpl ?? fetch;
42
+ const payload = {
43
+ apiKey: opts.apiKey,
44
+ agentVersion: version_1.AGENT_VERSION,
45
+ failureModes: sendable.map((r) => ({
46
+ patternId: r.patternId,
47
+ label: r.label,
48
+ severity: r.severity,
49
+ confidence: r.confidence,
50
+ detectedAt: r.detectedAt,
51
+ })),
52
+ };
53
+ try {
54
+ const res = await doFetch(failureModesUrl(opts.apiEndpoint), {
55
+ method: 'POST',
56
+ headers: { 'content-type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },
57
+ body: JSON.stringify(payload),
58
+ });
59
+ if (!res.ok) {
60
+ logger_1.logger.warn('flushFailureModes: non-OK response', { status: res.status });
61
+ return 0;
62
+ }
63
+ store.markFailureModesSent([...sendable.map((r) => r.id), ...skipIds]);
64
+ logger_1.logger.info('failure modes sent', { sent: sendable.length, skipped: skipIds.length });
65
+ return sendable.length;
66
+ }
67
+ catch (e) {
68
+ logger_1.logger.warn('flushFailureModes: send failed (will retry)', { error: e.message });
69
+ return 0;
70
+ }
71
+ }
72
+ //# sourceMappingURL=failure-mode-sender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-mode-sender.js","sourceRoot":"","sources":["../../src/analyze/failure-mode-sender.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export type FailureSeverity = 'low' | 'medium' | 'high';
2
+ export interface FailureModeDef {
3
+ /** 安定した機械可読 ID (出力・集計のキー)。 */
4
+ id: string;
5
+ /** 人間向けラベル (dashboard 表示用)。 */
6
+ label: string;
7
+ /** 既定の重大度 (件数集計時の並び・色分けに使う)。 */
8
+ severity: FailureSeverity;
9
+ /** モデルへ提示する判定の手がかり (1 行)。 */
10
+ hint: string;
11
+ }
12
+ /**
13
+ * 閉じた失敗モード分類。'none' / 'other' は番兵。
14
+ * カテゴリ追加はここに 1 行足すだけ (プロンプトとパーサが自動追従)。
15
+ */
16
+ export declare const FAILURE_MODES: readonly FailureModeDef[];
17
+ /** 番兵 (失敗として記録しない) を除いた「実際の失敗モード」か。 */
18
+ export declare function isRealFailure(id: string): boolean;
19
+ export declare function failureModeDef(id: string): FailureModeDef | undefined;
20
+ export declare const ANALYZE_SYSTEM: string;
21
+ /** 観測ログ (マスク済みテキスト) 1 セッション分から分類プロンプトを組み立てる。 */
22
+ export declare function buildAnalyzePrompt(transcript: string): string;
23
+ export interface ParsedFailureMode {
24
+ patternId: string;
25
+ label: string;
26
+ severity: FailureSeverity;
27
+ confidence: number;
28
+ signal: string;
29
+ }
30
+ /**
31
+ * モデル出力を堅牢にパースする。PoC #207 の所見どおり、2〜3B は出力を ```json
32
+ * フェンスで包んだり前置きを足したりするため、フェンス除去 + 最初の JSON オブジェクト
33
+ * 抽出 + フォールバックで吸収する。妥当な pattern_id が取れなければ null (= スキップ)。
34
+ */
35
+ export declare function parseFailureMode(raw: string): ParsedFailureMode | null;
36
+ //# sourceMappingURL=failure-modes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-modes.d.ts","sourceRoot":"","sources":["../../src/analyze/failure-modes.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,QAAQ,EAAE,eAAe,CAAA;IACzB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,EAQzC,CAAA;AAKV,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAErE;AAED,eAAO,MAAM,cAAc,QAQuD,CAAA;AAElF,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,eAAe,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAWtE"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ // =============================================
3
+ // 失敗モード分類 + プロンプト + 出力パース (Issue #208 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // PoC #207 の結論: ローカル 2〜3B は「明白な失敗モードのトリアージ/タグ付け」は
7
+ // 確実にできるが、多段の論理推論が要る深い根本原因には到達できない。
8
+ // → 本コアは **閉じた分類への振り分け (classification)** にタスクを絞る。
9
+ // 自由文の根本原因生成は当てにしない (2-3B が安定して当てられる範囲に限定)。
10
+ //
11
+ // 分類カテゴリは PoC fixtures (scripts/poc-local-llm/fixtures/cases.mjs) の 5 類型を起点。
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.ANALYZE_SYSTEM = exports.FAILURE_MODES = void 0;
14
+ exports.isRealFailure = isRealFailure;
15
+ exports.failureModeDef = failureModeDef;
16
+ exports.buildAnalyzePrompt = buildAnalyzePrompt;
17
+ exports.parseFailureMode = parseFailureMode;
18
+ /**
19
+ * 閉じた失敗モード分類。'none' / 'other' は番兵。
20
+ * カテゴリ追加はここに 1 行足すだけ (プロンプトとパーサが自動追従)。
21
+ */
22
+ exports.FAILURE_MODES = [
23
+ { id: 'tool_error_loop', label: '同一操作の失敗ループ', severity: 'medium', hint: '同じコマンド/ツールが同じエラーで連続失敗している' },
24
+ { id: 'edit_mismatch', label: 'Edit の不一致ループ', severity: 'low', hint: 'Edit/置換が old_string 不一致などで繰り返し失敗している' },
25
+ { id: 'test_fix_loop', label: 'テスト失敗の修正ループ', severity: 'medium', hint: '同じテストが落ち続け、修正が空回りしている' },
26
+ { id: 'network_abort', label: 'ネットワーク断による中断', severity: 'low', hint: 'ETIMEDOUT/ECONNRESET 等の通信エラーで作業が中断した' },
27
+ { id: 'context_derail', label: 'コンテキスト膨張・脱線', severity: 'medium', hint: '巨大ファイル全読み等でコンテキストが膨張し当初の指示を見失った' },
28
+ { id: 'other', label: 'その他の失敗', severity: 'low', hint: '上記いずれにも当てはまらないが何らかの失敗の兆候がある' },
29
+ { id: 'none', label: '失敗なし', severity: 'low', hint: '明白な失敗モードは見当たらない (健全)' },
30
+ ];
31
+ const BY_ID = new Map(exports.FAILURE_MODES.map((m) => [m.id, m]));
32
+ const VALID_IDS = exports.FAILURE_MODES.map((m) => m.id);
33
+ /** 番兵 (失敗として記録しない) を除いた「実際の失敗モード」か。 */
34
+ function isRealFailure(id) {
35
+ return id !== 'none' && BY_ID.has(id);
36
+ }
37
+ function failureModeDef(id) {
38
+ return BY_ID.get(id);
39
+ }
40
+ exports.ANALYZE_SYSTEM = `あなたはAIコーディング支援ツール(Claude Code / Codex CLI)のセッションログを解析する診断エンジンです。
41
+ 与えられた観測ログ(マスク済み)から、最も当てはまる「失敗モード」を**次の一覧から1つだけ**選んでください。
42
+ 推測を断定で書かず、ログから読み取れる事実だけで判断します。当てはまらなければ none を選びます。
43
+
44
+ 失敗モード一覧 (pattern_id: 説明):
45
+ ${exports.FAILURE_MODES.map((m) => `- ${m.id}: ${m.hint}`).join('\n')}
46
+
47
+ 必ず次のJSONのみを出力してください(コードフェンスや前置き・後置きは禁止):
48
+ {"pattern_id": "上記一覧のidを1つ", "confidence": 0.0〜1.0, "signal": "そう判断した根拠をログから1文で"}`;
49
+ /** 観測ログ (マスク済みテキスト) 1 セッション分から分類プロンプトを組み立てる。 */
50
+ function buildAnalyzePrompt(transcript) {
51
+ return `${exports.ANALYZE_SYSTEM}
52
+
53
+ === 観測ログ ===
54
+ ${transcript}
55
+ === ここまで ===
56
+
57
+ JSON:`;
58
+ }
59
+ /**
60
+ * モデル出力を堅牢にパースする。PoC #207 の所見どおり、2〜3B は出力を ```json
61
+ * フェンスで包んだり前置きを足したりするため、フェンス除去 + 最初の JSON オブジェクト
62
+ * 抽出 + フォールバックで吸収する。妥当な pattern_id が取れなければ null (= スキップ)。
63
+ */
64
+ function parseFailureMode(raw) {
65
+ const obj = extractJsonObject(raw);
66
+ if (!obj)
67
+ return null;
68
+ const id = typeof obj.pattern_id === 'string' ? obj.pattern_id.trim() : '';
69
+ if (!VALID_IDS.includes(id))
70
+ return null;
71
+ const def = BY_ID.get(id);
72
+ let confidence = typeof obj.confidence === 'number' ? obj.confidence : 0.5;
73
+ if (!Number.isFinite(confidence))
74
+ confidence = 0.5;
75
+ confidence = Math.min(1, Math.max(0, confidence));
76
+ const signal = typeof obj.signal === 'string' ? obj.signal.slice(0, 300) : '';
77
+ return { patternId: id, label: def.label, severity: def.severity, confidence, signal };
78
+ }
79
+ /**
80
+ * 文字列から最初の JSON オブジェクトを取り出して parse する。
81
+ * 1) ```json フェンス除去 → 全体 parse
82
+ * 2) 失敗時は最初の `{` 〜 対応する `}` を括弧深度で切り出して parse
83
+ */
84
+ function extractJsonObject(raw) {
85
+ const stripped = raw
86
+ .replace(/```json/gi, '')
87
+ .replace(/```/g, '')
88
+ .trim();
89
+ const direct = tryParse(stripped);
90
+ if (direct)
91
+ return direct;
92
+ const start = stripped.indexOf('{');
93
+ if (start < 0)
94
+ return null;
95
+ let depth = 0;
96
+ let inStr = false;
97
+ let esc = false;
98
+ for (let i = start; i < stripped.length; i++) {
99
+ const ch = stripped[i];
100
+ if (inStr) {
101
+ if (esc)
102
+ esc = false;
103
+ else if (ch === '\\')
104
+ esc = true;
105
+ else if (ch === '"')
106
+ inStr = false;
107
+ continue;
108
+ }
109
+ if (ch === '"')
110
+ inStr = true;
111
+ else if (ch === '{')
112
+ depth++;
113
+ else if (ch === '}') {
114
+ depth--;
115
+ if (depth === 0)
116
+ return tryParse(stripped.slice(start, i + 1));
117
+ }
118
+ }
119
+ return null;
120
+ }
121
+ function tryParse(s) {
122
+ try {
123
+ const v = JSON.parse(s);
124
+ return v && typeof v === 'object' && !Array.isArray(v) ? v : null;
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
130
+ //# sourceMappingURL=failure-modes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-modes.js","sourceRoot":"","sources":["../../src/analyze/failure-modes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type AgentConfig } from '../config';
2
+ import type { LocalStore } from '../store/local-store';
3
+ import { type AnalyzeCycleResult } from './analyzer';
4
+ import { OllamaClient } from './ollama-client';
5
+ export { OllamaClient, assertLoopbackEndpoint } from './ollama-client';
6
+ export { runAnalysisCycle, renderSessionTranscript, transcriptHash } from './analyzer';
7
+ export { flushFailureModes, failureModesUrl } from './failure-mode-sender';
8
+ export * from './failure-modes';
9
+ /** config から OllamaClient を構築する (endpoint はループバック強制)。 */
10
+ export declare function buildClient(config: AgentConfig, fetchImpl?: typeof fetch): OllamaClient;
11
+ /** 1 サイクルだけ走らせる (CLI `analyze` / テスト用)。available 判定込み。 */
12
+ export declare function analyzeOnce(store: LocalStore, config: AgentConfig, client?: OllamaClient): Promise<AnalyzeCycleResult | null>;
13
+ /**
14
+ * バックグラウンド解析スケジューラを起動する。
15
+ * - enabled=false → 即 null (何もしない)。
16
+ * - Ollama 不在 → opt-in 導線を 1 度ログして null (従来動作を維持)。
17
+ * - 利用可能 → 起動直後に 1 サイクル + interval。返り値の Timer は呼び出し側が unref/clear。
18
+ */
19
+ export declare function startAnalysisScheduler(store: LocalStore, config: AgentConfig): Promise<NodeJS.Timeout | null>;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyze/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC1E,cAAc,iBAAiB,CAAA;AAE/B,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,GAAG,YAAY,CAWvF;AAED,0DAA0D;AAC1D,wBAAsB,WAAW,CAC/B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,EACnB,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAQpC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,CAkChC"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ // =============================================
3
+ // ローカルLLM 解析の起動・スケジューリング (Issue #208 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // opt-in (config.analyze.enabled) かつ Ollama 到達可能なときだけ常駐スケジューラを起動する。
7
+ // 未導入 (enabled=false or Ollama 不在) なら何もしない = 従来動作 (回帰なし)。
8
+ // **送信経路からは決して呼ばない**。start.ts のバックグラウンド interval からのみ起動。
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.failureModesUrl = exports.flushFailureModes = exports.transcriptHash = exports.renderSessionTranscript = exports.runAnalysisCycle = exports.assertLoopbackEndpoint = exports.OllamaClient = void 0;
25
+ exports.buildClient = buildClient;
26
+ exports.analyzeOnce = analyzeOnce;
27
+ exports.startAnalysisScheduler = startAnalysisScheduler;
28
+ const config_1 = require("../config");
29
+ const logger_1 = require("../logger");
30
+ const analyzer_1 = require("./analyzer");
31
+ const failure_mode_sender_1 = require("./failure-mode-sender");
32
+ const ollama_client_1 = require("./ollama-client");
33
+ var ollama_client_2 = require("./ollama-client");
34
+ Object.defineProperty(exports, "OllamaClient", { enumerable: true, get: function () { return ollama_client_2.OllamaClient; } });
35
+ Object.defineProperty(exports, "assertLoopbackEndpoint", { enumerable: true, get: function () { return ollama_client_2.assertLoopbackEndpoint; } });
36
+ var analyzer_2 = require("./analyzer");
37
+ Object.defineProperty(exports, "runAnalysisCycle", { enumerable: true, get: function () { return analyzer_2.runAnalysisCycle; } });
38
+ Object.defineProperty(exports, "renderSessionTranscript", { enumerable: true, get: function () { return analyzer_2.renderSessionTranscript; } });
39
+ Object.defineProperty(exports, "transcriptHash", { enumerable: true, get: function () { return analyzer_2.transcriptHash; } });
40
+ var failure_mode_sender_2 = require("./failure-mode-sender");
41
+ Object.defineProperty(exports, "flushFailureModes", { enumerable: true, get: function () { return failure_mode_sender_2.flushFailureModes; } });
42
+ Object.defineProperty(exports, "failureModesUrl", { enumerable: true, get: function () { return failure_mode_sender_2.failureModesUrl; } });
43
+ __exportStar(require("./failure-modes"), exports);
44
+ /** config から OllamaClient を構築する (endpoint はループバック強制)。 */
45
+ function buildClient(config, fetchImpl) {
46
+ const a = config.analyze;
47
+ return new ollama_client_1.OllamaClient({
48
+ endpoint: a.endpoint,
49
+ model: a.model,
50
+ numCtx: a.numCtx,
51
+ numPredict: a.numPredict,
52
+ keepAlive: a.keepAlive,
53
+ requestTimeoutMs: a.requestTimeoutMs,
54
+ fetchImpl,
55
+ });
56
+ }
57
+ /** 1 サイクルだけ走らせる (CLI `analyze` / テスト用)。available 判定込み。 */
58
+ async function analyzeOnce(store, config, client) {
59
+ const c = client ?? buildClient(config);
60
+ if (!(await c.available()))
61
+ return null;
62
+ return (0, analyzer_1.runAnalysisCycle)(store, c, {
63
+ maxSessionsPerRun: config.analyze.maxSessionsPerRun,
64
+ minEventsPerSession: config.analyze.minEventsPerSession,
65
+ model: config.analyze.model,
66
+ });
67
+ }
68
+ /**
69
+ * バックグラウンド解析スケジューラを起動する。
70
+ * - enabled=false → 即 null (何もしない)。
71
+ * - Ollama 不在 → opt-in 導線を 1 度ログして null (従来動作を維持)。
72
+ * - 利用可能 → 起動直後に 1 サイクル + interval。返り値の Timer は呼び出し側が unref/clear。
73
+ */
74
+ async function startAnalysisScheduler(store, config) {
75
+ if (!config.analyze.enabled)
76
+ return null;
77
+ const client = buildClient(config);
78
+ if (!(await client.available())) {
79
+ logger_1.logger.info('local analysis enabled but Ollama/model not reachable — skipping (no regression). ' +
80
+ 'Install the Ollama app and `ollama pull ' +
81
+ config.analyze.model +
82
+ '` to activate.', { endpoint: config.analyze.endpoint, model: config.analyze.model });
83
+ return null;
84
+ }
85
+ logger_1.logger.info('local analysis active', { model: config.analyze.model, intervalMs: config.analyze.intervalMs });
86
+ const opts = {
87
+ maxSessionsPerRun: config.analyze.maxSessionsPerRun,
88
+ minEventsPerSession: config.analyze.minEventsPerSession,
89
+ model: config.analyze.model,
90
+ };
91
+ const tick = async () => {
92
+ try {
93
+ await (0, analyzer_1.runAnalysisCycle)(store, client, opts);
94
+ // オンライン時のみ、失敗モードの**メタ**を dashboard 集計用に送信 (#209)。
95
+ // signal・本文・session_id は送らない (送信ゼロの徹底)。完全ローカル時はスキップ。
96
+ if ((0, config_1.hasCloudToken)(config)) {
97
+ await (0, failure_mode_sender_1.flushFailureModes)(store, { apiEndpoint: config.apiEndpoint, apiKey: config.apiKey });
98
+ }
99
+ }
100
+ catch (e) {
101
+ logger_1.logger.warn('analysis cycle error', { error: e.message });
102
+ }
103
+ };
104
+ void tick(); // 起動直後に 1 回
105
+ return setInterval(() => void tick(), config.analyze.intervalMs);
106
+ }
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyze/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /** ループバック以外のホストを拒否する (解析のための外部送信ゼロを構造的に保証)。 */
2
+ export declare function assertLoopbackEndpoint(endpoint: string): void;
3
+ export interface OllamaGenerateResult {
4
+ text: string;
5
+ loadMs: number | null;
6
+ totalMs: number | null;
7
+ evalCount: number | null;
8
+ }
9
+ export interface OllamaClientOptions {
10
+ endpoint: string;
11
+ model: string;
12
+ numCtx: number;
13
+ numPredict: number;
14
+ keepAlive: string;
15
+ requestTimeoutMs: number;
16
+ /** テスト用の fetch 差し替え。 */
17
+ fetchImpl?: typeof fetch;
18
+ }
19
+ export declare class OllamaClient {
20
+ private readonly opts;
21
+ private readonly fetchImpl;
22
+ constructor(opts: OllamaClientOptions);
23
+ /**
24
+ * Ollama が起動していて選定モデルが存在するか。opt-in のプリフライト判定に使う。
25
+ * 到達不可・モデル未導入なら false (= 解析を無効化して従来動作にフォールバック)。
26
+ */
27
+ available(): Promise<boolean>;
28
+ /** 1 プロンプトを生成する。失敗時は例外を投げる (呼び出し側でそのセッションをスキップ)。 */
29
+ generate(prompt: string): Promise<OllamaGenerateResult>;
30
+ private base;
31
+ private withTimeout;
32
+ }
33
+ //# sourceMappingURL=ollama-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-client.d.ts","sourceRoot":"","sources":["../../src/analyze/ollama-client.ts"],"names":[],"mappings":"AAYA,+CAA+C;AAC/C,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAe7D;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAKD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;gBAE5B,IAAI,EAAE,mBAAmB;IAMrC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBnC,oDAAoD;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAgC7D,OAAO,CAAC,IAAI;YAIE,WAAW;CAc1B"}