@orion-agents/orion-code 0.3.4 → 0.3.7
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/CHANGELOG.md +124 -0
- package/README.md +61 -5
- package/README.zh-CN.md +7 -3
- package/dist/commands/context-tool-command-handlers.js +1 -5
- package/dist/commands/registry.js +1 -4
- package/dist/harness/intent.js +69 -16
- package/dist/harness/turn-summary.js +3 -1
- package/dist/memory/embeddings.js +2 -3
- package/dist/memory/prompts.js +1 -1
- package/dist/memory/relevant-finder.js +125 -15
- package/dist/memory/vector-store.js +13 -8
- package/dist/migration/migrate.js +8 -12
- package/dist/runtime/composer/history.js +1 -3
- package/dist/runtime/composer/layout.js +7 -4
- package/dist/runtime/legacy-thread-materializer.d.ts +3 -1
- package/dist/runtime/legacy-thread-materializer.js +15 -3
- package/dist/runtime/product-bootstrap.d.ts +12 -0
- package/dist/runtime/product-bootstrap.js +37 -22
- package/dist/runtime/rich-text/ansi-parser.js +12 -2
- package/dist/runtime/rich-text/layout.js +15 -19
- package/dist/runtime/subagents/budget.js +4 -1
- package/dist/runtime/subagents/policy.js +11 -4
- package/dist/runtime/subagents/provider-gate.js +6 -4
- package/dist/runtime/subagents/research-quality.js +3 -1
- package/dist/runtime/subagents/research-renderer.js +9 -2
- package/dist/runtime/subagents/result-parser.js +18 -7
- package/dist/runtime/thread-event-store.d.ts +5 -3
- package/dist/runtime/thread-event-store.js +29 -8
- package/dist/runtime/thread-projection.d.ts +17 -0
- package/dist/runtime/thread-projection.js +42 -1
- package/dist/runtime/tool-output-presentation.js +7 -7
- package/dist/runtime/turn-controller.js +1 -2
- package/dist/services/auth/auth.js +1 -4
- package/dist/services/auth/aws.js +24 -14
- package/dist/services/auto-fix/autoFixRunner.js +1 -1
- package/dist/services/auto-fix/index.d.ts +1 -1
- package/dist/services/diagnostic-tracking/diagnosticTracking.js +4 -2
- package/dist/services/diagnostic-tracking/index.d.ts +1 -1
- package/dist/services/effort.js +1 -9
- package/dist/services/file-glob.js +3 -4
- package/dist/services/mcp/transports.js +4 -4
- package/dist/services/model-catalog.js +179 -30
- package/dist/services/model-context.js +1 -1
- package/dist/services/provider-resilience/stream-recovery.js +1 -3
- package/dist/services/session-storage.d.ts +28 -3
- package/dist/services/session-storage.js +70 -6
- package/dist/services/smart-routing.js +19 -11
- package/dist/services/verification-profile.js +17 -22
- package/dist/services/web-search-provider.js +21 -9
- package/dist/services/workspace-diff.js +10 -4
- package/dist/skills/builtin/code-review/SKILL.md +1 -1
- package/dist/skills/builtin/security-check/SKILL.md +1 -1
- package/dist/skills/builtin/test-gen/SKILL.md +1 -1
- package/dist/terminal-ui/editor.js +6 -2
- package/dist/terminal-ui/output-queue.js +9 -3
- package/dist/tools/lsp.js +12 -6
- package/dist/tui-core/frame.js +9 -7
- package/dist/tui-ui/transcript-cache.js +6 -6
- package/dist/tui-ui/transcript-inspector-surface.js +4 -1
- package/dist/tui-ui/transcript-inspector.js +3 -8
- package/dist/ui/box.js +14 -7
- package/dist/ui/markdown.js +4 -2
- package/dist/ui/shared/input-frame.js +12 -8
- package/dist/ui/stream-markdown.js +1 -1
- package/dist/ui/tool-preview.js +11 -3
- package/dist/ui/user-input.js +16 -10
- package/dist/web/protocol.d.ts +2 -0
- package/dist/web/protocol.js +1 -0
- package/dist/web/server.js +69 -0
- package/dist/web/session-runtime-registry.d.ts +14 -0
- package/dist/web/session-runtime-registry.js +23 -0
- package/dist/web/workbench-controller.d.ts +55 -0
- package/dist/web/workbench-controller.js +224 -14
- package/dist/web-client/assets/{DiffViewer-D6mG729y.js → DiffViewer-DqbZ02RN.js} +1 -1
- package/dist/web-client/assets/{FilesPanel-CCDoAZ1J.js → FilesPanel-Bu1Ab2kJ.js} +1 -1
- package/dist/web-client/assets/{GitPanel-DtNgiH7A.js → GitPanel-BixIWb4k.js} +1 -1
- package/dist/web-client/assets/ReviewPanel-DsqJpku_.js +1 -0
- package/dist/web-client/assets/{TerminalPanel-CNxMaBLp.js → TerminalPanel-DdjQP2mp.js} +1 -1
- package/dist/web-client/assets/index-30GT9Vnx.js +17 -0
- package/dist/web-client/assets/index-DQfpqPTD.css +1 -0
- package/dist/web-client/index.html +2 -2
- package/npm-shrinkwrap.json +356 -120
- package/package.json +3 -1
- package/dist/web-client/assets/ReviewPanel-CKEBSt6P.js +0 -1
- package/dist/web-client/assets/index-BBvNg3By.css +0 -1
- package/dist/web-client/assets/index-C6TDJwMC.js +0 -17
|
@@ -292,11 +292,13 @@ class VectorStore {
|
|
|
292
292
|
const scopedIds = projectKeys.map(projectKey => this.memoryId(projectKey, name));
|
|
293
293
|
const idPlaceholders = scopedIds.map(() => '?').join(', ');
|
|
294
294
|
const projectPlaceholders = projectKeys.map(() => '?').join(', ');
|
|
295
|
-
const rows = this.db
|
|
295
|
+
const rows = this.db
|
|
296
|
+
.prepare(`
|
|
296
297
|
SELECT id FROM memories
|
|
297
298
|
WHERE id IN (${idPlaceholders})
|
|
298
299
|
OR (id = ? AND project IN (${projectPlaceholders}))
|
|
299
|
-
`)
|
|
300
|
+
`)
|
|
301
|
+
.all(...scopedIds, name, ...projectKeys);
|
|
300
302
|
this.deleteMemoryIds(rows.map(row => row.id));
|
|
301
303
|
}
|
|
302
304
|
/** Search by similarity */
|
|
@@ -409,12 +411,14 @@ class VectorStore {
|
|
|
409
411
|
}
|
|
410
412
|
/** Count rows by project key for storage maintenance diagnostics. */
|
|
411
413
|
getProjectStats() {
|
|
412
|
-
const rows = this.db
|
|
414
|
+
const rows = this.db
|
|
415
|
+
.prepare(`
|
|
413
416
|
SELECT COALESCE(project, 'global') as project, COUNT(*) as rows
|
|
414
417
|
FROM memories
|
|
415
418
|
GROUP BY COALESCE(project, 'global')
|
|
416
419
|
ORDER BY rows DESC, project ASC
|
|
417
|
-
`)
|
|
420
|
+
`)
|
|
421
|
+
.all();
|
|
418
422
|
return rows.map(row => ({ project: row.project, rows: row.rows }));
|
|
419
423
|
}
|
|
420
424
|
/** Delete all rows for projects that are not in validProjectKeys. */
|
|
@@ -430,8 +434,7 @@ class VectorStore {
|
|
|
430
434
|
return { orphanProjects, deletedRows };
|
|
431
435
|
}
|
|
432
436
|
deleteProjectRows(project) {
|
|
433
|
-
const ids = this.db.prepare('SELECT id FROM memories WHERE project = ?').all(project)
|
|
434
|
-
.map(row => row.id);
|
|
437
|
+
const ids = this.db.prepare('SELECT id FROM memories WHERE project = ?').all(project).map(row => row.id);
|
|
435
438
|
if (ids.length === 0)
|
|
436
439
|
return 0;
|
|
437
440
|
this.deleteMemoryIds(ids);
|
|
@@ -449,7 +452,9 @@ class VectorStore {
|
|
|
449
452
|
if (!this.hasTable('memory_vectors') || !this.hasTable('vec_memories') || ids.length === 0)
|
|
450
453
|
return;
|
|
451
454
|
const placeholders = ids.map(() => '?').join(', ');
|
|
452
|
-
this.db
|
|
455
|
+
this.db
|
|
456
|
+
.prepare(`DELETE FROM vec_memories WHERE rowid IN (SELECT vector_rowid FROM memory_vectors WHERE memory_id IN (${placeholders}))`)
|
|
457
|
+
.run(...ids);
|
|
453
458
|
this.db.prepare(`DELETE FROM memory_vectors WHERE memory_id IN (${placeholders})`).run(...ids);
|
|
454
459
|
}
|
|
455
460
|
/** Canonical project key used by v0.2.8+ storage. */
|
|
@@ -467,7 +472,7 @@ class VectorStore {
|
|
|
467
472
|
return projectKey === 'global' ? name : `${projectKey}:${name}`;
|
|
468
473
|
}
|
|
469
474
|
hasTable(name) {
|
|
470
|
-
const row = this.db.prepare(
|
|
475
|
+
const row = this.db.prepare('SELECT name FROM sqlite_master WHERE name = ?').get(name);
|
|
471
476
|
return !!row;
|
|
472
477
|
}
|
|
473
478
|
/** Close database */
|
|
@@ -42,14 +42,7 @@ const PROJECT_RENAME_MAP = [
|
|
|
42
42
|
{ from: 'OPENHORSE.local.md', to: 'ORION.local.md' },
|
|
43
43
|
];
|
|
44
44
|
/** Subdirectories whose contents are copied verbatim. */
|
|
45
|
-
const VERBATIM_DIRS = new Set([
|
|
46
|
-
'projects',
|
|
47
|
-
'skills',
|
|
48
|
-
'cost',
|
|
49
|
-
'cache',
|
|
50
|
-
'backups',
|
|
51
|
-
'migration-logs',
|
|
52
|
-
]);
|
|
45
|
+
const VERBATIM_DIRS = new Set(['projects', 'skills', 'cost', 'cache', 'backups', 'migration-logs']);
|
|
53
46
|
/** Directories whose parent is renamed (e.g. backups → backups/openhorse). */
|
|
54
47
|
const NESTED_DIRS = {
|
|
55
48
|
backups: 'openhorse',
|
|
@@ -144,9 +137,7 @@ function verifySqlite(path) {
|
|
|
144
137
|
try {
|
|
145
138
|
db = (0, vector_store_1.openBetterSqlite3)(path, { readonly: true });
|
|
146
139
|
const result = db.pragma('integrity_check');
|
|
147
|
-
return result?.[0]?.integrity_check === 'ok'
|
|
148
|
-
? { status: 'verified' }
|
|
149
|
-
: { status: 'invalid' };
|
|
140
|
+
return result?.[0]?.integrity_check === 'ok' ? { status: 'verified' } : { status: 'invalid' };
|
|
150
141
|
}
|
|
151
142
|
catch (error) {
|
|
152
143
|
// ABI/module failures are environmental and actionable, not evidence that
|
|
@@ -345,7 +336,12 @@ function migrateProjectFiles(projectPath, options = {}) {
|
|
|
345
336
|
const warnings = [];
|
|
346
337
|
const resolved = (0, path_1.resolve)(projectPath);
|
|
347
338
|
if (!(0, fs_1.existsSync)(resolved)) {
|
|
348
|
-
return {
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
renamed,
|
|
342
|
+
conflicts,
|
|
343
|
+
warnings: [`Project path ${resolved} does not exist.`],
|
|
344
|
+
};
|
|
349
345
|
}
|
|
350
346
|
for (const { from, to } of PROJECT_RENAME_MAP) {
|
|
351
347
|
const srcPath = (0, path_1.join)(resolved, from);
|
|
@@ -29,9 +29,7 @@ function pushHistoryEntry(state, value) {
|
|
|
29
29
|
if (!value)
|
|
30
30
|
return state;
|
|
31
31
|
// Deduplicate consecutive identical.
|
|
32
|
-
const entries = state.entries[state.entries.length - 1] === value
|
|
33
|
-
? state.entries
|
|
34
|
-
: [...state.entries, value];
|
|
32
|
+
const entries = state.entries[state.entries.length - 1] === value ? state.entries : [...state.entries, value];
|
|
35
33
|
// Bound size.
|
|
36
34
|
const trimmed = entries.length > exports.MAX_HISTORY_ENTRIES
|
|
37
35
|
? entries.slice(entries.length - exports.MAX_HISTORY_ENTRIES)
|
|
@@ -124,7 +124,9 @@ function buildPromptVisualLines(value, width, cursor = value.length) {
|
|
|
124
124
|
chunkStart: chunk.start,
|
|
125
125
|
chunkEnd: chunk.end,
|
|
126
126
|
};
|
|
127
|
-
if (cursorInThisLine &&
|
|
127
|
+
if (cursorInThisLine &&
|
|
128
|
+
clampedCursor - lineStart >= chunk.start &&
|
|
129
|
+
clampedCursor - lineStart <= chunk.end) {
|
|
128
130
|
cursorLineIndex = visualLines.length;
|
|
129
131
|
const cursorInChunk = Math.max(0, clampedCursor - lineStart - chunk.start);
|
|
130
132
|
cursorColumn = 5 + (0, string_width_1.default)(chunk.content.slice(0, cursorInChunk));
|
|
@@ -161,9 +163,10 @@ function formatPromptVisualLine(visualLine, width, options = {}) {
|
|
|
161
163
|
const before = content.slice(0, offset);
|
|
162
164
|
const after = content.slice(offset);
|
|
163
165
|
const beforeWithCursor = `${before}${exports.PROMPT_CURSOR_GLYPH}`;
|
|
164
|
-
content =
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
content =
|
|
167
|
+
(0, string_width_1.default)(beforeWithCursor) >= maxContentWidth
|
|
168
|
+
? `${takeVisualWidth(before, maxContentWidth - (0, string_width_1.default)(exports.PROMPT_CURSOR_GLYPH))}${exports.PROMPT_CURSOR_GLYPH}`
|
|
169
|
+
: `${beforeWithCursor}${takeVisualWidth(after, maxContentWidth - (0, string_width_1.default)(beforeWithCursor))}`;
|
|
167
170
|
}
|
|
168
171
|
const raw = `${prefix}${content}`;
|
|
169
172
|
const padding = Math.max(0, promptContentWidth(width) - (0, string_width_1.default)(raw));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RuntimeEventEnvelopeV1 } from './protocol/runtime-protocol-v1';
|
|
2
2
|
import { type LegacySessionImportReceiptV1 } from './legacy-session-importer';
|
|
3
3
|
import { ThreadEventStore, type ThreadCheckpointHeadV1 } from './thread-event-store';
|
|
4
|
-
import { type ThreadProjectionV1 } from './thread-projection';
|
|
4
|
+
import { type ThreadProjectionDigestVersionV1, type ThreadProjectionV1 } from './thread-projection';
|
|
5
5
|
export type LegacyThreadMaterializationBoundaryV1 = 'after_dry_run' | 'after_receipt_staged' | 'after_facts_materialized' | 'after_projection_verified' | 'after_source_recheck' | 'before_index_switch' | 'after_index_switch';
|
|
6
6
|
export interface LegacyThreadMaterializerOptionsV1 {
|
|
7
7
|
readonly projectPath: string;
|
|
@@ -26,6 +26,8 @@ export interface ThreadCutoverIndexEntryV1 {
|
|
|
26
26
|
readonly importDigest: string;
|
|
27
27
|
readonly eventDigest: string;
|
|
28
28
|
readonly projectionDigest: string;
|
|
29
|
+
/** Missing on v0.3.2 cutover entries; inferred against exact known schemes. */
|
|
30
|
+
readonly projectionDigestVersion?: ThreadProjectionDigestVersionV1;
|
|
29
31
|
readonly cursor: number;
|
|
30
32
|
readonly eventLogFile: string;
|
|
31
33
|
readonly projectionFile: string;
|
|
@@ -82,7 +82,7 @@ function materializeLegacyThreadV1(options) {
|
|
|
82
82
|
const existing = current.sessions[options.sessionId];
|
|
83
83
|
const entry = createIndexEntry(options.sessionId, store, plan);
|
|
84
84
|
if (existing) {
|
|
85
|
-
if ((
|
|
85
|
+
if (!sameCutoverEntry(existing, entry, plan.projection)) {
|
|
86
86
|
throw new LegacyThreadMaterializationError('ORION_THREAD_CUTOVER_CONFLICT', `Session ${options.sessionId} already points at a different v2 Thread`);
|
|
87
87
|
}
|
|
88
88
|
mode = 'already_cutover';
|
|
@@ -131,7 +131,10 @@ function openSessionCheckpointStorageV1(projectPathInput, sessionId) {
|
|
|
131
131
|
head.cursor < entry.cursor ||
|
|
132
132
|
!head.verifiedPrefixes.some(prefix => prefix.cursor === entry.cursor &&
|
|
133
133
|
prefix.eventDigest === entry.eventDigest &&
|
|
134
|
-
prefix.projectionDigest === entry.projectionDigest
|
|
134
|
+
prefix.projectionDigest === entry.projectionDigest &&
|
|
135
|
+
(entry.projectionDigestVersion === undefined ||
|
|
136
|
+
prefix.projectionDigestVersion === undefined ||
|
|
137
|
+
prefix.projectionDigestVersion === entry.projectionDigestVersion))) {
|
|
135
138
|
return undefined;
|
|
136
139
|
}
|
|
137
140
|
return Object.freeze({
|
|
@@ -179,7 +182,7 @@ function openSessionStorageV1(projectPathInput, sessionId) {
|
|
|
179
182
|
const store = new thread_event_store_1.ThreadEventStore((0, paths_1.getProjectThreadsV2Dir)(projectPath), entry.threadId, {
|
|
180
183
|
maxReplayEvents: Math.max(10000, entry.cursor),
|
|
181
184
|
});
|
|
182
|
-
const prefixVerified = store.verifyDurablePrefix(entry.cursor, entry.eventDigest, entry.projectionDigest);
|
|
185
|
+
const prefixVerified = store.verifyDurablePrefix(entry.cursor, entry.eventDigest, entry.projectionDigest, entry.projectionDigestVersion);
|
|
183
186
|
// The cutover receipt seals the imported prefix, not the forever-changing
|
|
184
187
|
// head of a live Thread. loadProjection() independently verifies/rebuilds the
|
|
185
188
|
// current cache against the complete hash-chained log.
|
|
@@ -523,6 +526,7 @@ function createIndexEntry(sessionId, store, plan) {
|
|
|
523
526
|
importDigest: plan.receipt.importDigest,
|
|
524
527
|
eventDigest: plan.eventDigest,
|
|
525
528
|
projectionDigest: plan.projection.digest,
|
|
529
|
+
projectionDigestVersion: thread_projection_1.CURRENT_THREAD_PROJECTION_DIGEST_VERSION_V1,
|
|
526
530
|
cursor: plan.events.length,
|
|
527
531
|
eventLogFile: (0, path_1.basename)(store.logPath),
|
|
528
532
|
projectionFile: (0, path_1.basename)(store.projectionPath),
|
|
@@ -530,6 +534,14 @@ function createIndexEntry(sessionId, store, plan) {
|
|
|
530
534
|
cutoverAt: plan.receipt.sourceTimestamp,
|
|
531
535
|
};
|
|
532
536
|
}
|
|
537
|
+
function sameCutoverEntry(existing, next, projection) {
|
|
538
|
+
const { projectionDigest: existingProjectionDigest, projectionDigestVersion: existingProjectionDigestVersion, ...existingIdentity } = existing;
|
|
539
|
+
const { projectionDigest: _nextProjectionDigest, projectionDigestVersion: _nextProjectionDigestVersion, ...nextIdentity } = next;
|
|
540
|
+
void _nextProjectionDigest;
|
|
541
|
+
void _nextProjectionDigestVersion;
|
|
542
|
+
return ((0, canonical_1.canonicalRuntimeJson)(existingIdentity) === (0, canonical_1.canonicalRuntimeJson)(nextIdentity) &&
|
|
543
|
+
(0, thread_projection_1.resolveThreadProjectionDigestVersionV1)(projection, existingProjectionDigest, existingProjectionDigestVersion) !== undefined);
|
|
544
|
+
}
|
|
533
545
|
function assertSourceUnchanged(projectPath, sessionId, expectedImportDigest) {
|
|
534
546
|
const current = (0, legacy_session_importer_1.readLegacySessionMaterializationSnapshotV1)(projectPath, sessionId).receipt;
|
|
535
547
|
if (current.importDigest !== expectedImportDigest) {
|
|
@@ -5,6 +5,18 @@ import type { ThreadSessionRuntimeActivationV1 } from './thread-session-view';
|
|
|
5
5
|
import type { OrionCodeUiRuntime } from './ui-events';
|
|
6
6
|
import type { WorkspaceMutationCoordinatorV1 } from './step-snapshot';
|
|
7
7
|
import { WorkspaceRuntimeKernelV1 } from './workspace-runtime-kernel';
|
|
8
|
+
export interface CreateWorkspaceRuntimeKernelOptionsV1 {
|
|
9
|
+
readonly cwd: string;
|
|
10
|
+
readonly uiRenderer?: UIRenderer;
|
|
11
|
+
readonly onSettingsInvalidated?: (event: SettingsInvalidationV1) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Composition root for one workspace-owned kernel. Web Hosts pool kernels per
|
|
15
|
+
* canonical Workspace so a Context switch can keep running Session actors on
|
|
16
|
+
* the config/Tool/MCP/Settings services they were created with, instead of
|
|
17
|
+
* rebuilding them against whatever Workspace is active at actor-start time.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createWorkspaceRuntimeKernelV1(options: CreateWorkspaceRuntimeKernelOptionsV1): WorkspaceRuntimeKernelV1;
|
|
8
20
|
export interface ProductUiRuntimeBootstrapOptions {
|
|
9
21
|
readonly cwd: string;
|
|
10
22
|
readonly uiRenderer?: UIRenderer;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWorkspaceRuntimeKernelV1 = createWorkspaceRuntimeKernelV1;
|
|
3
4
|
exports.createProductUiRuntime = createProductUiRuntime;
|
|
4
5
|
const path_1 = require("path");
|
|
5
6
|
const prompt_context_1 = require("../memory/prompt-context");
|
|
@@ -25,6 +26,40 @@ const orion_session_runner_1 = require("./orion-session-runner");
|
|
|
25
26
|
const product_orion_runtime_1 = require("./product-orion-runtime");
|
|
26
27
|
const skills_1 = require("./skills");
|
|
27
28
|
const workspace_runtime_kernel_1 = require("./workspace-runtime-kernel");
|
|
29
|
+
/**
|
|
30
|
+
* Composition root for one workspace-owned kernel. Web Hosts pool kernels per
|
|
31
|
+
* canonical Workspace so a Context switch can keep running Session actors on
|
|
32
|
+
* the config/Tool/MCP/Settings services they were created with, instead of
|
|
33
|
+
* rebuilding them against whatever Workspace is active at actor-start time.
|
|
34
|
+
*/
|
|
35
|
+
function createWorkspaceRuntimeKernelV1(options) {
|
|
36
|
+
const canonicalCwd = (0, path_1.resolve)(options.cwd);
|
|
37
|
+
(0, config_dir_1.ensureConfigDir)();
|
|
38
|
+
(0, global_config_1.recordFirstStartTime)();
|
|
39
|
+
const kernelConfig = (0, config_1.loadConfig)(options.uiRenderer ? { ui: { renderer: options.uiRenderer } } : {});
|
|
40
|
+
const kernelTools = (0, first_party_tool_universe_1.createProductionFirstPartyToolUniverseV1)({
|
|
41
|
+
context: {
|
|
42
|
+
cwd: canonicalCwd,
|
|
43
|
+
config: { name: kernelConfig.name, mode: kernelConfig.mode },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
const kernelSkillProvider = (0, skills_1.createProductionFilesystemSkillProviderV1)({
|
|
47
|
+
cwd: canonicalCwd,
|
|
48
|
+
configuredPaths: kernelConfig.skills?.paths,
|
|
49
|
+
});
|
|
50
|
+
const kernelMcpAdapter = (0, mcp_1.createFirstPartyMcpAdapterV1)({
|
|
51
|
+
config: (0, mcp_1.loadFirstPartyMcpConfigurationV1)(),
|
|
52
|
+
baseDirectory: canonicalCwd,
|
|
53
|
+
});
|
|
54
|
+
return new workspace_runtime_kernel_1.WorkspaceRuntimeKernelV1({
|
|
55
|
+
cwd: canonicalCwd,
|
|
56
|
+
config: kernelConfig,
|
|
57
|
+
toolUniverse: kernelTools,
|
|
58
|
+
skillProvider: kernelSkillProvider,
|
|
59
|
+
mcpAdapter: kernelMcpAdapter,
|
|
60
|
+
onSettingsInvalidated: options.onSettingsInvalidated,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
28
63
|
/**
|
|
29
64
|
* Shared product composition root for TUI, terminal, print and Web surfaces.
|
|
30
65
|
*
|
|
@@ -37,29 +72,9 @@ async function createProductUiRuntime(options) {
|
|
|
37
72
|
const ownsWorkspaceRuntimeKernel = options.workspaceRuntimeKernel === undefined;
|
|
38
73
|
let workspaceRuntimeKernel = options.workspaceRuntimeKernel;
|
|
39
74
|
if (!workspaceRuntimeKernel) {
|
|
40
|
-
|
|
41
|
-
(0, global_config_1.recordFirstStartTime)();
|
|
42
|
-
const kernelConfig = (0, config_1.loadConfig)(options.uiRenderer ? { ui: { renderer: options.uiRenderer } } : {});
|
|
43
|
-
const kernelTools = (0, first_party_tool_universe_1.createProductionFirstPartyToolUniverseV1)({
|
|
44
|
-
context: {
|
|
45
|
-
cwd: canonicalCwd,
|
|
46
|
-
config: { name: kernelConfig.name, mode: kernelConfig.mode },
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
const kernelSkillProvider = (0, skills_1.createProductionFilesystemSkillProviderV1)({
|
|
50
|
-
cwd: canonicalCwd,
|
|
51
|
-
configuredPaths: kernelConfig.skills?.paths,
|
|
52
|
-
});
|
|
53
|
-
const kernelMcpAdapter = (0, mcp_1.createFirstPartyMcpAdapterV1)({
|
|
54
|
-
config: (0, mcp_1.loadFirstPartyMcpConfigurationV1)(),
|
|
55
|
-
baseDirectory: canonicalCwd,
|
|
56
|
-
});
|
|
57
|
-
workspaceRuntimeKernel = new workspace_runtime_kernel_1.WorkspaceRuntimeKernelV1({
|
|
75
|
+
workspaceRuntimeKernel = createWorkspaceRuntimeKernelV1({
|
|
58
76
|
cwd: canonicalCwd,
|
|
59
|
-
|
|
60
|
-
toolUniverse: kernelTools,
|
|
61
|
-
skillProvider: kernelSkillProvider,
|
|
62
|
-
mcpAdapter: kernelMcpAdapter,
|
|
77
|
+
uiRenderer: options.uiRenderer,
|
|
63
78
|
onSettingsInvalidated: options.onSettingsInvalidated,
|
|
64
79
|
});
|
|
65
80
|
}
|
|
@@ -204,14 +204,24 @@ function parseSgrParams(params) {
|
|
|
204
204
|
setForeground(change, named('white'));
|
|
205
205
|
break;
|
|
206
206
|
// Unrecognised SGR codes are ignored (they are still valid SGR).
|
|
207
|
-
default:
|
|
207
|
+
default:
|
|
208
|
+
break;
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
if (!hasAny)
|
|
211
212
|
return null;
|
|
212
213
|
return change;
|
|
213
214
|
}
|
|
214
|
-
const VALID_NAMED_COLORS = [
|
|
215
|
+
const VALID_NAMED_COLORS = [
|
|
216
|
+
'black',
|
|
217
|
+
'red',
|
|
218
|
+
'green',
|
|
219
|
+
'yellow',
|
|
220
|
+
'blue',
|
|
221
|
+
'magenta',
|
|
222
|
+
'cyan',
|
|
223
|
+
'white',
|
|
224
|
+
];
|
|
215
225
|
function named(name) {
|
|
216
226
|
// The SGR code mapping only produces valid named colors, but guard anyway.
|
|
217
227
|
const value = VALID_NAMED_COLORS.includes(name)
|
|
@@ -32,10 +32,12 @@ function layoutBlock(block, width, theme, indent) {
|
|
|
32
32
|
return layoutTable(block, width, theme, indent);
|
|
33
33
|
case 'rule': {
|
|
34
34
|
const available = Math.max(1, width - indent);
|
|
35
|
-
return [
|
|
35
|
+
return [
|
|
36
|
+
[
|
|
36
37
|
{ text: ' '.repeat(indent), style: theme('muted') },
|
|
37
38
|
{ text: '─'.repeat(available), style: theme('muted') },
|
|
38
|
-
]
|
|
39
|
+
],
|
|
40
|
+
];
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -80,10 +82,12 @@ function layoutList(block, width, theme, indent) {
|
|
|
80
82
|
return rows;
|
|
81
83
|
}
|
|
82
84
|
function layoutQuote(block, width, theme, indent) {
|
|
83
|
-
const prefix = [
|
|
85
|
+
const prefix = [
|
|
86
|
+
{
|
|
84
87
|
text: `${' '.repeat(normalizeIndent(indent, width))}> `,
|
|
85
88
|
style: theme('muted'),
|
|
86
|
-
}
|
|
89
|
+
},
|
|
90
|
+
];
|
|
87
91
|
const prefixWidth = rowWidth(prefix);
|
|
88
92
|
const childWidth = Math.max(1, width - prefixWidth);
|
|
89
93
|
const rows = [];
|
|
@@ -105,14 +109,9 @@ function layoutCode(lines, width, theme, indent, language) {
|
|
|
105
109
|
const rows = [];
|
|
106
110
|
if (language) {
|
|
107
111
|
const labelStyle = mergeStyles(style, theme('muted'));
|
|
108
|
-
const labelPrefix = safeIndent > 0
|
|
109
|
-
? [{ text: ' '.repeat(safeIndent), style: labelStyle }]
|
|
110
|
-
: [];
|
|
112
|
+
const labelPrefix = safeIndent > 0 ? [{ text: ' '.repeat(safeIndent), style: labelStyle }] : [];
|
|
111
113
|
const label = truncateToWidth(language, available);
|
|
112
|
-
rows.push(clampRow([
|
|
113
|
-
...labelPrefix,
|
|
114
|
-
...padRow([{ text: label, style: labelStyle }], available, labelStyle),
|
|
115
|
-
], width));
|
|
114
|
+
rows.push(clampRow([...labelPrefix, ...padRow([{ text: label, style: labelStyle }], available, labelStyle)], width));
|
|
116
115
|
}
|
|
117
116
|
for (const line of lines.length > 0 ? lines : ['']) {
|
|
118
117
|
const wrapped = wrapStyledSpans([{ text: line, style }], available, false);
|
|
@@ -157,9 +156,7 @@ function layoutTable(block, width, theme, indent) {
|
|
|
157
156
|
if (columnWidth < 4)
|
|
158
157
|
return layoutTableAsKeyValue(block, width, theme, safeIndent);
|
|
159
158
|
const rows = [];
|
|
160
|
-
const indentSpan = safeIndent > 0
|
|
161
|
-
? [{ text: ' '.repeat(safeIndent), style: theme('assistantText') }]
|
|
162
|
-
: [];
|
|
159
|
+
const indentSpan = safeIndent > 0 ? [{ text: ' '.repeat(safeIndent), style: theme('assistantText') }] : [];
|
|
163
160
|
const header = [...indentSpan];
|
|
164
161
|
for (let column = 0; column < columnCount; column++) {
|
|
165
162
|
const text = block.headers[column]?.map(span => span.text).join('') ?? '';
|
|
@@ -195,7 +192,9 @@ function layoutTableAsKeyValue(block, width, theme, indent) {
|
|
|
195
192
|
const value = sourceRow[column] ?? [];
|
|
196
193
|
const prefix = [{ text: `${prefixIndent}${key}: `, style: theme('heading') }];
|
|
197
194
|
const safePrefix = clampRow(prefix, Math.max(1, width - 1));
|
|
198
|
-
const continuation = [
|
|
195
|
+
const continuation = [
|
|
196
|
+
{ text: ' '.repeat(rowWidth(safePrefix)), style: theme('muted') },
|
|
197
|
+
];
|
|
199
198
|
const styledValue = value.map(span => ({
|
|
200
199
|
text: span.text,
|
|
201
200
|
style: resolveSpanStyle(span, theme('assistantText'), theme),
|
|
@@ -214,10 +213,7 @@ function layoutPrefixedSpans(spans, width, firstPrefix, continuationPrefix, soft
|
|
|
214
213
|
return hasContent ? [prefixRow, ...body.map(row => clampRow(row, width))] : [prefixRow];
|
|
215
214
|
}
|
|
216
215
|
const bodyRows = wrapStyledSpans(spans, width - prefixWidth, softWrap);
|
|
217
|
-
return bodyRows.map((row, index) => clampRow([
|
|
218
|
-
...(index === 0 ? firstPrefix : continuationPrefix),
|
|
219
|
-
...row,
|
|
220
|
-
], width));
|
|
216
|
+
return bodyRows.map((row, index) => clampRow([...(index === 0 ? firstPrefix : continuationPrefix), ...row], width));
|
|
221
217
|
}
|
|
222
218
|
function wrapStyledSpans(spans, width, softWrap) {
|
|
223
219
|
const safeWidth = normalizeWidth(width);
|
|
@@ -122,7 +122,10 @@ class SubagentBudgetLedger {
|
|
|
122
122
|
}
|
|
123
123
|
snapshot() {
|
|
124
124
|
const used = (0, types_1.sumSubtaskUsage)(this.reconciled);
|
|
125
|
-
const reservedModelRequests = (0, types_1.sumSubtaskUsage)(Array.from(this.reserved.entries()).map(([, n]) => ({
|
|
125
|
+
const reservedModelRequests = (0, types_1.sumSubtaskUsage)(Array.from(this.reserved.entries()).map(([, n]) => ({
|
|
126
|
+
...types_1.EMPTY_SUBTASK_USAGE,
|
|
127
|
+
modelRequests: n,
|
|
128
|
+
}))).modelRequests;
|
|
126
129
|
const availableModelRequests = this.availableModelRequests();
|
|
127
130
|
return {
|
|
128
131
|
reservedModelRequests,
|
|
@@ -162,7 +162,9 @@ function clampSubagentConfig(config) {
|
|
|
162
162
|
const clamp = (value, bounds) => Math.max(bounds.min, Math.min(bounds.max, Math.floor(value) || bounds.min));
|
|
163
163
|
const roles = Array.from(new Set(config.roles)).filter(r => ['research', 'review', 'test-investigate'].includes(r));
|
|
164
164
|
const clampedRoles = roles.length > 0 ? roles : DEFAULT_ROLES;
|
|
165
|
-
const mode = ['off', 'explicit', 'auto'].includes(config.mode)
|
|
165
|
+
const mode = ['off', 'explicit', 'auto'].includes(config.mode)
|
|
166
|
+
? config.mode
|
|
167
|
+
: 'auto';
|
|
166
168
|
return {
|
|
167
169
|
mode,
|
|
168
170
|
maxParallel: clamp(config.maxParallel, types_1.SUBAGENT_LIMITS.maxParallel),
|
|
@@ -217,9 +219,14 @@ function hasMultipleInvestigationDirections(objective) {
|
|
|
217
219
|
const lower = objective.toLowerCase();
|
|
218
220
|
// Conjunctions that signal multiple independent directions.
|
|
219
221
|
const multiMarkers = [
|
|
220
|
-
/ and /,
|
|
221
|
-
|
|
222
|
-
/
|
|
222
|
+
/ and /,
|
|
223
|
+
/, and /,
|
|
224
|
+
/ or /,
|
|
225
|
+
/ both /,
|
|
226
|
+
/ each /,
|
|
227
|
+
/ parallel/,
|
|
228
|
+
/separately/,
|
|
229
|
+
/independently/,
|
|
223
230
|
/ respectively/,
|
|
224
231
|
// CJK: multiple items or separation
|
|
225
232
|
/(和|与|以及|分别|并行|独立|同时)/,
|
|
@@ -40,9 +40,8 @@ class SubagentProviderGate {
|
|
|
40
40
|
this.cooldownTimer = null;
|
|
41
41
|
const maxConcurrent = Number(options.maxConcurrent);
|
|
42
42
|
// N12: guard against NaN/undefined/negative — clamp to 1 as safe minimum.
|
|
43
|
-
this.maxConcurrent =
|
|
44
|
-
? Math.floor(maxConcurrent)
|
|
45
|
-
: 1;
|
|
43
|
+
this.maxConcurrent =
|
|
44
|
+
Number.isFinite(maxConcurrent) && maxConcurrent >= 1 ? Math.floor(maxConcurrent) : 1;
|
|
46
45
|
this.now = options.now ?? (() => Date.now());
|
|
47
46
|
this.scheduleTimer = options.scheduleTimer ?? defaultScheduleTimer;
|
|
48
47
|
this.sharedGate = options.sharedGate ?? null;
|
|
@@ -179,7 +178,10 @@ exports.SubagentProviderGate = SubagentProviderGate;
|
|
|
179
178
|
function defaultScheduleTimer(fn, ms) {
|
|
180
179
|
const handle = setTimeout(fn, ms);
|
|
181
180
|
// Don't keep the event loop alive solely for a cooldown wake.
|
|
182
|
-
if (typeof handle === 'object' &&
|
|
181
|
+
if (typeof handle === 'object' &&
|
|
182
|
+
handle &&
|
|
183
|
+
'unref' in handle &&
|
|
184
|
+
typeof handle.unref === 'function') {
|
|
183
185
|
handle.unref();
|
|
184
186
|
}
|
|
185
187
|
return {
|
|
@@ -87,7 +87,9 @@ function researchCostSummary(packet, opts = {}) {
|
|
|
87
87
|
if (packet.sources.length > packet.request.maxSources) {
|
|
88
88
|
notes.push(`source count exceeded request budget (${packet.sources.length} > ${packet.request.maxSources})`);
|
|
89
89
|
}
|
|
90
|
-
if (opts.fetchedBytes !== undefined &&
|
|
90
|
+
if (opts.fetchedBytes !== undefined &&
|
|
91
|
+
packet.request.maxFetchBytes > 0 &&
|
|
92
|
+
opts.fetchedBytes > packet.request.maxFetchBytes) {
|
|
91
93
|
notes.push(`fetched bytes exceeded budget (${opts.fetchedBytes} > ${packet.request.maxFetchBytes})`);
|
|
92
94
|
}
|
|
93
95
|
return {
|
|
@@ -126,7 +126,9 @@ function renderTerminal(view) {
|
|
|
126
126
|
}
|
|
127
127
|
function renderPrint(view) {
|
|
128
128
|
// Stable schema text (not raw concatenated claim text).
|
|
129
|
-
const claims = view.claims
|
|
129
|
+
const claims = view.claims
|
|
130
|
+
.map(c => ` - ${c.id}: ${c.verification} (${c.bindingStatus})`)
|
|
131
|
+
.join('\n');
|
|
130
132
|
return [
|
|
131
133
|
`# Research: ${view.objective}`,
|
|
132
134
|
`Status: ${view.stage} | Audit: ${view.auditStatus}`,
|
|
@@ -139,7 +141,12 @@ function renderPrint(view) {
|
|
|
139
141
|
}
|
|
140
142
|
function toLifecycleEvents(view, resolution) {
|
|
141
143
|
const events = [
|
|
142
|
-
{
|
|
144
|
+
{
|
|
145
|
+
type: 'research_started',
|
|
146
|
+
packetId: view.packetId,
|
|
147
|
+
objective: view.objective,
|
|
148
|
+
mode: view.mode,
|
|
149
|
+
},
|
|
143
150
|
];
|
|
144
151
|
for (const s of view.sources) {
|
|
145
152
|
events.push({
|
|
@@ -46,7 +46,9 @@ function parseFindings(raw) {
|
|
|
46
46
|
severity: parseSeverity(obj.severity),
|
|
47
47
|
evidence: str(obj.evidence, 1500),
|
|
48
48
|
file: obj.file != null ? str(obj.file, 500) : undefined,
|
|
49
|
-
line: typeof obj.line === 'number' && Number.isFinite(obj.line)
|
|
49
|
+
line: typeof obj.line === 'number' && Number.isFinite(obj.line)
|
|
50
|
+
? Math.max(0, Math.floor(obj.line))
|
|
51
|
+
: undefined,
|
|
50
52
|
});
|
|
51
53
|
if (out.length >= MAX_FINDINGS)
|
|
52
54
|
break;
|
|
@@ -54,7 +56,11 @@ function parseFindings(raw) {
|
|
|
54
56
|
return out;
|
|
55
57
|
}
|
|
56
58
|
function parseSeverity(value) {
|
|
57
|
-
if (value === 'critical' ||
|
|
59
|
+
if (value === 'critical' ||
|
|
60
|
+
value === 'high' ||
|
|
61
|
+
value === 'medium' ||
|
|
62
|
+
value === 'low' ||
|
|
63
|
+
value === 'info') {
|
|
58
64
|
return value;
|
|
59
65
|
}
|
|
60
66
|
return undefined;
|
|
@@ -163,11 +169,16 @@ function parseSubtaskResult(args) {
|
|
|
163
169
|
function summarizeFailure(status, content) {
|
|
164
170
|
const tail = truncate(content.trim(), 300);
|
|
165
171
|
switch (status) {
|
|
166
|
-
case 'timed_out':
|
|
167
|
-
|
|
168
|
-
case '
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
case 'timed_out':
|
|
173
|
+
return `Child timed out. Partial output: ${tail || '(none)'}`;
|
|
174
|
+
case 'cancelled':
|
|
175
|
+
return `Child was cancelled. Partial output: ${tail || '(none)'}`;
|
|
176
|
+
case 'failed':
|
|
177
|
+
return `Child failed. Output: ${tail || '(none)'}`;
|
|
178
|
+
case 'rejected':
|
|
179
|
+
return `Child was rejected by policy before running.`;
|
|
180
|
+
default:
|
|
181
|
+
return tail || '(no output)';
|
|
171
182
|
}
|
|
172
183
|
}
|
|
173
184
|
//# sourceMappingURL=result-parser.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RuntimeEventEnvelopeV1, type RuntimeEventV1 } from './protocol/runtime-protocol-v1';
|
|
2
|
-
import { type ThreadProjectionV1 } from './thread-projection';
|
|
2
|
+
import { type ThreadProjectionDigestVersionV1, type ThreadProjectionV1 } from './thread-projection';
|
|
3
3
|
import type { CompactAuthoritativeSourceV1, CompactCheckpointCommitReceiptV1, CompactCompareAndCommitInputV1, CompactCompareAndCommitResultV1, CompactRuntimeEventV1 } from './compact-transaction';
|
|
4
4
|
export interface AppendRuntimeEventV1<T extends RuntimeEventV1 = RuntimeEventV1> {
|
|
5
5
|
readonly turnId?: string;
|
|
@@ -14,7 +14,7 @@ export interface ThreadEventReplayV1 {
|
|
|
14
14
|
readonly nextCursor: number;
|
|
15
15
|
readonly hasMore: boolean;
|
|
16
16
|
}
|
|
17
|
-
export type ThreadEventReplayReasonV1 = 'direct' | 'capability_receipt_journal' | 'durable_tool_receipt' | 'legacy_materializer' | 'runtime_diagnostics_legacy' | 'subagent_receipt_journal' | 'thread_session_view' | 'turn_commit_journal' | 'ui_gap_recovery' | 'ui_initial_history';
|
|
17
|
+
export type ThreadEventReplayReasonV1 = 'direct' | 'capability_receipt_journal' | 'durable_tool_receipt' | 'legacy_materializer' | 'projection_schema_upgrade' | 'runtime_diagnostics_legacy' | 'subagent_receipt_journal' | 'thread_session_view' | 'turn_commit_journal' | 'ui_gap_recovery' | 'ui_initial_history';
|
|
18
18
|
export interface ThreadEventCommitV1 {
|
|
19
19
|
readonly events: readonly RuntimeEventEnvelopeV1[];
|
|
20
20
|
readonly projection: ThreadProjectionV1;
|
|
@@ -44,6 +44,8 @@ export interface ThreadVerifiedPrefixV1 {
|
|
|
44
44
|
readonly cursor: number;
|
|
45
45
|
readonly eventDigest: string;
|
|
46
46
|
readonly projectionDigest: string;
|
|
47
|
+
/** Missing on receipts written before projection digests were versioned. */
|
|
48
|
+
readonly projectionDigestVersion?: ThreadProjectionDigestVersionV1;
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
49
51
|
* Crash-safe derived checkpoint for opening a Thread in a fresh process.
|
|
@@ -136,7 +138,7 @@ export declare class ThreadEventStore {
|
|
|
136
138
|
* exact log identity/projection checkpoint remains current. Internal append
|
|
137
139
|
* carries the proof forward because the hash-chained prefix cannot change.
|
|
138
140
|
*/
|
|
139
|
-
verifyDurablePrefix(cursor: number, eventDigest: string, projectionDigest: string): boolean;
|
|
141
|
+
verifyDurablePrefix(cursor: number, eventDigest: string, projectionDigest: string, projectionDigestVersion?: ThreadProjectionDigestVersionV1): boolean;
|
|
140
142
|
getCursor(): number;
|
|
141
143
|
/**
|
|
142
144
|
* Read the compact persisted receipt without parsing the potentially large
|