@aopslabs/aops 0.3.24 → 0.3.26

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 (64) hide show
  1. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/SKILL.md +0 -1
  2. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/agentspace/SKILL.md +0 -6
  3. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/collaborative-work/SKILL.md +1 -2
  4. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/working-disciplines/SKILL.md +2 -5
  5. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/agentspace.md +1 -16
  6. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/aops-cli.md +4 -33
  7. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/working-disciplines.md +32 -138
  8. package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/manifest.json +17 -22
  9. package/agent-assets-release/agent-assets/inventory.json +5 -5
  10. package/agent-assets-release/agent-assets/projection.json +1 -1
  11. package/agent-assets-release/agent-assets-release.json +48 -53
  12. package/agent-assets-release/agent-assets-release.sigstore.json +27 -28
  13. package/assets/agent-assets/core/SKILL.md +0 -1
  14. package/assets/agent-assets/core/references/agentspace/SKILL.md +0 -6
  15. package/assets/agent-assets/core/references/collaborative-work/SKILL.md +1 -2
  16. package/assets/agent-assets/core/references/working-disciplines/SKILL.md +2 -5
  17. package/assets/agent-assets/core/user-guides/agentspace.md +1 -16
  18. package/assets/agent-assets/core/user-guides/aops-cli.md +4 -33
  19. package/assets/agent-assets/core/user-guides/working-disciplines.md +32 -138
  20. package/dist/commands/checkpoint.js +4 -23
  21. package/dist/commands/community-server.js +212 -6
  22. package/dist/commands/db.js +145 -0
  23. package/dist/commands/experience.js +0 -2
  24. package/dist/commands/memory.js +8 -2
  25. package/dist/commands/official-catalog.js +1 -1
  26. package/dist/commands/plan.js +2 -2
  27. package/dist/commands/pm/index.js +39 -3
  28. package/dist/commands/pm/projectman.js +281 -8
  29. package/dist/commands/start-disciplines.js +8 -21
  30. package/dist/commands/start.js +20 -504
  31. package/dist/lib/agent-assets/native-fs.js +2 -2
  32. package/dist/lib/community-migration-snapshot.js +43 -2
  33. package/dist/lib/community-native-backup.js +386 -0
  34. package/dist/lib/community-native-lifecycle.js +93 -4
  35. package/dist/lib/community-native-migration.js +20 -0
  36. package/dist/main.js +2 -2
  37. package/dist/seeds/agents-md.js +1 -1
  38. package/dist/utils/playbook-workspace.js +5 -33
  39. package/dist/utils/session-guidance.js +0 -7
  40. package/native/bin/darwin-arm64/aops-agent-assets-fs +0 -0
  41. package/native/bin/darwin-x64/aops-agent-assets-fs +0 -0
  42. package/native/bin/win32-x64/aops-agent-assets-fs.exe +0 -0
  43. package/native/manifest.json +4 -4
  44. package/native/qualifications/win32-x64.json +2 -2
  45. package/native/tui/darwin-arm64/aops-tui +0 -0
  46. package/native/tui/linux-x64/aops-tui +0 -0
  47. package/native/tui/win32-x64/aops-tui.exe +0 -0
  48. package/package.json +18 -6
  49. package/agent-assets-release/agent-assets/core/647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09/files/references/mission/SKILL.md +0 -54
  50. package/assets/agent-assets/core/references/mission/SKILL.md +0 -54
  51. package/dist/commands/mission.js +0 -562
  52. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/aops-cli-core/SKILL.md +0 -0
  53. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/chatv3/SKILL.md +0 -0
  54. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/discuss/SKILL.md +0 -0
  55. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/docman/SKILL.md +0 -0
  56. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/projectman/SKILL.md +0 -0
  57. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/sys/SKILL.md +0 -0
  58. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/references/view/SKILL.md +0 -0
  59. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/agent-assets.md +0 -0
  60. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/aops-system.md +0 -0
  61. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/chatv3.md +0 -0
  62. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/docman.md +0 -0
  63. /package/agent-assets-release/agent-assets/core/{647c6e84fbc48f9a36945d81660f4d2a5241f58a53a18054365bfc16868b0f09 → bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb}/files/user-guides/projectman.md +0 -0
  64. /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
- if (!options.backup)
1506
- throw new Error('community_restore_backup_path_required');
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, path.resolve(options.backup));
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', 'default')
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
- const restore = common(command.command('restore').description('Restore database data; legacy flat form remains OCI-only until P4'))
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, [])
@@ -486,13 +486,19 @@ function matchesClassificationFilters(record, options) {
486
486
  }
487
487
  return true;
488
488
  }
489
- function filterHostedMemoryResult(result, options) {
489
+ export function filterHostedMemoryResult(result, options) {
490
490
  if (buildClassificationTags(options).length === 0)
491
491
  return result;
492
492
  if (Array.isArray(result)) {
493
493
  return result.filter((entry) => matchesClassificationFilters(entry, options));
494
494
  }
495
- if (!isRecord(result) || !Array.isArray(result.data))
495
+ if (!isRecord(result))
496
+ return result;
497
+ if (Array.isArray(result.items)) {
498
+ const items = result.items.filter((entry) => matchesClassificationFilters(entry, options));
499
+ return { ...result, items, returned: items.length };
500
+ }
501
+ if (!Array.isArray(result.data))
496
502
  return result;
497
503
  return {
498
504
  ...result,
@@ -115,7 +115,7 @@ export function makeOfficialCatalogSetupCommand(dependencies = {}) {
115
115
  The reserved scope is fixed to ${OFFICIAL_CATALOG_SCOPE_V1.slug}. It is routing
116
116
  identity only: official trust comes from the verified Community release and the
117
117
  package/release digests persisted in SkillVersion meta. Import is inert and does
118
- not select a discipline, mutate a mission policy, or touch user/project scopes.
118
+ not select a discipline, mutate a policy, or touch user/project scopes.
119
119
 
120
120
  Agentspace owns the atomic composite operations and durable receipts. Inspect
121
121
  their exact server contracts with:
@@ -37,8 +37,8 @@ export function makePlanCommand() {
37
37
  ' For one-item checklist edits, use `aops-cli pm utask ...` until top-level plan microtask sugar is added.\n');
38
38
  applyPlanContextOptions(applyMemoryCadenceOptions(applyWriteOptions(cmd
39
39
  .command('create')
40
- .description('Create a sprint-backed implementation plan for a kanban task')
41
- .requiredOption('--task <id>', 'Kanban task id')
40
+ .description('Create a sprint-backed implementation plan, optionally bound to a kanban task')
41
+ .option('--task <id>', 'Optional kanban task id to bind the plan to')
42
42
  .requiredOption('--name <name>', 'Plan name')
43
43
  .requiredOption('--goal <text>', 'Plan goal')
44
44
  .option('--reference <value>', 'Repeatable reference item', collectRepeatedOption, [])
@@ -2,7 +2,7 @@ import { Command } from 'commander';
2
2
  import { applyCommonOptions } from '../../utils/command.js';
3
3
  import { buildOperatorCookbook } from '../../utils/hosted-sugar.js';
4
4
  import { GUIDE_PATHS } from '../../utils/guide-paths.js';
5
- import { collectRepeatedOption, runPmBoardArchive, runPmBoardCreate, runPmBoardCloseout, runPmBoardDelete, runPmBoardBootstrapGet, runPmBoardBootstrapSet, runPmBoardGet, runPmBoardKickoff, runPmBoardList, runPmBoardResume, runPmBoardUnarchive, runPmFeedbackCreate, runPmFeedbackDelete, runPmFeedbackGet, runPmFeedbackList, runPmFeedbackUpdate, runPmResumeBrief, runPmReviewRequestCreate, runPmReviewRequestDelete, runPmReviewRequestGet, runPmReviewRequestList, runPmReviewRequestResult, runPmReviewRequestUpdate, runPmUtaskCreate, runPmUtaskDelete, runPmUtaskSetStatus, runPmUtaskUpdate, runPmIssueCreate, runPmIssueDelete, runPmIssueGet, runPmIssueList, runPmIssueUpdate, runPmSprintCreate, runPmSprintDelete, runPmSprintGet, runPmSprintArchive, runPmSprintList, runPmSprintSetStatus, runPmSprintUnarchive, runPmSprintUpdatePlan, runPmStatusAudit, runPmStatusReconcile, runPmTaskCreate, runPmTaskDelete, runPmTaskGet, runPmTaskList, runPmTaskSetStatus, runPmHandoffResume, runPmHandoffWrite, } from './projectman.js';
5
+ import { collectRepeatedOption, runPmBoardArchive, runPmBoardCreate, runPmColumnAdd, runPmColumnList, runPmColumnRemove, runPmColumnReorder, runPmBoardCloseout, runPmBoardDelete, runPmBoardBootstrapGet, runPmBoardBootstrapSet, runPmBoardGet, runPmBoardKickoff, runPmBoardList, runPmBoardResume, runPmBoardUnarchive, runPmFeedbackCreate, runPmFeedbackDelete, runPmFeedbackGet, runPmFeedbackList, runPmFeedbackUpdate, runPmResumeBrief, runPmReviewRequestCreate, runPmReviewRequestDelete, runPmReviewRequestGet, runPmReviewRequestList, runPmReviewRequestResult, runPmReviewRequestUpdate, runPmUtaskCreate, runPmUtaskDelete, runPmUtaskSetStatus, runPmUtaskUpdate, runPmIssueCreate, runPmIssueDelete, runPmIssueGet, runPmIssueList, runPmIssueUpdate, runPmSprintCreate, runPmSprintDelete, runPmSprintGet, runPmSprintArchive, runPmSprintList, runPmSprintSetStatus, runPmSprintUnarchive, runPmSprintUpdatePlan, runPmStatusAudit, runPmStatusReconcile, runPmTaskCreate, runPmTaskDelete, runPmTaskGet, runPmTaskList, runPmTaskSetStatus, runPmHandoffResume, runPmHandoffWrite, } from './projectman.js';
6
6
  function applyPmContextOptions(cmd) {
7
7
  applyCommonOptions(cmd, { withProject: false });
8
8
  cmd.option('--scope-id <id>', 'Canonical owner scope override');
@@ -100,6 +100,41 @@ function addStatusCommands(cmd) {
100
100
  await runPmStatusReconcile(options);
101
101
  }));
102
102
  }
103
+ function addColumnCommands(cmd) {
104
+ const column = cmd.command('column').description('Projectman board column commands');
105
+ applyPmContextOptions(column
106
+ .command('list')
107
+ .description("List a board's columns in board order")
108
+ .requiredOption('--board <value>', 'Board id, exact name, or slug')
109
+ .action(async (options) => {
110
+ await runPmColumnList(options);
111
+ }));
112
+ applyPmContextOptions(applyWriteOptions(column
113
+ .command('add')
114
+ .description('Create a column and place it on a board in one step')
115
+ .requiredOption('--board <value>', 'Board id, exact name, or slug')
116
+ .requiredOption('--name <name>', 'Column name')
117
+ .option('--slug <slug>', 'Optional column slug override')
118
+ .option('--description <text>', 'Optional column description')
119
+ .option('--wip-limit <n>', 'Optional WIP limit')
120
+ .option('--position <n>', 'Optional placement position'), { destructive: false }).action(async (options) => {
121
+ await runPmColumnAdd(options);
122
+ }));
123
+ applyPmContextOptions(applyWriteOptions(column
124
+ .command('remove')
125
+ .description('Remove a column from a board; refused while it still holds tasks')
126
+ .requiredOption('--board <value>', 'Board id, exact name, or slug')
127
+ .requiredOption('--column <value>', 'Column id, placement id, slug, or name on that board'), { destructive: true }).action(async (options) => {
128
+ await runPmColumnRemove(options);
129
+ }));
130
+ applyPmContextOptions(applyWriteOptions(column
131
+ .command('reorder')
132
+ .description('Set the board column order; name every column exactly once')
133
+ .requiredOption('--board <value>', 'Board id, exact name, or slug')
134
+ .option('--order <value>', 'Repeatable column selector, in the wanted order', collectRepeatedOption, []), { destructive: false }).action(async (options) => {
135
+ await runPmColumnReorder(options);
136
+ }));
137
+ }
103
138
  function addBoardCommands(cmd) {
104
139
  const board = cmd.command('board').description('Projectman kanban board commands');
105
140
  const bootstrap = board.command('bootstrap').description('Board-slug bootstrap registry commands');
@@ -281,8 +316,8 @@ function addSprintCommands(cmd) {
281
316
  const sprint = cmd.command('sprint').description('Projectman sprint commands');
282
317
  applyPmContextOptions(applyMemoryCadenceOptions(applyWriteOptions(sprint
283
318
  .command('create')
284
- .description('Create a Projectman sprint execution document')
285
- .requiredOption('--task <id>', 'Kanban task id')
319
+ .description('Create a Projectman sprint execution document, optionally bound to a kanban task')
320
+ .option('--task <id>', 'Optional kanban task id to bind the sprint to')
286
321
  .requiredOption('--name <name>', 'Sprint name')
287
322
  .requiredOption('--goal <text>', 'Sprint goal')
288
323
  .option('--reference <value>', 'Repeatable reference item', collectRepeatedOption, [])
@@ -645,6 +680,7 @@ function addHandoffCommands(cmd) {
645
680
  export function makePmCommand() {
646
681
  const cmd = new Command('pm').description('Projectman authoring commands (hosted server-first)');
647
682
  addBoardCommands(cmd);
683
+ addColumnCommands(cmd);
648
684
  addTaskCommands(cmd);
649
685
  addSprintCommands(cmd);
650
686
  addUtaskCommands(cmd);