promptkaizen-agent 0.3.7 → 0.5.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 (67) 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 +22 -0
  14. package/dist/analyze/index.d.ts.map +1 -0
  15. package/dist/analyze/index.js +128 -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/analyze/optimize-rules-fetcher.d.ts +53 -0
  22. package/dist/analyze/optimize-rules-fetcher.d.ts.map +1 -0
  23. package/dist/analyze/optimize-rules-fetcher.js +118 -0
  24. package/dist/analyze/optimize-rules-fetcher.js.map +1 -0
  25. package/dist/analyze/optimize-rules.d.ts +33 -0
  26. package/dist/analyze/optimize-rules.d.ts.map +1 -0
  27. package/dist/analyze/optimize-rules.js +105 -0
  28. package/dist/analyze/optimize-rules.js.map +1 -0
  29. package/dist/cli/analyze.d.ts +2 -0
  30. package/dist/cli/analyze.d.ts.map +1 -0
  31. package/dist/cli/analyze.js +66 -0
  32. package/dist/cli/analyze.js.map +1 -0
  33. package/dist/cli/hook.d.ts.map +1 -1
  34. package/dist/cli/hook.js +27 -1
  35. package/dist/cli/hook.js.map +1 -1
  36. package/dist/cli/start.d.ts.map +1 -1
  37. package/dist/cli/start.js +34 -2
  38. package/dist/cli/start.js.map +1 -1
  39. package/dist/config.d.ts +68 -0
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +51 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/hooks/optimize-hints.d.ts +24 -0
  44. package/dist/hooks/optimize-hints.d.ts.map +1 -0
  45. package/dist/hooks/optimize-hints.js +56 -0
  46. package/dist/hooks/optimize-hints.js.map +1 -0
  47. package/dist/index.js +4 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/optimize-rules-cache.d.ts +7 -0
  50. package/dist/optimize-rules-cache.d.ts.map +1 -0
  51. package/dist/optimize-rules-cache.js +45 -0
  52. package/dist/optimize-rules-cache.js.map +1 -0
  53. package/dist/store/local-store.d.ts +74 -0
  54. package/dist/store/local-store.d.ts.map +1 -1
  55. package/dist/store/local-store.js +132 -0
  56. package/dist/store/local-store.js.map +1 -1
  57. package/dist/store/schema.d.ts +25 -1
  58. package/dist/store/schema.d.ts.map +1 -1
  59. package/dist/store/schema.js +45 -2
  60. package/dist/store/schema.js.map +1 -1
  61. package/dist/suppress-sea-warning.d.ts +2 -0
  62. package/dist/suppress-sea-warning.d.ts.map +1 -0
  63. package/dist/suppress-sea-warning.js +21 -0
  64. package/dist/suppress-sea-warning.js.map +1 -0
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/package.json +1 -1
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ // =============================================
3
+ // Ollama クライアント (Issue #208 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // PoC #207 で選定したランタイム。常駐ロード済みの Ollama (gemma2:2b) に
7
+ // HTTP で投げる薄いアダプタ。**送信ゼロの不変条件を守るため、エンドポイントは
8
+ // ループバック (127.0.0.1 / localhost / ::1) のみ許可**する。外部ホストは構築時に弾く。
9
+ //
10
+ // 依存ゼロ (Node 20+ built-in fetch / AbortController を使用)。
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OllamaClient = void 0;
13
+ exports.assertLoopbackEndpoint = assertLoopbackEndpoint;
14
+ const logger_1 = require("../logger");
15
+ /** ループバック以外のホストを拒否する (解析のための外部送信ゼロを構造的に保証)。 */
16
+ function assertLoopbackEndpoint(endpoint) {
17
+ let host;
18
+ try {
19
+ host = new URL(endpoint).hostname;
20
+ }
21
+ catch {
22
+ throw new Error(`analyze.endpoint is not a valid URL: ${endpoint}`);
23
+ }
24
+ const h = host.replace(/^\[|\]$/g, '').toLowerCase();
25
+ const loopback = h === '127.0.0.1' || h === 'localhost' || h === '::1' || h.startsWith('127.');
26
+ if (!loopback) {
27
+ throw new Error(`analyze.endpoint must be loopback (127.0.0.1/localhost/::1) — got "${host}". ` +
28
+ 'Local analysis must never send prompts off the machine.');
29
+ }
30
+ }
31
+ const ns2ms = (ns) => typeof ns === 'number' && Number.isFinite(ns) ? Math.round(ns / 1e6) : null;
32
+ class OllamaClient {
33
+ opts;
34
+ fetchImpl;
35
+ constructor(opts) {
36
+ assertLoopbackEndpoint(opts.endpoint);
37
+ this.opts = opts;
38
+ this.fetchImpl = opts.fetchImpl ?? fetch;
39
+ }
40
+ /**
41
+ * Ollama が起動していて選定モデルが存在するか。opt-in のプリフライト判定に使う。
42
+ * 到達不可・モデル未導入なら false (= 解析を無効化して従来動作にフォールバック)。
43
+ */
44
+ async available() {
45
+ try {
46
+ const res = await this.withTimeout((signal) => this.fetchImpl(`${this.base()}/api/tags`, { signal }));
47
+ if (!res.ok)
48
+ return false;
49
+ const json = (await res.json());
50
+ const names = (json.models ?? []).map((m) => m.name ?? '');
51
+ // "gemma2:2b" 完全一致、または "gemma2:2b-..." のような派生タグも許容。
52
+ const want = this.opts.model;
53
+ return names.some((n) => n === want || n.startsWith(`${want}-`) || n.split(':')[0] === want.split(':')[0]);
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ /** 1 プロンプトを生成する。失敗時は例外を投げる (呼び出し側でそのセッションをスキップ)。 */
60
+ async generate(prompt) {
61
+ const body = {
62
+ model: this.opts.model,
63
+ prompt,
64
+ stream: false,
65
+ keep_alive: this.opts.keepAlive,
66
+ options: {
67
+ temperature: 0,
68
+ num_ctx: this.opts.numCtx,
69
+ num_predict: this.opts.numPredict,
70
+ },
71
+ };
72
+ const res = await this.withTimeout((signal) => this.fetchImpl(`${this.base()}/api/generate`, {
73
+ method: 'POST',
74
+ headers: { 'content-type': 'application/json' },
75
+ body: JSON.stringify(body),
76
+ signal,
77
+ }));
78
+ if (!res.ok) {
79
+ throw new Error(`Ollama generate HTTP ${res.status}: ${await safeText(res)}`);
80
+ }
81
+ const json = (await res.json());
82
+ return {
83
+ text: typeof json.response === 'string' ? json.response.trim() : '',
84
+ loadMs: ns2ms(json.load_duration),
85
+ totalMs: ns2ms(json.total_duration),
86
+ evalCount: typeof json.eval_count === 'number' ? json.eval_count : null,
87
+ };
88
+ }
89
+ base() {
90
+ return this.opts.endpoint.replace(/\/$/, '');
91
+ }
92
+ async withTimeout(fn) {
93
+ const ctrl = new AbortController();
94
+ const t = setTimeout(() => ctrl.abort(), this.opts.requestTimeoutMs);
95
+ try {
96
+ return await fn(ctrl.signal);
97
+ }
98
+ catch (e) {
99
+ if (e.name === 'AbortError') {
100
+ logger_1.logger.warn('Ollama request timed out', { timeoutMs: this.opts.requestTimeoutMs });
101
+ }
102
+ throw e;
103
+ }
104
+ finally {
105
+ clearTimeout(t);
106
+ }
107
+ }
108
+ }
109
+ exports.OllamaClient = OllamaClient;
110
+ async function safeText(res) {
111
+ try {
112
+ return (await res.text()).slice(0, 200);
113
+ }
114
+ catch {
115
+ return '';
116
+ }
117
+ }
118
+ //# sourceMappingURL=ollama-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-client.js","sourceRoot":"","sources":["../../src/analyze/ollama-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ import type { CandidateRule } from './optimize-rules';
3
+ export declare function optimizeRulesUrl(apiEndpoint: string): string;
4
+ export declare function candidatesUrl(apiEndpoint: string): string;
5
+ export declare function optimizeStatsUrl(apiEndpoint: string): string;
6
+ /**
7
+ * 送信時にヒントが発火したヒット (ruleId/sessionId) を効果計測 (#216) に送る。
8
+ * メタのみ (本文を含まない)。失敗は握りつぶす (計測は best-effort)。
9
+ */
10
+ export declare function sendOptimizeStats(hits: Array<{
11
+ ruleId: string;
12
+ sessionId?: string | null;
13
+ }>, opts: OptimizeRulesIO): Promise<number>;
14
+ declare const OptimizeRuleSchema: z.ZodObject<{
15
+ ruleId: z.ZodString;
16
+ pattern: z.ZodString;
17
+ hint: z.ZodString;
18
+ enabled: z.ZodBoolean;
19
+ source: z.ZodEnum<["local_llm", "manual"]>;
20
+ patternId: z.ZodOptional<z.ZodString>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ enabled: boolean;
23
+ pattern: string;
24
+ ruleId: string;
25
+ source: "local_llm" | "manual";
26
+ hint: string;
27
+ patternId?: string | undefined;
28
+ }, {
29
+ enabled: boolean;
30
+ pattern: string;
31
+ ruleId: string;
32
+ source: "local_llm" | "manual";
33
+ hint: string;
34
+ patternId?: string | undefined;
35
+ }>;
36
+ export type FetchedOptimizeRule = z.infer<typeof OptimizeRuleSchema>;
37
+ export interface OptimizeRulesIO {
38
+ apiEndpoint: string;
39
+ apiKey: string;
40
+ fetchImpl?: typeof fetch;
41
+ }
42
+ /**
43
+ * cloud から enabled な OptimizeRule を取得する。
44
+ * 未設定・通信エラー・不正レスポンスは null (送信時はルール無しで動作 = 回帰なし)。
45
+ */
46
+ export declare function fetchOptimizeRules(opts: OptimizeRulesIO): Promise<FetchedOptimizeRule[] | null>;
47
+ /**
48
+ * ローカル生成した候補を cloud に送る。pattern/hint のみ (本文を含まない)。
49
+ * 戻り値は送信した候補数 (0 = 送信なし or 失敗)。
50
+ */
51
+ export declare function sendOptimizeRuleCandidates(candidates: CandidateRule[], opts: OptimizeRulesIO): Promise<number>;
52
+ export {};
53
+ //# sourceMappingURL=optimize-rules-fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimize-rules-fetcher.d.ts","sourceRoot":"","sources":["../../src/analyze/optimize-rules-fetcher.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AACD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AACD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,EAC1D,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAajB;AAGD,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;EAOtB,CAAA;AAYF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEpE,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,EAAE,GAAG,IAAI,CAAC,CAkBrG;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,aAAa,EAAE,EAC3B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ // =============================================
3
+ // 最適化ルールの取得・候補送信 (Issue #214 / Epic #206 Phase 2)
4
+ // =============================================
5
+ //
6
+ // - fetchOptimizeRules: cloud から enabled な OptimizeRule を取得 (送信時適用 #215 が消費)。
7
+ // - sendOptimizeRuleCandidates: ローカル生成した候補を cloud に送る (dashboard レビュー用)。
8
+ // 認証は getAgentMaskRules / receiveObservations と同じ Bearer apiKey。
9
+ // 候補送信は pattern/hint のみ (生プロンプト本文は含まない)。
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.optimizeRulesUrl = optimizeRulesUrl;
12
+ exports.candidatesUrl = candidatesUrl;
13
+ exports.optimizeStatsUrl = optimizeStatsUrl;
14
+ exports.sendOptimizeStats = sendOptimizeStats;
15
+ exports.fetchOptimizeRules = fetchOptimizeRules;
16
+ exports.sendOptimizeRuleCandidates = sendOptimizeRuleCandidates;
17
+ const zod_1 = require("zod");
18
+ const logger_1 = require("../logger");
19
+ const version_1 = require("../version");
20
+ function optimizeRulesUrl(apiEndpoint) {
21
+ return apiEndpoint.replace(/\/receiveObservations\/?$/, '/getOptimizeRules');
22
+ }
23
+ function candidatesUrl(apiEndpoint) {
24
+ return apiEndpoint.replace(/\/receiveObservations\/?$/, '/receiveOptimizeRuleCandidates');
25
+ }
26
+ function optimizeStatsUrl(apiEndpoint) {
27
+ return apiEndpoint.replace(/\/receiveObservations\/?$/, '/receiveOptimizeStats');
28
+ }
29
+ /**
30
+ * 送信時にヒントが発火したヒット (ruleId/sessionId) を効果計測 (#216) に送る。
31
+ * メタのみ (本文を含まない)。失敗は握りつぶす (計測は best-effort)。
32
+ */
33
+ async function sendOptimizeStats(hits, opts) {
34
+ if (hits.length === 0)
35
+ return 0;
36
+ const doFetch = opts.fetchImpl ?? fetch;
37
+ try {
38
+ const res = await doFetch(optimizeStatsUrl(opts.apiEndpoint), {
39
+ method: 'POST',
40
+ headers: { 'content-type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },
41
+ body: JSON.stringify({ agentVersion: version_1.AGENT_VERSION, hits }),
42
+ });
43
+ return res.ok ? hits.length : 0;
44
+ }
45
+ catch {
46
+ return 0;
47
+ }
48
+ }
49
+ // cloud 側 (functions/src/agent/optimizeRulesConfig.ts) の schema と整合させること。
50
+ const OptimizeRuleSchema = zod_1.z.object({
51
+ ruleId: zod_1.z.string(),
52
+ pattern: zod_1.z.string(),
53
+ hint: zod_1.z.string(),
54
+ enabled: zod_1.z.boolean(),
55
+ source: zod_1.z.enum(['local_llm', 'manual']),
56
+ patternId: zod_1.z.string().optional(),
57
+ });
58
+ const GetResponseSchema = zod_1.z.object({
59
+ success: zod_1.z.boolean(),
60
+ rules: zod_1.z
61
+ .object({
62
+ rules: zod_1.z.array(OptimizeRuleSchema),
63
+ updatedAt: zod_1.z.number().optional(),
64
+ })
65
+ .nullable(),
66
+ });
67
+ /**
68
+ * cloud から enabled な OptimizeRule を取得する。
69
+ * 未設定・通信エラー・不正レスポンスは null (送信時はルール無しで動作 = 回帰なし)。
70
+ */
71
+ async function fetchOptimizeRules(opts) {
72
+ const doFetch = opts.fetchImpl ?? fetch;
73
+ try {
74
+ const res = await doFetch(optimizeRulesUrl(opts.apiEndpoint), {
75
+ method: 'GET',
76
+ headers: { Authorization: `Bearer ${opts.apiKey}` },
77
+ });
78
+ if (!res.ok) {
79
+ logger_1.logger.warn('fetchOptimizeRules: non-OK response', { status: res.status });
80
+ return null;
81
+ }
82
+ const parsed = GetResponseSchema.safeParse(await res.json());
83
+ if (!parsed.success || !parsed.data.rules)
84
+ return null;
85
+ return parsed.data.rules.rules;
86
+ }
87
+ catch (e) {
88
+ logger_1.logger.warn('fetchOptimizeRules: failed', { error: e.message });
89
+ return null;
90
+ }
91
+ }
92
+ /**
93
+ * ローカル生成した候補を cloud に送る。pattern/hint のみ (本文を含まない)。
94
+ * 戻り値は送信した候補数 (0 = 送信なし or 失敗)。
95
+ */
96
+ async function sendOptimizeRuleCandidates(candidates, opts) {
97
+ if (candidates.length === 0)
98
+ return 0;
99
+ const doFetch = opts.fetchImpl ?? fetch;
100
+ try {
101
+ const res = await doFetch(candidatesUrl(opts.apiEndpoint), {
102
+ method: 'POST',
103
+ headers: { 'content-type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },
104
+ body: JSON.stringify({ agentVersion: version_1.AGENT_VERSION, candidates }),
105
+ });
106
+ if (!res.ok) {
107
+ logger_1.logger.warn('sendOptimizeRuleCandidates: non-OK response', { status: res.status });
108
+ return 0;
109
+ }
110
+ logger_1.logger.info('optimize rule candidates sent', { count: candidates.length });
111
+ return candidates.length;
112
+ }
113
+ catch (e) {
114
+ logger_1.logger.warn('sendOptimizeRuleCandidates: failed', { error: e.message });
115
+ return 0;
116
+ }
117
+ }
118
+ //# sourceMappingURL=optimize-rules-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimize-rules-fetcher.js","sourceRoot":"","sources":["../../src/analyze/optimize-rules-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { LocalStore } from '../store/local-store';
2
+ import { OllamaClient } from './ollama-client';
3
+ export interface CandidateRule {
4
+ ruleId: string;
5
+ pattern: string;
6
+ hint: string;
7
+ patternId: string;
8
+ }
9
+ /**
10
+ * 失敗モード分類ごとの curated テンプレート。
11
+ * pattern = 送信時にユーザープロンプトへローカル照合する正規表現 (#215 が消費)。
12
+ * defaultHint = LLM 生成に失敗した時のフォールバック文。
13
+ * テンプレートが無い分類 (network_abort 等の環境要因) は候補化しない。
14
+ */
15
+ export declare const RULE_TEMPLATES: Record<string, {
16
+ pattern: string;
17
+ defaultHint: string;
18
+ }>;
19
+ export interface GenerateOptions {
20
+ /** この件数以上検出された失敗モードのみ候補化する。 */
21
+ minCount: number;
22
+ /** 直近 N ms の集計を対象 (既定 30 日)。 */
23
+ sinceMs?: number;
24
+ }
25
+ /**
26
+ * 失敗モード集計から候補ルールを生成する。
27
+ * - テンプレートがある分類のうち minCount 以上のものを候補化。
28
+ * - hint はローカルLLM で生成し、失敗時は defaultHint。
29
+ */
30
+ export declare function generateCandidates(store: LocalStore, client: OllamaClient, opts: GenerateOptions): Promise<CandidateRule[]>;
31
+ /** LLM 出力から hint を堅牢に取り出す (フェンス/前置き吸収・長さ制限)。 */
32
+ export declare function parseHint(raw: string): string | null;
33
+ //# sourceMappingURL=optimize-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimize-rules.d.ts","sourceRoot":"","sources":["../../src/analyze/optimize-rules.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqBnF,CAAA;AAID,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CA6B1B;AAED,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAepD"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ // =============================================
3
+ // 最適化ルール (OptimizeRule) のローカル生成 (Issue #214 / Epic #206 Phase 2)
4
+ // =============================================
5
+ //
6
+ // 失敗モード集計 (#208 failure_modes) から OptimizeRule の **候補** を生成する。
7
+ // 候補は cloud (receiveOptimizeRuleCandidates) に送られ、dashboard でレビュー→承認して
8
+ // 初めて正式ルール化される (自動有効化しない = 誤適用ガード)。
9
+ //
10
+ // PoC #207 の所見: 2-3B は自由文(hint)は書けるが、正規表現(pattern)の自動生成は不安定。
11
+ // → **pattern は patternId 別の curated テンプレート (安全・決定的)**、
12
+ // **hint はローカルLLM が生成 (失敗時は既定文へフォールバック)** の役割分担にする。
13
+ // 完全ローカル・送信ゼロ (推論はループバック Ollama のみ)。
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.RULE_TEMPLATES = void 0;
16
+ exports.generateCandidates = generateCandidates;
17
+ exports.parseHint = parseHint;
18
+ const logger_1 = require("../logger");
19
+ const failure_modes_1 = require("./failure-modes");
20
+ /**
21
+ * 失敗モード分類ごとの curated テンプレート。
22
+ * pattern = 送信時にユーザープロンプトへローカル照合する正規表現 (#215 が消費)。
23
+ * defaultHint = LLM 生成に失敗した時のフォールバック文。
24
+ * テンプレートが無い分類 (network_abort 等の環境要因) は候補化しない。
25
+ */
26
+ exports.RULE_TEMPLATES = {
27
+ tool_error_loop: {
28
+ // 同じ操作を「もう一度」「再度」と繰り返す兆候。
29
+ pattern: '(もう一度|再度|again|retry|もう一回)',
30
+ defaultHint: '同じ操作で詰まったら、前提・権限・手順を一度見直すと往復が減ります。',
31
+ },
32
+ edit_mismatch: {
33
+ // ファイル編集・置換の依頼。
34
+ pattern: '(編集|置換|書き換え|edit|replace|修正して)',
35
+ defaultHint: '編集対象は直前に読み直し、正確な箇所を指定すると空振りが減ります。',
36
+ },
37
+ test_fix_loop: {
38
+ // テスト関連の依頼。
39
+ pattern: '(テスト|test|spec|失敗|fail)',
40
+ defaultHint: 'テストが落ち続ける時は、テストではなく実装側の前提を疑うと抜けやすいです。',
41
+ },
42
+ context_derail: {
43
+ // 大きいファイル・全体読み込みの依頼。
44
+ pattern: '(全部|すべて|全体|lock|ログ全|まるごと)',
45
+ defaultHint: '大きいファイルは必要箇所だけ参照すると、コンテキストが膨らまず安定します。',
46
+ },
47
+ };
48
+ const HINT_SYSTEM = `あなたはAIコーディングのコーチです。次の「失敗モード」に対し、ユーザーが次回詰まらないための短い助言を1文(40〜80文字・日本語・前向き・命令形を避ける)で書いてください。JSONのみ出力: {"hint": "助言"}`;
49
+ /**
50
+ * 失敗モード集計から候補ルールを生成する。
51
+ * - テンプレートがある分類のうち minCount 以上のものを候補化。
52
+ * - hint はローカルLLM で生成し、失敗時は defaultHint。
53
+ */
54
+ async function generateCandidates(store, client, opts) {
55
+ const summary = store.failureModeSummary({ sinceMs: opts.sinceMs ?? 30 * 24 * 3600 * 1000 });
56
+ const candidates = [];
57
+ for (const row of summary) {
58
+ if (!(0, failure_modes_1.isRealFailure)(row.patternId))
59
+ continue;
60
+ const tmpl = exports.RULE_TEMPLATES[row.patternId];
61
+ if (!tmpl)
62
+ continue;
63
+ if (row.count < opts.minCount)
64
+ continue;
65
+ let hint = tmpl.defaultHint;
66
+ try {
67
+ const out = await client.generate(`${HINT_SYSTEM}\n\n失敗モード: ${row.label}\nJSON:`);
68
+ const parsedHint = parseHint(out.text);
69
+ if (parsedHint)
70
+ hint = parsedHint;
71
+ }
72
+ catch (e) {
73
+ logger_1.logger.warn('generateCandidates: hint generation failed (using default)', {
74
+ patternId: row.patternId,
75
+ error: e.message,
76
+ });
77
+ }
78
+ candidates.push({
79
+ ruleId: `opt_${row.patternId}`,
80
+ pattern: tmpl.pattern,
81
+ hint,
82
+ patternId: row.patternId,
83
+ });
84
+ }
85
+ return candidates;
86
+ }
87
+ /** LLM 出力から hint を堅牢に取り出す (フェンス/前置き吸収・長さ制限)。 */
88
+ function parseHint(raw) {
89
+ const stripped = raw.replace(/```json/gi, '').replace(/```/g, '').trim();
90
+ const start = stripped.indexOf('{');
91
+ const end = stripped.lastIndexOf('}');
92
+ if (start >= 0 && end > start) {
93
+ try {
94
+ const obj = JSON.parse(stripped.slice(start, end + 1));
95
+ if (obj && typeof obj.hint === 'string' && obj.hint.trim()) {
96
+ return obj.hint.trim().slice(0, 300);
97
+ }
98
+ }
99
+ catch {
100
+ /* fall through */
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+ //# sourceMappingURL=optimize-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimize-rules.js","sourceRoot":"","sources":["../../src/analyze/optimize-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runAnalyze(argv: string[]): Promise<void>;
2
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/cli/analyze.ts"],"names":[],"mappings":"AAYA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD9D"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ // =============================================
3
+ // `promptkaizen-agent analyze` (Issue #208 / Epic #206 Phase 1)
4
+ // =============================================
5
+ //
6
+ // ローカル SQLite のマスク済み観測を 1 回だけ解析し、失敗モードの集計を表示する。
7
+ // 常駐の interval を待たずに動作確認・デモ・dashboard 連携の確認に使う。
8
+ // 完全ローカル: ループバック Ollama のみ・送信ゼロ。
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.runAnalyze = runAnalyze;
11
+ const analyze_1 = require("../analyze");
12
+ const config_1 = require("../config");
13
+ const local_store_1 = require("../store/local-store");
14
+ async function runAnalyze(argv) {
15
+ const json = argv.includes('--json');
16
+ const configPathArg = readArg(argv, '--config');
17
+ const config = await (0, config_1.loadConfig)(configPathArg);
18
+ const store = (0, local_store_1.openLocalStore)(config.localStore.path);
19
+ if (!store) {
20
+ fail(json, 'local store unavailable (better-sqlite3 native module missing). Analysis needs the local DB.');
21
+ return;
22
+ }
23
+ if (!config.analyze.enabled) {
24
+ fail(json, 'analysis is opt-in and currently disabled. Set analyze.enabled=true in ~/.promptkaizen/agent.config.json.');
25
+ store.close();
26
+ return;
27
+ }
28
+ const result = await (0, analyze_1.analyzeOnce)(store, config);
29
+ if (result === null) {
30
+ fail(json, `Ollama not reachable at ${config.analyze.endpoint} (model ${config.analyze.model}). ` +
31
+ `Install the Ollama app and run: ollama pull ${config.analyze.model}`);
32
+ store.close();
33
+ return;
34
+ }
35
+ const summary = store.failureModeSummary({ sinceMs: 30 * 24 * 3600 * 1000 });
36
+ store.close();
37
+ if (json) {
38
+ process.stdout.write(JSON.stringify({ cycle: result, summary }, null, 2) + '\n');
39
+ return;
40
+ }
41
+ console.log(`解析完了 — 対象 ${result.sessionsConsidered} / 解析 ${result.sessionsAnalyzed} セッション` +
42
+ ` (既解析スキップ ${result.skippedAlreadyAnalyzed} / エラー ${result.errors})`);
43
+ if (summary.length === 0) {
44
+ console.log('失敗モードの記録はまだありません。');
45
+ return;
46
+ }
47
+ console.log('\n失敗モード集計 (直近30日):');
48
+ const sev = { high: '🔴', medium: '🟡', low: '🟢' };
49
+ for (const r of summary) {
50
+ console.log(` ${sev[r.severity] ?? '·'} ${r.label} (${r.patternId}) — ${r.count} 件`);
51
+ }
52
+ }
53
+ function fail(json, message) {
54
+ if (json)
55
+ process.stdout.write(JSON.stringify({ error: message }) + '\n');
56
+ else
57
+ console.error(message);
58
+ process.exitCode = 1;
59
+ }
60
+ function readArg(argv, name) {
61
+ const idx = argv.indexOf(name);
62
+ if (idx >= 0 && idx + 1 < argv.length)
63
+ return argv[idx + 1];
64
+ return undefined;
65
+ }
66
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/cli/analyze.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/cli/hook.ts"],"names":[],"mappings":"AA6CA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqH3D"}
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/cli/hook.ts"],"names":[],"mappings":"AAgDA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+I3D"}
package/dist/cli/hook.js CHANGED
@@ -13,6 +13,9 @@ const block_store_1 = require("../hooks/block-store");
13
13
  const claude_hook_1 = require("../hooks/claude-hook");
14
14
  const platforms_1 = require("../hooks/platforms");
15
15
  const continuity_1 = require("../hooks/continuity");
16
+ const optimize_hints_1 = require("../hooks/optimize-hints");
17
+ const optimize_rules_fetcher_1 = require("../analyze/optimize-rules-fetcher");
18
+ const optimize_rules_cache_1 = require("../optimize-rules-cache");
16
19
  const observation_1 = require("../hooks/observation");
17
20
  const reduction_1 = require("../hooks/reduction");
18
21
  const read_cache_1 = require("../hooks/read-cache");
@@ -105,6 +108,28 @@ async function runHook(argv) {
105
108
  additionalContext = null;
106
109
  }
107
110
  }
111
+ // 2.5. 送信時の最適化ヒント付加 (#215)。配信済み OptimizeRule をローカル照合し、
112
+ // ヒット時に additionalContext でヒントを**付加** (置換しない)。
113
+ // ⚠️ **ローカルLLMは呼ばない**。ローカルキャッシュ (file) を同期 read + 正規表現照合のみ
114
+ // = 数ms・ネットワークなし (30 秒制約を踏まない)。Claude Code 限定。
115
+ if (event === 'UserPromptSubmit' && platform === 'claude-code') {
116
+ try {
117
+ const prompt = (0, observation_1.hookPromptText)(event, input);
118
+ if (prompt) {
119
+ const rules = (0, optimize_rules_cache_1.loadOptimizeRulesCache)();
120
+ const hits = (0, optimize_hints_1.matchOptimizeHints)(prompt, rules);
121
+ additionalContext = (0, optimize_hints_1.buildHintText)(hits);
122
+ // 効果計測 (#216): 発火したヒットのメタ (ruleId/session) を送る。online のみ・best-effort。
123
+ if (hits.length > 0 && (0, config_1.hasCloudToken)(config)) {
124
+ const sessionId = typeof input.session_id === 'string' ? input.session_id : null;
125
+ await (0, optimize_rules_fetcher_1.sendOptimizeStats)(hits.map((h) => ({ ruleId: h.ruleId, sessionId })), { apiEndpoint: config.apiEndpoint, apiKey: config.apiKey }).catch(() => undefined);
126
+ }
127
+ }
128
+ }
129
+ catch {
130
+ additionalContext = null; // 照合失敗は無介入 (送信を壊さない)
131
+ }
132
+ }
108
133
  // 3. PostToolUse / UserPromptSubmit: 受信→マスク (buildEntry 内) → ローカル保存 → 送信。
109
134
  const entry = buildEntry(platform, event, input, config, detector);
110
135
  if (entry) {
@@ -138,7 +163,8 @@ async function runHook(argv) {
138
163
  }
139
164
  // 4. 退避/キャッシュ/連続Read誘導が成立した場合のみ stdout で返す。
140
165
  if (updatedToolOutput !== null || additionalContext !== null) {
141
- const hookSpecificOutput = { hookEventName: 'PostToolUse' };
166
+ // hookEventName は実イベントに合わせる (UserPromptSubmit のヒント付加も正しく届ける)。
167
+ const hookSpecificOutput = { hookEventName: event };
142
168
  if (updatedToolOutput !== null)
143
169
  hookSpecificOutput.updatedToolOutput = updatedToolOutput;
144
170
  if (additionalContext !== null)