@orion-agents/orion-code 0.3.21 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +67 -6
  2. package/README.md +6 -6
  3. package/README.zh-CN.md +5 -5
  4. package/dist/harness/failure-attribution.d.ts +23 -0
  5. package/dist/harness/failure-attribution.js +103 -0
  6. package/dist/harness/verified-repair.d.ts +71 -0
  7. package/dist/harness/verified-repair.js +212 -0
  8. package/dist/product/paths.d.ts +20 -1
  9. package/dist/product/paths.js +293 -10
  10. package/dist/runtime/release-receipts.d.ts +3 -3
  11. package/dist/runtime/release-receipts.js +29 -0
  12. package/dist/runtime/tool-gateway.d.ts +6 -0
  13. package/dist/runtime/tool-gateway.js +37 -7
  14. package/dist/services/config-dir.d.ts +3 -2
  15. package/dist/services/config-dir.js +6 -29
  16. package/dist/services/repo-intelligence/index.d.ts +11 -0
  17. package/dist/services/repo-intelligence/index.js +20 -0
  18. package/dist/services/repo-intelligence/recall.d.ts +44 -0
  19. package/dist/services/repo-intelligence/recall.js +115 -0
  20. package/dist/services/repo-intelligence/symbol-index.d.ts +52 -0
  21. package/dist/services/repo-intelligence/symbol-index.js +258 -0
  22. package/dist/services/session-storage.d.ts +18 -2
  23. package/dist/services/session-storage.js +196 -60
  24. package/dist/web/protocol.d.ts +8 -0
  25. package/dist/web/workbench-controller.js +46 -2
  26. package/dist/web-client/assets/{FilesPanel-CKeXPofZ.js → FilesPanel-BjEDjE7l.js} +1 -1
  27. package/dist/web-client/assets/{GitPanel-DollPxv0.js → GitPanel-DvgAZDRA.js} +1 -1
  28. package/dist/web-client/assets/{ReviewPanel-CNADacIn.js → ReviewPanel-BMPaYKDY.js} +1 -1
  29. package/dist/web-client/assets/{TerminalPanel-Cyns4uJt.js → TerminalPanel-Da1ZEhGF.js} +1 -1
  30. package/dist/web-client/assets/index-DZOlUgt6.js +20 -0
  31. package/dist/web-client/assets/{useAutoNotice-BLADeFFj.js → useAutoNotice-Ylj5bfSH.js} +1 -1
  32. package/dist/web-client/index.html +1 -1
  33. package/npm-shrinkwrap.json +2 -2
  34. package/package.json +1 -1
  35. package/dist/services/auto-fix/autoFixConfig.d.ts +0 -30
  36. package/dist/services/auto-fix/autoFixConfig.js +0 -78
  37. package/dist/services/auto-fix/autoFixHook.d.ts +0 -27
  38. package/dist/services/auto-fix/autoFixHook.js +0 -99
  39. package/dist/services/auto-fix/autoFixRunner.d.ts +0 -60
  40. package/dist/services/auto-fix/autoFixRunner.js +0 -207
  41. package/dist/services/auto-fix/index.d.ts +0 -7
  42. package/dist/services/auto-fix/index.js +0 -17
  43. package/dist/web-client/assets/index-BhGhORAX.js +0 -20
@@ -7,7 +7,7 @@
7
7
  * of concatenating ".orion-code" directly.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.PROJECT_CONFIG_CANDIDATES = void 0;
10
+ exports.PROJECT_CONFIG_CANDIDATES = exports.ProjectStorageIdentityUnavailableError = void 0;
11
11
  exports.getConfigHome = getConfigHome;
12
12
  exports.getConfigDir = getConfigDir;
13
13
  exports.getGlobalConfigPath = getGlobalConfigPath;
@@ -20,7 +20,10 @@ exports.getMcpConfigPath = getMcpConfigPath;
20
20
  exports.getProjectsDir = getProjectsDir;
21
21
  exports.getGlobalEnvPath = getGlobalEnvPath;
22
22
  exports.encodeProjectPath = encodeProjectPath;
23
+ exports.resolveProjectStorageIdentityAsync = resolveProjectStorageIdentityAsync;
24
+ exports.assertProjectStorageIdentity = assertProjectStorageIdentity;
23
25
  exports.resolveProjectStoragePath = resolveProjectStoragePath;
26
+ exports.resolveProjectStoragePathAsync = resolveProjectStoragePathAsync;
24
27
  exports.getCanonicalProjectKey = getCanonicalProjectKey;
25
28
  exports.getProjectDir = getProjectDir;
26
29
  exports.getProjectMetadataPath = getProjectMetadataPath;
@@ -46,6 +49,7 @@ exports.getMemoryPath = getMemoryPath;
46
49
  exports.getExistingMemoryPaths = getExistingMemoryPaths;
47
50
  exports.ensureConfigDir = ensureConfigDir;
48
51
  exports.ensureProjectDir = ensureProjectDir;
52
+ exports.ensureResolvedProjectDir = ensureResolvedProjectDir;
49
53
  exports.getProjectInstructionsPath = getProjectInstructionsPath;
50
54
  exports.getProjectSkillsDir = getProjectSkillsDir;
51
55
  const os_1 = require("os");
@@ -108,30 +112,296 @@ function encodeProjectPath(projectPath) {
108
112
  const suffix = (0, crypto_1.createHash)('sha256').update(normalized).digest('hex').slice(0, 8);
109
113
  return `${encoded || 'root'}-${suffix}`;
110
114
  }
111
- /** Resolve a project path for storage identity. */
115
+ const projectStorageIdentities = new Map();
116
+ const MAX_PROJECT_STORAGE_IDENTITIES = 256;
117
+ const pendingProjectStorageIdentities = new Map();
118
+ /** Interactive Hosts must not persist an unverified Git project identity. */
119
+ class ProjectStorageIdentityUnavailableError extends Error {
120
+ constructor(message = 'Git 项目身份暂时无法确认,请检查本地 Git 后重试;未创建会话。') {
121
+ super(message);
122
+ this.code = 'project_storage_identity_unavailable';
123
+ this.name = 'ProjectStorageIdentityUnavailableError';
124
+ }
125
+ }
126
+ exports.ProjectStorageIdentityUnavailableError = ProjectStorageIdentityUnavailableError;
127
+ function gitIdentityFileFingerprint(path) {
128
+ try {
129
+ const file = (0, fs_1.statSync)(path);
130
+ return [file.dev, file.ino, file.mode, file.size, file.mtimeMs, file.ctimeMs].join(':');
131
+ }
132
+ catch {
133
+ return 'missing';
134
+ }
135
+ }
136
+ /** Git's small pointer files, not repository contents, identify external gitdirs. */
137
+ function readGitIdentityPointer(path) {
138
+ try {
139
+ const file = (0, fs_1.statSync)(path);
140
+ if (!file.isFile() || file.size > 4096)
141
+ return undefined;
142
+ return (0, fs_1.readFileSync)(path, 'utf-8').trim();
143
+ }
144
+ catch {
145
+ return undefined;
146
+ }
147
+ }
148
+ /**
149
+ * Track the nearest Git boundary without spawning Git. New nested repos,
150
+ * removed/replaced .git markers, root-affecting Git configuration and symlink
151
+ * retargeting invalidate identities; ordinary Git object/ref writes do not.
152
+ */
153
+ function projectStorageFingerprint(canonicalPath) {
154
+ let directory = canonicalPath;
155
+ while (true) {
156
+ try {
157
+ const markerPath = (0, path_1.join)(directory, '.git');
158
+ const marker = (0, fs_1.statSync)(markerPath);
159
+ const markerIdentity = marker.isDirectory()
160
+ ? [marker.dev, marker.ino, marker.mode]
161
+ : [marker.dev, marker.ino, marker.mode, marker.size, marker.mtimeMs, marker.ctimeMs];
162
+ const pointer = marker.isDirectory() ? undefined : readGitIdentityPointer(markerPath);
163
+ const gitDirectory = marker.isDirectory()
164
+ ? markerPath
165
+ : pointer?.startsWith('gitdir: ')
166
+ ? (0, path_1.resolve)(directory, pointer.slice('gitdir: '.length))
167
+ : undefined;
168
+ const configIdentity = [];
169
+ if (gitDirectory) {
170
+ configIdentity.push(gitDirectory, gitIdentityFileFingerprint((0, path_1.join)(gitDirectory, 'config')), gitIdentityFileFingerprint((0, path_1.join)(gitDirectory, 'config.worktree')));
171
+ // Linked worktrees keep shared configuration outside their own gitdir.
172
+ // Track both the pointer and shared config, including enabling/disabling
173
+ // extensions.worktreeConfig, without running another Git subprocess.
174
+ const commonPointerPath = (0, path_1.join)(gitDirectory, 'commondir');
175
+ const commonPointer = readGitIdentityPointer(commonPointerPath);
176
+ configIdentity.push(gitIdentityFileFingerprint(commonPointerPath));
177
+ if (commonPointer) {
178
+ const commonDirectory = (0, path_1.resolve)(gitDirectory, commonPointer);
179
+ configIdentity.push(commonDirectory, gitIdentityFileFingerprint((0, path_1.join)(commonDirectory, 'config')));
180
+ }
181
+ }
182
+ return {
183
+ fingerprint: `${directory}:${markerIdentity.join(':')}|${configIdentity.join('|')}`,
184
+ hasGitBoundary: true,
185
+ };
186
+ }
187
+ catch {
188
+ // No readable Git marker at this level; check its parent.
189
+ }
190
+ const parent = (0, path_1.dirname)(directory);
191
+ if (parent === directory)
192
+ return { fingerprint: 'folder', hasGitBoundary: false };
193
+ directory = parent;
194
+ }
195
+ }
196
+ function storageOperationFingerprintUnchecked(projectPath) {
197
+ const absolute = (0, path_1.resolve)(projectPath);
198
+ const exists = (0, fs_1.existsSync)(absolute);
199
+ const canonical = exists ? (0, fs_1.realpathSync)(absolute) : absolute;
200
+ const directory = exists ? (0, fs_1.statSync)(canonical) : undefined;
201
+ const gitEnvironment = Object.entries(process.env)
202
+ .filter(([key]) => key.startsWith('GIT_'))
203
+ .sort(([left], [right]) => left.localeCompare(right));
204
+ const external = ['GIT_DIR', 'GIT_COMMON_DIR', 'GIT_WORK_TREE'].map(key => {
205
+ const value = process.env[key];
206
+ if (!value)
207
+ return '';
208
+ const path = (0, path_1.resolve)(canonical, value);
209
+ const target = (0, fs_1.existsSync)(path) ? (0, fs_1.realpathSync)(path) : path;
210
+ const common = readGitIdentityPointer((0, path_1.join)(target, 'commondir'));
211
+ return [
212
+ target,
213
+ gitIdentityFileFingerprint((0, path_1.join)(target, 'config')),
214
+ gitIdentityFileFingerprint((0, path_1.join)(target, 'config.worktree')),
215
+ gitIdentityFileFingerprint((0, path_1.join)(target, 'commondir')),
216
+ common ? gitIdentityFileFingerprint((0, path_1.join)((0, path_1.resolve)(target, common), 'config')) : '',
217
+ ].join('|');
218
+ });
219
+ return JSON.stringify([
220
+ canonical,
221
+ directory ? [directory.dev, directory.ino, directory.mode] : 'missing',
222
+ projectStorageFingerprint(canonical).fingerprint,
223
+ gitEnvironment,
224
+ external,
225
+ ]);
226
+ }
227
+ function storageOperationFingerprint(projectPath) {
228
+ try {
229
+ return storageOperationFingerprintUnchecked(projectPath);
230
+ }
231
+ catch {
232
+ throw new ProjectStorageIdentityUnavailableError('Project storage path changed or became unavailable. Retry.');
233
+ }
234
+ }
235
+ async function resolveProjectStorageIdentityAsync(projectPath) {
236
+ const requestedPath = (0, path_1.resolve)(projectPath);
237
+ const before = storageOperationFingerprint(requestedPath);
238
+ const canonicalPath = await resolveProjectStoragePathAsync(requestedPath);
239
+ if (storageOperationFingerprint(requestedPath) !== before) {
240
+ throw new ProjectStorageIdentityUnavailableError('Project storage identity changed. Retry.');
241
+ }
242
+ return Object.freeze({
243
+ requestedPath,
244
+ canonicalPath,
245
+ projectKey: encodeProjectPath(canonicalPath),
246
+ fingerprint: JSON.stringify([before, storageOperationFingerprint(canonicalPath)]),
247
+ });
248
+ }
249
+ /** Cheap lock-admission validation: filesystem/environment only, no Git spawn. */
250
+ function assertProjectStorageIdentity(identity) {
251
+ if (JSON.stringify([
252
+ storageOperationFingerprint(identity.requestedPath),
253
+ storageOperationFingerprint(identity.canonicalPath),
254
+ ]) !== identity.fingerprint) {
255
+ throw new ProjectStorageIdentityUnavailableError('Project storage identity changed while waiting. Retry.');
256
+ }
257
+ }
258
+ /** Resolve a project path for storage identity with bounded, invalidatable reuse. */
112
259
  function resolveProjectStoragePath(projectPath) {
113
260
  const absolute = (0, path_1.resolve)(projectPath);
114
261
  if ((0, fs_1.existsSync)(absolute)) {
262
+ let canonical = absolute;
263
+ try {
264
+ canonical = (0, fs_1.realpathSync)(absolute);
265
+ }
266
+ catch {
267
+ return absolute;
268
+ }
269
+ // Explicit external Git configuration can change identity independently of
270
+ // the local .git boundary. Preserve its live Git semantics rather than cache it.
271
+ const cacheable = !process.env.GIT_DIR && !process.env.GIT_WORK_TREE && !process.env.GIT_COMMON_DIR;
272
+ const boundary = projectStorageFingerprint(canonical);
273
+ const fingerprint = [
274
+ boundary.fingerprint,
275
+ process.env.GIT_CEILING_DIRECTORIES ?? '',
276
+ process.env.GIT_DISCOVERY_ACROSS_FILESYSTEM ?? '',
277
+ ].join('|');
278
+ const cached = cacheable ? projectStorageIdentities.get(canonical) : undefined;
279
+ if (cached?.fingerprint === fingerprint && (0, fs_1.existsSync)(cached.path)) {
280
+ projectStorageIdentities.delete(canonical);
281
+ projectStorageIdentities.set(canonical, cached);
282
+ return cached.path;
283
+ }
284
+ let resolvedPath = canonical;
285
+ let gitResolved = false;
115
286
  try {
116
287
  const root = (0, child_process_1.execFileSync)('git', ['-C', absolute, 'rev-parse', '--show-toplevel'], {
117
288
  encoding: 'utf-8',
118
289
  stdio: ['ignore', 'pipe', 'ignore'],
290
+ timeout: 250,
291
+ killSignal: 'SIGKILL',
292
+ maxBuffer: 4096,
293
+ env: process.env,
119
294
  }).trim();
120
- if (root)
121
- return (0, fs_1.realpathSync)(root);
295
+ if (root) {
296
+ resolvedPath = (0, fs_1.realpathSync)(root);
297
+ gitResolved = true;
298
+ }
122
299
  }
123
300
  catch {
124
- // Not a git worktree.
301
+ // Unavailable Git falls back to the existing canonical-folder identity.
125
302
  }
126
- try {
127
- return (0, fs_1.realpathSync)(absolute);
128
- }
129
- catch {
130
- return absolute;
303
+ // A failure under a real Git boundary may be transient. Do not pin its
304
+ // fallback folder identity; a later successful probe must recover the root.
305
+ if (cacheable && (gitResolved || !boundary.hasGitBoundary)) {
306
+ projectStorageIdentities.set(canonical, { fingerprint, path: resolvedPath });
307
+ if (projectStorageIdentities.size > MAX_PROJECT_STORAGE_IDENTITIES) {
308
+ const oldest = projectStorageIdentities.keys().next().value;
309
+ if (oldest)
310
+ projectStorageIdentities.delete(oldest);
311
+ }
131
312
  }
313
+ return resolvedPath;
132
314
  }
133
315
  return absolute;
134
316
  }
317
+ /** Pre-resolve interactive Host identities without blocking its event loop. */
318
+ async function resolveProjectStoragePathAsync(projectPath) {
319
+ const absolute = (0, path_1.resolve)(projectPath);
320
+ if (!(0, fs_1.existsSync)(absolute))
321
+ return absolute;
322
+ let canonical;
323
+ try {
324
+ canonical = (0, fs_1.realpathSync)(absolute);
325
+ }
326
+ catch {
327
+ throw new ProjectStorageIdentityUnavailableError('Project storage path became unavailable. Retry.');
328
+ }
329
+ const cacheable = !process.env.GIT_DIR && !process.env.GIT_WORK_TREE && !process.env.GIT_COMMON_DIR;
330
+ const boundary = projectStorageFingerprint(canonical);
331
+ const operationFingerprint = storageOperationFingerprint(absolute);
332
+ const fingerprint = [
333
+ boundary.fingerprint,
334
+ process.env.GIT_CEILING_DIRECTORIES ?? '',
335
+ process.env.GIT_DISCOVERY_ACROSS_FILESYSTEM ?? '',
336
+ ].join('|');
337
+ const cached = cacheable ? projectStorageIdentities.get(canonical) : undefined;
338
+ if (cached?.fingerprint === fingerprint && (0, fs_1.existsSync)(cached.path))
339
+ return cached.path;
340
+ const pendingKey = `${canonical}|${fingerprint}`;
341
+ const pending = cacheable ? pendingProjectStorageIdentities.get(pendingKey) : undefined;
342
+ if (pending)
343
+ return pending;
344
+ const probe = new Promise((resolveIdentity, rejectIdentity) => {
345
+ (0, child_process_1.execFile)('git', ['-C', absolute, 'rev-parse', '--show-toplevel'], {
346
+ encoding: 'utf-8',
347
+ timeout: 250,
348
+ killSignal: 'SIGKILL',
349
+ maxBuffer: 4096,
350
+ env: process.env,
351
+ }, (error, stdout) => {
352
+ let currentFingerprint;
353
+ try {
354
+ currentFingerprint = storageOperationFingerprint(absolute);
355
+ }
356
+ catch (failure) {
357
+ rejectIdentity(failure);
358
+ return;
359
+ }
360
+ if (currentFingerprint !== operationFingerprint) {
361
+ rejectIdentity(new ProjectStorageIdentityUnavailableError('Project storage identity changed during Git discovery. Retry.'));
362
+ return;
363
+ }
364
+ if (boundary.hasGitBoundary && (error || !stdout.trim())) {
365
+ rejectIdentity(new ProjectStorageIdentityUnavailableError());
366
+ return;
367
+ }
368
+ let result = canonical;
369
+ let gitResolved = false;
370
+ if (!error && stdout.trim()) {
371
+ try {
372
+ result = (0, fs_1.realpathSync)(stdout.trim());
373
+ gitResolved = true;
374
+ }
375
+ catch {
376
+ if (boundary.hasGitBoundary) {
377
+ rejectIdentity(new ProjectStorageIdentityUnavailableError());
378
+ return;
379
+ }
380
+ }
381
+ }
382
+ // Never seed a completed probe under a boundary changed while it ran.
383
+ if (cacheable && (gitResolved || !boundary.hasGitBoundary)) {
384
+ projectStorageIdentities.set(canonical, { fingerprint, path: result });
385
+ if (projectStorageIdentities.size > MAX_PROJECT_STORAGE_IDENTITIES) {
386
+ const oldest = projectStorageIdentities.keys().next().value;
387
+ if (oldest)
388
+ projectStorageIdentities.delete(oldest);
389
+ }
390
+ }
391
+ resolveIdentity(result);
392
+ });
393
+ });
394
+ if (cacheable)
395
+ pendingProjectStorageIdentities.set(pendingKey, probe);
396
+ try {
397
+ return await probe;
398
+ }
399
+ finally {
400
+ if (pendingProjectStorageIdentities.get(pendingKey) === probe) {
401
+ pendingProjectStorageIdentities.delete(pendingKey);
402
+ }
403
+ }
404
+ }
135
405
  function getCanonicalProjectKey(projectPath) {
136
406
  return encodeProjectPath(resolveProjectStoragePath(projectPath));
137
407
  }
@@ -246,6 +516,19 @@ function ensureProjectDir(projectPath) {
246
516
  const { updateProjectMetadata } = require('../services/config-dir');
247
517
  updateProjectMetadata(projectPath);
248
518
  }
519
+ /** Use the already-verified identity; do not re-probe Git under explicit env. */
520
+ function ensureResolvedProjectDir(identity) {
521
+ assertProjectStorageIdentity(identity);
522
+ ensureConfigDir();
523
+ const projectDir = (0, path_1.join)(getProjectsDir(), identity.projectKey);
524
+ const sessionsDir = (0, path_1.join)(projectDir, 'sessions');
525
+ (0, fs_1.mkdirSync)(sessionsDir, { recursive: true, mode: 0o700 });
526
+ sweepStorageDirectory(projectDir);
527
+ sweepStorageDirectory(sessionsDir);
528
+ const { updateProjectMetadata } = require('../services/config-dir');
529
+ updateProjectMetadata(identity.canonicalPath, new Date(), identity);
530
+ return sessionsDir;
531
+ }
249
532
  // ── Project filesystem scanning ─────────────────────────────────────────────
250
533
  /** Ordered project config candidate files (relative to project root). */
251
534
  exports.PROJECT_CONFIG_CANDIDATES = [
@@ -7,7 +7,7 @@ export declare const WEB_E2E_LEGACY_SCENARIOS_V1: readonly ["E2E-P0-01", "E2E-P0
7
7
  export declare const WEB_E2E_WEB31_SCENARIOS_V1: readonly ["WEB31-P0-01", "WEB31-P0-02", "WEB31-P0-03", "WEB31-P0-04", "WEB31-P0-05", "WEB31-P0-06", "WEB31-P0-07", "WEB31-P0-08", "WEB31-P0-09", "WEB31-P0-10", "WEB31-P0-11", "WEB31-P0-12"];
8
8
  export declare const WEB_E2E_WEB32_SCENARIOS_V1: readonly ["WEB32-P0-01", "WEB32-P0-02", "WEB32-P0-03", "WEB32-P0-04", "WEB32-P0-05", "WEB32-P0-06", "WEB32-P0-07", "WEB32-P0-08", "WEB32-P0-09", "WEB32-P0-10", "WEB32-P0-11", "WEB32-P0-12"];
9
9
  export declare const WEB_E2E_WEB33_THEME_SCENARIOS_V1: readonly ["WEB33-P0-01", "WEB33-P0-02", "WEB33-P0-03", "WEB33-P0-04", "WEB33-P0-05", "WEB33-P0-06", "WEB33-P0-07", "WEB33-P0-08", "WEB33-P0-09", "WEB33-P0-10", "WEB33-P0-11", "WEB33-P0-12"];
10
- export declare const WEB_E2E_WEB33_SESSION_SCENARIOS_V1: readonly ["WEB33-P0-16", "WEB33-P0-17", "WEB33-P0-18", "WEB33-P0-19", "WEB33-P0-20", "WEB33-P0-21", "WEB33-P0-22", "WEB33-P0-23", "WEB33-P0-24"];
10
+ export declare const WEB_E2E_WEB33_SESSION_SCENARIOS_V1: readonly ["WEB33-P0-16", "WEB33-P0-17", "WEB33-P0-18", "WEB33-P0-19", "WEB33-P0-20", "WEB33-P0-21", "WEB33-P0-22", "WEB33-P0-23", "WEB33-P0-24", "WEB33-P0-44", "WEB33-P0-45", "WEB33-P0-46", "WEB33-P0-47", "WEB33-P0-48", "WEB33-P0-49", "WEB33-P0-50", "WEB33-P0-51", "WEB33-P0-52", "WEB33-P0-53", "WEB33-P0-54", "WEB33-P0-55", "WEB33-P0-56", "WEB33-P0-57"];
11
11
  /**
12
12
  * v0.3.20 — the WEB33 scenarios whose specs shipped between v0.3.13 and
13
13
  * v0.3.15 (rail, transcript navigator, brand, files editor, resource layout)
@@ -37,7 +37,7 @@ export declare const WEB_E2E_WEB38_SCENARIOS_V1: readonly ["WEB38-P0-01", "WEB38
37
37
  * actually verify; the per-stage unit suites are registered separately.
38
38
  */
39
39
  export declare const WEB_E2E_WEB317_SCENARIOS_V1: readonly string[];
40
- export declare const WEB_E2E_WEB33_SCENARIOS_V1: readonly ("WEB33-P0-01" | "WEB33-P0-02" | "WEB33-P0-03" | "WEB33-P0-04" | "WEB33-P0-05" | "WEB33-P0-06" | "WEB33-P0-07" | "WEB33-P0-08" | "WEB33-P0-09" | "WEB33-P0-10" | "WEB33-P0-11" | "WEB33-P0-12" | "WEB33-P0-16" | "WEB33-P0-17" | "WEB33-P0-18" | "WEB33-P0-19" | "WEB33-P0-20" | "WEB33-P0-21" | "WEB33-P0-22" | "WEB33-P0-23" | "WEB33-P0-24" | "WEB33-P0-13" | "WEB33-P0-14" | "WEB33-P0-15" | "WEB33-P0-25" | "WEB33-P0-26" | "WEB33-P0-27" | "WEB33-P0-28" | "WEB33-P0-29" | "WEB33-P0-30" | "WEB33-P0-31" | "WEB33-P0-32" | "WEB33-P0-34" | "WEB33-P0-41" | "WEB33-P0-42" | "WEB33-P0-43")[];
40
+ export declare const WEB_E2E_WEB33_SCENARIOS_V1: readonly ("WEB33-P0-01" | "WEB33-P0-02" | "WEB33-P0-03" | "WEB33-P0-04" | "WEB33-P0-05" | "WEB33-P0-06" | "WEB33-P0-07" | "WEB33-P0-08" | "WEB33-P0-09" | "WEB33-P0-10" | "WEB33-P0-11" | "WEB33-P0-12" | "WEB33-P0-16" | "WEB33-P0-17" | "WEB33-P0-18" | "WEB33-P0-19" | "WEB33-P0-20" | "WEB33-P0-21" | "WEB33-P0-22" | "WEB33-P0-23" | "WEB33-P0-24" | "WEB33-P0-44" | "WEB33-P0-45" | "WEB33-P0-46" | "WEB33-P0-47" | "WEB33-P0-48" | "WEB33-P0-49" | "WEB33-P0-50" | "WEB33-P0-51" | "WEB33-P0-52" | "WEB33-P0-53" | "WEB33-P0-54" | "WEB33-P0-55" | "WEB33-P0-56" | "WEB33-P0-57" | "WEB33-P0-13" | "WEB33-P0-14" | "WEB33-P0-15" | "WEB33-P0-25" | "WEB33-P0-26" | "WEB33-P0-27" | "WEB33-P0-28" | "WEB33-P0-29" | "WEB33-P0-30" | "WEB33-P0-31" | "WEB33-P0-32" | "WEB33-P0-34" | "WEB33-P0-41" | "WEB33-P0-42" | "WEB33-P0-43")[];
41
41
  /**
42
42
  * v0.3.19 — closing the v0.3.17 G317 assertion backlog.
43
43
  *
@@ -51,7 +51,7 @@ export declare const WEB_E2E_FULL_SCENARIOS_V1: readonly string[];
51
51
  export declare const WEB_E2E_SETTINGS_SCENARIOS_V1: readonly string[];
52
52
  export declare const WEB_E2E_WEB31_CRITICAL_SCENARIOS_V1: readonly ["WEB31-P0-01", "WEB31-P0-02", "WEB31-P0-08", "WEB31-P0-09", "WEB31-P0-10", "WEB31-P0-12"];
53
53
  export declare const WEB_E2E_WEB32_CRITICAL_SCENARIOS_V1: readonly ["WEB32-P0-01", "WEB32-P0-04", "WEB32-P0-05", "WEB32-P0-06", "WEB32-P0-09", "WEB32-P0-11", "WEB32-P0-12"];
54
- export declare const WEB_E2E_WEB33_CRITICAL_SCENARIOS_V1: readonly ["WEB33-P0-01", "WEB33-P0-03", "WEB33-P0-08", "WEB33-P0-10", "WEB33-P0-12", "WEB33-P0-16", "WEB33-P0-17", "WEB33-P0-18", "WEB33-P0-20", "WEB33-P0-21", "WEB33-P0-23", "WEB33-P0-24"];
54
+ export declare const WEB_E2E_WEB33_CRITICAL_SCENARIOS_V1: readonly ["WEB33-P0-01", "WEB33-P0-03", "WEB33-P0-08", "WEB33-P0-10", "WEB33-P0-12", "WEB33-P0-16", "WEB33-P0-17", "WEB33-P0-18", "WEB33-P0-20", "WEB33-P0-21", "WEB33-P0-23", "WEB33-P0-24", "WEB33-P0-44", "WEB33-P0-45", "WEB33-P0-46", "WEB33-P0-47", "WEB33-P0-48", "WEB33-P0-49", "WEB33-P0-50", "WEB33-P0-51", "WEB33-P0-52", "WEB33-P0-53", "WEB33-P0-54", "WEB33-P0-55", "WEB33-P0-56", "WEB33-P0-57"];
55
55
  export declare const WEB_E2E_CRITICAL_SCENARIOS_V1: readonly string[];
56
56
  export type ReleaseGateDecisionV1 = 'GO' | 'NO_GO';
57
57
  export interface TarballArtifactReceiptV1 {
@@ -96,6 +96,21 @@ exports.WEB_E2E_WEB33_SESSION_SCENARIOS_V1 = Object.freeze([
96
96
  'WEB33-P0-22',
97
97
  'WEB33-P0-23',
98
98
  'WEB33-P0-24',
99
+ // v0.3.24 — admission-window, creation and warm-switch regressions.
100
+ 'WEB33-P0-44',
101
+ 'WEB33-P0-45',
102
+ 'WEB33-P0-46',
103
+ 'WEB33-P0-47',
104
+ 'WEB33-P0-48',
105
+ 'WEB33-P0-49',
106
+ 'WEB33-P0-50',
107
+ 'WEB33-P0-51',
108
+ 'WEB33-P0-52',
109
+ 'WEB33-P0-53',
110
+ 'WEB33-P0-54',
111
+ 'WEB33-P0-55',
112
+ 'WEB33-P0-56',
113
+ 'WEB33-P0-57',
99
114
  ]);
100
115
  /**
101
116
  * v0.3.20 — the WEB33 scenarios whose specs shipped between v0.3.13 and
@@ -226,6 +241,20 @@ exports.WEB_E2E_WEB33_CRITICAL_SCENARIOS_V1 = Object.freeze([
226
241
  'WEB33-P0-21',
227
242
  'WEB33-P0-23',
228
243
  'WEB33-P0-24',
244
+ 'WEB33-P0-44',
245
+ 'WEB33-P0-45',
246
+ 'WEB33-P0-46',
247
+ 'WEB33-P0-47',
248
+ 'WEB33-P0-48',
249
+ 'WEB33-P0-49',
250
+ 'WEB33-P0-50',
251
+ 'WEB33-P0-51',
252
+ 'WEB33-P0-52',
253
+ 'WEB33-P0-53',
254
+ 'WEB33-P0-54',
255
+ 'WEB33-P0-55',
256
+ 'WEB33-P0-56',
257
+ 'WEB33-P0-57',
229
258
  ]);
230
259
  exports.WEB_E2E_CRITICAL_SCENARIOS_V1 = Object.freeze([
231
260
  ...exports.WEB_E2E_LEGACY_SCENARIOS_V1.slice(0, 4),
@@ -140,6 +140,12 @@ export declare class ToolGatewayError extends Error {
140
140
  /** Capability → Policy → Approval → Sandbox → Execute → durable terminal receipt. */
141
141
  export declare class ToolGateway {
142
142
  private readonly services;
143
+ /**
144
+ * v0.3.22 T22-01 — in-flight entries carry the full request digest so the
145
+ * same invocationId with different arguments, tool, snapshot, or parent
146
+ * conflicts instead of silently reusing the first execution's promise
147
+ * (matching the durable journal's guard strength).
148
+ */
143
149
  private readonly inflight;
144
150
  private readonly clock;
145
151
  constructor(services: ToolGatewayServicesV1);
@@ -19,16 +19,38 @@ exports.ToolGatewayError = ToolGatewayError;
19
19
  class ToolGateway {
20
20
  constructor(services) {
21
21
  this.services = services;
22
+ /**
23
+ * v0.3.22 T22-01 — in-flight entries carry the full request digest so the
24
+ * same invocationId with different arguments, tool, snapshot, or parent
25
+ * conflicts instead of silently reusing the first execution's promise
26
+ * (matching the durable journal's guard strength).
27
+ */
22
28
  this.inflight = new Map();
23
29
  this.clock = services.clock ?? Date.now;
24
30
  }
25
31
  invoke(invocation) {
32
+ const requestDigest = computeRequestDigest(invocation);
26
33
  const existing = this.inflight.get(invocation.invocationId);
27
- if (existing)
28
- return existing;
29
- const run = this.invokeOnce(invocation).finally(() => this.inflight.delete(invocation.invocationId));
30
- this.inflight.set(invocation.invocationId, run);
31
- return run;
34
+ if (existing) {
35
+ if (existing.requestDigest !== requestDigest) {
36
+ // Reject (rather than throw synchronously) so callers awaiting the
37
+ // invocation observe the conflict through the same promise channel as
38
+ // the durable-journal conflict.
39
+ return Promise.reject(new ToolGatewayError('ORION_TOOL_INVOCATION_CONFLICT', 'Invocation ID is already executing with different arguments or snapshot', invocation.invocationId));
40
+ }
41
+ return existing.promise;
42
+ }
43
+ const promise = this.invokeOnce(invocation).finally(() => {
44
+ // Remove only our own entry: the guard keeps a defensive barrier against
45
+ // deleting an entry created by a later invocation after this run
46
+ // finished.
47
+ const current = this.inflight.get(invocation.invocationId);
48
+ if (current && current.requestDigest === requestDigest) {
49
+ this.inflight.delete(invocation.invocationId);
50
+ }
51
+ });
52
+ this.inflight.set(invocation.invocationId, { requestDigest, promise });
53
+ return promise;
32
54
  }
33
55
  async invokeOnce(invocation) {
34
56
  validateInvocation(invocation);
@@ -237,8 +259,13 @@ function createStaticApprovalDecisionV1(input) {
237
259
  function createSandboxPreparationV1(input) {
238
260
  return deepFreeze({ ...input, digest: (0, canonical_1.digestRuntimeValue)(input) });
239
261
  }
240
- function createIntent(invocation, startedAt) {
241
- const requestDigest = (0, canonical_1.digestRuntimeValue)({
262
+ /**
263
+ * v0.3.22 T22-01 — the authoritative request identity, shared by the durable
264
+ * intent and the in-flight dedupe map. Excludes startedAt so identity stays
265
+ * stable across retries within one execution.
266
+ */
267
+ function computeRequestDigest(invocation) {
268
+ return (0, canonical_1.digestRuntimeValue)({
242
269
  invocationId: invocation.invocationId,
243
270
  parentInvocationId: invocation.parentInvocationId,
244
271
  threadId: invocation.snapshot.threadId,
@@ -248,6 +275,9 @@ function createIntent(invocation, startedAt) {
248
275
  snapshotDigest: invocation.snapshot.digest,
249
276
  argsDigest: (0, canonical_1.digestRuntimeValue)(invocation.args),
250
277
  });
278
+ }
279
+ function createIntent(invocation, startedAt) {
280
+ const requestDigest = computeRequestDigest(invocation);
251
281
  const content = {
252
282
  version: 1,
253
283
  invocationId: invocation.invocationId,
@@ -4,7 +4,7 @@
4
4
  * Re-exports from src/product/paths.ts for backward compatibility.
5
5
  * All new code should import directly from src/product/paths.ts.
6
6
  */
7
- export { getConfigHome, getConfigDir, getGlobalConfigPath, getSettingsPath, getUsageStatePath, getUsageLedgerPath, getUserMemoryPath, getHistoryPath, getMcpConfigPath, getProjectsDir, getGlobalEnvPath, encodeProjectPath, resolveProjectStoragePath, getCanonicalProjectKey, getProjectDir, getProjectMetadataPath, getProjectSessionsDir, getProjectSessionMetaPath, getProjectSessionMessagesPath, getProjectSessionHarnessPath, getProjectSessionCompactPath, getProjectSessionTracePath, getProjectSessionGoalPath, getProjectMemoryDir, getLegacyProjectMemoryDir, getProjectArtifactsDir, getProjectCheckpointsDir, getProjectIndexesDir, getCostDir, getDailyCostPath, getCacheDir, getMemoryPath, getExistingMemoryPaths, ensureConfigDir, ensureProjectDir, PROJECT_CONFIG_CANDIDATES, getProjectInstructionsPath, getProjectSkillsDir, type MemoryType, } from '../product/paths';
7
+ export { getConfigHome, getConfigDir, getGlobalConfigPath, getSettingsPath, getUsageStatePath, getUsageLedgerPath, getUserMemoryPath, getHistoryPath, getMcpConfigPath, getProjectsDir, getGlobalEnvPath, encodeProjectPath, resolveProjectStoragePath, resolveProjectStoragePathAsync, getCanonicalProjectKey, getProjectDir, getProjectMetadataPath, getProjectSessionsDir, getProjectSessionMetaPath, getProjectSessionMessagesPath, getProjectSessionHarnessPath, getProjectSessionCompactPath, getProjectSessionTracePath, getProjectSessionGoalPath, getProjectMemoryDir, getLegacyProjectMemoryDir, getProjectArtifactsDir, getProjectCheckpointsDir, getProjectIndexesDir, getCostDir, getDailyCostPath, getCacheDir, getMemoryPath, getExistingMemoryPaths, ensureConfigDir, ensureProjectDir, PROJECT_CONFIG_CANDIDATES, getProjectInstructionsPath, getProjectSkillsDir, type MemoryType, } from '../product/paths';
8
8
  export declare const PROJECT_METADATA_SCHEMA_VERSION = 1;
9
9
  export interface ProjectMetadata {
10
10
  schemaVersion: number;
@@ -13,6 +13,7 @@ export interface ProjectMetadata {
13
13
  createdAt: string;
14
14
  lastSeenAt: string;
15
15
  }
16
+ import { type ProjectStorageIdentity } from '../product/paths';
16
17
  export declare function readProjectMetadata(projectPath: string): ProjectMetadata | null;
17
- export declare function updateProjectMetadata(projectPath: string, now?: Date): ProjectMetadata;
18
+ export declare function updateProjectMetadata(projectPath: string, now?: Date, identity?: ProjectStorageIdentity): ProjectMetadata;
18
19
  //# sourceMappingURL=config-dir.d.ts.map
@@ -6,11 +6,10 @@
6
6
  * All new code should import directly from src/product/paths.ts.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.PROJECT_METADATA_SCHEMA_VERSION = exports.getProjectSkillsDir = exports.getProjectInstructionsPath = exports.PROJECT_CONFIG_CANDIDATES = exports.ensureProjectDir = exports.ensureConfigDir = exports.getExistingMemoryPaths = exports.getMemoryPath = exports.getCacheDir = exports.getDailyCostPath = exports.getCostDir = exports.getProjectIndexesDir = exports.getProjectCheckpointsDir = exports.getProjectArtifactsDir = exports.getLegacyProjectMemoryDir = exports.getProjectMemoryDir = exports.getProjectSessionGoalPath = exports.getProjectSessionTracePath = exports.getProjectSessionCompactPath = exports.getProjectSessionHarnessPath = exports.getProjectSessionMessagesPath = exports.getProjectSessionMetaPath = exports.getProjectSessionsDir = exports.getProjectMetadataPath = exports.getProjectDir = exports.getCanonicalProjectKey = exports.resolveProjectStoragePath = exports.encodeProjectPath = exports.getGlobalEnvPath = exports.getProjectsDir = exports.getMcpConfigPath = exports.getHistoryPath = exports.getUserMemoryPath = exports.getUsageLedgerPath = exports.getUsageStatePath = exports.getSettingsPath = exports.getGlobalConfigPath = exports.getConfigDir = exports.getConfigHome = void 0;
9
+ exports.PROJECT_METADATA_SCHEMA_VERSION = exports.getProjectSkillsDir = exports.getProjectInstructionsPath = exports.PROJECT_CONFIG_CANDIDATES = exports.ensureProjectDir = exports.ensureConfigDir = exports.getExistingMemoryPaths = exports.getMemoryPath = exports.getCacheDir = exports.getDailyCostPath = exports.getCostDir = exports.getProjectIndexesDir = exports.getProjectCheckpointsDir = exports.getProjectArtifactsDir = exports.getLegacyProjectMemoryDir = exports.getProjectMemoryDir = exports.getProjectSessionGoalPath = exports.getProjectSessionTracePath = exports.getProjectSessionCompactPath = exports.getProjectSessionHarnessPath = exports.getProjectSessionMessagesPath = exports.getProjectSessionMetaPath = exports.getProjectSessionsDir = exports.getProjectMetadataPath = exports.getProjectDir = exports.getCanonicalProjectKey = exports.resolveProjectStoragePathAsync = exports.resolveProjectStoragePath = exports.encodeProjectPath = exports.getGlobalEnvPath = exports.getProjectsDir = exports.getMcpConfigPath = exports.getHistoryPath = exports.getUserMemoryPath = exports.getUsageLedgerPath = exports.getUsageStatePath = exports.getSettingsPath = exports.getGlobalConfigPath = exports.getConfigDir = exports.getConfigHome = void 0;
10
10
  exports.readProjectMetadata = readProjectMetadata;
11
11
  exports.updateProjectMetadata = updateProjectMetadata;
12
12
  const fs_1 = require("fs");
13
- const child_process_1 = require("child_process");
14
13
  const path_1 = require("path");
15
14
  const atomic_write_1 = require("./atomic-write");
16
15
  const debug_log_1 = require("../utils/debug-log");
@@ -28,6 +27,7 @@ Object.defineProperty(exports, "getProjectsDir", { enumerable: true, get: functi
28
27
  Object.defineProperty(exports, "getGlobalEnvPath", { enumerable: true, get: function () { return paths_1.getGlobalEnvPath; } });
29
28
  Object.defineProperty(exports, "encodeProjectPath", { enumerable: true, get: function () { return paths_1.encodeProjectPath; } });
30
29
  Object.defineProperty(exports, "resolveProjectStoragePath", { enumerable: true, get: function () { return paths_1.resolveProjectStoragePath; } });
30
+ Object.defineProperty(exports, "resolveProjectStoragePathAsync", { enumerable: true, get: function () { return paths_1.resolveProjectStoragePathAsync; } });
31
31
  Object.defineProperty(exports, "getCanonicalProjectKey", { enumerable: true, get: function () { return paths_1.getCanonicalProjectKey; } });
32
32
  Object.defineProperty(exports, "getProjectDir", { enumerable: true, get: function () { return paths_1.getProjectDir; } });
33
33
  Object.defineProperty(exports, "getProjectMetadataPath", { enumerable: true, get: function () { return paths_1.getProjectMetadataPath; } });
@@ -75,33 +75,10 @@ function readProjectMetadata(projectPath) {
75
75
  return null;
76
76
  }
77
77
  }
78
- function updateProjectMetadata(projectPath, now = new Date()) {
79
- const resolvedPath = (() => {
80
- const absolute = (0, path_1.resolve)(projectPath);
81
- if ((0, fs_1.existsSync)(absolute)) {
82
- try {
83
- const root = (0, child_process_1.execFileSync)('git', ['-C', absolute, 'rev-parse', '--show-toplevel'], {
84
- encoding: 'utf-8',
85
- stdio: ['ignore', 'pipe', 'ignore'],
86
- }).trim();
87
- if (root)
88
- return (0, fs_1.realpathSync)(root);
89
- }
90
- catch (error) {
91
- // Not a git worktree, or git is unavailable: fall back to the path.
92
- (0, debug_log_1.debugError)('config-dir.resolveGitRoot', error, absolute);
93
- }
94
- try {
95
- return (0, fs_1.realpathSync)(absolute);
96
- }
97
- catch (error) {
98
- // Broken symlink or a race with a deletion; the literal path is
99
- // still a usable project key.
100
- (0, debug_log_1.debugError)('config-dir.realpath', error, absolute);
101
- }
102
- }
103
- return absolute;
104
- })();
78
+ function updateProjectMetadata(projectPath, now = new Date(), identity) {
79
+ if (identity)
80
+ (0, paths_2.assertProjectStorageIdentity)(identity);
81
+ const resolvedPath = identity?.canonicalPath ?? (0, paths_2.resolveProjectStoragePath)(projectPath);
105
82
  const projectKey = (0, paths_2.encodeProjectPath)(resolvedPath);
106
83
  const projectDir = (0, path_1.join)((0, paths_2.getProjectsDir)(), projectKey);
107
84
  if (!(0, fs_1.existsSync)(projectDir)) {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * v0.3.23 T23-B — Repo Intelligence facade: symbol index, incremental
3
+ * maintenance, task-relevant recall with sourced reasons, and budget-aware
4
+ * selection. Feature-flagged at the integration seam (ORION_CODE_REPO_INTELLIGENCE)
5
+ * so the prompt assembly can adopt it incrementally.
6
+ */
7
+ export { RepoSymbolIndexV1, type RepoSymbolEntryV1, type RepoFileRecordV1, type RepoIndexStatsV1, type RepoSymbolIndexOptionsV1, } from './symbol-index';
8
+ export { recallFiles, selectWithinBudget, type RecallCandidateV1, type RecallOptionsV1, } from './recall';
9
+ /** The runtime integration flag: 'on' enables harness wiring; default off. */
10
+ export declare function isRepoIntelligenceEnabled(env?: Readonly<Record<string, string | undefined>>): boolean;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectWithinBudget = exports.recallFiles = exports.RepoSymbolIndexV1 = void 0;
4
+ exports.isRepoIntelligenceEnabled = isRepoIntelligenceEnabled;
5
+ /**
6
+ * v0.3.23 T23-B — Repo Intelligence facade: symbol index, incremental
7
+ * maintenance, task-relevant recall with sourced reasons, and budget-aware
8
+ * selection. Feature-flagged at the integration seam (ORION_CODE_REPO_INTELLIGENCE)
9
+ * so the prompt assembly can adopt it incrementally.
10
+ */
11
+ var symbol_index_1 = require("./symbol-index");
12
+ Object.defineProperty(exports, "RepoSymbolIndexV1", { enumerable: true, get: function () { return symbol_index_1.RepoSymbolIndexV1; } });
13
+ var recall_1 = require("./recall");
14
+ Object.defineProperty(exports, "recallFiles", { enumerable: true, get: function () { return recall_1.recallFiles; } });
15
+ Object.defineProperty(exports, "selectWithinBudget", { enumerable: true, get: function () { return recall_1.selectWithinBudget; } });
16
+ /** The runtime integration flag: 'on' enables harness wiring; default off. */
17
+ function isRepoIntelligenceEnabled(env = process.env) {
18
+ return env.ORION_CODE_REPO_INTELLIGENCE === 'on';
19
+ }
20
+ //# sourceMappingURL=index.js.map