agl 21.0.2 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +9 -0
- package/dist_serve/bundle.js +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.aglhome.d.ts +25 -0
- package/dist_ts/classes.aglhome.js +65 -0
- package/dist_ts/classes.authmodels.js +7 -12
- package/dist_ts/classes.authstore.js +2 -29
- package/dist_ts/classes.cli.js +93 -35
- package/dist_ts/classes.config.d.ts +2 -11
- package/dist_ts/classes.config.js +14 -80
- package/dist_ts/classes.controller.d.ts +4 -1
- package/dist_ts/classes.controller.js +64 -26
- package/dist_ts/classes.embeddeddb.js +6 -5
- package/dist_ts/classes.gitreversion.js +3 -2
- package/dist_ts/classes.upgradecoordinator.d.ts +6 -1
- package/dist_ts/classes.upgradecoordinator.js +588 -177
- package/dist_ts/classes.upgradetransaction.js +46 -12
- package/dist_ts/classes.uploadmanager.d.ts +12 -0
- package/dist_ts/classes.uploadmanager.js +204 -2
- package/dist_ts/constants.upgradeenvironment.d.ts +2 -0
- package/dist_ts/constants.upgradeenvironment.js +3 -0
- package/dist_ts/functions.controllerdataroot.d.ts +4 -5
- package/dist_ts/functions.controllerdataroot.js +4 -29
- package/dist_ts/functions.embeddeddb.d.ts +1 -1
- package/dist_ts/functions.embeddeddb.js +8 -3
- package/dist_ts/functions.runtimeenvironment.js +2 -1
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces.config.d.ts +5 -7
- package/dist_ts_migration/classes.documentmigrationrunner.js +3 -1
- package/dist_ts_migration/index.d.ts +2 -0
- package/dist_ts_migration/index.js +3 -1
- package/dist_ts_migration/v23_aglhome.d.ts +91 -0
- package/dist_ts_migration/v23_aglhome.js +1775 -0
- package/dist_ts_migration/v23_runtimeconfig.d.ts +11 -0
- package/dist_ts_migration/v23_runtimeconfig.js +87 -0
- package/dist_ts_migration/v2_controllerdataroot.d.ts +5 -0
- package/dist_ts_migration/v2_controllerdataroot.js +176 -15
- package/package.json +1 -1
- package/readme.md +116 -35
- package/readme.plan.md +24 -9
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.aglhome.ts +116 -0
- package/ts/classes.authmodels.ts +5 -13
- package/ts/classes.authstore.ts +1 -39
- package/ts/classes.cli.ts +92 -34
- package/ts/classes.config.ts +20 -117
- package/ts/classes.controller.ts +92 -26
- package/ts/classes.embeddeddb.ts +5 -4
- package/ts/classes.gitreversion.ts +3 -2
- package/ts/classes.upgradecoordinator.ts +668 -191
- package/ts/classes.upgradetransaction.ts +46 -11
- package/ts/classes.uploadmanager.ts +231 -1
- package/ts/constants.upgradeenvironment.ts +2 -0
- package/ts/functions.controllerdataroot.ts +11 -47
- package/ts/functions.embeddeddb.ts +13 -2
- package/ts/functions.runtimeenvironment.ts +1 -0
- package/ts/index.ts +1 -0
- package/ts/interfaces.config.ts +5 -7
- package/ts_migration/classes.documentmigrationrunner.ts +2 -0
- package/ts_migration/index.ts +2 -0
- package/ts_migration/v23_aglhome.ts +2101 -0
- package/ts_migration/v23_runtimeconfig.ts +112 -0
- package/ts_migration/v2_controllerdataroot.ts +174 -16
- package/ts_web/00_commitinfo_data.ts +1 -1
package/ts/classes.controller.ts
CHANGED
|
@@ -129,6 +129,7 @@ import {
|
|
|
129
129
|
resolveInitialRuntimeConfig,
|
|
130
130
|
resolveStoredRuntimeConfig,
|
|
131
131
|
} from './classes.config.js';
|
|
132
|
+
import { resolveAGLHomePaths } from './classes.aglhome.js';
|
|
132
133
|
import { ensureControllerDataRootForStartup } from './functions.controllerdataroot.js';
|
|
133
134
|
import { SmartDataAuthStore } from './classes.authstore.js';
|
|
134
135
|
import { PasskeyManager } from './classes.passkeymanager.js';
|
|
@@ -301,6 +302,10 @@ import {
|
|
|
301
302
|
resolveCurrentPnpmGlobalInstallation,
|
|
302
303
|
resolveInheritedUpgradeTargetInstallation,
|
|
303
304
|
} from './classes.upgradetransaction.js';
|
|
305
|
+
import {
|
|
306
|
+
upgradeCoordinationRootEnvironmentVariable,
|
|
307
|
+
upgradeTokenEnvironmentVariable,
|
|
308
|
+
} from './constants.upgradeenvironment.js';
|
|
304
309
|
|
|
305
310
|
const currentCliName = String(controllerPackageName) === upgradePackageTransitionSource.packageName
|
|
306
311
|
? upgradePackageTransitionSource.cliName
|
|
@@ -1443,6 +1448,7 @@ export class OpenCodeController {
|
|
|
1443
1448
|
private flexAutoAcceptDrainTask?: Promise<void>;
|
|
1444
1449
|
private runtimeConfig?: Awaited<ReturnType<typeof resolveInitialRuntimeConfig>>;
|
|
1445
1450
|
private controllerId?: string;
|
|
1451
|
+
private openCodeRuntimeDirectory?: string;
|
|
1446
1452
|
private authStore?: SmartDataAuthStore;
|
|
1447
1453
|
private passkeyManager?: PasskeyManager;
|
|
1448
1454
|
private openCodeSupervisor?: OpenCodeSupervisor;
|
|
@@ -1594,6 +1600,23 @@ export class OpenCodeController {
|
|
|
1594
1600
|
});
|
|
1595
1601
|
}
|
|
1596
1602
|
|
|
1603
|
+
private captureInheritedUpgradeCoordination(): void {
|
|
1604
|
+
try {
|
|
1605
|
+
if (Boolean(this.options.upgradeToken) !== Boolean(this.options.upgradeGlobalRoot)) {
|
|
1606
|
+
throw new Error('Inherited upgrade coordination requires both its token and global root.');
|
|
1607
|
+
}
|
|
1608
|
+
if (!this.options.upgradeToken || !this.options.upgradeGlobalRoot) return;
|
|
1609
|
+
if (process.env[upgradeTokenEnvironmentVariable] !== this.options.upgradeToken) {
|
|
1610
|
+
throw new Error('The inherited upgrade coordination token changed before controller startup.');
|
|
1611
|
+
}
|
|
1612
|
+
this.upgradeToken = this.options.upgradeToken;
|
|
1613
|
+
this.upgradeCoordinator = new UpgradeCoordinator(this.options.upgradeGlobalRoot);
|
|
1614
|
+
} finally {
|
|
1615
|
+
delete process.env[upgradeTokenEnvironmentVariable];
|
|
1616
|
+
delete process.env[upgradeCoordinationRootEnvironmentVariable];
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1597
1620
|
public async start(): Promise<IControllerStartResult> {
|
|
1598
1621
|
if (this.lifecycleState === 'ready') {
|
|
1599
1622
|
return { status: this.getStatus(), publicUrl: this.requireRuntimeConfig().publicOrigin };
|
|
@@ -1705,7 +1728,9 @@ export class OpenCodeController {
|
|
|
1705
1728
|
}
|
|
1706
1729
|
|
|
1707
1730
|
private async performStart(): Promise<IControllerStartResult> {
|
|
1731
|
+
process.env.AGL_HOME = resolveAGLHomePaths().root;
|
|
1708
1732
|
this.lifecycleState = 'starting';
|
|
1733
|
+
this.captureInheritedUpgradeCoordination();
|
|
1709
1734
|
const identity = await readControllerProcessIdentity(process.pid);
|
|
1710
1735
|
this.assertStartActive();
|
|
1711
1736
|
if (identity) {
|
|
@@ -1714,9 +1739,11 @@ export class OpenCodeController {
|
|
|
1714
1739
|
}
|
|
1715
1740
|
let upgradeCliPath: string | undefined;
|
|
1716
1741
|
if (this.options.upgradeToken && this.options.upgradeGlobalRoot) {
|
|
1717
|
-
|
|
1718
|
-
this.
|
|
1719
|
-
|
|
1742
|
+
const inheritedCoordinator = this.upgradeCoordinator;
|
|
1743
|
+
if (!inheritedCoordinator || this.upgradeToken !== this.options.upgradeToken) {
|
|
1744
|
+
throw new Error('The inherited upgrade coordination was not captured before startup.');
|
|
1745
|
+
}
|
|
1746
|
+
const transaction = await inheritedCoordinator.readTransaction(this.options.upgradeToken);
|
|
1720
1747
|
const installation = await resolveInheritedUpgradeTargetInstallation(transaction);
|
|
1721
1748
|
const cliPath = await plugins.fs.promises.realpath(
|
|
1722
1749
|
plugins.url.fileURLToPath(new URL('../cli.js', import.meta.url)),
|
|
@@ -1732,11 +1759,11 @@ export class OpenCodeController {
|
|
|
1732
1759
|
cliName: currentCliName,
|
|
1733
1760
|
cliRelativePath: './cli.js',
|
|
1734
1761
|
});
|
|
1735
|
-
this.upgradeStatus = await
|
|
1762
|
+
this.upgradeStatus = await inheritedCoordinator.readSanitizedUpgradeStatus(
|
|
1736
1763
|
this.options.upgradeToken,
|
|
1737
1764
|
);
|
|
1738
1765
|
upgradeCliPath = cliPath;
|
|
1739
|
-
await
|
|
1766
|
+
await inheritedCoordinator.recordController(this.options.upgradeToken, {
|
|
1740
1767
|
pid: process.pid,
|
|
1741
1768
|
processGroupId: this.processGroupId,
|
|
1742
1769
|
fingerprint: this.processFingerprint,
|
|
@@ -1872,6 +1899,17 @@ export class OpenCodeController {
|
|
|
1872
1899
|
this.assertStartActive();
|
|
1873
1900
|
this.runtimeConfig = runtimeConfig;
|
|
1874
1901
|
this.controllerId = authDocument.id;
|
|
1902
|
+
this.openCodeRuntimeDirectory = plugins.path.join(
|
|
1903
|
+
dataDirectory,
|
|
1904
|
+
'runtime',
|
|
1905
|
+
'opencode',
|
|
1906
|
+
plugins.crypto.createHash('sha256').update(authDocument.id, 'utf8').digest('hex'),
|
|
1907
|
+
);
|
|
1908
|
+
await plugins.fs.promises.mkdir(this.openCodeRuntimeDirectory, {
|
|
1909
|
+
recursive: true,
|
|
1910
|
+
mode: 0o700,
|
|
1911
|
+
});
|
|
1912
|
+
await plugins.fs.promises.chmod(this.openCodeRuntimeDirectory, 0o700);
|
|
1875
1913
|
|
|
1876
1914
|
const passkeyManager = new PasskeyManager({ store: authStore });
|
|
1877
1915
|
this.passkeyManager = passkeyManager;
|
|
@@ -1972,8 +2010,9 @@ export class OpenCodeController {
|
|
|
1972
2010
|
this.setupCodeExpiresAt = setupAuthority?.expiresAt.getTime();
|
|
1973
2011
|
this.assertStartActive();
|
|
1974
2012
|
|
|
1975
|
-
|
|
1976
|
-
|
|
2013
|
+
const pendingProjectRemovals = await this.registerExplicitInitialProject(
|
|
2014
|
+
this.options.runtimeOverrides.initialProjectDirectory,
|
|
2015
|
+
);
|
|
1977
2016
|
const startupProjectState = await this.reconcileProjectState(false);
|
|
1978
2017
|
for (const project of pendingProjectRemovals) this.retiringProjectIds.add(project.id);
|
|
1979
2018
|
for (const project of startupProjectState.projects) {
|
|
@@ -2107,6 +2146,7 @@ export class OpenCodeController {
|
|
|
2107
2146
|
database: flexDatabase,
|
|
2108
2147
|
flexCredentialDirectory: plugins.path.join(
|
|
2109
2148
|
dataDirectory,
|
|
2149
|
+
'credentials',
|
|
2110
2150
|
'flex-provider-credentials',
|
|
2111
2151
|
plugins.crypto.createHash('sha256').update(controllerId, 'utf8').digest('hex'),
|
|
2112
2152
|
),
|
|
@@ -2212,7 +2252,8 @@ export class OpenCodeController {
|
|
|
2212
2252
|
browserResourceHost = new ControllerBrowserResourceHost({
|
|
2213
2253
|
runtimeDirectory: plugins.path.join(
|
|
2214
2254
|
dataDirectory,
|
|
2215
|
-
'
|
|
2255
|
+
'runtime',
|
|
2256
|
+
'browser',
|
|
2216
2257
|
plugins.crypto.createHash('sha256').update(controllerId).digest('hex'),
|
|
2217
2258
|
),
|
|
2218
2259
|
authorizeCapability: (requestArg) => (
|
|
@@ -2338,6 +2379,19 @@ export class OpenCodeController {
|
|
|
2338
2379
|
};
|
|
2339
2380
|
}
|
|
2340
2381
|
|
|
2382
|
+
private coordinatorForUpgradeToken(
|
|
2383
|
+
tokenArg: string,
|
|
2384
|
+
globalRootArg: string,
|
|
2385
|
+
): UpgradeCoordinator {
|
|
2386
|
+
if (this.upgradeToken === tokenArg && this.upgradeCoordinator) {
|
|
2387
|
+
if (this.upgradeCoordinator.canonicalGlobalRoot !== globalRootArg) {
|
|
2388
|
+
throw new Error('The inherited upgrade coordination global root changed unexpectedly.');
|
|
2389
|
+
}
|
|
2390
|
+
return this.upgradeCoordinator;
|
|
2391
|
+
}
|
|
2392
|
+
return new UpgradeCoordinator(globalRootArg);
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2341
2395
|
private startOpenCodeEventStream(
|
|
2342
2396
|
openCodeClientArg: OpenCodeClientAdapter,
|
|
2343
2397
|
skipInitialStreamAdvanceArg = false,
|
|
@@ -2476,9 +2530,12 @@ export class OpenCodeController {
|
|
|
2476
2530
|
|
|
2477
2531
|
private createOpenCodeSupervisor(): OpenCodeSupervisor {
|
|
2478
2532
|
const runtimeConfig = this.requireRuntimeConfig();
|
|
2533
|
+
if (!this.openCodeRuntimeDirectory) {
|
|
2534
|
+
throw new Error('The OpenCode runtime directory is unavailable.');
|
|
2535
|
+
}
|
|
2479
2536
|
let supervisor!: OpenCodeSupervisor;
|
|
2480
2537
|
supervisor = new OpenCodeSupervisor({
|
|
2481
|
-
directory:
|
|
2538
|
+
directory: this.openCodeRuntimeDirectory,
|
|
2482
2539
|
port: runtimeConfig.opencodePort,
|
|
2483
2540
|
onChildExit: () => {
|
|
2484
2541
|
this.openCodeSupervisorExitSignals.get(supervisor)?.resolve();
|
|
@@ -3192,6 +3249,7 @@ export class OpenCodeController {
|
|
|
3192
3249
|
this.authStore = undefined;
|
|
3193
3250
|
this.passkeyManager = undefined;
|
|
3194
3251
|
this.controllerId = undefined;
|
|
3252
|
+
this.openCodeRuntimeDirectory = undefined;
|
|
3195
3253
|
}
|
|
3196
3254
|
});
|
|
3197
3255
|
}
|
|
@@ -3312,7 +3370,10 @@ export class OpenCodeController {
|
|
|
3312
3370
|
try {
|
|
3313
3371
|
const installation = await resolveCurrentPnpmGlobalInstallation();
|
|
3314
3372
|
const status = this.getStatus();
|
|
3315
|
-
const coordinator =
|
|
3373
|
+
const coordinator = this.coordinatorForUpgradeToken(
|
|
3374
|
+
requestArg.token,
|
|
3375
|
+
installation.globalRoot,
|
|
3376
|
+
);
|
|
3316
3377
|
await coordinator.consumeLaunchGrant({
|
|
3317
3378
|
token: requestArg.token,
|
|
3318
3379
|
port: this.requireRuntimeConfig().controllerPort,
|
|
@@ -3372,7 +3433,10 @@ export class OpenCodeController {
|
|
|
3372
3433
|
return this.runOperation(peer, async (signalArg) => (
|
|
3373
3434
|
this.runUpgradePreparationAdmission(async () => {
|
|
3374
3435
|
const installation = await resolveCurrentPnpmGlobalInstallation();
|
|
3375
|
-
const coordinator =
|
|
3436
|
+
const coordinator = this.coordinatorForUpgradeToken(
|
|
3437
|
+
requestArg.token,
|
|
3438
|
+
installation.globalRoot,
|
|
3439
|
+
);
|
|
3376
3440
|
const status = this.getStatus();
|
|
3377
3441
|
await coordinator.consumeControllerActionGrant({
|
|
3378
3442
|
token: requestArg.token,
|
|
@@ -3406,7 +3470,10 @@ export class OpenCodeController {
|
|
|
3406
3470
|
return this.runOperation(peer, async () => (
|
|
3407
3471
|
this.runUpgradePreparationAdmission(async () => {
|
|
3408
3472
|
const installation = await resolveCurrentPnpmGlobalInstallation();
|
|
3409
|
-
const coordinator =
|
|
3473
|
+
const coordinator = this.coordinatorForUpgradeToken(
|
|
3474
|
+
requestArg.token,
|
|
3475
|
+
installation.globalRoot,
|
|
3476
|
+
);
|
|
3410
3477
|
if (await this.upgradePreparationReplayIsAccepted(
|
|
3411
3478
|
coordinator,
|
|
3412
3479
|
requestArg.token,
|
|
@@ -3454,7 +3521,10 @@ export class OpenCodeController {
|
|
|
3454
3521
|
);
|
|
3455
3522
|
return this.runOperation(peer, async () => {
|
|
3456
3523
|
const installation = await resolveCurrentPnpmGlobalInstallation();
|
|
3457
|
-
const coordinator =
|
|
3524
|
+
const coordinator = this.coordinatorForUpgradeToken(
|
|
3525
|
+
requestArg.token,
|
|
3526
|
+
installation.globalRoot,
|
|
3527
|
+
);
|
|
3458
3528
|
const status = this.getStatus();
|
|
3459
3529
|
await coordinator.consumeControllerActionGrant({
|
|
3460
3530
|
token: requestArg.token,
|
|
@@ -6187,20 +6257,17 @@ export class OpenCodeController {
|
|
|
6187
6257
|
return projectsRoot;
|
|
6188
6258
|
}
|
|
6189
6259
|
|
|
6190
|
-
private async
|
|
6191
|
-
|
|
6260
|
+
private async registerExplicitInitialProject(
|
|
6261
|
+
initialProjectDirectoryArg: string | undefined,
|
|
6192
6262
|
): Promise<IControllerProjectDocument[]> {
|
|
6193
6263
|
const authStore = this.requireAuthStore();
|
|
6194
|
-
const
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
]);
|
|
6198
|
-
if (activeProjects.length === 0 && pendingRemovals.length === 0) {
|
|
6199
|
-
const workspaceDirectory = await resolveCanonicalDirectory(workspaceDirectoryArg);
|
|
6264
|
+
const pendingRemovals = await authStore.listPendingProjectRemovals();
|
|
6265
|
+
if (initialProjectDirectoryArg !== undefined) {
|
|
6266
|
+
const initialProjectDirectory = await resolveCanonicalDirectory(initialProjectDirectoryArg);
|
|
6200
6267
|
await authStore.createProject(
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6268
|
+
this.deriveProjectName(initialProjectDirectory.directory),
|
|
6269
|
+
initialProjectDirectory.directory,
|
|
6270
|
+
initialProjectDirectory,
|
|
6204
6271
|
);
|
|
6205
6272
|
}
|
|
6206
6273
|
return pendingRemovals;
|
|
@@ -14170,13 +14237,12 @@ export class OpenCodeController {
|
|
|
14170
14237
|
if (!client) return;
|
|
14171
14238
|
const deadline = AbortSignal.timeout(abortConversationsOnStopTimeoutMs);
|
|
14172
14239
|
const directories = new Set<string>();
|
|
14173
|
-
if (this.runtimeConfig) directories.add(this.runtimeConfig.workspaceDirectory);
|
|
14174
14240
|
try {
|
|
14175
14241
|
for (const project of (await this.authStore?.listProjects()) ?? []) {
|
|
14176
14242
|
directories.add(project.directory);
|
|
14177
14243
|
}
|
|
14178
14244
|
} catch {
|
|
14179
|
-
// Project registry unavailable
|
|
14245
|
+
// Project registry unavailable; shutdown continues with owned resources.
|
|
14180
14246
|
}
|
|
14181
14247
|
for (const directory of directories) {
|
|
14182
14248
|
try {
|
package/ts/classes.embeddeddb.ts
CHANGED
|
@@ -46,10 +46,8 @@ export class EmbeddedControllerDatabase {
|
|
|
46
46
|
constructor(private readonly options: IEmbeddedControllerDatabaseOptions) {}
|
|
47
47
|
|
|
48
48
|
public get socketPath(): string {
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// deterministic, so a second controller process attaches to the same
|
|
52
|
-
// engine, and independent of how deep the data directory is nested.
|
|
49
|
+
// The hashed name is deterministic so another AGL process can attach to
|
|
50
|
+
// the same engine without owning its storage files.
|
|
53
51
|
return embeddedDatabaseSocketPath(this.options.dataDirectory);
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -74,6 +72,9 @@ export class EmbeddedControllerDatabase {
|
|
|
74
72
|
if (this.localDb || this.migrationRunner?.hasOwnedResources) {
|
|
75
73
|
throw new Error('Embedded database startup cleanup must complete before retrying.');
|
|
76
74
|
}
|
|
75
|
+
const socketDirectory = plugins.path.dirname(this.socketPath);
|
|
76
|
+
await plugins.fs.promises.mkdir(socketDirectory, { recursive: true, mode: 0o700 });
|
|
77
|
+
await plugins.fs.promises.chmod(socketDirectory, 0o700);
|
|
77
78
|
if (this.options.legacyDataDirectory) {
|
|
78
79
|
const migrationRunner = new EmbeddedDatabaseMigrationRunner({
|
|
79
80
|
sourceDirectory: this.options.legacyDataDirectory,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
+
import { resolveAGLHomePaths } from './classes.aglhome.js';
|
|
2
3
|
import {
|
|
3
4
|
assertCanonicalDirectory,
|
|
4
5
|
assertCanonicalFilesystemObject,
|
|
@@ -746,8 +747,8 @@ export class ControllerGitReversion {
|
|
|
746
747
|
this.validateLimits();
|
|
747
748
|
this.maximumPrivateTreeEntries = privateTreeTraversalLimit(this.limits);
|
|
748
749
|
this.rootDirectory = optionsArg.temporaryRoot ?? plugins.path.join(
|
|
749
|
-
|
|
750
|
-
|
|
750
|
+
resolveAGLHomePaths().gitReversion,
|
|
751
|
+
sha256(optionsArg.ownerId),
|
|
751
752
|
);
|
|
752
753
|
if (!plugins.path.isAbsolute(this.rootDirectory)) {
|
|
753
754
|
throw new Error('The Git reversion temporary root must be absolute.');
|