@aopslabs/aops 0.3.23 → 0.3.25
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/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/SKILL.md +0 -1
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/agentspace/SKILL.md +0 -6
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/collaborative-work/SKILL.md +1 -2
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/working-disciplines/SKILL.md +2 -5
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/agentspace.md +1 -16
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/aops-cli.md +4 -33
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/working-disciplines.md +32 -138
- package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/manifest.json +17 -22
- package/agent-assets-release/agent-assets/inventory.json +5 -5
- package/agent-assets-release/agent-assets/projection.json +1 -1
- package/agent-assets-release/agent-assets-release.json +48 -53
- package/agent-assets-release/agent-assets-release.sigstore.json +27 -31
- package/assets/agent-assets/core/SKILL.md +0 -1
- package/assets/agent-assets/core/references/agentspace/SKILL.md +0 -6
- package/assets/agent-assets/core/references/collaborative-work/SKILL.md +1 -2
- package/assets/agent-assets/core/references/working-disciplines/SKILL.md +2 -5
- package/assets/agent-assets/core/user-guides/agentspace.md +1 -16
- package/assets/agent-assets/core/user-guides/aops-cli.md +4 -33
- package/assets/agent-assets/core/user-guides/working-disciplines.md +32 -138
- package/dist/commands/checkpoint.js +4 -23
- package/dist/commands/community-server.js +212 -6
- package/dist/commands/db.js +145 -0
- package/dist/commands/experience.js +0 -2
- package/dist/commands/global-update.js +447 -22
- package/dist/commands/memory.js +8 -2
- package/dist/commands/official-catalog.js +1 -1
- package/dist/commands/plan.js +2 -2
- package/dist/commands/pm/index.js +39 -3
- package/dist/commands/pm/projectman.js +281 -8
- package/dist/commands/start-disciplines.js +8 -21
- package/dist/commands/start.js +20 -504
- package/dist/lib/agent-assets/native-fs.js +2 -2
- package/dist/lib/community-cockpit-lifecycle.js +95 -1
- package/dist/lib/community-migration-snapshot.js +43 -2
- package/dist/lib/community-native-backup.js +386 -0
- package/dist/lib/community-native-lifecycle.js +147 -5
- package/dist/lib/community-native-migration.js +20 -0
- package/dist/main.js +2 -2
- package/dist/seeds/agents-md.js +1 -1
- package/dist/utils/playbook-workspace.js +5 -33
- package/dist/utils/session-guidance.js +0 -7
- package/native/bin/darwin-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/darwin-x64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-x64/aops-agent-assets-fs +0 -0
- package/native/bin/win32-x64/aops-agent-assets-fs.exe +0 -0
- package/native/manifest.json +6 -6
- package/native/qualifications/win32-x64.json +2 -2
- package/native/tui/darwin-arm64/aops-tui +0 -0
- package/native/tui/linux-x64/aops-tui +0 -0
- package/native/tui/win32-x64/aops-tui.exe +0 -0
- package/package.json +21 -9
- package/agent-assets-release/agent-assets/core/647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09/files/references/mission/SKILL.md +0 -54
- package/assets/agent-assets/core/references/mission/SKILL.md +0 -54
- package/dist/commands/mission.js +0 -562
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/aops-cli-core/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/chatv3/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/discuss/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/docman/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/projectman/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/sys/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/view/SKILL.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/agent-assets.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/aops-system.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/chatv3.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/docman.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/projectman.md +0 -0
- /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/sys.md +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync, } from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { Command } from 'commander';
|
|
4
5
|
import { abandonInterruptedCommunityRecovery, assertCommunityLedgerHasNoNonterminalOperation, assertNoCommunityRecoveryCommitJournal, assertCommunityRecoveryMutationFence, buildCommunityComposeInvocation, inspectCommunityInstall, readCommunityBackupReceipt, reconcileCommunityRecoveryCommit, recoverCommunityUpdate, resolveCommunityInstallPaths, restoreCommunitySourceRuntime, restoreCommunityBackup, rollbackCommunityInstall, setupCommunityInstall, stageCommunityRelease, updateCommunityInstall, verifyStagedCommunityRelease, verifyCommunityBackupRecord, writeCommunityBackupReceipt, } from '../lib/community-lifecycle.js';
|
|
5
6
|
import { communityProcessRuntime, createCommunityDockerAdapter } from '../lib/community-docker-adapter.js';
|
|
6
7
|
import { communityCommandAbortRuntime, throwIfCommunityCommandAborted, withCommunityCommandAbortScope, } from '../lib/community-command-abort.js';
|
|
8
|
+
import { compareCanonicalText } from '@aopslabs/artifact-trust-contracts';
|
|
9
|
+
import { createCommunityNativeBackupV1, restoreCommunityNativeBackupV1, verifyCommunityNativeBackupV1, } from '../lib/community-native-backup.js';
|
|
7
10
|
import { resolveCommunityInstanceLayout } from '../lib/community-instance-layout.js';
|
|
8
11
|
import { assertCommunityOperationJournalFence, captureCommunityOperationDigests, createCommunityOperationJournal, digestsEqual, finishCommunityOperationJournal, inspectCommunityOperationJournalFile, openCommunityOperationJournalForReconciliation, runCommunityJournaledPromotion, runCommunityJournaledSideEffect, } from '../lib/community-operation-journal.js';
|
|
9
12
|
import { COMMUNITY_OPERATION_LOCK_DIRECTORY_NAME, inspectCommunityOperationLock, recoverStaleCommunityOperationLock, withCommunityOperationLock, } from '../lib/community-operation-lock.js';
|
|
@@ -1479,6 +1482,30 @@ export async function runCommunityServerRollback(options, dependencies = {}) {
|
|
|
1479
1482
|
});
|
|
1480
1483
|
}
|
|
1481
1484
|
export async function runCommunityServerBackup(options, dependencies = {}) {
|
|
1485
|
+
const native = inspectNativeFrom(options);
|
|
1486
|
+
if (native.status !== 'not-installed' && native.state?.postgres.mode === 'external') {
|
|
1487
|
+
const paths = resolveCommunityNativePaths(installSelection(options));
|
|
1488
|
+
const repoUrl = loadExternalPostgresUrl(native.state.postgres.configRef, native.state.postgres.tlsPolicy);
|
|
1489
|
+
const { record, receiptPath } = await createCommunityNativeBackupV1({
|
|
1490
|
+
backupRoot: paths.backupRoot,
|
|
1491
|
+
repoUrl,
|
|
1492
|
+
instanceName: native.state.instanceName,
|
|
1493
|
+
releaseVersion: native.state.source.releaseVersion ?? null,
|
|
1494
|
+
pgBinDir: options.pgBinDir,
|
|
1495
|
+
});
|
|
1496
|
+
writeResult({
|
|
1497
|
+
status: 'community-backup-created',
|
|
1498
|
+
profile: native.state.profile,
|
|
1499
|
+
backup: {
|
|
1500
|
+
path: record.path,
|
|
1501
|
+
receiptPath,
|
|
1502
|
+
sha256: record.sha256,
|
|
1503
|
+
byteLength: record.byteLength,
|
|
1504
|
+
kind: record.kind,
|
|
1505
|
+
},
|
|
1506
|
+
}, options.json);
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1482
1509
|
await withMutatingCommandScope(dependencies, async (runtime, signal) => {
|
|
1483
1510
|
const output = await withInstalledOperation(options, 'backup', runtime, signal, async ({ paths, state }, { journal, lifecycle }) => {
|
|
1484
1511
|
const record = await lifecycle.createBackup({ paths, state });
|
|
@@ -1501,12 +1528,181 @@ export async function runCommunityServerBackup(options, dependencies = {}) {
|
|
|
1501
1528
|
writeResult(output, options.json);
|
|
1502
1529
|
});
|
|
1503
1530
|
}
|
|
1531
|
+
function restoreGateForInstall(options) {
|
|
1532
|
+
try {
|
|
1533
|
+
const native = inspectNativeFrom(options);
|
|
1534
|
+
return native.status !== 'not-installed' && native.state?.postgres.mode === 'external'
|
|
1535
|
+
? 'native'
|
|
1536
|
+
: 'oci';
|
|
1537
|
+
}
|
|
1538
|
+
catch {
|
|
1539
|
+
return 'either';
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
async function scanCommunityBackups(options) {
|
|
1543
|
+
const restoreGate = options.restoreGate ?? restoreGateForInstall(options);
|
|
1544
|
+
const paths = pathsFrom(options);
|
|
1545
|
+
const updatesRoot = options.updatesRoot
|
|
1546
|
+
? path.resolve(options.updatesRoot)
|
|
1547
|
+
: path.join(os.homedir(), '.aops', 'global-updates');
|
|
1548
|
+
const entries = [];
|
|
1549
|
+
const candidates = [];
|
|
1550
|
+
const collect = (directory, origin) => {
|
|
1551
|
+
if (!existsSync(directory))
|
|
1552
|
+
return;
|
|
1553
|
+
let names;
|
|
1554
|
+
try {
|
|
1555
|
+
names = readdirSync(directory);
|
|
1556
|
+
}
|
|
1557
|
+
catch {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
for (const name of names) {
|
|
1561
|
+
if (!name.endsWith('.dump'))
|
|
1562
|
+
continue;
|
|
1563
|
+
candidates.push({ dumpPath: path.join(directory, name), origin });
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
collect(paths.backupRoot, 'instance-backup');
|
|
1567
|
+
if (existsSync(updatesRoot)) {
|
|
1568
|
+
let updateDirs;
|
|
1569
|
+
try {
|
|
1570
|
+
updateDirs = readdirSync(updatesRoot);
|
|
1571
|
+
}
|
|
1572
|
+
catch {
|
|
1573
|
+
updateDirs = [];
|
|
1574
|
+
}
|
|
1575
|
+
for (const updateDir of updateDirs) {
|
|
1576
|
+
collect(path.join(updatesRoot, updateDir, 'database-backup'), 'update-backup');
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
for (const candidate of candidates) {
|
|
1580
|
+
let stats;
|
|
1581
|
+
try {
|
|
1582
|
+
stats = lstatSync(candidate.dumpPath);
|
|
1583
|
+
}
|
|
1584
|
+
catch {
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if (!stats.isFile())
|
|
1588
|
+
continue;
|
|
1589
|
+
const receiptPresent = existsSync(`${candidate.dumpPath}.json`);
|
|
1590
|
+
let eligible = false;
|
|
1591
|
+
let reason = null;
|
|
1592
|
+
let verifiedBy = null;
|
|
1593
|
+
let nativeRefusal = null;
|
|
1594
|
+
if (restoreGate !== 'oci') {
|
|
1595
|
+
try {
|
|
1596
|
+
const record = await verifyCommunityNativeBackupV1({ backupPath: candidate.dumpPath });
|
|
1597
|
+
eligible = true;
|
|
1598
|
+
verifiedBy = record.verifiedBy ?? null;
|
|
1599
|
+
}
|
|
1600
|
+
catch (nativeError) {
|
|
1601
|
+
nativeRefusal = nativeError instanceof Error ? nativeError.message : String(nativeError);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
if (!eligible && restoreGate !== 'native') {
|
|
1605
|
+
try {
|
|
1606
|
+
await readCommunityBackupReceipt(paths, candidate.dumpPath);
|
|
1607
|
+
eligible = true;
|
|
1608
|
+
}
|
|
1609
|
+
catch (ociError) {
|
|
1610
|
+
const ociRefusal = ociError instanceof Error ? ociError.message : String(ociError);
|
|
1611
|
+
reason = nativeRefusal === null ? ociRefusal : `native: ${nativeRefusal}; oci: ${ociRefusal}`;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
else if (!eligible) {
|
|
1615
|
+
reason = nativeRefusal;
|
|
1616
|
+
}
|
|
1617
|
+
entries.push({
|
|
1618
|
+
path: candidate.dumpPath,
|
|
1619
|
+
origin: candidate.origin,
|
|
1620
|
+
byteLength: stats.size,
|
|
1621
|
+
modifiedAt: new Date(stats.mtimeMs).toISOString(),
|
|
1622
|
+
receiptPresent,
|
|
1623
|
+
eligible,
|
|
1624
|
+
reason,
|
|
1625
|
+
verifiedBy,
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
entries.sort((left, right) => compareCanonicalText(right.modifiedAt, left.modifiedAt));
|
|
1629
|
+
return { paths, updatesRoot, entries };
|
|
1630
|
+
}
|
|
1631
|
+
export async function runCommunityServerBackupList(options, dependencies = {}) {
|
|
1632
|
+
const { paths, updatesRoot, entries } = await scanCommunityBackups(options);
|
|
1633
|
+
writeResult({
|
|
1634
|
+
status: 'community-backup-list',
|
|
1635
|
+
mutationFree: true,
|
|
1636
|
+
instance: options.instance ?? 'default',
|
|
1637
|
+
searched: [paths.backupRoot, updatesRoot],
|
|
1638
|
+
count: entries.length,
|
|
1639
|
+
restoreGate: options.restoreGate ?? restoreGateForInstall(options),
|
|
1640
|
+
eligibleCount: entries.filter((entry) => entry.eligible).length,
|
|
1641
|
+
backups: entries,
|
|
1642
|
+
}, options.json);
|
|
1643
|
+
}
|
|
1644
|
+
export async function resolveCommunityRestoreSource(options) {
|
|
1645
|
+
const explicit = typeof options.backup === 'string' && options.backup.trim() !== '';
|
|
1646
|
+
if (explicit && options.latest === true) {
|
|
1647
|
+
throw new Error('community_restore_source_ambiguous:pass_either_--latest_or_--backup_not_both');
|
|
1648
|
+
}
|
|
1649
|
+
if (!explicit && options.latest !== true) {
|
|
1650
|
+
throw new Error('community_restore_backup_path_required:pass_--backup_<path>_or_--latest');
|
|
1651
|
+
}
|
|
1652
|
+
if (explicit) {
|
|
1653
|
+
return { backupPath: path.resolve(options.backup), selection: 'explicit', candidate: null };
|
|
1654
|
+
}
|
|
1655
|
+
const { entries } = await scanCommunityBackups(options);
|
|
1656
|
+
const eligible = entries.filter((entry) => entry.eligible);
|
|
1657
|
+
if (eligible.length === 0) {
|
|
1658
|
+
const refusals = entries
|
|
1659
|
+
.slice(0, 5)
|
|
1660
|
+
.map((entry) => `${entry.path}: ${entry.reason ?? 'unknown'}`)
|
|
1661
|
+
.join('; ');
|
|
1662
|
+
throw new Error(entries.length === 0
|
|
1663
|
+
? 'community_restore_no_backup_found: no backup files were found to restore from'
|
|
1664
|
+
: `community_restore_no_eligible_backup: found ${entries.length} backup file(s), none restorable (${refusals})`);
|
|
1665
|
+
}
|
|
1666
|
+
return { backupPath: eligible[0].path, selection: 'latest', candidate: eligible[0] };
|
|
1667
|
+
}
|
|
1504
1668
|
export async function runCommunityServerRestore(options, dependencies = {}) {
|
|
1505
|
-
|
|
1506
|
-
|
|
1669
|
+
const gate = restoreGateForInstall(options);
|
|
1670
|
+
const source = await resolveCommunityRestoreSource({ ...options, restoreGate: gate });
|
|
1671
|
+
if (gate === 'native') {
|
|
1672
|
+
const native = inspectNativeFrom(options);
|
|
1673
|
+
const postgres = native.state?.postgres;
|
|
1674
|
+
if (postgres?.mode !== 'external') {
|
|
1675
|
+
throw new Error('community_server_restore_native_profile_lost');
|
|
1676
|
+
}
|
|
1677
|
+
const paths = resolveCommunityNativePaths(installSelection(options));
|
|
1678
|
+
const repoUrl = loadExternalPostgresUrl(postgres.configRef, postgres.tlsPolicy);
|
|
1679
|
+
const result = await restoreCommunityNativeBackupV1({
|
|
1680
|
+
backupPath: source.backupPath,
|
|
1681
|
+
repoUrl,
|
|
1682
|
+
backupRoot: paths.backupRoot,
|
|
1683
|
+
instanceName: native.state.instanceName,
|
|
1684
|
+
releaseVersion: native.state.source.releaseVersion ?? null,
|
|
1685
|
+
confirmDataRewind: options.confirmDataRewind === true,
|
|
1686
|
+
confirmNoUndo: options.confirmNoUndo === true,
|
|
1687
|
+
skipPreRestoreBackup: options.preRestoreBackup === false,
|
|
1688
|
+
pgBinDir: options.pgBinDir,
|
|
1689
|
+
});
|
|
1690
|
+
writeResult({
|
|
1691
|
+
status: 'community-backup-restored',
|
|
1692
|
+
profile: native.state.profile,
|
|
1693
|
+
selection: source.selection,
|
|
1694
|
+
backup: {
|
|
1695
|
+
path: result.restored.path,
|
|
1696
|
+
sha256: result.restored.sha256,
|
|
1697
|
+
byteLength: result.restored.byteLength,
|
|
1698
|
+
},
|
|
1699
|
+
preRestoreBackup: result.preRestoreBackup,
|
|
1700
|
+
}, options.json);
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1507
1703
|
await withMutatingCommandScope(dependencies, async (runtime, signal) => {
|
|
1508
1704
|
const output = await withInstalledOperation(options, 'restore', runtime, signal, async ({ paths }, { journal, receipt, lifecycle }) => {
|
|
1509
|
-
const backup = await readCommunityBackupReceipt(paths,
|
|
1705
|
+
const backup = await readCommunityBackupReceipt(paths, source.backupPath);
|
|
1510
1706
|
throwIfCommunityCommandAborted(signal);
|
|
1511
1707
|
const result = await restoreCommunityBackup({
|
|
1512
1708
|
paths,
|
|
@@ -1520,6 +1716,7 @@ export async function runCommunityServerRestore(options, dependencies = {}) {
|
|
|
1520
1716
|
throwIfCommunityCommandAborted(signal);
|
|
1521
1717
|
return {
|
|
1522
1718
|
status: 'community-backup-restored',
|
|
1719
|
+
selection: source.selection,
|
|
1523
1720
|
backup: { path: backup.path, sha256: backup.sha256, byteLength: backup.byteLength },
|
|
1524
1721
|
replacementVolumeName: result.replacementVolumeName,
|
|
1525
1722
|
};
|
|
@@ -1947,7 +2144,7 @@ export async function runCommunityServerReset(options, dependencies = {}) {
|
|
|
1947
2144
|
}
|
|
1948
2145
|
function common(command) {
|
|
1949
2146
|
return command
|
|
1950
|
-
.option('--instance <name>', 'Installation instance name
|
|
2147
|
+
.option('--instance <name>', 'Installation instance name (default: "default")')
|
|
1951
2148
|
.option('--data-root <path>', 'Absolute Community data root override')
|
|
1952
2149
|
.option('--json', 'Output JSON');
|
|
1953
2150
|
}
|
|
@@ -2042,11 +2239,20 @@ export function makeCommunityServerCommand(identity = {}) {
|
|
|
2042
2239
|
.option('--detach', 'Start the rolled-back native server in the background (default)')
|
|
2043
2240
|
.option('--ready-timeout-ms <milliseconds>', 'Native Server readiness budget from 1000 to 900000 ms; default 120000')
|
|
2044
2241
|
.action((options, child) => runCommunityServerRollbackApplication(mergeCommunityCommandOptions(options, child), dependencies));
|
|
2045
|
-
common(command.command('backup').description('Create and verify a custom-format PostgreSQL backup plus receipt'))
|
|
2242
|
+
const backup = common(command.command('backup').description('Create and verify a custom-format PostgreSQL backup plus receipt'))
|
|
2243
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_dump / pg_restore, when they are not on PATH')
|
|
2046
2244
|
.action((options) => runCommunityServerBackup(options, dependencies));
|
|
2047
|
-
|
|
2245
|
+
common(backup.command('list').description('List existing backups and say which ones restore will accept'))
|
|
2246
|
+
.option('--updates-root <path>', 'Global update root to scan for updater-written dumps')
|
|
2247
|
+
.action((options, child) => runCommunityServerBackupList(mergeCommunityCommandOptions(options, child), dependencies));
|
|
2248
|
+
const restore = common(command.command('restore').description('Restore database data; dispatches on the install profile'))
|
|
2048
2249
|
.option('--backup <path>', 'Backup dump path; its JSON receipt must exist beside it')
|
|
2250
|
+
.option('--latest', 'Restore the newest backup that restore will accept; mutually exclusive with --backup')
|
|
2251
|
+
.option('--updates-root <path>', 'Global update root to scan when resolving --latest')
|
|
2049
2252
|
.option('--confirm-data-rewind', 'Confirm that data will be rewound to the selected backup')
|
|
2253
|
+
.option('--no-pre-restore-backup', 'Skip the automatic backup of the current state (native profile)')
|
|
2254
|
+
.option('--confirm-no-undo', 'Required alongside --no-pre-restore-backup: there will be nothing to go back to')
|
|
2255
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_restore / psql, when they are not on PATH')
|
|
2050
2256
|
.action((options) => runCommunityServerRestore(options, dependencies));
|
|
2051
2257
|
common(restore.command('db').description('Restore only PostgreSQL for one exact native application update'))
|
|
2052
2258
|
.requiredOption('--update-id <id>', 'Exact native application update ID whose snapshot evidence will be used')
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createCommunityNativeBackupV1, restoreCommunityNativeBackupV1, } from '../lib/community-native-backup.js';
|
|
4
|
+
import { inspectCommunityNativeInstall, loadExternalPostgresUrl, resolveCommunityNativePaths, } from '../lib/community-native-lifecycle.js';
|
|
5
|
+
import { reportCommunityNativePendingMigrations } from '../lib/community-native-migration.js';
|
|
6
|
+
import { resolveCommunityRestoreSource, runCommunityServerBackupList, } from './community-server.js';
|
|
7
|
+
function selection(command) {
|
|
8
|
+
return command.optsWithGlobals();
|
|
9
|
+
}
|
|
10
|
+
function withCommonOptions(command) {
|
|
11
|
+
return command
|
|
12
|
+
.option('--instance <name>', 'Installation instance name')
|
|
13
|
+
.option('--data-root <path>', 'Absolute Community data root override')
|
|
14
|
+
.option('--json', 'Output JSON');
|
|
15
|
+
}
|
|
16
|
+
export async function runDbBackup(options) {
|
|
17
|
+
const selectionInput = { instanceName: options.instance, dataRoot: options.dataRoot };
|
|
18
|
+
const native = inspectCommunityNativeInstall(selectionInput);
|
|
19
|
+
if (native.status === 'not-installed' || !native.state) {
|
|
20
|
+
throw new Error('community_db_backup_requires_installed_native_server');
|
|
21
|
+
}
|
|
22
|
+
if (native.state.postgres.mode !== 'external') {
|
|
23
|
+
throw new Error('community_db_backup_external_postgres_only:use_aops_server_backup_for_managed_postgres');
|
|
24
|
+
}
|
|
25
|
+
const paths = resolveCommunityNativePaths(selectionInput);
|
|
26
|
+
const repoUrl = loadExternalPostgresUrl(native.state.postgres.configRef, native.state.postgres.tlsPolicy);
|
|
27
|
+
const { record, receiptPath } = await createCommunityNativeBackupV1({
|
|
28
|
+
backupRoot: paths.backupRoot,
|
|
29
|
+
repoUrl,
|
|
30
|
+
instanceName: native.state.instanceName,
|
|
31
|
+
releaseVersion: native.state.source.releaseVersion ?? null,
|
|
32
|
+
pgBinDir: options.pgBinDir,
|
|
33
|
+
});
|
|
34
|
+
const payload = {
|
|
35
|
+
status: 'community-db-backup-created',
|
|
36
|
+
instance: native.state.instanceName,
|
|
37
|
+
backup: {
|
|
38
|
+
path: record.path,
|
|
39
|
+
receiptPath,
|
|
40
|
+
sha256: record.sha256,
|
|
41
|
+
byteLength: record.byteLength,
|
|
42
|
+
kind: record.kind,
|
|
43
|
+
createdAt: record.createdAt,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
if (options.json) {
|
|
47
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write(`Backup written and verified.\n ${record.path}\n ${record.byteLength} bytes ${record.sha256}\n`);
|
|
51
|
+
}
|
|
52
|
+
export async function runDbRestore(options) {
|
|
53
|
+
const selectionInput = { instanceName: options.instance, dataRoot: options.dataRoot };
|
|
54
|
+
const native = inspectCommunityNativeInstall(selectionInput);
|
|
55
|
+
if (native.status === 'not-installed' || !native.state) {
|
|
56
|
+
throw new Error('community_db_restore_requires_installed_native_server');
|
|
57
|
+
}
|
|
58
|
+
if (native.state.postgres.mode !== 'external') {
|
|
59
|
+
throw new Error('community_db_restore_external_postgres_only');
|
|
60
|
+
}
|
|
61
|
+
const source = await resolveCommunityRestoreSource({ ...options, restoreGate: 'native' });
|
|
62
|
+
const paths = resolveCommunityNativePaths(selectionInput);
|
|
63
|
+
const repoUrl = loadExternalPostgresUrl(native.state.postgres.configRef, native.state.postgres.tlsPolicy);
|
|
64
|
+
const result = await restoreCommunityNativeBackupV1({
|
|
65
|
+
backupPath: source.backupPath,
|
|
66
|
+
repoUrl,
|
|
67
|
+
backupRoot: paths.backupRoot,
|
|
68
|
+
instanceName: native.state.instanceName,
|
|
69
|
+
releaseVersion: native.state.source.releaseVersion ?? null,
|
|
70
|
+
confirmDataRewind: options.confirmDataRewind === true,
|
|
71
|
+
pgBinDir: options.pgBinDir,
|
|
72
|
+
skipPreRestoreBackup: options.preRestoreBackup === false,
|
|
73
|
+
confirmNoUndo: options.confirmNoUndo === true,
|
|
74
|
+
});
|
|
75
|
+
const reportRoot = options.sourceRoot
|
|
76
|
+
? path.resolve(options.sourceRoot)
|
|
77
|
+
: native.state.source.root;
|
|
78
|
+
const schema = reportRoot
|
|
79
|
+
? await reportCommunityNativePendingMigrations({ repoUrl, sourceRoot: reportRoot })
|
|
80
|
+
: { status: 'unavailable', reason: 'no source root is known, so the migration policy could not be read' };
|
|
81
|
+
const payload = {
|
|
82
|
+
status: 'community-db-restored',
|
|
83
|
+
schema,
|
|
84
|
+
instance: native.state.instanceName,
|
|
85
|
+
selection: source.selection,
|
|
86
|
+
restored: {
|
|
87
|
+
path: result.restored.path,
|
|
88
|
+
sha256: result.restored.sha256,
|
|
89
|
+
byteLength: result.restored.byteLength,
|
|
90
|
+
},
|
|
91
|
+
preRestoreBackup: result.preRestoreBackup,
|
|
92
|
+
};
|
|
93
|
+
if (options.json) {
|
|
94
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
process.stdout.write(`Restored ${result.restored.path}\n` +
|
|
98
|
+
(result.preRestoreBackup
|
|
99
|
+
? ` previous state saved to ${result.preRestoreBackup.path}\n`
|
|
100
|
+
: ' no pre-restore backup was taken\n'));
|
|
101
|
+
}
|
|
102
|
+
export function makeDbCommand() {
|
|
103
|
+
const command = new Command('db').description('Operator database surface: full PostgreSQL backup, listing and restore');
|
|
104
|
+
withCommonOptions(command.command('backup').description('Take one full PostgreSQL backup with pg_dump and verify it'))
|
|
105
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_dump / pg_restore, when they are not on PATH')
|
|
106
|
+
.action(async (_options, child) => {
|
|
107
|
+
await runDbBackup(selection(child));
|
|
108
|
+
});
|
|
109
|
+
withCommonOptions(command.command('list').description('List backups and say which ones a restore will accept'))
|
|
110
|
+
.option('--updates-root <path>', 'Global update root to scan for updater-written dumps')
|
|
111
|
+
.action(async (_options, child) => {
|
|
112
|
+
await runCommunityServerBackupList({ ...selection(child), restoreGate: 'native' });
|
|
113
|
+
});
|
|
114
|
+
withCommonOptions(command.command('restore').description('Restore one full backup: --latest or --backup <path>'))
|
|
115
|
+
.option('--backup <path>', 'Exact backup dump to restore')
|
|
116
|
+
.option('--latest', 'Restore the newest backup a restore will accept')
|
|
117
|
+
.option('--updates-root <path>', 'Global update root to scan when resolving --latest')
|
|
118
|
+
.option('--confirm-data-rewind', 'Confirm that data will be rewound to the selected backup')
|
|
119
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_dump / pg_restore, when they are not on PATH')
|
|
120
|
+
.option('--no-pre-restore-backup', 'Skip the automatic backup of the current state; requires --confirm-no-undo')
|
|
121
|
+
.option('--confirm-no-undo', 'Acknowledge that skipping the pre-restore backup removes the ability to undo')
|
|
122
|
+
.option('--source-root <path>', 'Repository root holding the migration policy; enables the post-restore schema report')
|
|
123
|
+
.action(async (_options, child) => {
|
|
124
|
+
await runDbRestore(selection(child));
|
|
125
|
+
});
|
|
126
|
+
withCommonOptions(command.command('which').description('Print the backup that --latest would choose, without restoring'))
|
|
127
|
+
.option('--updates-root <path>', 'Global update root to scan')
|
|
128
|
+
.action(async (_options, child) => {
|
|
129
|
+
const options = selection(child);
|
|
130
|
+
const source = await resolveCommunityRestoreSource({ ...options, latest: true, restoreGate: 'native' });
|
|
131
|
+
const payload = {
|
|
132
|
+
status: 'community-db-restore-source',
|
|
133
|
+
mutationFree: true,
|
|
134
|
+
selection: source.selection,
|
|
135
|
+
backup: source.backupPath,
|
|
136
|
+
candidate: source.candidate,
|
|
137
|
+
};
|
|
138
|
+
if (options.json) {
|
|
139
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
process.stdout.write(`--latest would restore:\n ${source.backupPath}\n`);
|
|
143
|
+
});
|
|
144
|
+
return command;
|
|
145
|
+
}
|
|
@@ -161,7 +161,6 @@ function parseSourceRefs(values) {
|
|
|
161
161
|
function buildExperienceMeta(options) {
|
|
162
162
|
const sessionContext = compactPayload({
|
|
163
163
|
sessionId: normalizeNonEmpty(options.sessionId),
|
|
164
|
-
missionId: normalizeNonEmpty(options.missionId),
|
|
165
164
|
chatv3Seq: normalizeNonEmpty(options.chatv3Seq),
|
|
166
165
|
pmRefs: toStringArray(options.pmRef),
|
|
167
166
|
discussRefs: toStringArray(options.discussRef),
|
|
@@ -832,7 +831,6 @@ Promote a hosted experience into a durable memory item, or a playbook:
|
|
|
832
831
|
.option('--tag <tag>', 'General tag; repeatable', collectRepeatedOption, [])
|
|
833
832
|
.option('--source-ref <json-or-ref>', 'Source reference JSON or string; repeatable', collectRepeatedOption, [])
|
|
834
833
|
.option('--session-id <id>', 'Session id for session-scoped experience context')
|
|
835
|
-
.option('--mission-id <id>', 'Mission id for session-scoped experience context')
|
|
836
834
|
.option('--chatv3-seq <seq>', 'ChatV3 sequence anchor for session-scoped experience context')
|
|
837
835
|
.option('--pm-ref <ref>', 'Projectman reference for session-scoped experience context; repeatable', collectRepeatedOption, [])
|
|
838
836
|
.option('--discuss-ref <ref>', 'Discuss topic/turn reference for session-scoped experience context; repeatable', collectRepeatedOption, [])
|