@aopslabs/aops 0.3.24 → 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 -28
- 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/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-migration-snapshot.js +43 -2
- package/dist/lib/community-native-backup.js +386 -0
- package/dist/lib/community-native-lifecycle.js +93 -4
- 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/win32-x64/aops-agent-assets-fs.exe +0 -0
- package/native/manifest.json +4 -4
- 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 +18 -6
- 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, [])
|
package/dist/commands/memory.js
CHANGED
|
@@ -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)
|
|
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
|
|
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:
|
package/dist/commands/plan.js
CHANGED
|
@@ -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
|
|
41
|
-
.
|
|
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
|
-
.
|
|
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);
|