byterover-cli 2.0.0 → 2.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.
- package/README.md +6 -81
- package/dist/agent/core/domain/llm/index.d.ts +1 -1
- package/dist/agent/core/domain/llm/index.js +1 -1
- package/dist/agent/core/domain/llm/registry.d.ts +8 -0
- package/dist/agent/core/domain/llm/registry.js +34 -0
- package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
- package/dist/agent/core/domain/tools/constants.d.ts +3 -0
- package/dist/agent/core/domain/tools/constants.js +3 -0
- package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
- package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
- package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
- package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
- package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
- package/dist/agent/infra/agent/agent-schemas.js +0 -3
- package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
- package/dist/agent/infra/agent/cipher-agent.js +138 -11
- package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
- package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
- package/dist/agent/infra/agent/service-initializer.js +45 -38
- package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
- package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
- package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
- package/dist/agent/infra/blob/file-blob-storage.js +454 -0
- package/dist/agent/infra/blob/index.d.ts +2 -3
- package/dist/agent/infra/blob/index.js +4 -6
- package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
- package/dist/agent/infra/llm/agent-llm-service.js +34 -52
- package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
- package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
- package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
- package/dist/agent/infra/llm/context/compression/index.js +3 -0
- package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
- package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
- package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
- package/dist/agent/infra/llm/context/context-manager.js +37 -7
- package/dist/agent/infra/llm/providers/index.js +0 -2
- package/dist/agent/infra/llm/providers/types.d.ts +1 -5
- package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
- package/dist/agent/infra/map/agentic-map-service.js +309 -0
- package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
- package/dist/agent/infra/map/context-tree-store.js +278 -0
- package/dist/agent/infra/map/index.d.ts +4 -0
- package/dist/agent/infra/map/index.js +4 -0
- package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
- package/dist/agent/infra/map/llm-map-memory.js +187 -0
- package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
- package/dist/agent/infra/map/llm-map-service.js +118 -0
- package/dist/agent/infra/map/map-shared.d.ts +140 -0
- package/dist/agent/infra/map/map-shared.js +325 -0
- package/dist/agent/infra/map/worker-pool.d.ts +45 -0
- package/dist/agent/infra/map/worker-pool.js +73 -0
- package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
- package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
- package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
- package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
- package/dist/agent/infra/session/session-manager.d.ts +8 -1
- package/dist/agent/infra/session/session-manager.js +24 -4
- package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
- package/dist/agent/infra/storage/file-key-storage.js +572 -0
- package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
- package/dist/agent/infra/storage/granular-history-storage.js +1 -1
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
- package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
- package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
- package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
- package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
- package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
- package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
- package/dist/agent/infra/tools/tool-manager.js +6 -0
- package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
- package/dist/agent/infra/tools/tool-provider.js +78 -0
- package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
- package/dist/agent/infra/tools/tool-registry.js +32 -0
- package/dist/agent/resources/prompts/system-prompt.yml +48 -74
- package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
- package/dist/oclif/commands/curate/index.js +1 -2
- package/dist/oclif/commands/main.js +1 -0
- package/dist/oclif/commands/providers/connect.d.ts +1 -3
- package/dist/oclif/commands/providers/connect.js +7 -29
- package/dist/oclif/commands/query.js +1 -2
- package/dist/server/constants.d.ts +7 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/entities/provider-registry.js +1 -15
- package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
- package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
- package/dist/server/core/domain/knowledge/summary-types.js +7 -0
- package/dist/server/core/domain/transport/schemas.d.ts +0 -4
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
- package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
- package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
- package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
- package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
- package/dist/server/infra/context-tree/children-hash.js +22 -0
- package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
- package/dist/server/infra/context-tree/derived-artifact.js +48 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
- package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
- package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
- package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
- package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
- package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
- package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
- package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
- package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
- package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
- package/dist/server/infra/daemon/agent-process.js +2 -14
- package/dist/server/infra/executor/curate-executor.d.ts +1 -0
- package/dist/server/infra/executor/curate-executor.js +82 -34
- package/dist/server/infra/executor/folder-pack-executor.js +1 -1
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
- package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
- package/dist/server/infra/executor/pre-compaction/index.js +1 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
- package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
- package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
- package/dist/server/infra/executor/query-executor.d.ts +3 -0
- package/dist/server/infra/executor/query-executor.js +39 -4
- package/dist/server/infra/http/authenticated-http-client.js +4 -0
- package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
- package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
- package/dist/server/infra/http/provider-model-fetchers.js +0 -132
- package/dist/server/infra/provider/provider-config-resolver.js +0 -55
- package/dist/server/utils/curate-result-parser.d.ts +4 -4
- package/dist/shared/constants/curation.d.ts +6 -0
- package/dist/shared/constants/curation.js +6 -0
- package/dist/shared/utils/escalation-utils.d.ts +59 -0
- package/dist/shared/utils/escalation-utils.js +141 -0
- package/dist/tui/components/command-input.js +1 -1
- package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
- package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/exit.js +9 -0
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
- package/dist/tui/features/exit/components/exit-flow.js +19 -0
- package/dist/tui/features/provider/components/provider-flow.js +1 -21
- package/oclif.manifest.json +100 -109
- package/package.json +11 -4
- package/dist/agent/infra/blob/migrations.d.ts +0 -63
- package/dist/agent/infra/blob/migrations.js +0 -148
- package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
- package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
- package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
- package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
- package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
- package/dist/agent/infra/storage/blob-history-storage.js +0 -193
- package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
- package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
- package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
- package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
- package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
- package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
- package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
- package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose, inner;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
53
|
-
import Database from 'better-sqlite3';
|
|
54
|
-
import * as fs from 'node:fs/promises';
|
|
55
|
-
import { join } from 'node:path';
|
|
56
|
-
import { lockKeyFromStorageKey, RWLock } from '../llm/context/rw-lock.js';
|
|
57
|
-
/**
|
|
58
|
-
* SQLite-based key storage implementation.
|
|
59
|
-
*
|
|
60
|
-
* Stores key-value pairs where keys are hierarchical (StorageKey = string[])
|
|
61
|
-
* and values are JSON-serializable objects.
|
|
62
|
-
*
|
|
63
|
-
* Key path structure:
|
|
64
|
-
* - ["session", sessionId] → Session metadata
|
|
65
|
-
* - ["message", sessionId, messageId] → Individual message
|
|
66
|
-
* - ["part", messageId, partId] → Message part (tool output, file, etc.)
|
|
67
|
-
*
|
|
68
|
-
* Schema:
|
|
69
|
-
* - key_store: key_path (primary), value (JSON blob), created_at, updated_at
|
|
70
|
-
*
|
|
71
|
-
* Features:
|
|
72
|
-
* - Hierarchical key organization with prefix-based listing
|
|
73
|
-
* - Reader-writer locks for concurrent access
|
|
74
|
-
* - Atomic batch operations
|
|
75
|
-
* - ACID transactions via SQLite
|
|
76
|
-
*/
|
|
77
|
-
export class SqliteKeyStorage {
|
|
78
|
-
db = null;
|
|
79
|
-
dbPath;
|
|
80
|
-
initialized = false;
|
|
81
|
-
inMemory;
|
|
82
|
-
storageDir;
|
|
83
|
-
constructor(config) {
|
|
84
|
-
this.inMemory = config?.inMemory ?? false;
|
|
85
|
-
this.storageDir = config?.storageDir ?? '';
|
|
86
|
-
if (!this.inMemory && !this.storageDir) {
|
|
87
|
-
throw new Error('SqliteKeyStorage: storageDir is required when inMemory is false');
|
|
88
|
-
}
|
|
89
|
-
this.dbPath = this.inMemory ? ':memory:' : join(this.storageDir, config?.dbPath ?? 'context.db');
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Execute batch operations atomically.
|
|
93
|
-
* All operations succeed or fail together.
|
|
94
|
-
*/
|
|
95
|
-
async batch(operations) {
|
|
96
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
97
|
-
try {
|
|
98
|
-
this.ensureInitialized();
|
|
99
|
-
if (operations.length === 0) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
// Acquire write lock for all affected keys
|
|
103
|
-
const lockKey = 'batch:global';
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
105
|
-
const _lock = __addDisposableResource(env_1, await RWLock.write(lockKey), false);
|
|
106
|
-
const runBatch = this.db.transaction(() => {
|
|
107
|
-
for (const op of operations) {
|
|
108
|
-
const keyPath = this.serializeKey(op.key);
|
|
109
|
-
if (op.type === 'set') {
|
|
110
|
-
const now = Date.now();
|
|
111
|
-
const valueJson = JSON.stringify(op.value);
|
|
112
|
-
// Check if exists to preserve created_at
|
|
113
|
-
const existing = this.db.prepare('SELECT created_at FROM key_store WHERE key_path = ?').get(keyPath);
|
|
114
|
-
this.db.prepare(`
|
|
115
|
-
INSERT INTO key_store (key_path, value, created_at, updated_at)
|
|
116
|
-
VALUES (?, ?, ?, ?)
|
|
117
|
-
ON CONFLICT(key_path) DO UPDATE SET
|
|
118
|
-
value = excluded.value,
|
|
119
|
-
updated_at = excluded.updated_at
|
|
120
|
-
`).run(keyPath, Buffer.from(valueJson), existing?.created_at ?? now, now);
|
|
121
|
-
}
|
|
122
|
-
else if (op.type === 'delete') {
|
|
123
|
-
this.db.prepare('DELETE FROM key_store WHERE key_path = ?').run(keyPath);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
try {
|
|
128
|
-
runBatch();
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
throw new Error(`Batch operation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
catch (e_1) {
|
|
135
|
-
env_1.error = e_1;
|
|
136
|
-
env_1.hasError = true;
|
|
137
|
-
}
|
|
138
|
-
finally {
|
|
139
|
-
__disposeResources(env_1);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Close the database connection.
|
|
144
|
-
*/
|
|
145
|
-
close() {
|
|
146
|
-
if (this.db) {
|
|
147
|
-
this.db.close();
|
|
148
|
-
this.db = null;
|
|
149
|
-
this.initialized = false;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Delete a value by its composite key.
|
|
154
|
-
*/
|
|
155
|
-
async delete(key) {
|
|
156
|
-
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
157
|
-
try {
|
|
158
|
-
this.ensureInitialized();
|
|
159
|
-
const keyPath = this.serializeKey(key);
|
|
160
|
-
const lockKey = lockKeyFromStorageKey(key);
|
|
161
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
162
|
-
const _lock = __addDisposableResource(env_2, await RWLock.write(lockKey), false);
|
|
163
|
-
try {
|
|
164
|
-
const result = this.db.prepare('DELETE FROM key_store WHERE key_path = ?').run(keyPath);
|
|
165
|
-
return result.changes > 0;
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
throw new Error(`Failed to delete key ${keyPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
catch (e_2) {
|
|
172
|
-
env_2.error = e_2;
|
|
173
|
-
env_2.hasError = true;
|
|
174
|
-
}
|
|
175
|
-
finally {
|
|
176
|
-
__disposeResources(env_2);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Check if a key exists.
|
|
181
|
-
*/
|
|
182
|
-
async exists(key) {
|
|
183
|
-
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
184
|
-
try {
|
|
185
|
-
this.ensureInitialized();
|
|
186
|
-
const keyPath = this.serializeKey(key);
|
|
187
|
-
const lockKey = lockKeyFromStorageKey(key);
|
|
188
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
189
|
-
const _lock = __addDisposableResource(env_3, await RWLock.read(lockKey), false);
|
|
190
|
-
const row = this.db.prepare('SELECT 1 FROM key_store WHERE key_path = ?').get(keyPath);
|
|
191
|
-
return row !== undefined;
|
|
192
|
-
}
|
|
193
|
-
catch (e_3) {
|
|
194
|
-
env_3.error = e_3;
|
|
195
|
-
env_3.hasError = true;
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
__disposeResources(env_3);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Get a value by its composite key.
|
|
203
|
-
*/
|
|
204
|
-
async get(key) {
|
|
205
|
-
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
206
|
-
try {
|
|
207
|
-
this.ensureInitialized();
|
|
208
|
-
const keyPath = this.serializeKey(key);
|
|
209
|
-
const lockKey = lockKeyFromStorageKey(key);
|
|
210
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
211
|
-
const _lock = __addDisposableResource(env_4, await RWLock.read(lockKey), false);
|
|
212
|
-
try {
|
|
213
|
-
const row = this.db.prepare('SELECT value FROM key_store WHERE key_path = ?').get(keyPath);
|
|
214
|
-
if (!row) {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
return JSON.parse(row.value.toString('utf8'));
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
throw new Error(`Failed to get key ${keyPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
catch (e_4) {
|
|
224
|
-
env_4.error = e_4;
|
|
225
|
-
env_4.hasError = true;
|
|
226
|
-
}
|
|
227
|
-
finally {
|
|
228
|
-
__disposeResources(env_4);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Initialize the storage backend.
|
|
233
|
-
* Creates the database and runs migrations.
|
|
234
|
-
*/
|
|
235
|
-
async initialize() {
|
|
236
|
-
if (this.initialized) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
// Ensure storage directory exists (skip for in-memory)
|
|
241
|
-
if (!this.inMemory) {
|
|
242
|
-
await fs.mkdir(this.storageDir, { recursive: true });
|
|
243
|
-
}
|
|
244
|
-
// Open/create database
|
|
245
|
-
this.db = new Database(this.dbPath);
|
|
246
|
-
// Enable WAL mode for better concurrent performance
|
|
247
|
-
this.db.pragma('journal_mode = WAL');
|
|
248
|
-
// Create key_store table
|
|
249
|
-
this.db.exec(`
|
|
250
|
-
CREATE TABLE IF NOT EXISTS key_store (
|
|
251
|
-
key_path TEXT PRIMARY KEY,
|
|
252
|
-
value BLOB NOT NULL,
|
|
253
|
-
created_at INTEGER NOT NULL,
|
|
254
|
-
updated_at INTEGER NOT NULL
|
|
255
|
-
)
|
|
256
|
-
`);
|
|
257
|
-
// Create index for prefix-based listing
|
|
258
|
-
this.db.exec(`CREATE INDEX IF NOT EXISTS idx_key_store_prefix ON key_store(key_path)`);
|
|
259
|
-
this.initialized = true;
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
throw new Error(`Failed to initialize SQLite key storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* List all keys matching a prefix.
|
|
267
|
-
*/
|
|
268
|
-
async list(prefix) {
|
|
269
|
-
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
270
|
-
try {
|
|
271
|
-
this.ensureInitialized();
|
|
272
|
-
const prefixPath = this.serializeKey(prefix);
|
|
273
|
-
const lockKey = lockKeyFromStorageKey(prefix);
|
|
274
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
275
|
-
const _lock = __addDisposableResource(env_5, await RWLock.read(lockKey), false);
|
|
276
|
-
try {
|
|
277
|
-
// Use LIKE with prefix pattern for efficient prefix matching
|
|
278
|
-
const rows = this.db.prepare('SELECT key_path FROM key_store WHERE key_path LIKE ? ORDER BY key_path').all(`${prefixPath}%`);
|
|
279
|
-
return rows.map((row) => this.deserializeKey(row.key_path));
|
|
280
|
-
}
|
|
281
|
-
catch (error) {
|
|
282
|
-
throw new Error(`Failed to list keys with prefix ${prefixPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
catch (e_5) {
|
|
286
|
-
env_5.error = e_5;
|
|
287
|
-
env_5.hasError = true;
|
|
288
|
-
}
|
|
289
|
-
finally {
|
|
290
|
-
__disposeResources(env_5);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* List all key-value pairs matching a prefix.
|
|
295
|
-
* More efficient than list() followed by individual get() calls.
|
|
296
|
-
*/
|
|
297
|
-
async listWithValues(prefix) {
|
|
298
|
-
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
299
|
-
try {
|
|
300
|
-
this.ensureInitialized();
|
|
301
|
-
const prefixPath = this.serializeKey(prefix);
|
|
302
|
-
const lockKey = lockKeyFromStorageKey(prefix);
|
|
303
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
304
|
-
const _lock = __addDisposableResource(env_6, await RWLock.read(lockKey), false);
|
|
305
|
-
try {
|
|
306
|
-
const rows = this.db.prepare('SELECT key_path, value FROM key_store WHERE key_path LIKE ? ORDER BY key_path').all(`${prefixPath}%`);
|
|
307
|
-
return rows.map((row) => ({
|
|
308
|
-
key: this.deserializeKey(row.key_path),
|
|
309
|
-
value: JSON.parse(row.value.toString('utf8')),
|
|
310
|
-
}));
|
|
311
|
-
}
|
|
312
|
-
catch (error) {
|
|
313
|
-
throw new Error(`Failed to list keys with values for prefix ${prefixPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
catch (e_6) {
|
|
317
|
-
env_6.error = e_6;
|
|
318
|
-
env_6.hasError = true;
|
|
319
|
-
}
|
|
320
|
-
finally {
|
|
321
|
-
__disposeResources(env_6);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Set a value at a composite key.
|
|
326
|
-
*/
|
|
327
|
-
async set(key, value) {
|
|
328
|
-
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
329
|
-
try {
|
|
330
|
-
this.ensureInitialized();
|
|
331
|
-
const keyPath = this.serializeKey(key);
|
|
332
|
-
const lockKey = lockKeyFromStorageKey(key);
|
|
333
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
334
|
-
const _lock = __addDisposableResource(env_7, await RWLock.write(lockKey), false);
|
|
335
|
-
const now = Date.now();
|
|
336
|
-
const valueJson = JSON.stringify(value);
|
|
337
|
-
try {
|
|
338
|
-
// Check if exists to preserve created_at
|
|
339
|
-
const existing = this.db.prepare('SELECT created_at FROM key_store WHERE key_path = ?').get(keyPath);
|
|
340
|
-
this.db.prepare(`
|
|
341
|
-
INSERT INTO key_store (key_path, value, created_at, updated_at)
|
|
342
|
-
VALUES (?, ?, ?, ?)
|
|
343
|
-
ON CONFLICT(key_path) DO UPDATE SET
|
|
344
|
-
value = excluded.value,
|
|
345
|
-
updated_at = excluded.updated_at
|
|
346
|
-
`).run(keyPath, Buffer.from(valueJson), existing?.created_at ?? now, now);
|
|
347
|
-
}
|
|
348
|
-
catch (error) {
|
|
349
|
-
throw new Error(`Failed to set key ${keyPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
catch (e_7) {
|
|
353
|
-
env_7.error = e_7;
|
|
354
|
-
env_7.hasError = true;
|
|
355
|
-
}
|
|
356
|
-
finally {
|
|
357
|
-
__disposeResources(env_7);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Atomic update with optimistic locking.
|
|
362
|
-
*/
|
|
363
|
-
async update(key, updater) {
|
|
364
|
-
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
365
|
-
try {
|
|
366
|
-
this.ensureInitialized();
|
|
367
|
-
const keyPath = this.serializeKey(key);
|
|
368
|
-
const lockKey = lockKeyFromStorageKey(key);
|
|
369
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
370
|
-
const _lock = __addDisposableResource(env_8, await RWLock.write(lockKey), false);
|
|
371
|
-
try {
|
|
372
|
-
// Read current value
|
|
373
|
-
const row = this.db.prepare('SELECT value, created_at FROM key_store WHERE key_path = ?').get(keyPath);
|
|
374
|
-
const currentValue = row ? JSON.parse(row.value.toString('utf8')) : undefined;
|
|
375
|
-
// Apply updater function
|
|
376
|
-
const newValue = updater(currentValue);
|
|
377
|
-
// Write new value
|
|
378
|
-
const now = Date.now();
|
|
379
|
-
const valueJson = JSON.stringify(newValue);
|
|
380
|
-
this.db.prepare(`
|
|
381
|
-
INSERT INTO key_store (key_path, value, created_at, updated_at)
|
|
382
|
-
VALUES (?, ?, ?, ?)
|
|
383
|
-
ON CONFLICT(key_path) DO UPDATE SET
|
|
384
|
-
value = excluded.value,
|
|
385
|
-
updated_at = excluded.updated_at
|
|
386
|
-
`).run(keyPath, Buffer.from(valueJson), row?.created_at ?? now, now);
|
|
387
|
-
return newValue;
|
|
388
|
-
}
|
|
389
|
-
catch (error) {
|
|
390
|
-
throw new Error(`Failed to update key ${keyPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
catch (e_8) {
|
|
394
|
-
env_8.error = e_8;
|
|
395
|
-
env_8.hasError = true;
|
|
396
|
-
}
|
|
397
|
-
finally {
|
|
398
|
-
__disposeResources(env_8);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Deserialize a key path string back to StorageKey.
|
|
403
|
-
* Converts "message:session123:msg456" to ["message", "session123", "msg456"]
|
|
404
|
-
*/
|
|
405
|
-
deserializeKey(keyPath) {
|
|
406
|
-
return keyPath.split(':');
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Ensure storage has been initialized.
|
|
410
|
-
*/
|
|
411
|
-
ensureInitialized() {
|
|
412
|
-
if (!this.initialized || !this.db) {
|
|
413
|
-
throw new Error('SqliteKeyStorage not initialized. Call initialize() first.');
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Serialize a StorageKey to a string path.
|
|
418
|
-
* Converts ["message", "session123", "msg456"] to "message:session123:msg456"
|
|
419
|
-
*/
|
|
420
|
-
serializeKey(key) {
|
|
421
|
-
if (key.length === 0) {
|
|
422
|
-
throw new Error('Storage key cannot be empty');
|
|
423
|
-
}
|
|
424
|
-
// Validate key segments don't contain the separator
|
|
425
|
-
for (const segment of key) {
|
|
426
|
-
if (segment.includes(':')) {
|
|
427
|
-
throw new Error(`Key segment cannot contain ':': ${segment}`);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return key.join(':');
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Factory function to create SqliteKeyStorage with common defaults.
|
|
435
|
-
*/
|
|
436
|
-
export function createKeyStorage(config) {
|
|
437
|
-
return new SqliteKeyStorage(config);
|
|
438
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vertex AI Utilities
|
|
3
|
-
*
|
|
4
|
-
* Shared helpers for Google Vertex AI provider configuration.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Resolve the Google Cloud project ID for Vertex AI.
|
|
8
|
-
* Priority: GOOGLE_CLOUD_PROJECT env var → project_id from service account JSON.
|
|
9
|
-
*/
|
|
10
|
-
export declare function resolveVertexAiProject(credentialPath: string | undefined): string | undefined;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vertex AI Utilities
|
|
3
|
-
*
|
|
4
|
-
* Shared helpers for Google Vertex AI provider configuration.
|
|
5
|
-
*/
|
|
6
|
-
import { readFileSync } from 'node:fs';
|
|
7
|
-
/**
|
|
8
|
-
* Resolve the Google Cloud project ID for Vertex AI.
|
|
9
|
-
* Priority: GOOGLE_CLOUD_PROJECT env var → project_id from service account JSON.
|
|
10
|
-
*/
|
|
11
|
-
export function resolveVertexAiProject(credentialPath) {
|
|
12
|
-
if (process.env.GOOGLE_CLOUD_PROJECT) {
|
|
13
|
-
return process.env.GOOGLE_CLOUD_PROJECT;
|
|
14
|
-
}
|
|
15
|
-
const filePath = credentialPath || process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
16
|
-
if (filePath) {
|
|
17
|
-
try {
|
|
18
|
-
const content = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
19
|
-
if (typeof content.project_id === 'string' && content.project_id) {
|
|
20
|
-
return content.project_id;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// File read/parse failed — fall through to undefined
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CredentialPathDialog Component
|
|
3
|
-
*
|
|
4
|
-
* Dialog for entering a file path to a service account JSON credential.
|
|
5
|
-
* Used by Google Vertex AI provider which uses file-based credentials
|
|
6
|
-
* instead of API keys.
|
|
7
|
-
* Features:
|
|
8
|
-
* - Unmasked input (file paths, not secrets)
|
|
9
|
-
* - Real-time validation (file existence + JSON parse)
|
|
10
|
-
* - Error message display
|
|
11
|
-
* - Link to service account key page
|
|
12
|
-
*/
|
|
13
|
-
import React from 'react';
|
|
14
|
-
import type { ProviderDTO } from '../../../../shared/transport/types/dto.js';
|
|
15
|
-
export interface CredentialPathDialogProps {
|
|
16
|
-
/** Whether the dialog is active for keyboard input */
|
|
17
|
-
isActive?: boolean;
|
|
18
|
-
/** Callback when dialog is cancelled */
|
|
19
|
-
onCancel: () => void;
|
|
20
|
-
/** Callback when credential path is successfully validated */
|
|
21
|
-
onSuccess: (credentialPath: string) => void;
|
|
22
|
-
/** The provider to connect to */
|
|
23
|
-
provider: ProviderDTO;
|
|
24
|
-
/** Optional validation function */
|
|
25
|
-
validateCredential?: (path: string, provider: ProviderDTO) => Promise<{
|
|
26
|
-
error?: string;
|
|
27
|
-
isValid: boolean;
|
|
28
|
-
}>;
|
|
29
|
-
}
|
|
30
|
-
export declare const CredentialPathDialog: React.FC<CredentialPathDialogProps>;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* CredentialPathDialog Component
|
|
4
|
-
*
|
|
5
|
-
* Dialog for entering a file path to a service account JSON credential.
|
|
6
|
-
* Used by Google Vertex AI provider which uses file-based credentials
|
|
7
|
-
* instead of API keys.
|
|
8
|
-
* Features:
|
|
9
|
-
* - Unmasked input (file paths, not secrets)
|
|
10
|
-
* - Real-time validation (file existence + JSON parse)
|
|
11
|
-
* - Error message display
|
|
12
|
-
* - Link to service account key page
|
|
13
|
-
*/
|
|
14
|
-
import { Box, Text, useInput } from 'ink';
|
|
15
|
-
import { homedir } from 'node:os';
|
|
16
|
-
import { useCallback, useState } from 'react';
|
|
17
|
-
import { useTheme } from '../../../hooks/index.js';
|
|
18
|
-
import { stripBracketedPaste } from '../../../utils/index.js';
|
|
19
|
-
function expandTilde(filePath) {
|
|
20
|
-
if (filePath === '~')
|
|
21
|
-
return homedir();
|
|
22
|
-
if (filePath.startsWith('~/'))
|
|
23
|
-
return homedir() + filePath.slice(1);
|
|
24
|
-
return filePath;
|
|
25
|
-
}
|
|
26
|
-
const defaultValidate = async () => ({ isValid: true });
|
|
27
|
-
export const CredentialPathDialog = ({ isActive = true, onCancel, onSuccess, provider, validateCredential = defaultValidate, }) => {
|
|
28
|
-
const { theme: { colors } } = useTheme();
|
|
29
|
-
const [filePath, setFilePath] = useState('');
|
|
30
|
-
const [isValidating, setIsValidating] = useState(false);
|
|
31
|
-
const [error, setError] = useState();
|
|
32
|
-
const handleSubmit = useCallback(async () => {
|
|
33
|
-
if (!filePath.trim()) {
|
|
34
|
-
setError('File path is required');
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const resolvedPath = expandTilde(filePath.trim());
|
|
38
|
-
setIsValidating(true);
|
|
39
|
-
setError(undefined);
|
|
40
|
-
try {
|
|
41
|
-
const result = await validateCredential(resolvedPath, provider);
|
|
42
|
-
if (result.isValid) {
|
|
43
|
-
onSuccess(resolvedPath);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
setError(result.error ?? 'Invalid credential file');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
catch (error_) {
|
|
50
|
-
setError(error_ instanceof Error ? error_.message : 'Validation failed');
|
|
51
|
-
}
|
|
52
|
-
finally {
|
|
53
|
-
setIsValidating(false);
|
|
54
|
-
}
|
|
55
|
-
}, [filePath, provider, validateCredential, onSuccess]);
|
|
56
|
-
useInput((input, key) => {
|
|
57
|
-
if (key.return && !isValidating) {
|
|
58
|
-
handleSubmit();
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (key.escape) {
|
|
62
|
-
if (filePath.length > 0) {
|
|
63
|
-
setFilePath('');
|
|
64
|
-
setError(undefined);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
onCancel();
|
|
68
|
-
}
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (key.backspace || key.delete) {
|
|
72
|
-
setFilePath((prev) => prev.slice(0, -1));
|
|
73
|
-
setError(undefined);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (input && !key.ctrl && !key.meta) {
|
|
77
|
-
const cleaned = stripBracketedPaste(input);
|
|
78
|
-
if (cleaned) {
|
|
79
|
-
setFilePath((prev) => prev + cleaned);
|
|
80
|
-
setError(undefined);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}, { isActive });
|
|
84
|
-
return (_jsxs(Box, { borderColor: colors.border, borderStyle: "single", flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { bold: true, color: colors.text, children: ["Connect to ", provider.name] }) }), provider.apiKeyUrl && (_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.dimText, children: ["Get your service account key at:", ' '] }), _jsx(Text, { color: colors.dimText, underline: true, children: provider.apiKeyUrl })] })), _jsx(Box, { marginBottom: 1, children: isValidating ? (_jsx(Text, { color: colors.primary, children: "\u27F3 Validating..." })) : (_jsxs(Box, { children: [_jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: colors.primary, children: ["Service account JSON key file path:", ' '] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: filePath ? colors.text : colors.dimText, children: filePath || '/path/to/service-account.json' }), filePath && _jsx(Text, { color: colors.primary, children: "\u258E" })] }) })] })) }), _jsx(Box, { marginBottom: 1, children: error && !isValidating && (_jsxs(Text, { color: colors.warning, children: ["\u2717 ", error] })) }), !isValidating && (_jsxs(Box, { gap: 2, children: [_jsxs(Text, { color: colors.dimText, children: [_jsx(Text, { color: colors.text, children: "Enter" }), " Submit"] }), _jsxs(Text, { color: colors.dimText, children: [_jsx(Text, { color: colors.text, children: "Esc" }), " ", filePath.length > 0 ? 'Clear' : 'Cancel'] })] }))] }));
|
|
85
|
-
};
|