@hopping-dev/hub 0.1.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 (165) hide show
  1. package/assets/hopping-skill/SKILL.md +221 -0
  2. package/dist/approval/manager.d.ts +60 -0
  3. package/dist/approval/manager.d.ts.map +1 -0
  4. package/dist/approval/manager.js +101 -0
  5. package/dist/approval/manager.js.map +1 -0
  6. package/dist/approval/session-memory.d.ts +37 -0
  7. package/dist/approval/session-memory.d.ts.map +1 -0
  8. package/dist/approval/session-memory.js +63 -0
  9. package/dist/approval/session-memory.js.map +1 -0
  10. package/dist/cli/config-writer.d.ts +57 -0
  11. package/dist/cli/config-writer.d.ts.map +1 -0
  12. package/dist/cli/config-writer.js +318 -0
  13. package/dist/cli/config-writer.js.map +1 -0
  14. package/dist/cli/index.d.ts +3 -0
  15. package/dist/cli/index.d.ts.map +1 -0
  16. package/dist/cli/index.js +82 -0
  17. package/dist/cli/index.js.map +1 -0
  18. package/dist/cli/path-resolver.d.ts +48 -0
  19. package/dist/cli/path-resolver.d.ts.map +1 -0
  20. package/dist/cli/path-resolver.js +212 -0
  21. package/dist/cli/path-resolver.js.map +1 -0
  22. package/dist/cli/setup.d.ts +10 -0
  23. package/dist/cli/setup.d.ts.map +1 -0
  24. package/dist/cli/setup.js +268 -0
  25. package/dist/cli/setup.js.map +1 -0
  26. package/dist/cloud/connector.d.ts +74 -0
  27. package/dist/cloud/connector.d.ts.map +1 -0
  28. package/dist/cloud/connector.js +524 -0
  29. package/dist/cloud/connector.js.map +1 -0
  30. package/dist/cloud/index.d.ts +3 -0
  31. package/dist/cloud/index.d.ts.map +1 -0
  32. package/dist/cloud/index.js +6 -0
  33. package/dist/cloud/index.js.map +1 -0
  34. package/dist/config/manager.d.ts +76 -0
  35. package/dist/config/manager.d.ts.map +1 -0
  36. package/dist/config/manager.js +296 -0
  37. package/dist/config/manager.js.map +1 -0
  38. package/dist/dev-mode.d.ts +30 -0
  39. package/dist/dev-mode.d.ts.map +1 -0
  40. package/dist/dev-mode.js +53 -0
  41. package/dist/dev-mode.js.map +1 -0
  42. package/dist/index.d.ts +10 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +354 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/ipc/index.d.ts +12 -0
  47. package/dist/ipc/index.d.ts.map +1 -0
  48. package/dist/ipc/index.js +15 -0
  49. package/dist/ipc/index.js.map +1 -0
  50. package/dist/ipc/watcher.d.ts +226 -0
  51. package/dist/ipc/watcher.d.ts.map +1 -0
  52. package/dist/ipc/watcher.js +745 -0
  53. package/dist/ipc/watcher.js.map +1 -0
  54. package/dist/local/approval-dialog.d.ts +30 -0
  55. package/dist/local/approval-dialog.d.ts.map +1 -0
  56. package/dist/local/approval-dialog.js +214 -0
  57. package/dist/local/approval-dialog.js.map +1 -0
  58. package/dist/local/index.d.ts +8 -0
  59. package/dist/local/index.d.ts.map +1 -0
  60. package/dist/local/index.js +13 -0
  61. package/dist/local/index.js.map +1 -0
  62. package/dist/local/local-approval.d.ts +55 -0
  63. package/dist/local/local-approval.d.ts.map +1 -0
  64. package/dist/local/local-approval.js +125 -0
  65. package/dist/local/local-approval.js.map +1 -0
  66. package/dist/local/notifier.d.ts +19 -0
  67. package/dist/local/notifier.d.ts.map +1 -0
  68. package/dist/local/notifier.js +110 -0
  69. package/dist/local/notifier.js.map +1 -0
  70. package/dist/local/sanitize.d.ts +20 -0
  71. package/dist/local/sanitize.d.ts.map +1 -0
  72. package/dist/local/sanitize.js +28 -0
  73. package/dist/local/sanitize.js.map +1 -0
  74. package/dist/mcp/file-extractor.d.ts +11 -0
  75. package/dist/mcp/file-extractor.d.ts.map +1 -0
  76. package/dist/mcp/file-extractor.js +74 -0
  77. package/dist/mcp/file-extractor.js.map +1 -0
  78. package/dist/mcp/risk-level.d.ts +44 -0
  79. package/dist/mcp/risk-level.d.ts.map +1 -0
  80. package/dist/mcp/risk-level.js +127 -0
  81. package/dist/mcp/risk-level.js.map +1 -0
  82. package/dist/mcp/schemas.d.ts +83 -0
  83. package/dist/mcp/schemas.d.ts.map +1 -0
  84. package/dist/mcp/schemas.js +84 -0
  85. package/dist/mcp/schemas.js.map +1 -0
  86. package/dist/mcp/summary.d.ts +11 -0
  87. package/dist/mcp/summary.d.ts.map +1 -0
  88. package/dist/mcp/summary.js +150 -0
  89. package/dist/mcp/summary.js.map +1 -0
  90. package/dist/mcp/tools.d.ts +45 -0
  91. package/dist/mcp/tools.d.ts.map +1 -0
  92. package/dist/mcp/tools.js +1217 -0
  93. package/dist/mcp/tools.js.map +1 -0
  94. package/dist/pairing/auto-pairing.d.ts +37 -0
  95. package/dist/pairing/auto-pairing.d.ts.map +1 -0
  96. package/dist/pairing/auto-pairing.js +144 -0
  97. package/dist/pairing/auto-pairing.js.map +1 -0
  98. package/dist/pairing/binding-poller.d.ts +26 -0
  99. package/dist/pairing/binding-poller.d.ts.map +1 -0
  100. package/dist/pairing/binding-poller.js +108 -0
  101. package/dist/pairing/binding-poller.js.map +1 -0
  102. package/dist/pairing/pairing-server.d.ts +14 -0
  103. package/dist/pairing/pairing-server.d.ts.map +1 -0
  104. package/dist/pairing/pairing-server.js +277 -0
  105. package/dist/pairing/pairing-server.js.map +1 -0
  106. package/dist/pairing/qr-display.d.ts +14 -0
  107. package/dist/pairing/qr-display.d.ts.map +1 -0
  108. package/dist/pairing/qr-display.js +40 -0
  109. package/dist/pairing/qr-display.js.map +1 -0
  110. package/dist/policy/engine.d.ts +31 -0
  111. package/dist/policy/engine.d.ts.map +1 -0
  112. package/dist/policy/engine.js +187 -0
  113. package/dist/policy/engine.js.map +1 -0
  114. package/dist/policy/store.d.ts +26 -0
  115. package/dist/policy/store.d.ts.map +1 -0
  116. package/dist/policy/store.js +70 -0
  117. package/dist/policy/store.js.map +1 -0
  118. package/dist/policy/system-policies.d.ts +15 -0
  119. package/dist/policy/system-policies.d.ts.map +1 -0
  120. package/dist/policy/system-policies.js +265 -0
  121. package/dist/policy/system-policies.js.map +1 -0
  122. package/dist/policy/tool-mapping.d.ts +45 -0
  123. package/dist/policy/tool-mapping.d.ts.map +1 -0
  124. package/dist/policy/tool-mapping.js +88 -0
  125. package/dist/policy/tool-mapping.js.map +1 -0
  126. package/dist/policy/tool-registry.json +85 -0
  127. package/dist/store/db.d.ts +17 -0
  128. package/dist/store/db.d.ts.map +1 -0
  129. package/dist/store/db.js +193 -0
  130. package/dist/store/db.js.map +1 -0
  131. package/dist/store/index.d.ts +4 -0
  132. package/dist/store/index.d.ts.map +1 -0
  133. package/dist/store/index.js +7 -0
  134. package/dist/store/index.js.map +1 -0
  135. package/dist/store/metadata.d.ts +31 -0
  136. package/dist/store/metadata.d.ts.map +1 -0
  137. package/dist/store/metadata.js +178 -0
  138. package/dist/store/metadata.js.map +1 -0
  139. package/dist/store/operations.d.ts +26 -0
  140. package/dist/store/operations.d.ts.map +1 -0
  141. package/dist/store/operations.js +171 -0
  142. package/dist/store/operations.js.map +1 -0
  143. package/dist/utils/json.d.ts +7 -0
  144. package/dist/utils/json.d.ts.map +1 -0
  145. package/dist/utils/json.js +33 -0
  146. package/dist/utils/json.js.map +1 -0
  147. package/dist/utils/logger.d.ts +13 -0
  148. package/dist/utils/logger.d.ts.map +1 -0
  149. package/dist/utils/logger.js +58 -0
  150. package/dist/utils/logger.js.map +1 -0
  151. package/dist/utils/open-browser.d.ts +8 -0
  152. package/dist/utils/open-browser.d.ts.map +1 -0
  153. package/dist/utils/open-browser.js +38 -0
  154. package/dist/utils/open-browser.js.map +1 -0
  155. package/node_modules/@hopping/shared/dist/types.d.ts +649 -0
  156. package/node_modules/@hopping/shared/dist/types.js +48 -0
  157. package/node_modules/@hopping/shared/dist/types.js.map +1 -0
  158. package/node_modules/@hopping/shared/package.json +14 -0
  159. package/node_modules/@hopping/shared/tsconfig.json +16 -0
  160. package/node_modules/@hopping/shared/types.d.ts +650 -0
  161. package/node_modules/@hopping/shared/types.d.ts.map +1 -0
  162. package/node_modules/@hopping/shared/types.js +48 -0
  163. package/node_modules/@hopping/shared/types.js.map +1 -0
  164. package/node_modules/@hopping/shared/types.ts +895 -0
  165. package/package.json +52 -0
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.HubDatabase = void 0;
40
+ exports.resolveDbPath = resolveDbPath;
41
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const fs = __importStar(require("fs"));
45
+ const operations_1 = require("./operations");
46
+ const metadata_1 = require("./metadata");
47
+ // ============================================
48
+ // DB Path Resolution
49
+ // ============================================
50
+ function resolveDbPath(dbPath) {
51
+ if (dbPath !== undefined)
52
+ return dbPath;
53
+ const envPath = process.env.HOPPING_DB_PATH;
54
+ if (envPath)
55
+ return envPath.replace(/^~/, os.homedir());
56
+ return path.join(os.homedir(), '.hopping', 'hopping.db');
57
+ }
58
+ // ============================================
59
+ // Schema Initialization
60
+ // ============================================
61
+ const CURRENT_SCHEMA_VERSION = 4;
62
+ /** 檢查某 table 是否已有指定欄位(用於安全 migration) */
63
+ function hasColumn(db, table, column) {
64
+ const columns = db.prepare(`PRAGMA table_info('${table}')`).all();
65
+ return columns.some((c) => c.name === column);
66
+ }
67
+ function initSchema(db) {
68
+ const version = db.pragma('user_version', { simple: true });
69
+ if (version >= CURRENT_SCHEMA_VERSION)
70
+ return;
71
+ // v0(全新安裝):建立所有表格(含 v2+v3 欄位),直接跳到最新版本
72
+ if (version === 0) {
73
+ db.exec(`
74
+ CREATE TABLE IF NOT EXISTS operations (
75
+ id TEXT PRIMARY KEY,
76
+ approval_id TEXT,
77
+ tool_name TEXT NOT NULL,
78
+ tool_params TEXT,
79
+ file_paths TEXT,
80
+ risk_level TEXT,
81
+ decision TEXT,
82
+ created_at TEXT NOT NULL,
83
+ decided_at TEXT,
84
+ tool_use_id TEXT,
85
+ prompt_type TEXT,
86
+ response_type TEXT,
87
+ response_data TEXT
88
+ );
89
+
90
+ CREATE TABLE IF NOT EXISTS metadata (
91
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
92
+ operation_id TEXT REFERENCES operations(id),
93
+ agent_type TEXT,
94
+ session_id TEXT,
95
+ duration_ms INTEGER,
96
+ token_usage INTEGER,
97
+ context_tags TEXT,
98
+ source TEXT,
99
+ result_status TEXT,
100
+ tool_result_summary TEXT,
101
+ created_at TEXT NOT NULL
102
+ );
103
+
104
+ CREATE INDEX IF NOT EXISTS idx_operations_created_at ON operations(created_at);
105
+ CREATE INDEX IF NOT EXISTS idx_operations_tool_use_id ON operations(tool_use_id);
106
+ CREATE INDEX IF NOT EXISTS idx_metadata_operation_id ON metadata(operation_id);
107
+ CREATE INDEX IF NOT EXISTS idx_metadata_session_id ON metadata(session_id);
108
+ CREATE INDEX IF NOT EXISTS idx_metadata_source ON metadata(source);
109
+ `);
110
+ db.pragma(`user_version = ${CURRENT_SCHEMA_VERSION}`);
111
+ return;
112
+ }
113
+ // --- 以下為既有安裝的增量 migration ---
114
+ // v1 → v2:metadata 新增 source / result_status / tool_result_summary
115
+ if (version <= 1) {
116
+ const migrateToV2 = db.transaction(() => {
117
+ if (!hasColumn(db, 'metadata', 'source')) {
118
+ db.exec(`ALTER TABLE metadata ADD COLUMN source TEXT`);
119
+ }
120
+ if (!hasColumn(db, 'metadata', 'result_status')) {
121
+ db.exec(`ALTER TABLE metadata ADD COLUMN result_status TEXT`);
122
+ }
123
+ if (!hasColumn(db, 'metadata', 'tool_result_summary')) {
124
+ db.exec(`ALTER TABLE metadata ADD COLUMN tool_result_summary TEXT`);
125
+ }
126
+ db.exec(`CREATE INDEX IF NOT EXISTS idx_metadata_session_id ON metadata(session_id)`);
127
+ db.exec(`CREATE INDEX IF NOT EXISTS idx_metadata_source ON metadata(source)`);
128
+ });
129
+ migrateToV2();
130
+ }
131
+ // v2 → v3:operations 新增 tool_use_id(pre/post 關聯鍵)
132
+ if (version <= 2) {
133
+ const migrateToV3 = db.transaction(() => {
134
+ if (!hasColumn(db, 'operations', 'tool_use_id')) {
135
+ db.exec(`ALTER TABLE operations ADD COLUMN tool_use_id TEXT`);
136
+ }
137
+ db.exec(`CREATE INDEX IF NOT EXISTS idx_operations_tool_use_id ON operations(tool_use_id)`);
138
+ });
139
+ migrateToV3();
140
+ }
141
+ // v3 → v4:operations 新增 prompt_type/response_type/response_data(Rich Permission)
142
+ if (version <= 3) {
143
+ const migrateToV4 = db.transaction(() => {
144
+ if (!hasColumn(db, 'operations', 'prompt_type')) {
145
+ db.exec(`ALTER TABLE operations ADD COLUMN prompt_type TEXT`);
146
+ }
147
+ if (!hasColumn(db, 'operations', 'response_type')) {
148
+ db.exec(`ALTER TABLE operations ADD COLUMN response_type TEXT`);
149
+ }
150
+ if (!hasColumn(db, 'operations', 'response_data')) {
151
+ db.exec(`ALTER TABLE operations ADD COLUMN response_data TEXT`);
152
+ }
153
+ });
154
+ migrateToV4();
155
+ }
156
+ db.pragma(`user_version = ${CURRENT_SCHEMA_VERSION}`);
157
+ }
158
+ // ============================================
159
+ // HubDatabase Class
160
+ // ============================================
161
+ class HubDatabase {
162
+ db;
163
+ operations;
164
+ metadata;
165
+ /**
166
+ * @param dbPath - undefined = 預設路徑, ':memory:' = 測試用
167
+ */
168
+ constructor(dbPath) {
169
+ const resolvedPath = resolveDbPath(dbPath);
170
+ // 若不是記憶體模式,自動建立父目錄
171
+ if (resolvedPath !== ':memory:') {
172
+ const dir = path.dirname(resolvedPath);
173
+ fs.mkdirSync(dir, { recursive: true });
174
+ }
175
+ this.db = new better_sqlite3_1.default(resolvedPath);
176
+ // 啟用 WAL 模式(讀寫並行,Hook IPC 安全)
177
+ this.db.pragma('journal_mode = WAL');
178
+ // 啟用外鍵約束
179
+ this.db.pragma('foreign_keys = ON');
180
+ initSchema(this.db);
181
+ this.operations = (0, operations_1.createOperationStore)(this.db);
182
+ this.metadata = (0, metadata_1.createMetadataStore)(this.db);
183
+ }
184
+ close() {
185
+ this.db.close();
186
+ }
187
+ /** 取得底層 Database 實例(僅供測試使用) */
188
+ get _db() {
189
+ return this.db;
190
+ }
191
+ }
192
+ exports.HubDatabase = HubDatabase;
193
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/store/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { HubDatabase, resolveDbPath } from './db';
2
+ export type { OperationStore, DecisionCounts } from './operations';
3
+ export type { MetadataStore } from './metadata';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveDbPath = exports.HubDatabase = void 0;
4
+ var db_1 = require("./db");
5
+ Object.defineProperty(exports, "HubDatabase", { enumerable: true, get: function () { return db_1.HubDatabase; } });
6
+ Object.defineProperty(exports, "resolveDbPath", { enumerable: true, get: function () { return db_1.resolveDbPath; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":";;;AAAA,2BAAkD;AAAzC,iGAAA,WAAW,OAAA;AAAE,mGAAA,aAAa,OAAA"}
@@ -0,0 +1,31 @@
1
+ import Database from 'better-sqlite3';
2
+ import type { OperationMetadataRecord, OperationSource, ResultStatus } from '@hopping/shared';
3
+ export interface ToolUsageStat {
4
+ toolName: string;
5
+ count: number;
6
+ avgDurationMs: number | null;
7
+ successRate: number | null;
8
+ }
9
+ export interface SessionTimelineEntry {
10
+ operationId: string;
11
+ toolName: string;
12
+ riskLevel: string | null;
13
+ decision: string | null;
14
+ durationMs: number | null;
15
+ resultStatus: ResultStatus | null;
16
+ source: OperationSource | null;
17
+ createdAt: string;
18
+ }
19
+ export interface MetadataStore {
20
+ insert(record: Omit<OperationMetadataRecord, 'id'>): void;
21
+ getByOperationId(operationId: string): OperationMetadataRecord[];
22
+ getBySessionId(sessionId: string, limit?: number): OperationMetadataRecord[];
23
+ getToolUsageStats(date?: string): ToolUsageStat[];
24
+ /** Get tool usage stats across a UTC datetime range, sorted by count DESC. startUtc inclusive, endUtc exclusive. */
25
+ getToolUsageStatsRange(startUtc: string, endUtc: string, limit?: number): ToolUsageStat[];
26
+ getSessionTimeline(sessionId: string, limit?: number): SessionTimelineEntry[];
27
+ /** Get the most recent N timeline entries regardless of session, ordered by created_at DESC. */
28
+ getRecentTimeline(limit?: number): SessionTimelineEntry[];
29
+ }
30
+ export declare function createMetadataStore(db: Database.Database): MetadataStore;
31
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/store/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM9F,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAAC;IACjE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAAC;IAC7E,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAClD,oHAAoH;IACpH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAC1F,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAAC;IAC9E,gGAAgG;IAChG,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAAC;CAC3D;AAoFD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,aAAa,CA0KxE"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMetadataStore = createMetadataStore;
4
+ // ============================================
5
+ // Mapping Helpers
6
+ // ============================================
7
+ function rowToRecord(row) {
8
+ return {
9
+ id: row.id,
10
+ operationId: row.operation_id,
11
+ agentType: row.agent_type,
12
+ sessionId: row.session_id,
13
+ durationMs: row.duration_ms,
14
+ tokenUsage: row.token_usage,
15
+ contextTags: row.context_tags,
16
+ source: row.source,
17
+ resultStatus: row.result_status,
18
+ toolResultSummary: row.tool_result_summary,
19
+ createdAt: row.created_at,
20
+ };
21
+ }
22
+ function rowToToolUsageStat(row) {
23
+ return {
24
+ toolName: row.tool_name,
25
+ count: row.count,
26
+ avgDurationMs: row.avg_duration_ms,
27
+ successRate: row.success_rate,
28
+ };
29
+ }
30
+ function rowToSessionTimelineEntry(row) {
31
+ return {
32
+ operationId: row.operation_id,
33
+ toolName: row.tool_name,
34
+ riskLevel: row.risk_level,
35
+ decision: row.decision,
36
+ durationMs: row.duration_ms,
37
+ resultStatus: row.result_status,
38
+ source: row.source,
39
+ createdAt: row.created_at,
40
+ };
41
+ }
42
+ // ============================================
43
+ // Factory
44
+ // ============================================
45
+ function createMetadataStore(db) {
46
+ const insertStmt = db.prepare(`
47
+ INSERT INTO metadata (operation_id, agent_type, session_id, duration_ms, token_usage, context_tags, source, result_status, tool_result_summary, created_at)
48
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
49
+ `);
50
+ const getByOperationIdStmt = db.prepare(`
51
+ SELECT id, operation_id, agent_type, session_id, duration_ms, token_usage, context_tags,
52
+ source, result_status, tool_result_summary, created_at
53
+ FROM metadata
54
+ WHERE operation_id = ?
55
+ ORDER BY id ASC
56
+ `);
57
+ const getBySessionIdStmt = db.prepare(`
58
+ SELECT id, operation_id, agent_type, session_id, duration_ms, token_usage, context_tags,
59
+ source, result_status, tool_result_summary, created_at
60
+ FROM metadata
61
+ WHERE session_id = ?
62
+ ORDER BY id ASC
63
+ LIMIT ?
64
+ `);
65
+ // getToolUsageStats — 兩個 prepared statements(有/無日期過濾)
66
+ const getToolUsageStatsAllStmt = db.prepare(`
67
+ SELECT
68
+ o.tool_name,
69
+ COUNT(*) as count,
70
+ AVG(m.duration_ms) as avg_duration_ms,
71
+ AVG(
72
+ CASE
73
+ WHEN m.result_status = 'success' THEN 1.0
74
+ WHEN m.result_status = 'failure' THEN 0.0
75
+ ELSE NULL
76
+ END
77
+ ) as success_rate
78
+ FROM metadata m
79
+ JOIN operations o ON m.operation_id = o.id
80
+ GROUP BY o.tool_name
81
+ ORDER BY count DESC
82
+ `);
83
+ const getToolUsageStatsByDateStmt = db.prepare(`
84
+ SELECT
85
+ o.tool_name,
86
+ COUNT(*) as count,
87
+ AVG(m.duration_ms) as avg_duration_ms,
88
+ AVG(
89
+ CASE
90
+ WHEN m.result_status = 'success' THEN 1.0
91
+ WHEN m.result_status = 'failure' THEN 0.0
92
+ ELSE NULL
93
+ END
94
+ ) as success_rate
95
+ FROM metadata m
96
+ JOIN operations o ON m.operation_id = o.id
97
+ WHERE DATE(m.created_at) = ?
98
+ GROUP BY o.tool_name
99
+ ORDER BY count DESC
100
+ `);
101
+ const getToolUsageStatsRangeStmt = db.prepare(`
102
+ SELECT
103
+ o.tool_name,
104
+ COUNT(*) as count,
105
+ AVG(m.duration_ms) as avg_duration_ms,
106
+ AVG(
107
+ CASE
108
+ WHEN m.result_status = 'success' THEN 1.0
109
+ WHEN m.result_status = 'failure' THEN 0.0
110
+ ELSE NULL
111
+ END
112
+ ) as success_rate
113
+ FROM metadata m
114
+ JOIN operations o ON m.operation_id = o.id
115
+ WHERE o.created_at >= ? AND o.created_at < ?
116
+ GROUP BY o.tool_name
117
+ ORDER BY count DESC
118
+ LIMIT ?
119
+ `);
120
+ const getSessionTimelineStmt = db.prepare(`
121
+ SELECT
122
+ o.id as operation_id,
123
+ o.tool_name,
124
+ o.risk_level,
125
+ o.decision,
126
+ m.duration_ms,
127
+ m.result_status,
128
+ m.source,
129
+ m.created_at
130
+ FROM metadata m
131
+ JOIN operations o ON m.operation_id = o.id
132
+ WHERE m.session_id = ?
133
+ ORDER BY m.created_at ASC
134
+ LIMIT ?
135
+ `);
136
+ const getRecentTimelineStmt = db.prepare(`
137
+ SELECT
138
+ o.id as operation_id,
139
+ o.tool_name,
140
+ o.risk_level,
141
+ o.decision,
142
+ m.duration_ms,
143
+ m.result_status,
144
+ m.source,
145
+ m.created_at
146
+ FROM metadata m
147
+ JOIN operations o ON m.operation_id = o.id
148
+ ORDER BY m.created_at DESC
149
+ LIMIT ?
150
+ `);
151
+ return {
152
+ insert(record) {
153
+ insertStmt.run(record.operationId, record.agentType, record.sessionId, record.durationMs ?? null, record.tokenUsage ?? null, record.contextTags ?? null, record.source ?? null, record.resultStatus ?? null, record.toolResultSummary?.slice(0, 500) ?? null, record.createdAt);
154
+ },
155
+ getByOperationId(operationId) {
156
+ return getByOperationIdStmt.all(operationId).map(rowToRecord);
157
+ },
158
+ getBySessionId(sessionId, limit = 100) {
159
+ return getBySessionIdStmt.all(sessionId, limit).map(rowToRecord);
160
+ },
161
+ getToolUsageStats(date) {
162
+ if (date) {
163
+ return getToolUsageStatsByDateStmt.all(date).map(rowToToolUsageStat);
164
+ }
165
+ return getToolUsageStatsAllStmt.all().map(rowToToolUsageStat);
166
+ },
167
+ getToolUsageStatsRange(startUtc, endUtc, limit = 10) {
168
+ return getToolUsageStatsRangeStmt.all(startUtc, endUtc, limit).map(rowToToolUsageStat);
169
+ },
170
+ getSessionTimeline(sessionId, limit = 50) {
171
+ return getSessionTimelineStmt.all(sessionId, limit).map(rowToSessionTimelineEntry);
172
+ },
173
+ getRecentTimeline(limit = 100) {
174
+ return getRecentTimelineStmt.all(limit).map(rowToSessionTimelineEntry);
175
+ },
176
+ };
177
+ }
178
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/store/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import Database from 'better-sqlite3';
2
+ import type { OperationRecord } from '@hopping/shared';
3
+ export interface DecisionCounts {
4
+ approved: number;
5
+ denied: number;
6
+ autoApproved: number;
7
+ total: number;
8
+ }
9
+ export interface OperationStore {
10
+ insert(record: OperationRecord): void;
11
+ getById(id: string): OperationRecord | undefined;
12
+ /** 透過 tool_use_id 查找 operation(pre/post 關聯用) */
13
+ getByToolUseId(toolUseId: string): OperationRecord | undefined;
14
+ countToday(): number;
15
+ updateDecision(id: string, decision: string, decidedAt: string): void;
16
+ /** 更新 response_data(Rich Permission 回應後寫入) */
17
+ updateResponseData(id: string, responseData: string): void;
18
+ /** List recent operations, ordered by created_at DESC */
19
+ listRecent(limit: number): OperationRecord[];
20
+ /** Count operations by decision for a given date (YYYY-MM-DD) */
21
+ countByDecision(date?: string): DecisionCounts;
22
+ /** Count operations by decision across a UTC datetime range (timezone-aware). startUtc inclusive, endUtc exclusive. */
23
+ countByDecisionRange(startUtc: string, endUtc: string): DecisionCounts;
24
+ }
25
+ export declare function createOperationStore(db: Database.Database): OperationStore;
26
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/store/operations.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACjD,gDAAgD;IAChD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAC/D,UAAU,IAAI,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtE,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,yDAAyD;IACzD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;IAC7C,iEAAiE;IACjE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAC/C,uHAAuH;IACvH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC;CACxE;AAgDD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,cAAc,CAqM1E"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOperationStore = createOperationStore;
4
+ // ============================================
5
+ // Mapping Helpers
6
+ // ============================================
7
+ function rowToRecord(row) {
8
+ return {
9
+ id: row.id,
10
+ approvalId: row.approval_id,
11
+ toolName: row.tool_name,
12
+ toolParams: row.tool_params,
13
+ filePaths: row.file_paths,
14
+ riskLevel: row.risk_level,
15
+ decision: row.decision,
16
+ createdAt: row.created_at,
17
+ decidedAt: row.decided_at,
18
+ toolUseId: row.tool_use_id,
19
+ promptType: row.prompt_type,
20
+ responseType: row.response_type,
21
+ responseData: row.response_data,
22
+ };
23
+ }
24
+ // ============================================
25
+ // Factory
26
+ // ============================================
27
+ function createOperationStore(db) {
28
+ const insertStmt = db.prepare(`
29
+ INSERT INTO operations (id, approval_id, tool_name, tool_params, file_paths, risk_level, decision, created_at, decided_at, tool_use_id, prompt_type, response_type, response_data)
30
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
31
+ `);
32
+ const getByIdStmt = db.prepare(`
33
+ SELECT id, approval_id, tool_name, tool_params, file_paths, risk_level, decision, created_at, decided_at, tool_use_id, prompt_type, response_type, response_data
34
+ FROM operations
35
+ WHERE id = ?
36
+ `);
37
+ const getByToolUseIdStmt = db.prepare(`
38
+ SELECT id, approval_id, tool_name, tool_params, file_paths, risk_level, decision, created_at, decided_at, tool_use_id, prompt_type, response_type, response_data
39
+ FROM operations
40
+ WHERE tool_use_id = ?
41
+ LIMIT 1
42
+ `);
43
+ const countTodayStmt = db.prepare(`
44
+ SELECT COUNT(*) AS count
45
+ FROM operations
46
+ WHERE date(created_at) = ?
47
+ `);
48
+ const updateDecisionStmt = db.prepare(`
49
+ UPDATE operations
50
+ SET decision = ?, decided_at = ?
51
+ WHERE id = ?
52
+ `);
53
+ const updateResponseDataStmt = db.prepare(`
54
+ UPDATE operations
55
+ SET response_data = ?
56
+ WHERE id = ?
57
+ `);
58
+ const listRecentStmt = db.prepare(`
59
+ SELECT id, approval_id, tool_name, tool_params, file_paths, risk_level, decision, created_at, decided_at, tool_use_id, prompt_type, response_type, response_data
60
+ FROM operations
61
+ ORDER BY created_at DESC
62
+ LIMIT ?
63
+ `);
64
+ const countByDecisionStmt = db.prepare(`
65
+ SELECT decision, COUNT(*) AS count
66
+ FROM operations
67
+ WHERE date(created_at) = ?
68
+ GROUP BY decision
69
+ `);
70
+ const countAutoApprovedStmt = db.prepare(`
71
+ SELECT COUNT(*) AS count FROM operations
72
+ WHERE date(created_at) = ? AND decision = 'approved' AND risk_level = 'low'
73
+ `);
74
+ const countByDecisionRangeStmt = db.prepare(`
75
+ SELECT decision, COUNT(*) AS count
76
+ FROM operations
77
+ WHERE created_at >= ? AND created_at < ?
78
+ GROUP BY decision
79
+ `);
80
+ const countAutoApprovedRangeStmt = db.prepare(`
81
+ SELECT COUNT(*) AS count FROM operations
82
+ WHERE created_at >= ? AND created_at < ? AND decision = 'approved' AND risk_level = 'low'
83
+ `);
84
+ return {
85
+ insert(record) {
86
+ insertStmt.run(record.id, record.approvalId ?? null, record.toolName, record.toolParams ?? null, record.filePaths ?? null, record.riskLevel ?? null, record.decision ?? null, record.createdAt, record.decidedAt ?? null, record.toolUseId ?? null, record.promptType ?? null, record.responseType ?? null, record.responseData ?? null);
87
+ },
88
+ getById(id) {
89
+ const row = getByIdStmt.get(id);
90
+ return row ? rowToRecord(row) : undefined;
91
+ },
92
+ getByToolUseId(toolUseId) {
93
+ const row = getByToolUseIdStmt.get(toolUseId);
94
+ return row ? rowToRecord(row) : undefined;
95
+ },
96
+ countToday() {
97
+ // Compute UTC date in JS to guarantee consistency with ISO 8601 created_at values
98
+ const todayUTC = new Date().toISOString().slice(0, 10);
99
+ const result = countTodayStmt.get(todayUTC);
100
+ return result?.count ?? 0;
101
+ },
102
+ updateDecision(id, decision, decidedAt) {
103
+ updateDecisionStmt.run(decision, decidedAt, id);
104
+ },
105
+ updateResponseData(id, responseData) {
106
+ updateResponseDataStmt.run(responseData, id);
107
+ },
108
+ listRecent(limit) {
109
+ return listRecentStmt.all(limit).map(rowToRecord);
110
+ },
111
+ countByDecision(date) {
112
+ const targetDate = date ?? new Date().toISOString().slice(0, 10);
113
+ const rows = countByDecisionStmt.all(targetDate);
114
+ const counts = { approved: 0, denied: 0, autoApproved: 0, total: 0 };
115
+ for (const row of rows) {
116
+ const c = row.count;
117
+ counts.total += c;
118
+ switch (row.decision) {
119
+ case 'approved':
120
+ counts.approved += c;
121
+ break;
122
+ case 'denied':
123
+ case 'timeout':
124
+ counts.denied += c;
125
+ break;
126
+ case 'answered':
127
+ // hopping.ask 問題回答 — 非審核操作,僅計入 total
128
+ break;
129
+ case null:
130
+ // Operations with null decision are pending or auto-processed
131
+ break;
132
+ default:
133
+ // conditional, etc.
134
+ counts.approved += c;
135
+ break;
136
+ }
137
+ }
138
+ counts.autoApproved = countAutoApprovedStmt.get(targetDate)?.count ?? 0;
139
+ return counts;
140
+ },
141
+ countByDecisionRange(startUtc, endUtc) {
142
+ const rows = countByDecisionRangeStmt.all(startUtc, endUtc);
143
+ const counts = { approved: 0, denied: 0, autoApproved: 0, total: 0 };
144
+ for (const row of rows) {
145
+ const c = row.count;
146
+ counts.total += c;
147
+ switch (row.decision) {
148
+ case 'approved':
149
+ counts.approved += c;
150
+ break;
151
+ case 'denied':
152
+ case 'timeout':
153
+ counts.denied += c;
154
+ break;
155
+ case 'answered':
156
+ // hopping.ask 問題回答 — 非審核操作,僅計入 total
157
+ break;
158
+ case null:
159
+ break;
160
+ default:
161
+ // conditional → approved
162
+ counts.approved += c;
163
+ break;
164
+ }
165
+ }
166
+ counts.autoApproved = countAutoApprovedRangeStmt.get(startUtc, endUtc)?.count ?? 0;
167
+ return counts;
168
+ },
169
+ };
170
+ }
171
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/store/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Safe JSON parse helpers — 從 SQLite 讀取 JSON 字串時使用
3
+ * 解析失敗回傳 undefined,不 throw
4
+ */
5
+ export declare function safeJsonParseObject(value: string): Record<string, unknown> | undefined;
6
+ export declare function safeJsonParseArray(value: string): string[] | undefined;
7
+ //# sourceMappingURL=json.d.ts.map