@open-agent-toolkit/cli 0.2.50 → 0.2.51

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 (60) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/reference/cli-reference.md +20 -5
  3. package/assets/docs/reference/file-locations.md +8 -2
  4. package/assets/docs/reference/oat-directory-structure.md +14 -5
  5. package/assets/docs/workflows/projects/artifacts.md +9 -4
  6. package/assets/docs/workflows/projects/lifecycle.md +17 -5
  7. package/assets/docs/workflows/projects/picking-up-projects.md +26 -9
  8. package/assets/docs/workflows/projects/pr-flow.md +5 -3
  9. package/assets/docs/workflows/projects/reviewing-oat-prs.md +12 -8
  10. package/assets/public-package-versions.json +4 -4
  11. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +2 -2
  12. package/assets/skills/oat-project-complete/SKILL.md +193 -26
  13. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +306 -0
  14. package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +125 -0
  15. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +106 -0
  16. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +110 -0
  17. package/assets/skills/oat-project-complete/scripts/resolve-synced-archive-entry.mjs +164 -0
  18. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +2 -2
  19. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +2 -2
  20. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +2 -2
  21. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +2 -2
  22. package/dist/commands/project/archive/archive-utils.d.ts +8 -1
  23. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  24. package/dist/commands/project/archive/archive-utils.js +147 -50
  25. package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
  26. package/dist/commands/project/archive/push-runner.js +15 -2
  27. package/dist/commands/project/links/compute.d.ts +1 -0
  28. package/dist/commands/project/links/compute.d.ts.map +1 -1
  29. package/dist/commands/project/links/compute.js +5 -4
  30. package/dist/commands/project/links/index.d.ts +9 -0
  31. package/dist/commands/project/links/index.d.ts.map +1 -1
  32. package/dist/commands/project/links/index.js +71 -2
  33. package/dist/commands/project/list.d.ts +10 -2
  34. package/dist/commands/project/list.d.ts.map +1 -1
  35. package/dist/commands/project/list.js +205 -29
  36. package/dist/commands/project/open/index.d.ts +2 -0
  37. package/dist/commands/project/open/index.d.ts.map +1 -1
  38. package/dist/commands/project/open/index.js +16 -1
  39. package/dist/commands/project/prune/index.d.ts +10 -4
  40. package/dist/commands/project/prune/index.d.ts.map +1 -1
  41. package/dist/commands/project/prune/index.js +85 -15
  42. package/dist/commands/project/pull/index.d.ts +4 -0
  43. package/dist/commands/project/pull/index.d.ts.map +1 -1
  44. package/dist/commands/project/pull/index.js +82 -3
  45. package/dist/commands/project/sync/git.d.ts +9 -0
  46. package/dist/commands/project/sync/git.d.ts.map +1 -1
  47. package/dist/commands/project/sync/git.js +18 -0
  48. package/dist/commands/project/sync/ref-sync.d.ts +16 -1
  49. package/dist/commands/project/sync/ref-sync.d.ts.map +1 -1
  50. package/dist/commands/project/sync/ref-sync.js +288 -17
  51. package/dist/commands/project/sync/resolve-target.d.ts +10 -0
  52. package/dist/commands/project/sync/resolve-target.d.ts.map +1 -1
  53. package/dist/commands/project/sync/resolve-target.js +56 -1
  54. package/dist/commands/shared/project-scope.d.ts +2 -0
  55. package/dist/commands/shared/project-scope.d.ts.map +1 -1
  56. package/dist/commands/shared/project-scope.js +5 -0
  57. package/dist/commands/state/generate.d.ts +2 -0
  58. package/dist/commands/state/generate.d.ts.map +1 -1
  59. package/dist/commands/state/generate.js +93 -28
  60. package/package.json +2 -2
@@ -1,7 +1,11 @@
1
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
1
2
  import { buildCommandContext, } from '../../../app/command-context.js';
2
3
  import { defaultGitRunner } from '../../project/sync/git.js';
3
- import { abortSynced as defaultAbortSynced, commitRecordChange as defaultCommitRecordChange, continueSynced as defaultContinueSynced, pullChildren as defaultPullChildren, pullSynced as defaultPullSynced, } from '../../project/sync/ref-sync.js';
4
- import { resolveSyncedTarget, } from '../../project/sync/resolve-target.js';
4
+ import { readSyncedRecord } from '../../project/sync/record.js';
5
+ import { abortSynced as defaultAbortSynced, commitRecordChange as defaultCommitRecordChange, continueSynced as defaultContinueSynced, pullChildren as defaultPullChildren, pullSynced as defaultPullSynced, buildSyncTarget, classifyRemoteRefLookup, } from '../../project/sync/ref-sync.js';
6
+ import { probeSyncedTerminalRefs, resolveSyncedTarget, } from '../../project/sync/resolve-target.js';
7
+ import { resolveProjectsRoot } from '../../shared/oat-paths.js';
8
+ import { completedSyncedRefName, resolveProjectScope, resolveScopeRoot, syncedRecordPath, } from '../../shared/project-scope.js';
5
9
  import { readGlobalOptions } from '../../shared/shared.utils.js';
6
10
  import { CliError } from '../../../errors/cli-error.js';
7
11
  import { resolveProjectRoot } from '../../../fs/paths.js';
@@ -9,6 +13,8 @@ import { Command } from 'commander';
9
13
  const DEFAULT_DEPENDENCIES = {
10
14
  buildCommandContext,
11
15
  resolveProjectRoot,
16
+ resolveProjectsRoot,
17
+ guardSyncedTerminalTarget,
12
18
  resolveSyncedTarget,
13
19
  pullSynced: defaultPullSynced,
14
20
  pullChildren: defaultPullChildren,
@@ -21,6 +27,66 @@ const DEFAULT_DEPENDENCIES = {
21
27
  function shellQuote(value) {
22
28
  return `'${value.replaceAll("'", "'\\''")}'`;
23
29
  }
30
+ function slugForTerminalGuard(repoRoot, projectsRoot, pathOrSlug) {
31
+ if (!pathOrSlug)
32
+ return null;
33
+ if (!pathOrSlug.includes('/') && !pathOrSlug.includes('\\')) {
34
+ return pathOrSlug;
35
+ }
36
+ const absolute = isAbsolute(pathOrSlug)
37
+ ? resolve(pathOrSlug)
38
+ : resolve(repoRoot, pathOrSlug);
39
+ const syncedRoot = resolveScopeRoot(repoRoot, projectsRoot, 'synced');
40
+ if (resolveProjectScope(absolute, resolveScopeRoot(repoRoot, projectsRoot, 'shared'), repoRoot) !== 'synced') {
41
+ return null;
42
+ }
43
+ const child = relative(syncedRoot, absolute);
44
+ return child && !child.includes(sep) ? child : null;
45
+ }
46
+ function terminalActionError(slug, action, state, completedRef, sha) {
47
+ const alias = state === 'both'
48
+ ? ' The matching active ref is only a stale terminal alias and is ignored.'
49
+ : '';
50
+ return new CliError(`Synced project ${slug} is already archived at ${completedRef}@${sha} and cannot be ${action === 'pull' ? 'pulled' : 'opened'}.${alias} Inspect the durable archive, or use oat project prune ${shellQuote(slug)} only to intentionally remove retained terminal ref reachability.`, 1);
51
+ }
52
+ export async function guardSyncedTerminalTarget(repoRoot, projectsRoot, pathOrSlug, action, git) {
53
+ const slug = slugForTerminalGuard(repoRoot, projectsRoot, pathOrSlug);
54
+ if (!slug)
55
+ return;
56
+ const target = buildSyncTarget(repoRoot, projectsRoot, slug);
57
+ const record = await readSyncedRecord(syncedRecordPath(target.syncedRoot, slug));
58
+ if (record?.status === 'complete') {
59
+ if (record.archiveSourceRefSha) {
60
+ const probe = await probeSyncedTerminalRefs(target, record.archiveSourceRefSha, git);
61
+ if (probe.state === 'wrong-sha') {
62
+ throw new CliError(`Invalid terminal refs for ${slug}: active ${probe.activeRef} is ${probe.activeSha ?? 'absent'}, completed ${probe.completedRef} is ${probe.completedSha ?? 'absent'}, expected archived source ${record.archiveSourceRefSha}. Repair the ref mismatch before retrying completion or prune; the project was not ${action === 'pull' ? 'pulled' : 'opened'}.`, 1);
63
+ }
64
+ }
65
+ const detail = record.archiveSnapshot
66
+ ? 'Its durable archive exists, but legacy terminal cleanup is still pending.'
67
+ : 'Its archive snapshot metadata is incomplete.';
68
+ throw new CliError(`Synced project ${slug} has a legacy complete record and cannot be ${action === 'pull' ? 'pulled' : 'opened'}. ${detail} Retry oat-project-complete to finish archive retirement; do not rematerialize the checkout.`, 1);
69
+ }
70
+ const completedRef = completedSyncedRefName(slug);
71
+ const lookup = await git.run(['ls-remote', '--exit-code', target.remote, completedRef], { cwd: repoRoot, allowFailure: true });
72
+ if (classifyRemoteRefLookup(lookup, target.remote, completedRef) === 'absent') {
73
+ return;
74
+ }
75
+ const rows = lookup.stdout.split('\n').filter(Boolean);
76
+ const [sha, advertisedRef] = rows[0]?.trim().split(/\s+/) ?? [];
77
+ if (rows.length !== 1 ||
78
+ advertisedRef !== completedRef ||
79
+ !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i.test(sha ?? '')) {
80
+ throw new CliError(`Unable to verify terminal identity for ${slug}: origin returned a malformed completed-ref advertisement.`, 2);
81
+ }
82
+ const probe = await probeSyncedTerminalRefs(target, sha, git);
83
+ if (probe.state === 'wrong-sha') {
84
+ throw new CliError(`Invalid terminal refs for ${slug}: active ${probe.activeRef} is ${probe.activeSha ?? 'absent'}, completed ${probe.completedRef} is ${probe.completedSha ?? 'absent'}, expected ${sha}. Repair the ref mismatch before retrying completion or prune; the project was not ${action === 'pull' ? 'pulled' : 'opened'}.`, 1);
85
+ }
86
+ if (probe.state === 'completed-only' || probe.state === 'both') {
87
+ throw terminalActionError(slug, action, probe.state, completedRef, sha);
88
+ }
89
+ }
24
90
  function reportPullResult(context, result, target, targetArg, children = []) {
25
91
  const payload = {
26
92
  ...result,
@@ -89,7 +155,20 @@ async function runPull(context, pathOrSlug, options, dependencies) {
89
155
  throw new CliError('`--continue` and `--abort` are mutually exclusive.', 1);
90
156
  }
91
157
  const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
92
- const target = await dependencies.resolveSyncedTarget({ repoRoot, env: dependencies.processEnv }, pathOrSlug, {}, { allowMissingCheckout: !options.continue && !options.abort });
158
+ const projectsRoot = await dependencies.resolveProjectsRoot(repoRoot, dependencies.processEnv);
159
+ let target;
160
+ try {
161
+ target = await dependencies.resolveSyncedTarget({ repoRoot, env: dependencies.processEnv }, pathOrSlug, {}, { allowMissingCheckout: !options.continue && !options.abort });
162
+ }
163
+ catch (error) {
164
+ if (error instanceof CliError &&
165
+ error.exitCode === 1 &&
166
+ error.message.startsWith('No synced project named ')) {
167
+ await dependencies.guardSyncedTerminalTarget(repoRoot, projectsRoot, pathOrSlug, 'pull', dependencies.gitRunner);
168
+ }
169
+ throw error;
170
+ }
171
+ await dependencies.guardSyncedTerminalTarget(repoRoot, projectsRoot, pathOrSlug ?? target.projectPath, 'pull', dependencies.gitRunner);
93
172
  const targetArg = pathOrSlug ?? target.projectPath;
94
173
  if (options.abort) {
95
174
  await dependencies.abortSynced(target, dependencies.gitRunner);
@@ -12,7 +12,16 @@ export interface GitRunOptions {
12
12
  export interface GitRunner {
13
13
  run(args: string[], options: GitRunOptions): Promise<GitResult>;
14
14
  }
15
+ export interface AtomicRefTransition {
16
+ remote: string;
17
+ sourceSha: string;
18
+ activeRef: string;
19
+ completedRef: string;
20
+ completedExpectedSha: string | null;
21
+ }
15
22
  export type ExecFileImplementation = (file: string, args: readonly string[], options: ExecFileOptionsWithStringEncoding, callback: (error: ExecFileException | null, stdout: string, stderr: string) => void) => unknown;
23
+ export declare function pushAtomicRefTransition(git: GitRunner, cwd: string, transition: AtomicRefTransition): Promise<GitResult>;
24
+ export declare function isAtomicPushUnsupported(result: GitResult): boolean;
16
25
  export declare function createGitRunner(execFileImpl?: ExecFileImplementation): GitRunner;
17
26
  export declare const defaultGitRunner: GitRunner;
18
27
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iCAAiC,EACvC,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACjE;AAED,MAAM,MAAM,sBAAsB,GAAG,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,iCAAiC,EAC1C,QAAQ,EAAE,CACR,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,KACX,IAAI,KACN,OAAO,CAAC;AAqCb,wBAAgB,eAAe,CAC7B,YAAY,GAAE,sBAAiC,GAC9C,SAAS,CAqCX;AAED,eAAO,MAAM,gBAAgB,WAAoB,CAAC"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iCAAiC,EACvC,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,MAAM,sBAAsB,GAAG,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,iCAAiC,EAC1C,QAAQ,EAAE,CACR,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,KACX,IAAI,KACN,OAAO,CAAC;AAEb,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,SAAS,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAAC,SAAS,CAAC,CAapB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CASlE;AAqCD,wBAAgB,eAAe,CAC7B,YAAY,GAAE,sBAAiC,GAC9C,SAAS,CAqCX;AAED,eAAO,MAAM,gBAAgB,WAAoB,CAAC"}
@@ -1,5 +1,23 @@
1
1
  import { execFile, } from 'node:child_process';
2
2
  import { CliError } from '../../../errors/cli-error.js';
3
+ export function pushAtomicRefTransition(git, cwd, transition) {
4
+ return git.run([
5
+ 'push',
6
+ '--atomic',
7
+ `--force-with-lease=${transition.activeRef}:${transition.sourceSha}`,
8
+ `--force-with-lease=${transition.completedRef}:${transition.completedExpectedSha ?? ''}`,
9
+ transition.remote,
10
+ `${transition.sourceSha}:${transition.completedRef}`,
11
+ `:${transition.activeRef}`,
12
+ ], { cwd, allowFailure: true });
13
+ }
14
+ export function isAtomicPushUnsupported(result) {
15
+ if (result.code === 0)
16
+ return false;
17
+ const detail = `${result.stderr}\n${result.stdout}`;
18
+ return (/(?:does not support|not supported).*(?:--atomic|atomic push)/i.test(detail) ||
19
+ /(?:--atomic|atomic push).*(?:does not support|not supported)/i.test(detail));
20
+ }
3
21
  function numericExitCode(error) {
4
22
  return typeof error?.code === 'number' ? error.code : 0;
5
23
  }
@@ -1,7 +1,7 @@
1
1
  import { ensureScopedRootGitignore } from '../../init/gitignore.js';
2
2
  import { readOatLocalConfig, writeOatLocalConfig } from '../../../config/oat-config.js';
3
3
  import { copyDirectory } from '../../../fs/io.js';
4
- import type { GitRunner } from './git.js';
4
+ import { type GitRunner } from './git.js';
5
5
  export interface SyncTarget {
6
6
  repoRoot: string;
7
7
  sharedRoot: string;
@@ -62,6 +62,18 @@ export type MigrateResult = {
62
62
  lifecycleCommit: string | null;
63
63
  sha: string;
64
64
  };
65
+ export type SyncedRefRetirementReceipt = {
66
+ status: 'retired' | 'already-retired';
67
+ state: 'completed-only' | 'matching-aliases';
68
+ activeAliasRetained: boolean;
69
+ activeRef: string;
70
+ completedRef: string;
71
+ verifiedSha: string;
72
+ };
73
+ export type CompletedSyncedRefDeletionReceipt = {
74
+ completedRef: string;
75
+ deleted: boolean;
76
+ };
65
77
  export declare function classifyRemoteRefLookup(result: {
66
78
  code: number;
67
79
  stdout: string;
@@ -105,9 +117,12 @@ export declare function preflightSyncedCheckout(target: SyncTarget, git: GitRunn
105
117
  export declare function removeSyncedCheckout(target: SyncTarget, git: GitRunner, options?: {
106
118
  force?: boolean;
107
119
  }): Promise<RemoveResult>;
120
+ export declare function retireSyncedRef(target: SyncTarget, sourceSha: string, git: GitRunner): Promise<SyncedRefRetirementReceipt>;
121
+ export declare function deleteCompletedSyncedRefForPrune(target: SyncTarget, git: GitRunner): Promise<CompletedSyncedRefDeletionReceipt>;
108
122
  export declare function pruneSynced(target: SyncTarget, git: GitRunner, options: {
109
123
  force: boolean;
110
124
  commit: boolean;
125
+ expectedActiveAliasSha?: string;
111
126
  }): Promise<PruneResult>;
112
127
  export declare function migrateSharedToSynced(target: SyncTarget, git: GitRunner, options: MigrateSharedToSyncedOptions): Promise<MigrateResult>;
113
128
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ref-sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/ref-sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ref-sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/ref-sync.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,12 @@ import { lstat, mkdir, readFile, readdir, realpath, rm, stat, writeFile, } from
2
2
  import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
3
3
  import { ensureScopedRootGitignore } from '../../init/gitignore.js';
4
4
  import { getFrontmatterBlock } from '../../shared/frontmatter.js';
5
- import { canonicalizePath, isSyncedCheckout, resolveScopeRoot, SYNCED_REMOTE, syncedRefName, syncedRecordPath, } from '../../shared/project-scope.js';
5
+ import { canonicalizePath, completedSyncedRefName, isSyncedCheckout, resolveScopeRoot, SYNCED_REMOTE, syncedRefName, syncedRecordPath, } from '../../shared/project-scope.js';
6
6
  import { readOatLocalConfig, writeOatLocalConfig } from '../../../config/oat-config.js';
7
7
  import { CliError } from '../../../errors/cli-error.js';
8
8
  import { copyDirectory } from '../../../fs/io.js';
9
9
  import YAML from 'yaml';
10
+ import { isAtomicPushUnsupported, pushAtomicRefTransition, } from './git.js';
10
11
  import { buildSyncedRecord, readSyncedRecord, writeSyncedRecord, } from './record.js';
11
12
  export function classifyRemoteRefLookup(result, remote, ref) {
12
13
  if (result.code === 0)
@@ -442,6 +443,32 @@ async function prepareAdoptionRecord(target, result, adoptionRecord, now, additi
442
443
  pendingRecordPaths: [recordPath, ...additionalPendingPaths],
443
444
  };
444
445
  }
446
+ async function probeChildRemoteRefs(target, git) {
447
+ const completedRef = completedSyncedRefName(target.slug);
448
+ const lookup = await git.run(['ls-remote', '--exit-code', target.remote, target.ref, completedRef], { cwd: target.repoRoot, allowFailure: true });
449
+ if (classifyRemoteRefLookup(lookup, target.remote, `${target.ref} and ${completedRef}`) === 'absent') {
450
+ return { activeSha: null, completedSha: null };
451
+ }
452
+ const expectedRefs = new Set([target.ref, completedRef]);
453
+ const advertised = new Map();
454
+ for (const row of lookup.stdout.split('\n').filter(Boolean)) {
455
+ const fields = row.trim().split(/\s+/);
456
+ if (fields.length !== 2 ||
457
+ !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i.test(fields[0] ?? '') ||
458
+ !expectedRefs.has(fields[1] ?? '') ||
459
+ advertised.has(fields[1] ?? '')) {
460
+ throw new CliError(`Unable to verify terminal refs for child ${target.slug}: origin returned a malformed ref advertisement.`, 2);
461
+ }
462
+ advertised.set(fields[1], fields[0]);
463
+ }
464
+ if (advertised.size === 0) {
465
+ throw new CliError(`Unable to verify terminal refs for child ${target.slug}: origin returned a malformed empty advertisement.`, 2);
466
+ }
467
+ return {
468
+ activeSha: advertised.get(target.ref) ?? null,
469
+ completedSha: advertised.get(completedRef) ?? null,
470
+ };
471
+ }
445
472
  export async function pullChildren(parentTarget, git) {
446
473
  await assertCanonicalSyncTargetIdentity(parentTarget);
447
474
  const statePath = resolve(parentTarget.projectPath, 'state.md');
@@ -477,11 +504,9 @@ export async function pullChildren(parentTarget, git) {
477
504
  };
478
505
  try {
479
506
  await assertCanonicalSyncTargetIdentity(childTarget);
480
- const adoptionRecord = await classifyAdoptionRecord(childTarget, git);
481
- const remote = await git.run(['ls-remote', '--exit-code', childTarget.remote, childTarget.ref], { cwd: parentTarget.repoRoot, allowFailure: true });
482
- if (remote.code === 2 &&
483
- remote.stdout.trim() === '' &&
484
- remote.stderr.trim() === '') {
507
+ const completedRef = completedSyncedRefName(slug);
508
+ const { activeSha, completedSha } = await probeChildRemoteRefs(childTarget, git);
509
+ if (activeSha === null && completedSha === null) {
485
510
  results.push({
486
511
  slug,
487
512
  status: 'missing',
@@ -490,15 +515,27 @@ export async function pullChildren(parentTarget, git) {
490
515
  });
491
516
  continue;
492
517
  }
493
- if (remote.code !== 0) {
518
+ if (activeSha !== null &&
519
+ completedSha !== null &&
520
+ activeSha !== completedSha) {
521
+ results.push({
522
+ slug,
523
+ status: 'error',
524
+ message: `Invalid terminal refs for child ${slug}: active ${childTarget.ref} is ${activeSha}, completed ${completedRef} is ${completedSha}. Repair the ref mismatch before retrying; the child was not pulled.`,
525
+ exitCode: 1,
526
+ });
527
+ continue;
528
+ }
529
+ if (completedSha !== null) {
494
530
  results.push({
495
531
  slug,
496
532
  status: 'error',
497
- message: `git ls-remote ${childTarget.remote} ${childTarget.ref} failed (exit ${remote.code}): ${remote.stderr || remote.stdout || 'unknown Git error'}`,
498
- exitCode: 2,
533
+ message: `Synced child ${slug} is already archived at ${completedRef}@${completedSha} and will not be pulled.${activeSha === completedSha ? ` The matching active ref ${childTarget.ref} is only an inert alias.` : ''}`,
534
+ exitCode: 1,
499
535
  });
500
536
  continue;
501
537
  }
538
+ const adoptionRecord = await classifyAdoptionRecord(childTarget, git);
502
539
  const result = await pullSynced(childTarget, git, {
503
540
  adopt: adoptionRecord !== 'durable',
504
541
  adoptionRecord,
@@ -613,6 +650,216 @@ async function removePreflightedSyncedCheckout(target, git, force) {
613
650
  await git.run(['worktree', 'prune'], { cwd: target.repoRoot });
614
651
  return { status: 'removed' };
615
652
  }
653
+ async function probeTerminalRefs(target, expectedSha, git) {
654
+ const { probeSyncedTerminalRefs } = await import('./resolve-target.js');
655
+ return probeSyncedTerminalRefs(target, expectedSha, git);
656
+ }
657
+ function assertRetirementProbe(target, expectedSha, probe) {
658
+ if (probe.state === 'wrong-sha') {
659
+ if (probe.completedSha !== null && probe.completedSha !== expectedSha) {
660
+ throw new CliError(`Refusing to retire ${target.slug}: completed ref ${probe.completedRef} points to a different SHA (${probe.completedSha}) than the bound source SHA ${expectedSha}.`, 2);
661
+ }
662
+ throw new CliError(`Refusing to retire ${target.slug}: active source ref ${probe.activeRef} points to ${probe.activeSha ?? 'an unknown SHA'}, not the bound source SHA ${expectedSha}.`, 2);
663
+ }
664
+ if (probe.state === 'absent') {
665
+ throw new CliError(`Refusing to retire ${target.slug}: source ref ${probe.activeRef} is missing and completed ref ${probe.completedRef} does not preserve ${expectedSha}.`, 2);
666
+ }
667
+ }
668
+ function isTerminalRetirementProbe(probe) {
669
+ return probe.state === 'completed-only' || probe.state === 'both';
670
+ }
671
+ async function fallbackRemoteRefTransition(target, sourceSha, completedRef, completedExpectedSha, git) {
672
+ const create = await git.run([
673
+ 'push',
674
+ `--force-with-lease=${completedRef}:${completedExpectedSha ?? ''}`,
675
+ target.remote,
676
+ `${sourceSha}:${completedRef}`,
677
+ ], { cwd: target.repoRoot, allowFailure: true });
678
+ if (create.code !== 0) {
679
+ const afterFailure = await probeTerminalRefs(target, sourceSha, git);
680
+ assertRetirementProbe(target, sourceSha, afterFailure);
681
+ if (isTerminalRetirementProbe(afterFailure))
682
+ return;
683
+ throw new CliError(`Remote ref retirement for ${target.slug} was rejected while creating ${completedRef}: ${create.stderr || create.stdout || 'unknown Git error'}`, 2);
684
+ }
685
+ const afterCreate = await probeTerminalRefs(target, sourceSha, git);
686
+ assertRetirementProbe(target, sourceSha, afterCreate);
687
+ if (!isTerminalRetirementProbe(afterCreate)) {
688
+ throw new CliError(`Remote ref retirement for ${target.slug} did not preserve both refs after completed-ref creation.`, 2);
689
+ }
690
+ }
691
+ async function transitionRemoteRefs(target, sourceSha, completedRef, completedExpectedSha, git) {
692
+ const result = await pushAtomicRefTransition(git, target.repoRoot, {
693
+ remote: target.remote,
694
+ sourceSha,
695
+ activeRef: target.ref,
696
+ completedRef,
697
+ completedExpectedSha,
698
+ });
699
+ if (result.code === 0)
700
+ return;
701
+ if (isAtomicPushUnsupported(result)) {
702
+ await fallbackRemoteRefTransition(target, sourceSha, completedRef, completedExpectedSha, git);
703
+ return;
704
+ }
705
+ const afterFailure = await probeTerminalRefs(target, sourceSha, git);
706
+ assertRetirementProbe(target, sourceSha, afterFailure);
707
+ if (!isTerminalRetirementProbe(afterFailure)) {
708
+ throw new CliError(`Remote ref retirement for ${target.slug} was rejected; active ref ${target.ref} was retained: ${result.stderr || result.stdout || 'unknown Git error'}`, 2);
709
+ }
710
+ }
711
+ async function localRefSha(target, ref, git) {
712
+ const result = await git.run(['show-ref', '--hash', ref], {
713
+ cwd: target.repoRoot,
714
+ allowFailure: true,
715
+ });
716
+ assertExpectedGitResult(`git show-ref --hash ${ref}`, result, [0, 1]);
717
+ return result.code === 0 ? result.stdout : null;
718
+ }
719
+ async function reconcileLocalTerminalRefs(target, sourceSha, completedRef, git) {
720
+ const [activeSha, completedSha] = await Promise.all([
721
+ localRefSha(target, target.ref, git),
722
+ localRefSha(target, completedRef, git),
723
+ ]);
724
+ if (activeSha !== null && activeSha !== sourceSha) {
725
+ throw new CliError(`Refusing local ref cleanup for ${target.slug}: ${target.ref} points to ${activeSha}, not ${sourceSha}.`, 2);
726
+ }
727
+ if (completedSha !== null && completedSha !== sourceSha) {
728
+ throw new CliError(`Refusing local ref cleanup for ${target.slug}: ${completedRef} points to ${completedSha}, not ${sourceSha}.`, 2);
729
+ }
730
+ if (completedSha === null) {
731
+ const object = await git.run(['cat-file', '-e', `${sourceSha}^{commit}`], {
732
+ cwd: target.repoRoot,
733
+ allowFailure: true,
734
+ });
735
+ if (object.code !== 0) {
736
+ await git.run([
737
+ 'fetch',
738
+ '--no-tags',
739
+ '--no-write-fetch-head',
740
+ target.remote,
741
+ completedRef,
742
+ ], { cwd: target.repoRoot });
743
+ const afterFetch = await probeTerminalRefs(target, sourceSha, git);
744
+ assertRetirementProbe(target, sourceSha, afterFetch);
745
+ if (!isTerminalRetirementProbe(afterFetch)) {
746
+ throw new CliError(`Refusing local ref reconciliation for ${target.slug}: remote terminal refs changed while fetching ${completedRef}.`, 2);
747
+ }
748
+ await git.run(['cat-file', '-e', `${sourceSha}^{commit}`], {
749
+ cwd: target.repoRoot,
750
+ });
751
+ }
752
+ await git.run(['update-ref', completedRef, sourceSha], {
753
+ cwd: target.repoRoot,
754
+ });
755
+ }
756
+ if (activeSha !== null) {
757
+ await git.run(['update-ref', '-d', target.ref, sourceSha], {
758
+ cwd: target.repoRoot,
759
+ });
760
+ }
761
+ const [finalActiveSha, finalCompletedSha] = await Promise.all([
762
+ localRefSha(target, target.ref, git),
763
+ localRefSha(target, completedRef, git),
764
+ ]);
765
+ if (finalActiveSha !== null || finalCompletedSha !== sourceSha) {
766
+ throw new CliError(`Unable to verify local terminal refs for ${target.slug} after remote retirement.`, 2);
767
+ }
768
+ }
769
+ export async function retireSyncedRef(target, sourceSha, git) {
770
+ await assertCanonicalSyncTargetIdentity(target);
771
+ const initial = await probeTerminalRefs(target, sourceSha, git);
772
+ assertRetirementProbe(target, sourceSha, initial);
773
+ const completedRef = initial.completedRef;
774
+ if (initial.state === 'active-only') {
775
+ await transitionRemoteRefs(target, sourceSha, completedRef, initial.completedSha, git);
776
+ }
777
+ const terminal = await probeTerminalRefs(target, sourceSha, git);
778
+ assertRetirementProbe(target, sourceSha, terminal);
779
+ if (!isTerminalRetirementProbe(terminal)) {
780
+ throw new CliError(`Unable to verify a completed terminal state for ${target.slug}; completed ref ${completedRef} was not safely established.`, 2);
781
+ }
782
+ await reconcileLocalTerminalRefs(target, sourceSha, completedRef, git);
783
+ const activeAliasRetained = terminal.state === 'both';
784
+ return {
785
+ status: isTerminalRetirementProbe(initial) ? 'already-retired' : 'retired',
786
+ state: activeAliasRetained ? 'matching-aliases' : 'completed-only',
787
+ activeAliasRetained,
788
+ activeRef: target.ref,
789
+ completedRef,
790
+ verifiedSha: sourceSha,
791
+ };
792
+ }
793
+ function exactRemoteRefSha(result, remote, ref) {
794
+ if (classifyRemoteRefLookup(result, remote, ref) === 'absent')
795
+ return null;
796
+ const rows = result.stdout.split('\n').filter((row) => row.length > 0);
797
+ if (rows.length !== 1) {
798
+ throw new CliError(`Unable to verify ${remote}/${ref}: git ls-remote returned an unexpected number of exact-ref rows.`, 2);
799
+ }
800
+ const fields = rows[0]?.trim().split(/\s+/) ?? [];
801
+ if (fields.length !== 2 ||
802
+ fields[1] !== ref ||
803
+ !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i.test(fields[0] ?? '')) {
804
+ throw new CliError(`Unable to verify ${remote}/${ref}: git ls-remote returned a malformed or unexpected row.`, 2);
805
+ }
806
+ const [sha] = fields;
807
+ return sha;
808
+ }
809
+ export async function deleteCompletedSyncedRefForPrune(target, git) {
810
+ await assertCanonicalSyncTargetIdentity(target);
811
+ const completedRef = completedSyncedRefName(target.slug);
812
+ const [remote, localSha] = await Promise.all([
813
+ git.run(['ls-remote', '--exit-code', target.remote, completedRef], {
814
+ cwd: target.repoRoot,
815
+ allowFailure: true,
816
+ }),
817
+ localRefSha(target, completedRef, git),
818
+ ]);
819
+ const remoteSha = exactRemoteRefSha(remote, target.remote, completedRef);
820
+ if (remoteSha !== null) {
821
+ const deletion = await git.run([
822
+ 'push',
823
+ `--force-with-lease=${completedRef}:${remoteSha}`,
824
+ target.remote,
825
+ `:${completedRef}`,
826
+ ], { cwd: target.repoRoot, allowFailure: true });
827
+ if (deletion.code !== 0) {
828
+ const afterRejection = exactRemoteRefSha(await git.run(['ls-remote', '--exit-code', target.remote, completedRef], { cwd: target.repoRoot, allowFailure: true }), target.remote, completedRef);
829
+ if (afterRejection !== null) {
830
+ if (afterRejection !== remoteSha) {
831
+ throw new CliError(`Explicit prune stopped because remote completed ref ${completedRef} advanced from observed ${remoteSha} to ${afterRejection}; the advanced ref was retained. Review the new terminal identity and retry the destructive prune.`, 2);
832
+ }
833
+ throw new CliError(`Explicit prune could not delete retained terminal history at ${completedRef}; the local completed ref was retained. Restore access to ${target.remote} and retry the destructive prune: ${deletion.stderr || deletion.stdout || 'unknown Git error'}`, 2);
834
+ }
835
+ }
836
+ else {
837
+ const verifiedSha = exactRemoteRefSha(await git.run(['ls-remote', '--exit-code', target.remote, completedRef], { cwd: target.repoRoot, allowFailure: true }), target.remote, completedRef);
838
+ if (verifiedSha !== null) {
839
+ if (verifiedSha !== remoteSha) {
840
+ throw new CliError(`Explicit prune stopped because remote completed ref ${completedRef} advanced from observed ${remoteSha} to ${verifiedSha}; the advanced ref was retained. Review the new terminal identity and retry the destructive prune.`, 2);
841
+ }
842
+ throw new CliError(`Explicit prune could not verify deletion of retained terminal history at ${completedRef}; the local completed ref was retained.`, 2);
843
+ }
844
+ }
845
+ }
846
+ if (localSha !== null) {
847
+ const localDeletion = await git.run(['update-ref', '-d', completedRef, localSha], { cwd: target.repoRoot, allowFailure: true });
848
+ if (localDeletion.code !== 0) {
849
+ const currentLocalSha = await localRefSha(target, completedRef, git);
850
+ if (currentLocalSha !== null) {
851
+ if (currentLocalSha !== localSha) {
852
+ throw new CliError(`Explicit prune stopped because local completed ref ${completedRef} advanced from observed ${localSha} to ${currentLocalSha}; the advanced ref was retained. Review the new terminal identity and retry the destructive prune.`, 2);
853
+ }
854
+ throw new CliError(`Explicit prune could not delete local completed ref ${completedRef} at observed SHA ${localSha}; the ref was retained. Retry after resolving the local Git error: ${localDeletion.stderr || localDeletion.stdout || 'unknown Git error'}`, 2);
855
+ }
856
+ }
857
+ }
858
+ return {
859
+ completedRef,
860
+ deleted: remoteSha !== null || localSha !== null,
861
+ };
862
+ }
616
863
  export async function pruneSynced(target, git, options) {
617
864
  await assertCanonicalSyncTargetIdentity(target);
618
865
  const scopeRelativeSyncedRoot = relative(resolve(target.repoRoot), resolve(target.syncedRoot));
@@ -678,15 +925,39 @@ export async function pruneSynced(target, git, options) {
678
925
  throw new CliError(`Refusing to prune ${target.slug}: checkout ${checkout.projectPath} is ${preflight.status}. Push it first or pass --force. Pinned PR links will stop resolving after prune.`, 1);
679
926
  }
680
927
  }
681
- try {
682
- await git.run(['push', target.remote, `:${target.ref}`], {
683
- cwd: target.repoRoot,
684
- });
928
+ if (options.expectedActiveAliasSha) {
929
+ const expectedSha = options.expectedActiveAliasSha;
930
+ const deletion = await git.run([
931
+ 'push',
932
+ `--force-with-lease=${target.ref}:${expectedSha}`,
933
+ target.remote,
934
+ `:${target.ref}`,
935
+ ], { cwd: target.repoRoot, allowFailure: true });
936
+ const afterDeletion = await probeTerminalRefs(target, expectedSha, git);
937
+ if (afterDeletion.activeSha === null &&
938
+ afterDeletion.completedSha === expectedSha) {
939
+ // A rejected transport may still have applied the deletion. The
940
+ // authoritative postcondition is safe, so cleanup may continue.
941
+ }
942
+ else if (afterDeletion.activeSha !== null &&
943
+ afterDeletion.activeSha !== expectedSha) {
944
+ throw new CliError(`Explicit prune stopped because active alias ${target.ref} advanced from observed ${expectedSha} to ${afterDeletion.activeSha}; the advanced active ref, all checkouts, the discovery record, and completed history were retained. Reconcile the terminal ref mismatch before retrying.`, 1);
945
+ }
946
+ else {
947
+ throw new CliError(`Unable to safely delete matching active alias ${target.ref} at ${expectedSha}; no local checkouts or discovery records were removed and completed history was retained. Restore access to ${target.remote}, verify both terminal refs, and retry explicit prune: ${deletion.stderr || deletion.stdout || 'terminal postcondition was not established'}`, 2);
948
+ }
685
949
  }
686
- catch (error) {
687
- const detail = error instanceof Error ? error.message : String(error);
688
- const forceFlag = options.force ? ' --force' : '';
689
- throw new CliError(`Unable to delete remote ref ${target.ref}; no local checkouts were removed. Restore access to ${target.remote}, then retry oat project prune ${shellQuote(target.slug)}${forceFlag}. ${detail}`, 2);
950
+ else {
951
+ try {
952
+ await git.run(['push', target.remote, `:${target.ref}`], {
953
+ cwd: target.repoRoot,
954
+ });
955
+ }
956
+ catch (error) {
957
+ const detail = error instanceof Error ? error.message : String(error);
958
+ const forceFlag = options.force ? ' --force' : '';
959
+ throw new CliError(`Unable to delete remote ref ${target.ref}; no local checkouts were removed. Restore access to ${target.remote}, then retry oat project prune ${shellQuote(target.slug)}${forceFlag}. ${detail}`, 2);
960
+ }
690
961
  }
691
962
  try {
692
963
  for (const checkout of checkouts) {
@@ -23,5 +23,15 @@ export interface ResolvedSyncTarget extends SyncTarget {
23
23
  adopt: boolean;
24
24
  adoptionRecord: AdoptionRecordState;
25
25
  }
26
+ export type SyncedTerminalRefState = 'absent' | 'active-only' | 'completed-only' | 'both' | 'wrong-sha';
27
+ export interface SyncedTerminalRefProbe {
28
+ state: SyncedTerminalRefState;
29
+ activeRef: string;
30
+ completedRef: string;
31
+ expectedSha: string;
32
+ activeSha: string | null;
33
+ completedSha: string | null;
34
+ }
35
+ export declare function probeSyncedTerminalRefs(target: SyncTarget, expectedSha: string, git: GitRunner): Promise<SyncedTerminalRefProbe>;
26
36
  export declare function resolveSyncedTarget(context: ResolveSyncedTargetContext, pathOrSlug?: string, overrides?: Partial<ResolveSyncedTargetDependencies>, options?: ResolveSyncedTargetOptions): Promise<ResolvedSyncTarget>;
27
37
  //# sourceMappingURL=resolve-target.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-target.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/resolve-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAQ,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAOjE,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAIL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,mBAAmB,CAAC;CACrC;AAsFD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,EACnC,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,EACxD,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,kBAAkB,CAAC,CA+H7B"}
1
+ {"version":3,"file":"resolve-target.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/sync/resolve-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAQ,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAQjE,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAIL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,MAAM,sBAAsB,GAC9B,QAAQ,GACR,aAAa,GACb,gBAAgB,GAChB,MAAM,GACN,WAAW,CAAC;AAEhB,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,sBAAsB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AA+DD,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,sBAAsB,CAAC,CA+BjC;AAsFD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,EACnC,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,EACxD,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,kBAAkB,CAAC,CA+H7B"}