@orion-agents/orion-code 0.1.4-2 → 0.1.5
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 +50 -20
- package/README.zh-CN.md +6 -5
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/context-commands.d.ts.map +1 -1
- package/dist/commands/context-commands.js +22 -0
- package/dist/commands/context-commands.js.map +1 -1
- package/dist/commands/context-tool-command-handlers.d.ts.map +1 -1
- package/dist/commands/context-tool-command-handlers.js +10 -3
- package/dist/commands/context-tool-command-handlers.js.map +1 -1
- package/dist/commands/core-command-handlers.d.ts +2 -2
- package/dist/commands/core-command-handlers.d.ts.map +1 -1
- package/dist/commands/core-command-handlers.js +65 -58
- package/dist/commands/core-command-handlers.js.map +1 -1
- package/dist/commands/diagnostic-command-handlers.d.ts.map +1 -1
- package/dist/commands/diagnostic-command-handlers.js +5 -5
- package/dist/commands/diagnostic-command-handlers.js.map +1 -1
- package/dist/commands/diagnostic-commands.d.ts.map +1 -1
- package/dist/commands/diagnostic-commands.js +43 -0
- package/dist/commands/diagnostic-commands.js.map +1 -1
- package/dist/commands/index.d.ts +4 -4
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +9 -2
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/legacy-commands.js +2 -2
- package/dist/commands/legacy-commands.js.map +1 -1
- package/dist/commands/model-command-handlers.d.ts +3 -1
- package/dist/commands/model-command-handlers.d.ts.map +1 -1
- package/dist/commands/model-command-handlers.js +293 -81
- package/dist/commands/model-command-handlers.js.map +1 -1
- package/dist/commands/model-commands.d.ts.map +1 -1
- package/dist/commands/model-commands.js +36 -3
- package/dist/commands/model-commands.js.map +1 -1
- package/dist/commands/parser.d.ts +12 -0
- package/dist/commands/parser.d.ts.map +1 -1
- package/dist/commands/parser.js +48 -7
- package/dist/commands/parser.js.map +1 -1
- package/dist/commands/registry.d.ts +4 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +566 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/session-command-handlers.d.ts +2 -1
- package/dist/commands/session-command-handlers.d.ts.map +1 -1
- package/dist/commands/session-command-handlers.js +119 -59
- package/dist/commands/session-command-handlers.js.map +1 -1
- package/dist/commands/session-commands.d.ts.map +1 -1
- package/dist/commands/session-commands.js +24 -0
- package/dist/commands/session-commands.js.map +1 -1
- package/dist/commands/system-commands.d.ts.map +1 -1
- package/dist/commands/system-commands.js +1 -13
- package/dist/commands/system-commands.js.map +1 -1
- package/dist/commands/types.d.ts +65 -1
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js +3 -4
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/workflow-command-handlers.d.ts.map +1 -1
- package/dist/commands/workflow-command-handlers.js +5 -8
- package/dist/commands/workflow-command-handlers.js.map +1 -1
- package/dist/commands/workflow-commands.d.ts.map +1 -1
- package/dist/commands/workflow-commands.js +36 -4
- package/dist/commands/workflow-commands.js.map +1 -1
- package/dist/core/cost-tracker.d.ts +12 -0
- package/dist/core/cost-tracker.d.ts.map +1 -1
- package/dist/core/cost-tracker.js +12 -6
- package/dist/core/cost-tracker.js.map +1 -1
- package/dist/framework/store.d.ts +11 -2
- package/dist/framework/store.d.ts.map +1 -1
- package/dist/framework/store.js +18 -0
- package/dist/framework/store.js.map +1 -1
- package/dist/framework/tool-scheduler.d.ts +1 -1
- package/dist/framework/tool-scheduler.d.ts.map +1 -1
- package/dist/framework/tool-scheduler.js +41 -27
- package/dist/framework/tool-scheduler.js.map +1 -1
- package/dist/framework/tool.d.ts +12 -0
- package/dist/framework/tool.d.ts.map +1 -1
- package/dist/framework/tool.js.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.d.ts +2 -1
- package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.js +103 -31
- package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
- package/dist/memory/storage.d.ts.map +1 -1
- package/dist/memory/storage.js +7 -1
- package/dist/memory/storage.js.map +1 -1
- package/dist/memory/vector-store.d.ts +18 -0
- package/dist/memory/vector-store.d.ts.map +1 -1
- package/dist/memory/vector-store.js +62 -40
- package/dist/memory/vector-store.js.map +1 -1
- package/dist/migration/migrate.d.ts.map +1 -1
- package/dist/migration/migrate.js +11 -5
- package/dist/migration/migrate.js.map +1 -1
- package/dist/print-ui/launch.d.ts +3 -0
- package/dist/print-ui/launch.d.ts.map +1 -1
- package/dist/print-ui/launch.js +10 -3
- package/dist/print-ui/launch.js.map +1 -1
- package/dist/product/paths.d.ts.map +1 -1
- package/dist/product/paths.js +4 -11
- package/dist/product/paths.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts +2 -0
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +127 -14
- package/dist/runtime/agent-runtime-controller.js.map +1 -1
- package/dist/runtime/agent-runtime-protocol.d.ts +15 -0
- package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-protocol.js +6 -0
- package/dist/runtime/agent-runtime-protocol.js.map +1 -1
- package/dist/runtime/chat-controller.d.ts +0 -5
- package/dist/runtime/chat-controller.d.ts.map +1 -1
- package/dist/runtime/chat-controller.js +102 -14
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/chat-effort.d.ts +5 -0
- package/dist/runtime/chat-effort.d.ts.map +1 -0
- package/dist/runtime/chat-effort.js +47 -0
- package/dist/runtime/chat-effort.js.map +1 -0
- package/dist/runtime/goals/prompt.d.ts.map +1 -1
- package/dist/runtime/goals/prompt.js +2 -2
- package/dist/runtime/goals/prompt.js.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.d.ts +2 -0
- package/dist/runtime/rich-text/markdown-parser.d.ts.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.js +50 -10
- package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
- package/dist/runtime/ui-events.d.ts +32 -0
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/runtime/ui-view-model.d.ts +13 -4
- package/dist/runtime/ui-view-model.d.ts.map +1 -1
- package/dist/runtime/ui-view-model.js +64 -10
- package/dist/runtime/ui-view-model.js.map +1 -1
- package/dist/services/concurrent-sessions.d.ts.map +1 -1
- package/dist/services/concurrent-sessions.js +28 -20
- package/dist/services/concurrent-sessions.js.map +1 -1
- package/dist/services/config.d.ts +2 -0
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +1 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/effort.d.ts +40 -0
- package/dist/services/effort.d.ts.map +1 -0
- package/dist/services/effort.js +88 -0
- package/dist/services/effort.js.map +1 -0
- package/dist/services/file-lock.d.ts.map +1 -1
- package/dist/services/file-lock.js +83 -29
- package/dist/services/file-lock.js.map +1 -1
- package/dist/services/global-config.d.ts +7 -0
- package/dist/services/global-config.d.ts.map +1 -1
- package/dist/services/global-config.js +12 -0
- package/dist/services/global-config.js.map +1 -1
- package/dist/services/llm.d.ts +23 -0
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +99 -3
- package/dist/services/llm.js.map +1 -1
- package/dist/services/model-registry.d.ts +3 -0
- package/dist/services/model-registry.d.ts.map +1 -1
- package/dist/services/model-registry.js +59 -2
- package/dist/services/model-registry.js.map +1 -1
- package/dist/services/provider-diagnostics.d.ts +1 -1
- package/dist/services/provider-diagnostics.d.ts.map +1 -1
- package/dist/services/provider-diagnostics.js +30 -16
- package/dist/services/provider-diagnostics.js.map +1 -1
- package/dist/services/provider-resilience/error-classifier.d.ts.map +1 -1
- package/dist/services/provider-resilience/error-classifier.js +15 -0
- package/dist/services/provider-resilience/error-classifier.js.map +1 -1
- package/dist/services/provider-resilience/types.d.ts +1 -1
- package/dist/services/provider-resilience/types.d.ts.map +1 -1
- package/dist/services/provider-resilience/types.js.map +1 -1
- package/dist/services/session-storage.d.ts +4 -0
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +252 -228
- package/dist/services/session-storage.js.map +1 -1
- package/dist/services/storage-maintenance.d.ts.map +1 -1
- package/dist/services/storage-maintenance.js +7 -7
- package/dist/services/storage-maintenance.js.map +1 -1
- package/dist/services/tool-allowlist.d.ts +20 -10
- package/dist/services/tool-allowlist.d.ts.map +1 -1
- package/dist/services/tool-allowlist.js +64 -15
- package/dist/services/tool-allowlist.js.map +1 -1
- package/dist/services/usage-state.d.ts +9 -0
- package/dist/services/usage-state.d.ts.map +1 -1
- package/dist/services/usage-state.js +35 -0
- package/dist/services/usage-state.js.map +1 -1
- package/dist/terminal-ui/launch.d.ts +10 -0
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +58 -37
- package/dist/terminal-ui/launch.js.map +1 -1
- package/dist/tools/bash_security.d.ts +9 -0
- package/dist/tools/bash_security.d.ts.map +1 -1
- package/dist/tools/bash_security.js +32 -0
- package/dist/tools/bash_security.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +40 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +3 -3
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.js +7 -3
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/pickers.d.ts.map +1 -1
- package/dist/tui-ui/pickers.js +1 -0
- package/dist/tui-ui/pickers.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +2 -1
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +17 -29
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +4 -0
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +15 -1
- package/dist/tui-ui/state.js.map +1 -1
- package/package.json +3 -3
|
@@ -12,6 +12,7 @@ exports.getProjectKey = getProjectKey;
|
|
|
12
12
|
exports.isSessionMetaFile = isSessionMetaFile;
|
|
13
13
|
exports.createSession = createSession;
|
|
14
14
|
exports.saveSessionMeta = saveSessionMeta;
|
|
15
|
+
exports.updateSessionEffort = updateSessionEffort;
|
|
15
16
|
exports.loadSessionMeta = loadSessionMeta;
|
|
16
17
|
exports.updateSessionStats = updateSessionStats;
|
|
17
18
|
exports.resumeSession = resumeSession;
|
|
@@ -51,6 +52,7 @@ const child_process_1 = require("child_process");
|
|
|
51
52
|
const path_1 = require("path");
|
|
52
53
|
const config_dir_1 = require("./config-dir");
|
|
53
54
|
const atomic_write_1 = require("./atomic-write");
|
|
55
|
+
const file_lock_1 = require("./file-lock");
|
|
54
56
|
const session_index_1 = require("./session-index");
|
|
55
57
|
const tool_call_groups_1 = require("./compact/tool-call-groups");
|
|
56
58
|
const redaction_1 = require("./redaction");
|
|
@@ -377,105 +379,129 @@ function createSession(projectPath, model) {
|
|
|
377
379
|
function saveSessionMeta(session) {
|
|
378
380
|
(0, config_dir_1.ensureConfigDir)();
|
|
379
381
|
const normalized = normalizeSessionMeta(session);
|
|
380
|
-
const payload = JSON.stringify(normalized, null, 2);
|
|
381
382
|
(0, config_dir_1.ensureProjectDir)(normalized.projectPath);
|
|
382
|
-
|
|
383
|
-
|
|
383
|
+
const metaPath = (0, config_dir_1.getProjectSessionMetaPath)(normalized.projectPath, normalized.id);
|
|
384
|
+
(0, file_lock_1.withFileLockSync)(metaPath, () => {
|
|
385
|
+
writeSessionMetaUnlocked(normalized);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
function writeSessionMetaUnlocked(session) {
|
|
389
|
+
const normalized = normalizeSessionMeta(session);
|
|
390
|
+
(0, config_dir_1.ensureProjectDir)(normalized.projectPath);
|
|
391
|
+
(0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionMetaPath)(normalized.projectPath, normalized.id), JSON.stringify(normalized, null, 2), { mode: 0o600 });
|
|
392
|
+
}
|
|
393
|
+
function findSessionMetaPath(sessionId) {
|
|
394
|
+
const projectsDir = (0, config_dir_1.getProjectsDir)();
|
|
395
|
+
if (!(0, fs_1.existsSync)(projectsDir))
|
|
396
|
+
return null;
|
|
397
|
+
for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
|
|
398
|
+
const path = (0, path_1.join)(projectsDir, projectKey, 'sessions', `${sessionId}.json`);
|
|
399
|
+
if ((0, fs_1.existsSync)(path) && readSessionMetaAtPath(path))
|
|
400
|
+
return path;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
function readSessionMetaAtPath(path) {
|
|
405
|
+
const session = parseSessionMetaFile(path);
|
|
406
|
+
return session ? tryNormalizeSessionMeta(session, path) : null;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Serialize a session read-modify-write transaction across Orion processes.
|
|
410
|
+
* The metadata path is rediscovered before each transaction and re-read only
|
|
411
|
+
* after the lock is held, so a stale snapshot can never overwrite a concurrent
|
|
412
|
+
* message/stat update.
|
|
413
|
+
*/
|
|
414
|
+
function withLockedSession(sessionId, operation) {
|
|
415
|
+
const metaPath = findSessionMetaPath(sessionId);
|
|
416
|
+
if (!metaPath)
|
|
417
|
+
return null;
|
|
418
|
+
return (0, file_lock_1.withFileLockSync)(metaPath, () => {
|
|
419
|
+
const session = readSessionMetaAtPath(metaPath);
|
|
420
|
+
if (!session)
|
|
421
|
+
return null;
|
|
422
|
+
return operation(session);
|
|
423
|
+
}, { waitMs: 10000 });
|
|
424
|
+
}
|
|
425
|
+
function mutateSessionMeta(sessionId, mutation) {
|
|
426
|
+
return withLockedSession(sessionId, session => {
|
|
427
|
+
mutation(session);
|
|
428
|
+
writeSessionMetaUnlocked(session);
|
|
429
|
+
return session;
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
function updateSessionEffort(sessionId, effortPreference) {
|
|
433
|
+
return mutateSessionMeta(sessionId, session => {
|
|
434
|
+
if (effortPreference === undefined || effortPreference === 'auto') {
|
|
435
|
+
delete session.effortPreference;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
session.effortPreference = effortPreference;
|
|
439
|
+
}
|
|
384
440
|
});
|
|
385
441
|
}
|
|
386
442
|
/**
|
|
387
443
|
* 加载会话元数据
|
|
388
444
|
*/
|
|
389
445
|
function loadSessionMeta(sessionId) {
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
|
|
393
|
-
const path = (0, path_1.join)(projectsDir, projectKey, 'sessions', `${sessionId}.json`);
|
|
394
|
-
if (!(0, fs_1.existsSync)(path))
|
|
395
|
-
continue;
|
|
396
|
-
const session = parseSessionMetaFile(path);
|
|
397
|
-
if (session) {
|
|
398
|
-
const normalized = tryNormalizeSessionMeta(session, path);
|
|
399
|
-
if (normalized)
|
|
400
|
-
return normalized;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return null;
|
|
446
|
+
const path = findSessionMetaPath(sessionId);
|
|
447
|
+
return path ? readSessionMetaAtPath(path) : null;
|
|
405
448
|
}
|
|
406
449
|
/**
|
|
407
450
|
* 更新会话统计
|
|
408
451
|
*/
|
|
409
452
|
function updateSessionStats(sessionId, tokens, cost) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
417
|
-
saveSessionMeta(session);
|
|
418
|
-
}
|
|
419
|
-
function touchSession(sessionId, messageDelta = 0) {
|
|
420
|
-
const session = loadSessionMeta(sessionId);
|
|
421
|
-
if (!session)
|
|
422
|
-
return null;
|
|
423
|
-
session.updatedAt = Date.now();
|
|
424
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
425
|
-
session.messageCount = (session.messageCount ?? 0) + messageDelta;
|
|
426
|
-
saveSessionMeta(session);
|
|
427
|
-
return session;
|
|
453
|
+
mutateSessionMeta(sessionId, session => {
|
|
454
|
+
session.tokenCount += tokens;
|
|
455
|
+
session.cost += cost;
|
|
456
|
+
session.updatedAt = Date.now();
|
|
457
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
458
|
+
});
|
|
428
459
|
}
|
|
429
460
|
/**
|
|
430
461
|
* Mark a saved session as active again and refresh project metadata.
|
|
431
462
|
*/
|
|
432
463
|
function resumeSession(sessionId) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
440
|
-
saveSessionMeta(session);
|
|
441
|
-
return session;
|
|
464
|
+
return mutateSessionMeta(sessionId, session => {
|
|
465
|
+
session.endTime = undefined;
|
|
466
|
+
session.gitBranch = getGitBranch(session.projectPath);
|
|
467
|
+
session.updatedAt = Date.now();
|
|
468
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
469
|
+
});
|
|
442
470
|
}
|
|
443
471
|
/** Keep the session metadata's additive Goal binding in sync with its sidecar. */
|
|
444
472
|
function updateSessionGoalBinding(sessionId, goal) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
452
|
-
saveSessionMeta(session);
|
|
453
|
-
return session;
|
|
473
|
+
return mutateSessionMeta(sessionId, session => {
|
|
474
|
+
session.activeGoalId = goal?.goalId;
|
|
475
|
+
session.activeGoalObjective = goal?.objective;
|
|
476
|
+
session.updatedAt = Date.now();
|
|
477
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
478
|
+
});
|
|
454
479
|
}
|
|
455
480
|
/**
|
|
456
481
|
* 更新会话 Harness 状态。
|
|
457
482
|
*/
|
|
458
483
|
function updateSessionHarnessState(sessionId, harnessState) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
484
|
+
withLockedSession(sessionId, session => {
|
|
485
|
+
const fullState = (0, harness_1.upgradeHarnessState)(harnessState, {
|
|
486
|
+
cwd: session.cwd ?? session.projectPath,
|
|
487
|
+
});
|
|
488
|
+
const sidecar = {
|
|
489
|
+
version: 2,
|
|
490
|
+
sessionId,
|
|
491
|
+
projectPath: session.projectPath,
|
|
492
|
+
state: fullState,
|
|
493
|
+
contextCapsule: fullState.capsule,
|
|
494
|
+
updatedAt: Date.now(),
|
|
495
|
+
diagnostics: fullState.diagnostics,
|
|
496
|
+
};
|
|
497
|
+
(0, config_dir_1.ensureProjectDir)(session.projectPath);
|
|
498
|
+
(0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionHarnessPath)(session.projectPath, sessionId), JSON.stringify(sidecar, null, 2), { mode: 0o600 });
|
|
499
|
+
session.harnessState = (0, harness_1.summarizeHarnessStateForMeta)(fullState);
|
|
500
|
+
session.contextCapsule = fullState.capsule;
|
|
501
|
+
session.updatedAt = Date.now();
|
|
502
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
503
|
+
writeSessionMetaUnlocked(session);
|
|
504
|
+
});
|
|
479
505
|
}
|
|
480
506
|
function loadSessionHarnessState(sessionId) {
|
|
481
507
|
const session = loadSessionMeta(sessionId);
|
|
@@ -509,23 +535,18 @@ function loadSessionHarnessState(sessionId) {
|
|
|
509
535
|
function updateSessionSkills(sessionId, skills) {
|
|
510
536
|
if (skills.length === 0)
|
|
511
537
|
return;
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
518
|
-
saveSessionMeta(session);
|
|
538
|
+
mutateSessionMeta(sessionId, session => {
|
|
539
|
+
session.skillsUsed = [...new Set([...(session.skillsUsed || []), ...skills])];
|
|
540
|
+
session.updatedAt = Date.now();
|
|
541
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
542
|
+
});
|
|
519
543
|
}
|
|
520
544
|
function markSessionTranscriptDisplayStart(sessionId, timestamp = Date.now()) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
session.updatedAtIso = new Date(timestamp).toISOString();
|
|
527
|
-
saveSessionMeta(session);
|
|
528
|
-
return session;
|
|
545
|
+
return mutateSessionMeta(sessionId, session => {
|
|
546
|
+
session.transcriptDisplayStartTime = timestamp;
|
|
547
|
+
session.updatedAt = timestamp;
|
|
548
|
+
session.updatedAtIso = new Date(timestamp).toISOString();
|
|
549
|
+
});
|
|
529
550
|
}
|
|
530
551
|
function persistSessionCompactHistory(sessionId, messages, timestamp = Date.now()) {
|
|
531
552
|
const session = loadSessionMeta(sessionId);
|
|
@@ -557,51 +578,53 @@ function loadSessionCompactCheckpoint(sessionId) {
|
|
|
557
578
|
return checkpoint;
|
|
558
579
|
}
|
|
559
580
|
function commitSessionCompactCheckpoint(input) {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
mode: input.mode,
|
|
574
|
-
modelId: input.modelId,
|
|
575
|
-
sourceMessageCount: input.sourceMessageCount,
|
|
576
|
-
transcriptStartMessageIndex: Math.max(0, Math.min(input.sourceMessageCount, input.transcriptStartMessageIndex)),
|
|
577
|
-
modelHistory: input.modelHistory
|
|
578
|
-
.filter(message => message.role !== 'system')
|
|
579
|
-
.map(message => ({ ...message })),
|
|
580
|
-
summary: {
|
|
581
|
-
...input.summary,
|
|
581
|
+
const checkpoint = withLockedSession(input.sessionId, session => {
|
|
582
|
+
const rawCount = readSessionMessagesForSession(session).length;
|
|
583
|
+
if (input.sourceMessageCount < 0 || input.sourceMessageCount > rawCount) {
|
|
584
|
+
throw new Error(`Invalid compact source boundary ${input.sourceMessageCount}; transcript has ${rawCount} messages`);
|
|
585
|
+
}
|
|
586
|
+
const createdAt = input.createdAt ?? Date.now();
|
|
587
|
+
const nextCheckpoint = {
|
|
588
|
+
version: 1,
|
|
589
|
+
checkpointId: (0, crypto_1.randomUUID)(),
|
|
590
|
+
sessionId: input.sessionId,
|
|
591
|
+
createdAt,
|
|
592
|
+
mode: input.mode,
|
|
593
|
+
modelId: input.modelId,
|
|
582
594
|
sourceMessageCount: input.sourceMessageCount,
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
595
|
+
transcriptStartMessageIndex: Math.max(0, Math.min(input.sourceMessageCount, input.transcriptStartMessageIndex)),
|
|
596
|
+
modelHistory: input.modelHistory
|
|
597
|
+
.filter(message => message.role !== 'system')
|
|
598
|
+
.map(message => ({ ...message })),
|
|
599
|
+
summary: {
|
|
600
|
+
...input.summary,
|
|
601
|
+
sourceMessageCount: input.sourceMessageCount,
|
|
602
|
+
},
|
|
603
|
+
beforeUsage: { ...input.beforeUsage },
|
|
604
|
+
afterUsage: { ...input.afterUsage },
|
|
605
|
+
};
|
|
606
|
+
const previousId = session.activeCompactCheckpointId;
|
|
607
|
+
const previousTime = session.lastCompactAt;
|
|
608
|
+
session.activeCompactCheckpointId = nextCheckpoint.checkpointId;
|
|
609
|
+
session.lastCompactAt = createdAt;
|
|
610
|
+
session.updatedAt = createdAt;
|
|
611
|
+
session.updatedAtIso = new Date(createdAt).toISOString();
|
|
612
|
+
// Commit the pointer before replacing the atomic sidecar. If the process
|
|
613
|
+
// crashes between writes, the loader safely uses the last valid sidecar.
|
|
614
|
+
writeSessionMetaUnlocked(session);
|
|
615
|
+
try {
|
|
616
|
+
(0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionCompactPath)(session.projectPath, input.sessionId), JSON.stringify(nextCheckpoint, null, 2), { mode: 0o600 });
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
session.activeCompactCheckpointId = previousId;
|
|
620
|
+
session.lastCompactAt = previousTime;
|
|
621
|
+
writeSessionMetaUnlocked(session);
|
|
622
|
+
throw error;
|
|
623
|
+
}
|
|
624
|
+
return nextCheckpoint;
|
|
625
|
+
});
|
|
626
|
+
if (!checkpoint)
|
|
627
|
+
throw new Error(`Session not found: ${input.sessionId}`);
|
|
605
628
|
return checkpoint;
|
|
606
629
|
}
|
|
607
630
|
function loadSessionTranscriptMessages(sessionId) {
|
|
@@ -625,22 +648,17 @@ function hasPersistedCompactContext(messages) {
|
|
|
625
648
|
* 结束会话
|
|
626
649
|
*/
|
|
627
650
|
function endSession(sessionId) {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
634
|
-
saveSessionMeta(session);
|
|
651
|
+
mutateSessionMeta(sessionId, session => {
|
|
652
|
+
session.endTime = Date.now();
|
|
653
|
+
session.updatedAt = session.endTime;
|
|
654
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
655
|
+
});
|
|
635
656
|
}
|
|
636
657
|
/**
|
|
637
658
|
* 更新会话任务摘要
|
|
638
659
|
* 从会话消息中提取关键信息并更新元数据
|
|
639
660
|
*/
|
|
640
661
|
function updateSessionSummary(sessionId, messages) {
|
|
641
|
-
const session = loadSessionMeta(sessionId);
|
|
642
|
-
if (!session)
|
|
643
|
-
return;
|
|
644
662
|
// 提取工具使用列表
|
|
645
663
|
const toolsUsed = [];
|
|
646
664
|
const filesModified = [];
|
|
@@ -668,14 +686,15 @@ function updateSessionSummary(sessionId, messages) {
|
|
|
668
686
|
// 提取任务摘要(从第一个用户消息)
|
|
669
687
|
const firstUserMsg = messages.find(m => m.role === 'user' && m.content);
|
|
670
688
|
const taskSummary = (0, redaction_1.redactTraceText)(firstUserMsg?.content ?? '').slice(0, 100);
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
689
|
+
mutateSessionMeta(sessionId, session => {
|
|
690
|
+
session.toolsUsed = [...new Set(toolsUsed)]; // unique
|
|
691
|
+
session.filesModified = [...new Set(filesModified)]; // unique
|
|
692
|
+
session.taskSummary =
|
|
693
|
+
taskSummary.length > 100 ? taskSummary.slice(0, 100) + '...' : taskSummary;
|
|
694
|
+
session.messageCount = messages.length;
|
|
695
|
+
session.updatedAt = Date.now();
|
|
696
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
697
|
+
});
|
|
679
698
|
}
|
|
680
699
|
/**
|
|
681
700
|
* 获取项目最近的会话
|
|
@@ -747,15 +766,19 @@ function readProjectHistory(projectPath, limit) {
|
|
|
747
766
|
function appendSessionMessage(sessionId, message) {
|
|
748
767
|
(0, config_dir_1.ensureConfigDir)();
|
|
749
768
|
const line = JSON.stringify(message) + '\n';
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
769
|
+
withLockedSession(sessionId, session => {
|
|
770
|
+
(0, config_dir_1.ensureProjectDir)(session.projectPath);
|
|
771
|
+
(0, fs_1.appendFileSync)((0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath, sessionId), line, {
|
|
772
|
+
mode: 0o600,
|
|
773
|
+
});
|
|
774
|
+
// Keep transcript, metadata, and search index inside the same session
|
|
775
|
+
// critical section so concurrent processes cannot lose counters.
|
|
776
|
+
(0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
|
|
777
|
+
session.updatedAt = Date.now();
|
|
778
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
779
|
+
session.messageCount = (session.messageCount ?? 0) + 1;
|
|
780
|
+
writeSessionMetaUnlocked(session);
|
|
756
781
|
});
|
|
757
|
-
// Update session index for fast search
|
|
758
|
-
(0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
|
|
759
782
|
}
|
|
760
783
|
/**
|
|
761
784
|
* 追加多条会话消息
|
|
@@ -765,16 +788,19 @@ function appendSessionMessages(sessionId, messages) {
|
|
|
765
788
|
return;
|
|
766
789
|
(0, config_dir_1.ensureConfigDir)();
|
|
767
790
|
const lines = messages.map(m => JSON.stringify(m)).join('\n') + '\n';
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
791
|
+
withLockedSession(sessionId, session => {
|
|
792
|
+
(0, config_dir_1.ensureProjectDir)(session.projectPath);
|
|
793
|
+
(0, fs_1.appendFileSync)((0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath, sessionId), lines, {
|
|
794
|
+
mode: 0o600,
|
|
795
|
+
});
|
|
796
|
+
for (const message of messages) {
|
|
797
|
+
(0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
|
|
798
|
+
}
|
|
799
|
+
session.updatedAt = Date.now();
|
|
800
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
801
|
+
session.messageCount = (session.messageCount ?? 0) + messages.length;
|
|
802
|
+
writeSessionMetaUnlocked(session);
|
|
774
803
|
});
|
|
775
|
-
for (const message of messages) {
|
|
776
|
-
(0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
|
|
777
|
-
}
|
|
778
804
|
}
|
|
779
805
|
function isFinalAssistantMessage(message) {
|
|
780
806
|
return message.role === 'assistant' && (!message.tool_calls || message.tool_calls.length === 0);
|
|
@@ -795,24 +821,20 @@ function findLastCompleteBoundary(messages) {
|
|
|
795
821
|
// sliced the prompt away).
|
|
796
822
|
return lastUserIndex + 1;
|
|
797
823
|
}
|
|
798
|
-
function
|
|
799
|
-
(0, config_dir_1.ensureConfigDir)();
|
|
800
|
-
const session = loadSessionMeta(sessionId);
|
|
801
|
-
if (!session)
|
|
802
|
-
return;
|
|
824
|
+
function overwriteSessionMessagesUnlocked(session, messages) {
|
|
803
825
|
const content = messages.length > 0 ? messages.map(message => JSON.stringify(message)).join('\n') + '\n' : '';
|
|
804
826
|
(0, config_dir_1.ensureProjectDir)(session.projectPath);
|
|
805
|
-
(0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath,
|
|
827
|
+
(0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath, session.id), content, {
|
|
806
828
|
mode: 0o600,
|
|
807
829
|
});
|
|
808
|
-
(0, session_index_1.deleteSessionIndex)(
|
|
830
|
+
(0, session_index_1.deleteSessionIndex)(session.id, session.projectPath);
|
|
809
831
|
for (const message of messages) {
|
|
810
|
-
(0, session_index_1.updateSessionIndex)(
|
|
832
|
+
(0, session_index_1.updateSessionIndex)(session.id, session.projectPath, message);
|
|
811
833
|
}
|
|
812
834
|
session.messageCount = messages.length;
|
|
813
835
|
session.updatedAt = Date.now();
|
|
814
836
|
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
815
|
-
|
|
837
|
+
writeSessionMetaUnlocked(session);
|
|
816
838
|
}
|
|
817
839
|
/**
|
|
818
840
|
* Remove a trailing incomplete turn from the persisted session transcript.
|
|
@@ -823,14 +845,15 @@ function overwriteSessionMessages(sessionId, messages) {
|
|
|
823
845
|
* resurrect partial state.
|
|
824
846
|
*/
|
|
825
847
|
function truncateSessionToLastComplete(sessionId) {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
848
|
+
return (withLockedSession(sessionId, session => {
|
|
849
|
+
const messages = readSessionMessagesForSession(session);
|
|
850
|
+
const boundary = findLastCompleteBoundary(messages);
|
|
851
|
+
if (boundary === messages.length)
|
|
852
|
+
return messages;
|
|
853
|
+
const truncated = messages.slice(0, boundary);
|
|
854
|
+
overwriteSessionMessagesUnlocked(session, truncated);
|
|
855
|
+
return truncated;
|
|
856
|
+
}) ?? []);
|
|
834
857
|
}
|
|
835
858
|
function removeLastIncompleteAssistantMessage(sessionId) {
|
|
836
859
|
return truncateSessionToLastComplete(sessionId);
|
|
@@ -843,14 +866,16 @@ function removeLastIncompleteAssistantMessage(sessionId) {
|
|
|
843
866
|
* this is a no-op when the last message is not a user message.
|
|
844
867
|
*/
|
|
845
868
|
function removeTrailingSessionUserMessage(sessionId) {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
869
|
+
return (withLockedSession(sessionId, session => {
|
|
870
|
+
const messages = readSessionMessagesForSession(session);
|
|
871
|
+
if (messages.length === 0)
|
|
872
|
+
return messages;
|
|
873
|
+
if (messages[messages.length - 1].role !== 'user')
|
|
874
|
+
return messages;
|
|
875
|
+
const truncated = messages.slice(0, -1);
|
|
876
|
+
overwriteSessionMessagesUnlocked(session, truncated);
|
|
877
|
+
return truncated;
|
|
878
|
+
}) ?? []);
|
|
854
879
|
}
|
|
855
880
|
/**
|
|
856
881
|
* 读取会话消息
|
|
@@ -859,6 +884,10 @@ function readSessionMessages(sessionId) {
|
|
|
859
884
|
const session = loadSessionMeta(sessionId);
|
|
860
885
|
if (!session)
|
|
861
886
|
return [];
|
|
887
|
+
return readSessionMessagesForSession(session);
|
|
888
|
+
}
|
|
889
|
+
function readSessionMessagesForSession(session) {
|
|
890
|
+
const sessionId = session.id;
|
|
862
891
|
const path = (0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath, sessionId);
|
|
863
892
|
if (!(0, fs_1.existsSync)(path))
|
|
864
893
|
return [];
|
|
@@ -1073,48 +1102,43 @@ function lookupSessionRef(ref, projectPath, options = {}) {
|
|
|
1073
1102
|
* Rename a session for easier picker/resume targeting.
|
|
1074
1103
|
*/
|
|
1075
1104
|
function renameSession(sessionId, name) {
|
|
1076
|
-
const session = loadSessionMeta(sessionId);
|
|
1077
|
-
if (!session)
|
|
1078
|
-
return null;
|
|
1079
1105
|
const trimmed = name.trim();
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1106
|
+
return mutateSessionMeta(sessionId, session => {
|
|
1107
|
+
session.name = trimmed || undefined;
|
|
1108
|
+
session.updatedAt = Date.now();
|
|
1109
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
1110
|
+
});
|
|
1085
1111
|
}
|
|
1086
1112
|
/**
|
|
1087
1113
|
* 删除会话
|
|
1088
1114
|
*/
|
|
1089
1115
|
function deleteSession(sessionId) {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
return false;
|
|
1108
|
-
}
|
|
1109
|
-
if (hadGoal)
|
|
1110
|
-
deleted = true;
|
|
1111
|
-
(0, session_index_1.deleteSessionIndex)(sessionId, session.projectPath);
|
|
1112
|
-
for (const path of uniquePaths(paths)) {
|
|
1113
|
-
if ((0, fs_1.existsSync)(path)) {
|
|
1114
|
-
(0, fs_1.unlinkSync)(path);
|
|
1116
|
+
return (withLockedSession(sessionId, session => {
|
|
1117
|
+
let deleted = false;
|
|
1118
|
+
const paths = [
|
|
1119
|
+
(0, config_dir_1.getProjectSessionMetaPath)(session.projectPath, sessionId),
|
|
1120
|
+
(0, config_dir_1.getProjectSessionMessagesPath)(session.projectPath, sessionId),
|
|
1121
|
+
(0, config_dir_1.getProjectSessionHarnessPath)(session.projectPath, sessionId),
|
|
1122
|
+
(0, config_dir_1.getProjectSessionCompactPath)(session.projectPath, sessionId),
|
|
1123
|
+
(0, config_dir_1.getProjectSessionTracePath)(session.projectPath, sessionId),
|
|
1124
|
+
];
|
|
1125
|
+
// Preserve a durable deletion fence so a stale writer in another process
|
|
1126
|
+
// cannot recreate the Goal after the rest of the session is removed.
|
|
1127
|
+
const goalPath = (0, path_1.join)((0, config_dir_1.getProjectSessionsDir)(session.projectPath), `${sessionId}.goal.json`);
|
|
1128
|
+
const hadGoal = (0, fs_1.existsSync)(goalPath);
|
|
1129
|
+
const goalDeletion = (0, goal_storage_1.deleteGoal)(session.projectPath, sessionId);
|
|
1130
|
+
if (!goalDeletion.ok)
|
|
1131
|
+
return false;
|
|
1132
|
+
if (hadGoal)
|
|
1115
1133
|
deleted = true;
|
|
1134
|
+
(0, session_index_1.deleteSessionIndex)(sessionId, session.projectPath);
|
|
1135
|
+
for (const path of uniquePaths(paths)) {
|
|
1136
|
+
if ((0, fs_1.existsSync)(path)) {
|
|
1137
|
+
(0, fs_1.unlinkSync)(path);
|
|
1138
|
+
deleted = true;
|
|
1139
|
+
}
|
|
1116
1140
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1141
|
+
return deleted;
|
|
1142
|
+
}) ?? false);
|
|
1119
1143
|
}
|
|
1120
1144
|
//# sourceMappingURL=session-storage.js.map
|