@skrr-ai/cli 0.1.47 → 0.1.48
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/README.md +1 -1
- package/dist/base-command.d.ts +18 -0
- package/dist/base-command.js +61 -1
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +26 -9
- package/dist/commands/balance/usage/breakdown.d.ts +14 -0
- package/dist/commands/balance/usage/breakdown.js +68 -0
- package/dist/commands/balance/usage.js +24 -0
- package/dist/commands/commerce/entitlements/explain.d.ts +22 -0
- package/dist/commands/commerce/entitlements/explain.js +40 -0
- package/dist/commands/commerce/incidents/audit.d.ts +20 -0
- package/dist/commands/commerce/incidents/audit.js +37 -0
- package/dist/commands/commerce/incidents/list.d.ts +22 -0
- package/dist/commands/commerce/incidents/list.js +49 -0
- package/dist/commands/commerce/incidents/resolve.d.ts +23 -0
- package/dist/commands/commerce/incidents/resolve.js +45 -0
- package/dist/commands/commerce/incidents/retry.d.ts +22 -0
- package/dist/commands/commerce/incidents/retry.js +45 -0
- package/dist/commands/commerce/incidents/show.d.ts +13 -0
- package/dist/commands/commerce/incidents/show.js +30 -0
- package/dist/commands/commerce/offers/approve.d.ts +17 -0
- package/dist/commands/commerce/offers/approve.js +33 -0
- package/dist/commands/commerce/offers/create.d.ts +18 -0
- package/dist/commands/commerce/offers/create.js +34 -0
- package/dist/commands/commerce/offers/publish.d.ts +13 -0
- package/dist/commands/commerce/offers/publish.js +28 -0
- package/dist/commands/commerce/offers/retire.d.ts +17 -0
- package/dist/commands/commerce/offers/retire.js +32 -0
- package/dist/commands/commerce/offers/validate.d.ts +18 -0
- package/dist/commands/commerce/offers/validate.js +33 -0
- package/dist/commands/commerce/products/create.d.ts +10 -0
- package/dist/commands/commerce/products/create.js +25 -0
- package/dist/commands/commerce/promotions/redeem.d.ts +13 -0
- package/dist/commands/commerce/promotions/redeem.js +32 -0
- package/dist/commands/commerce/terms/accept.d.ts +18 -0
- package/dist/commands/commerce/terms/accept.js +39 -0
- package/dist/commands/commerce/terms/show.d.ts +10 -0
- package/dist/commands/commerce/terms/show.js +34 -0
- package/dist/commands/commerce/trials/conversion-preview.d.ts +18 -0
- package/dist/commands/commerce/trials/conversion-preview.js +39 -0
- package/dist/commands/commerce/trials/start.d.ts +23 -0
- package/dist/commands/commerce/trials/start.js +58 -0
- package/dist/commands/commitments/accounting.d.ts +39 -0
- package/dist/commands/commitments/accounting.js +116 -0
- package/dist/commands/commitments/action-history.d.ts +1 -0
- package/dist/commands/commitments/action-history.js +8 -1
- package/dist/commands/commitments/case.d.ts +1 -0
- package/dist/commands/commitments/case.js +19 -3
- package/dist/commands/commitments/cases.d.ts +1 -0
- package/dist/commands/commitments/cases.js +11 -1
- package/dist/commands/commitments/checks.d.ts +1 -0
- package/dist/commands/commitments/checks.js +5 -1
- package/dist/commands/commitments/cost.d.ts +62 -0
- package/dist/commands/commitments/cost.js +130 -0
- package/dist/commands/commitments/create.js +1 -1
- package/dist/commands/commitments/delete.d.ts +1 -0
- package/dist/commands/commitments/delete.js +56 -6
- package/dist/commands/commitments/feedback.js +9 -1
- package/dist/commands/commitments/handover.js +16 -0
- package/dist/commands/commitments/hypotheses.d.ts +1 -0
- package/dist/commands/commitments/hypotheses.js +17 -2
- package/dist/commands/commitments/links/list.js +4 -1
- package/dist/commands/commitments/liveness.d.ts +18 -0
- package/dist/commands/commitments/liveness.js +80 -0
- package/dist/commands/commitments/metrics.d.ts +1 -0
- package/dist/commands/commitments/metrics.js +8 -1
- package/dist/commands/commitments/next-tick.d.ts +39 -0
- package/dist/commands/commitments/next-tick.js +122 -0
- package/dist/commands/commitments/observations.d.ts +1 -0
- package/dist/commands/commitments/observations.js +19 -2
- package/dist/commands/commitments/pause.js +12 -0
- package/dist/commands/commitments/receipt.d.ts +2 -0
- package/dist/commands/commitments/receipt.js +16 -2
- package/dist/commands/commitments/remediation-proposal.js +6 -2
- package/dist/commands/commitments/remediation-proposals.js +5 -1
- package/dist/commands/commitments/restore.d.ts +25 -0
- package/dist/commands/commitments/restore.js +46 -0
- package/dist/commands/commitments/show.js +32 -0
- package/dist/commands/commitments/trigger-status.js +33 -0
- package/dist/commands/commitments/update.d.ts +1 -0
- package/dist/commands/commitments/update.js +31 -5
- package/dist/commands/commitments/wake-capabilities.d.ts +0 -1
- package/dist/commands/commitments/wake-capabilities.js +8 -4
- package/dist/commands/enterprise/budgets/create.d.ts +11 -0
- package/dist/commands/enterprise/budgets/create.js +27 -0
- package/dist/commands/enterprise/budgets/evaluate.d.ts +17 -0
- package/dist/commands/enterprise/budgets/evaluate.js +32 -0
- package/dist/commands/enterprise/budgets/publish.d.ts +14 -0
- package/dist/commands/enterprise/budgets/publish.js +30 -0
- package/dist/commands/enterprise/contracts/activate.d.ts +14 -0
- package/dist/commands/enterprise/contracts/activate.js +30 -0
- package/dist/commands/enterprise/contracts/create.d.ts +14 -0
- package/dist/commands/enterprise/contracts/create.js +32 -0
- package/dist/commands/enterprise/contracts/issue.d.ts +18 -0
- package/dist/commands/enterprise/contracts/issue.js +34 -0
- package/dist/commands/enterprise/domains/begin.d.ts +20 -0
- package/dist/commands/enterprise/domains/begin.js +39 -0
- package/dist/commands/enterprise/domains/verify.d.ts +14 -0
- package/dist/commands/enterprise/domains/verify.js +32 -0
- package/dist/commands/enterprise/external-config/activate.d.ts +22 -0
- package/dist/commands/enterprise/external-config/activate.js +49 -0
- package/dist/commands/enterprise/external-config/set.d.ts +25 -0
- package/dist/commands/enterprise/external-config/set.js +123 -0
- package/dist/commands/enterprise/external-config/show.d.ts +12 -0
- package/dist/commands/enterprise/external-config/show.js +39 -0
- package/dist/commands/enterprise/external-config/suspend.d.ts +13 -0
- package/dist/commands/enterprise/external-config/suspend.js +41 -0
- package/dist/commands/enterprise/finance/close-snapshot.d.ts +11 -0
- package/dist/commands/enterprise/finance/close-snapshot.js +28 -0
- package/dist/commands/enterprise/finance/record-document.d.ts +18 -0
- package/dist/commands/enterprise/finance/record-document.js +35 -0
- package/dist/commands/enterprise/profile.d.ts +20 -0
- package/dist/commands/enterprise/profile.js +38 -0
- package/dist/commands/login.d.ts +13 -0
- package/dist/commands/login.js +77 -0
- package/dist/commands/machines/dedicated/index.js +3 -0
- package/dist/commands/machines/dedicated/service/apply.d.ts +23 -0
- package/dist/commands/machines/dedicated/service/apply.js +99 -0
- package/dist/commands/machines/dedicated/service/approve.d.ts +23 -0
- package/dist/commands/machines/dedicated/service/approve.js +52 -0
- package/dist/commands/machines/dedicated/service/create.d.ts +55 -0
- package/dist/commands/machines/dedicated/service/create.js +222 -0
- package/dist/commands/machines/dedicated/service/edit.d.ts +30 -0
- package/dist/commands/machines/dedicated/service/edit.js +146 -0
- package/dist/commands/machines/dedicated/service/exec.d.ts +26 -0
- package/dist/commands/machines/dedicated/service/exec.js +92 -0
- package/dist/commands/machines/dedicated/service/export.d.ts +29 -0
- package/dist/commands/machines/dedicated/service/export.js +106 -0
- package/dist/commands/machines/dedicated/service/index.d.ts +14 -0
- package/dist/commands/machines/dedicated/service/index.js +49 -0
- package/dist/commands/machines/dedicated/service/logs.d.ts +33 -0
- package/dist/commands/machines/dedicated/service/logs.js +148 -0
- package/dist/commands/machines/dedicated/service/ls.d.ts +20 -0
- package/dist/commands/machines/dedicated/service/ls.js +80 -0
- package/dist/commands/machines/dedicated/service/restart.d.ts +14 -0
- package/dist/commands/machines/dedicated/service/restart.js +29 -0
- package/dist/commands/machines/dedicated/service/rm.d.ts +20 -0
- package/dist/commands/machines/dedicated/service/rm.js +33 -0
- package/dist/commands/machines/dedicated/service/secret/index.d.ts +14 -0
- package/dist/commands/machines/dedicated/service/secret/index.js +25 -0
- package/dist/commands/machines/dedicated/service/secret/rm.d.ts +22 -0
- package/dist/commands/machines/dedicated/service/secret/rm.js +54 -0
- package/dist/commands/machines/dedicated/service/secret/set.d.ts +22 -0
- package/dist/commands/machines/dedicated/service/secret/set.js +93 -0
- package/dist/commands/machines/dedicated/service/start.d.ts +14 -0
- package/dist/commands/machines/dedicated/service/start.js +29 -0
- package/dist/commands/machines/dedicated/service/status.d.ts +21 -0
- package/dist/commands/machines/dedicated/service/status.js +85 -0
- package/dist/commands/machines/dedicated/service/stop.d.ts +20 -0
- package/dist/commands/machines/dedicated/service/stop.js +35 -0
- package/dist/commands/machines/dedicated/service/top.d.ts +22 -0
- package/dist/commands/machines/dedicated/service/top.js +120 -0
- package/dist/commands/machines/dedicated/sign-in-status.d.ts +22 -0
- package/dist/commands/machines/dedicated/sign-in-status.js +79 -0
- package/dist/commands/machines/dedicated/ssh-config.d.ts +28 -0
- package/dist/commands/machines/dedicated/ssh-config.js +66 -0
- package/dist/commands/machines/dedicated/ssh-proxy.d.ts +22 -0
- package/dist/commands/machines/dedicated/ssh-proxy.js +62 -0
- package/dist/commands/machines/dedicated/ssh.d.ts +29 -0
- package/dist/commands/machines/dedicated/ssh.js +121 -0
- package/dist/commands/native/allow-all.d.ts +14 -0
- package/dist/commands/native/allow-all.js +25 -0
- package/dist/commands/native/allow.d.ts +24 -0
- package/dist/commands/native/allow.js +45 -0
- package/dist/commands/native/deny.d.ts +24 -0
- package/dist/commands/native/deny.js +43 -0
- package/dist/commands/native/disable.d.ts +17 -0
- package/dist/commands/native/disable.js +28 -0
- package/dist/commands/native/enable.d.ts +12 -0
- package/dist/commands/native/enable.js +29 -0
- package/dist/commands/native/list-apps.d.ts +19 -0
- package/dist/commands/native/list-apps.js +30 -0
- package/dist/commands/native/restrict-to.d.ts +22 -0
- package/dist/commands/native/restrict-to.js +41 -0
- package/dist/commands/native/status.d.ts +19 -0
- package/dist/commands/native/status.js +33 -0
- package/dist/commands/native.d.ts +39 -0
- package/dist/commands/native.js +76 -0
- package/dist/commands/service/index.d.ts +14 -0
- package/dist/commands/service/index.js +31 -0
- package/dist/commands/service/logs.d.ts +18 -0
- package/dist/commands/service/logs.js +53 -0
- package/dist/commands/service/ls.d.ts +13 -0
- package/dist/commands/service/ls.js +48 -0
- package/dist/commands/service/propose.d.ts +34 -0
- package/dist/commands/service/propose.js +113 -0
- package/dist/commands/service/status.d.ts +17 -0
- package/dist/commands/service/status.js +56 -0
- package/dist/commands/spaces/auto-executor/runs.d.ts +13 -0
- package/dist/commands/spaces/auto-executor/runs.js +56 -0
- package/dist/commands/store/governance/artifacts.d.ts +25 -0
- package/dist/commands/store/governance/artifacts.js +55 -0
- package/dist/commands/store/governance/assign.d.ts +16 -0
- package/dist/commands/store/governance/assign.js +54 -0
- package/dist/commands/store/governance/create-license.d.ts +18 -0
- package/dist/commands/store/governance/create-license.js +35 -0
- package/dist/commands/store/governance/install-plan.d.ts +25 -0
- package/dist/commands/store/governance/install-plan.js +56 -0
- package/dist/commands/store/governance/license-policy.d.ts +30 -0
- package/dist/commands/store/governance/license-policy.js +69 -0
- package/dist/commands/store/governance/policy.d.ts +25 -0
- package/dist/commands/store/governance/policy.js +65 -0
- package/dist/commands/store/governance/publish-release.d.ts +17 -0
- package/dist/commands/store/governance/publish-release.js +34 -0
- package/dist/commands/tasks/deliverable/add.d.ts +15 -0
- package/dist/commands/tasks/deliverable/add.js +174 -0
- package/dist/commands/tasks/deliverable/archive.d.ts +35 -0
- package/dist/commands/tasks/deliverable/archive.js +205 -0
- package/dist/commands/tasks/labels/detach.js +3 -0
- package/dist/commands/tasks/labels/suggest.d.ts +24 -0
- package/dist/commands/tasks/labels/suggest.js +69 -0
- package/dist/commands/tasks/list.d.ts +16 -2
- package/dist/commands/tasks/list.js +100 -24
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +51 -1
- package/dist/commands/wiki/rm.d.ts +22 -1
- package/dist/commands/wiki/rm.js +52 -3
- package/dist/lib/agentic-stream.js +10 -2
- package/dist/lib/balance.d.ts +6 -1
- package/dist/lib/balance.js +15 -0
- package/dist/lib/commerce-command.d.ts +48 -0
- package/dist/lib/commerce-command.js +70 -0
- package/dist/lib/commerce.d.ts +93 -0
- package/dist/lib/commerce.js +129 -0
- package/dist/lib/commitment-product.js +1 -1
- package/dist/lib/commitments.d.ts +202 -29
- package/dist/lib/commitments.js +300 -33
- package/dist/lib/dedicated-lease-command.js +10 -0
- package/dist/lib/dedicated-machines.d.ts +37 -0
- package/dist/lib/dedicated-machines.js +47 -0
- package/dist/lib/dedicated-service-command.d.ts +60 -0
- package/dist/lib/dedicated-service-command.js +182 -0
- package/dist/lib/dedicated-service.d.ts +342 -0
- package/dist/lib/dedicated-service.js +741 -0
- package/dist/lib/dedicated-ssh.d.ts +136 -0
- package/dist/lib/dedicated-ssh.js +387 -0
- package/dist/lib/delegated-cli.js +51 -13
- package/dist/lib/enterprise-commerce.d.ts +67 -0
- package/dist/lib/enterprise-commerce.js +112 -0
- package/dist/lib/enterprise-external-configuration.d.ts +60 -0
- package/dist/lib/enterprise-external-configuration.js +58 -0
- package/dist/lib/first-party-harness.js +17 -3
- package/dist/lib/governed-store.d.ts +110 -0
- package/dist/lib/governed-store.js +79 -0
- package/dist/lib/guest-service-command.d.ts +16 -0
- package/dist/lib/guest-service-command.js +32 -0
- package/dist/lib/guest-service.d.ts +67 -0
- package/dist/lib/guest-service.js +112 -0
- package/dist/lib/prompt.d.ts +1 -0
- package/dist/lib/prompt.js +1 -0
- package/dist/lib/task-asset-upload.d.ts +20 -0
- package/dist/lib/task-asset-upload.js +30 -8
- package/dist/lib/task-extras.d.ts +23 -0
- package/dist/lib/task-extras.js +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.d.ts +9 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.js +10 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +6 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +16 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +21 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +24 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.d.ts +9 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.js +10 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +16 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +20 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +24 -2
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5060 -4827
- package/oclif.manifest.json +37416 -31416
- package/package.json +43 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr store governance policy` — which releases a workspace may run at all.
|
|
4
|
+
*
|
|
5
|
+
* `deny_all` and `allowlist` are the two modes the server accepts, and the
|
|
6
|
+
* command refuses an allowlist with nothing in it: an empty allowlist and
|
|
7
|
+
* `deny_all` have the same effect but say different things, and a workspace
|
|
8
|
+
* that reads "allowlist" while permitting nothing is a policy nobody can
|
|
9
|
+
* explain six months later. If you mean deny everything, say `deny_all`.
|
|
10
|
+
*/
|
|
11
|
+
export default class StoreGovernancePolicy extends BaseCommand {
|
|
12
|
+
static description: string;
|
|
13
|
+
static examples: string[];
|
|
14
|
+
static args: {
|
|
15
|
+
workspace: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
16
|
+
};
|
|
17
|
+
static flags: {
|
|
18
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
release: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
|
+
'policy-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
|
+
'expect-revision': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
|
+
};
|
|
24
|
+
run(): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../../base-command");
|
|
5
|
+
const governed_store_1 = require("../../../lib/governed-store");
|
|
6
|
+
/**
|
|
7
|
+
* `skrr store governance policy` — which releases a workspace may run at all.
|
|
8
|
+
*
|
|
9
|
+
* `deny_all` and `allowlist` are the two modes the server accepts, and the
|
|
10
|
+
* command refuses an allowlist with nothing in it: an empty allowlist and
|
|
11
|
+
* `deny_all` have the same effect but say different things, and a workspace
|
|
12
|
+
* that reads "allowlist" while permitting nothing is a policy nobody can
|
|
13
|
+
* explain six months later. If you mean deny everything, say `deny_all`.
|
|
14
|
+
*/
|
|
15
|
+
class StoreGovernancePolicy extends base_command_1.BaseCommand {
|
|
16
|
+
static description = 'Set which governed releases a workspace may run. `deny_all`, or an allowlist of release ids.';
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> store governance policy <workspace-id> --mode deny_all',
|
|
19
|
+
'<%= config.bin %> store governance policy <workspace-id> --mode allowlist --release <id> --release <id>',
|
|
20
|
+
];
|
|
21
|
+
static args = {
|
|
22
|
+
workspace: core_1.Args.string({ description: 'Workspace id', required: true, ignoreStdin: true }),
|
|
23
|
+
};
|
|
24
|
+
static flags = {
|
|
25
|
+
mode: core_1.Flags.string({
|
|
26
|
+
description: 'deny_all, or allowlist the releases named by --release',
|
|
27
|
+
options: ['deny_all', 'allowlist'],
|
|
28
|
+
required: true,
|
|
29
|
+
}),
|
|
30
|
+
release: core_1.Flags.string({
|
|
31
|
+
description: 'Release id to allow (repeatable). Required with --mode allowlist.',
|
|
32
|
+
multiple: true,
|
|
33
|
+
}),
|
|
34
|
+
'policy-id': core_1.Flags.string({ description: 'Policy id, when replacing a specific one' }),
|
|
35
|
+
'expect-revision': core_1.Flags.integer({
|
|
36
|
+
description: 'The policy revision you are replacing (compare-and-set)',
|
|
37
|
+
}),
|
|
38
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
39
|
+
};
|
|
40
|
+
async run() {
|
|
41
|
+
this.requireAuth();
|
|
42
|
+
const { args, flags } = await this.parse(StoreGovernancePolicy);
|
|
43
|
+
const releases = flags.release ?? [];
|
|
44
|
+
if (flags.mode === 'allowlist' && releases.length === 0) {
|
|
45
|
+
this.error('An allowlist with no --release permits nothing, which is what --mode deny_all says plainly. Pass at least one release, or say deny_all.', { exit: 2 });
|
|
46
|
+
}
|
|
47
|
+
let result;
|
|
48
|
+
try {
|
|
49
|
+
result = await (0, governed_store_1.setWorkspaceStorePolicy)(args.workspace, {
|
|
50
|
+
mode: flags.mode,
|
|
51
|
+
allowedReleaseIds: releases,
|
|
52
|
+
...(flags['policy-id'] ? { policyId: flags['policy-id'] } : {}),
|
|
53
|
+
...(flags['expect-revision'] !== undefined
|
|
54
|
+
? { expectedRevision: flags['expect-revision'] }
|
|
55
|
+
: {}),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
this.handleApiError(error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.log(JSON.stringify(result, null, 2));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.default = StoreGovernancePolicy;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Publish one artifact release into the governed catalogue (admin).
|
|
4
|
+
*
|
|
5
|
+
* The body carries verified-outcome evidence, which is why it is a file rather
|
|
6
|
+
* than flags: evidence is a list of records with sources and timestamps, and
|
|
7
|
+
* assembling that from a command line is how a claim loses its provenance.
|
|
8
|
+
*/
|
|
9
|
+
export default class StoreGovernancePublishRelease extends BaseCommand {
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
static flags: {
|
|
13
|
+
file: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const base_command_1 = require("../../../base-command");
|
|
4
|
+
const governed_store_1 = require("../../../lib/governed-store");
|
|
5
|
+
const commerce_command_1 = require("../../../lib/commerce-command");
|
|
6
|
+
/**
|
|
7
|
+
* Publish one artifact release into the governed catalogue (admin).
|
|
8
|
+
*
|
|
9
|
+
* The body carries verified-outcome evidence, which is why it is a file rather
|
|
10
|
+
* than flags: evidence is a list of records with sources and timestamps, and
|
|
11
|
+
* assembling that from a command line is how a claim loses its provenance.
|
|
12
|
+
*/
|
|
13
|
+
class StoreGovernancePublishRelease extends base_command_1.BaseCommand {
|
|
14
|
+
static description = 'Publish an artifact release into the governed store catalogue (admin).';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> store governance publish-release --file ./release.json',
|
|
17
|
+
];
|
|
18
|
+
static flags = { ...commerce_command_1.jsonBodyFlags };
|
|
19
|
+
async run() {
|
|
20
|
+
this.requireAuth();
|
|
21
|
+
const { flags } = await this.parse(StoreGovernancePublishRelease);
|
|
22
|
+
const body = await (0, commerce_command_1.jsonBodyFrom)(this, flags.file);
|
|
23
|
+
let result;
|
|
24
|
+
try {
|
|
25
|
+
result = await (0, governed_store_1.publishGovernedStoreRelease)(body);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
this.handleApiError(error);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.log(JSON.stringify(result, null, 2));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.default = StoreGovernancePublishRelease;
|
|
@@ -25,7 +25,22 @@ export default class TasksDeliverableAdd extends BaseCommand {
|
|
|
25
25
|
expectation: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
26
|
'run-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
27
27
|
'idempotency-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
28
|
+
file: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
29
|
+
'no-upload': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
28
30
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
29
31
|
};
|
|
30
32
|
run(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Archive the bytes and let the upload's own ledger receipt BE the
|
|
35
|
+
* Deliverable record.
|
|
36
|
+
*
|
|
37
|
+
* One record, not two: the receipt is keyed on the same coordinate this
|
|
38
|
+
* command would have recorded, so the archived copy and the citation are one
|
|
39
|
+
* Resource rather than a path nobody can open beside an opaque blob nobody
|
|
40
|
+
* can match to it.
|
|
41
|
+
*
|
|
42
|
+
* Returns false when the file cannot be archived and the caller should fall
|
|
43
|
+
* back to recording the coordinate alone.
|
|
44
|
+
*/
|
|
45
|
+
private archive;
|
|
31
46
|
}
|
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
3
38
|
const core_1 = require("@oclif/core");
|
|
4
39
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
40
|
const base_command_1 = require("../../../base-command");
|
|
41
|
+
const task_asset_upload_1 = require("../../../lib/task-asset-upload");
|
|
6
42
|
const outbox_1 = require("../../../lib/outbox");
|
|
7
43
|
const api_fetch_1 = require("../../../lib/api-fetch");
|
|
8
44
|
const session_task_endpoints_1 = require("../../../lib/session-task-endpoints");
|
|
@@ -68,6 +104,15 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
68
104
|
expectation: core_1.Flags.string({ multiple: true, description: 'Expectation id this satisfies' }),
|
|
69
105
|
'run-id': core_1.Flags.string({ description: 'Run that produced it' }),
|
|
70
106
|
'idempotency-key': core_1.Flags.string({ description: 'Stable retry key' }),
|
|
107
|
+
file: core_1.Flags.string({
|
|
108
|
+
description: "Archive THIS file as the Deliverable's exact content, when the bytes are somewhere " +
|
|
109
|
+
'other than the coordinate. Without it a coordinate that already names a readable ' +
|
|
110
|
+
'local file is archived automatically.',
|
|
111
|
+
}),
|
|
112
|
+
'no-upload': core_1.Flags.boolean({
|
|
113
|
+
description: 'Record the coordinate only. The Deliverable stays `locator_only`: nothing pins which ' +
|
|
114
|
+
'revision it is, and nobody can open it from the web app.',
|
|
115
|
+
}),
|
|
71
116
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
72
117
|
};
|
|
73
118
|
async run() {
|
|
@@ -84,6 +129,45 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
84
129
|
this.error('--status and deprecated --lifecycle cannot disagree', { exit: 1 });
|
|
85
130
|
}
|
|
86
131
|
const status = flags.status || flags.lifecycle;
|
|
132
|
+
// A bare path has no global meaning and nothing to open — the CLI's own
|
|
133
|
+
// help says so. Archiving the bytes is what turns it into something a
|
|
134
|
+
// person can click and a digest can pin, so a coordinate that already
|
|
135
|
+
// names a readable local file is archived by default.
|
|
136
|
+
//
|
|
137
|
+
// Not when the caller is pinning an EXTERNAL system's version
|
|
138
|
+
// (--provider/--version/--content-digest): that names a revision in
|
|
139
|
+
// somebody else's namespace, and a local file of the same name is not
|
|
140
|
+
// evidence about it.
|
|
141
|
+
const pinsExternalVersion = Boolean(flags.provider || flags.version || flags['content-digest']);
|
|
142
|
+
const archivePath = flags['no-upload']
|
|
143
|
+
? null
|
|
144
|
+
: flags.file
|
|
145
|
+
? flags.file
|
|
146
|
+
: pinsExternalVersion
|
|
147
|
+
? null
|
|
148
|
+
: localFileFor(parsed.value);
|
|
149
|
+
if (flags.file && flags['no-upload']) {
|
|
150
|
+
this.error('--file and --no-upload cannot both be given', { exit: 1 });
|
|
151
|
+
}
|
|
152
|
+
let archiveRefused = false;
|
|
153
|
+
if (archivePath) {
|
|
154
|
+
const uploaded = await this.archive({
|
|
155
|
+
taskId: args.task,
|
|
156
|
+
filePath: archivePath,
|
|
157
|
+
identity: parsed.value.identity,
|
|
158
|
+
title: flags.title,
|
|
159
|
+
expectationIds: flags.expectation,
|
|
160
|
+
requestedStatus: status,
|
|
161
|
+
json: Boolean(flags.json),
|
|
162
|
+
// `--file` is an instruction; a coordinate that happens to name a file
|
|
163
|
+
// is an inference. Only the inference is size-bounded.
|
|
164
|
+
auto: !flags.file,
|
|
165
|
+
});
|
|
166
|
+
if (uploaded)
|
|
167
|
+
return;
|
|
168
|
+
// It tried and said why; the closing hint below would only repeat it.
|
|
169
|
+
archiveRefused = true;
|
|
170
|
+
}
|
|
87
171
|
let result;
|
|
88
172
|
try {
|
|
89
173
|
const payload = {
|
|
@@ -116,6 +200,96 @@ class TasksDeliverableAdd extends base_command_1.BaseCommand {
|
|
|
116
200
|
}
|
|
117
201
|
const where = parsed.value.location ? ` at ${parsed.value.location}` : '';
|
|
118
202
|
this.log(`Recorded Deliverable ${result.link.id}: ${parsed.value.kind}:${parsed.value.identity}${where} (${status || 'local'}; self reported).`);
|
|
203
|
+
if (!pinsExternalVersion && !flags['no-upload'] && !archiveRefused) {
|
|
204
|
+
this.log('No copy was archived, so nothing pins this version and it cannot be opened from the ' +
|
|
205
|
+
'web app. Pass --file <path> to archive the bytes.');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Archive the bytes and let the upload's own ledger receipt BE the
|
|
210
|
+
* Deliverable record.
|
|
211
|
+
*
|
|
212
|
+
* One record, not two: the receipt is keyed on the same coordinate this
|
|
213
|
+
* command would have recorded, so the archived copy and the citation are one
|
|
214
|
+
* Resource rather than a path nobody can open beside an opaque blob nobody
|
|
215
|
+
* can match to it.
|
|
216
|
+
*
|
|
217
|
+
* Returns false when the file cannot be archived and the caller should fall
|
|
218
|
+
* back to recording the coordinate alone.
|
|
219
|
+
*/
|
|
220
|
+
async archive(opts) {
|
|
221
|
+
let stat;
|
|
222
|
+
try {
|
|
223
|
+
stat = fs.statSync(opts.filePath);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
this.error(`File not found: ${opts.filePath}`, { exit: 1 });
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (!stat.isFile()) {
|
|
230
|
+
this.error(`Not a regular file: ${opts.filePath}`, { exit: 1 });
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
// The platform archives a file of any supported size under its own name.
|
|
234
|
+
// What is bounded is the INFERENCE: `deliverable add code:…@build/out.bin`
|
|
235
|
+
// should not quietly send 400 MB because the coordinate resolved to a
|
|
236
|
+
// path. Naming the file with --file says do it anyway, and the only limit
|
|
237
|
+
// left is the platform's own.
|
|
238
|
+
if (opts.auto && stat.size > data_provider_1.TASK_ATTACHMENT_MAX_BYTES) {
|
|
239
|
+
const mb = Math.floor(data_provider_1.TASK_ATTACHMENT_MAX_BYTES / (1024 * 1024));
|
|
240
|
+
this.warn(`${path.basename(opts.filePath)} is larger than ${mb} MB, so it was not archived ` +
|
|
241
|
+
'automatically. Pass --file to archive it anyway.');
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
let asset;
|
|
245
|
+
try {
|
|
246
|
+
asset = await (0, task_asset_upload_1.uploadTaskAssetFile)({
|
|
247
|
+
taskId: opts.taskId,
|
|
248
|
+
filePath: opts.filePath,
|
|
249
|
+
role: 'deliverable',
|
|
250
|
+
ledger: {
|
|
251
|
+
identity: opts.identity,
|
|
252
|
+
title: opts.title,
|
|
253
|
+
expectationIds: opts.expectationIds,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
this.handleApiError(err);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
if (opts.json) {
|
|
262
|
+
this.log(JSON.stringify({ archived: asset, identity: opts.identity }, null, 2));
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
this.log(`Recorded Deliverable ${opts.identity} — archived copy ${asset.id} ` +
|
|
266
|
+
`(sha256 pinned; observed available; self reported).`);
|
|
267
|
+
if (opts.requestedStatus && opts.requestedStatus !== 'available') {
|
|
268
|
+
// Not silent: the platform WATCHED these bytes land, which is a stronger
|
|
269
|
+
// and verified statement than the one that was asked for. Who vouched
|
|
270
|
+
// is unchanged — still `self_reported`, still nobody else's word.
|
|
271
|
+
this.log(`--status ${opts.requestedStatus} did not apply: an archived copy is observed available.`);
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
119
274
|
}
|
|
120
275
|
}
|
|
121
276
|
exports.default = TasksDeliverableAdd;
|
|
277
|
+
/**
|
|
278
|
+
* The local file a coordinate already names, if it names one. `location` is
|
|
279
|
+
* checked first because it is where the thing IS; `identity` is the fallback
|
|
280
|
+
* for the common `file:docs/x.md` with no location.
|
|
281
|
+
*/
|
|
282
|
+
function localFileFor(value) {
|
|
283
|
+
for (const candidate of [value.location, value.identity]) {
|
|
284
|
+
if (!candidate)
|
|
285
|
+
continue;
|
|
286
|
+
try {
|
|
287
|
+
if (fs.statSync(candidate).isFile())
|
|
288
|
+
return candidate;
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
/* not a local file */
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr tasks deliverable archive <task>`
|
|
4
|
+
*
|
|
5
|
+
* Backfill for Deliverables recorded before archiving existed, or recorded
|
|
6
|
+
* with `--no-upload`. They are bare coordinates: nothing pins which revision
|
|
7
|
+
* they are, and nobody can open them from the web app.
|
|
8
|
+
*
|
|
9
|
+
* This is a CLI command and not a server migration, and that is not a
|
|
10
|
+
* shortcut. A Deliverable recorded as `docs/policies/payout.md` names a file
|
|
11
|
+
* the server has never seen and cannot reach — the bytes exist on the machine
|
|
12
|
+
* that produced them. Only something running THERE can archive them, so the
|
|
13
|
+
* backfill has to be a command someone runs in the working tree, not a job
|
|
14
|
+
* that sweeps a collection.
|
|
15
|
+
*
|
|
16
|
+
* What it will not do: guess. A row is archived only when its own coordinate
|
|
17
|
+
* resolves to a readable regular file relative to the current directory. Every
|
|
18
|
+
* row it skips is reported with the reason, because a backfill that silently
|
|
19
|
+
* covers 3 of 5 is worse than one that covers none.
|
|
20
|
+
*/
|
|
21
|
+
export default class TasksDeliverableArchive extends BaseCommand {
|
|
22
|
+
static description: string;
|
|
23
|
+
static examples: string[];
|
|
24
|
+
static args: {
|
|
25
|
+
task: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
26
|
+
};
|
|
27
|
+
static flags: {
|
|
28
|
+
task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
29
|
+
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
30
|
+
'max-bytes': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
31
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
32
|
+
};
|
|
33
|
+
run(): Promise<void>;
|
|
34
|
+
private report;
|
|
35
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const core_1 = require("@oclif/core");
|
|
39
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
40
|
+
const base_command_1 = require("../../../base-command");
|
|
41
|
+
const task_resolver_1 = require("../../../lib/task-resolver");
|
|
42
|
+
const task_asset_upload_1 = require("../../../lib/task-asset-upload");
|
|
43
|
+
/**
|
|
44
|
+
* `skrr tasks deliverable archive <task>`
|
|
45
|
+
*
|
|
46
|
+
* Backfill for Deliverables recorded before archiving existed, or recorded
|
|
47
|
+
* with `--no-upload`. They are bare coordinates: nothing pins which revision
|
|
48
|
+
* they are, and nobody can open them from the web app.
|
|
49
|
+
*
|
|
50
|
+
* This is a CLI command and not a server migration, and that is not a
|
|
51
|
+
* shortcut. A Deliverable recorded as `docs/policies/payout.md` names a file
|
|
52
|
+
* the server has never seen and cannot reach — the bytes exist on the machine
|
|
53
|
+
* that produced them. Only something running THERE can archive them, so the
|
|
54
|
+
* backfill has to be a command someone runs in the working tree, not a job
|
|
55
|
+
* that sweeps a collection.
|
|
56
|
+
*
|
|
57
|
+
* What it will not do: guess. A row is archived only when its own coordinate
|
|
58
|
+
* resolves to a readable regular file relative to the current directory. Every
|
|
59
|
+
* row it skips is reported with the reason, because a backfill that silently
|
|
60
|
+
* covers 3 of 5 is worse than one that covers none.
|
|
61
|
+
*/
|
|
62
|
+
class TasksDeliverableArchive extends base_command_1.BaseCommand {
|
|
63
|
+
static description = 'Archive the bytes of Deliverables that are still bare coordinates.\n' +
|
|
64
|
+
'\n' +
|
|
65
|
+
'Run it from the directory their paths are relative to — usually the repository root. ' +
|
|
66
|
+
'Each row whose coordinate resolves to a readable local file is uploaded and recorded ' +
|
|
67
|
+
'against those exact bytes, converging onto the SAME Deliverable rather than adding a ' +
|
|
68
|
+
'second one. Rows that already carry an archived copy are left alone.';
|
|
69
|
+
static examples = [
|
|
70
|
+
'<%= config.bin %> tasks deliverable archive <task-id> --dry-run',
|
|
71
|
+
'<%= config.bin %> tasks deliverable archive <task-id>',
|
|
72
|
+
];
|
|
73
|
+
static args = {
|
|
74
|
+
task: core_1.Args.string({ required: false, ignoreStdin: true, description: 'Task id or ref' }),
|
|
75
|
+
};
|
|
76
|
+
static flags = {
|
|
77
|
+
task: core_1.Flags.string({ description: 'Task id; overrides runtime context' }),
|
|
78
|
+
'dry-run': core_1.Flags.boolean({
|
|
79
|
+
description: 'Report what would be archived and upload nothing',
|
|
80
|
+
}),
|
|
81
|
+
'max-bytes': core_1.Flags.integer({
|
|
82
|
+
description: `Skip files larger than this (default ${data_provider_1.TASK_ATTACHMENT_MAX_BYTES})`,
|
|
83
|
+
default: data_provider_1.TASK_ATTACHMENT_MAX_BYTES,
|
|
84
|
+
}),
|
|
85
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
86
|
+
};
|
|
87
|
+
async run() {
|
|
88
|
+
this.requireAuth();
|
|
89
|
+
const { args, flags } = await this.parse(TasksDeliverableArchive);
|
|
90
|
+
const task = (0, task_resolver_1.resolveTaskIdentity)({ positionalId: args.task, flagTask: flags.task });
|
|
91
|
+
let listed;
|
|
92
|
+
try {
|
|
93
|
+
listed = await data_provider_1.dataService.listTaskDeliverables(task.id);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
this.handleApiError(error);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const plan = (listed.data || []).map((row) => classify(row, flags['max-bytes']));
|
|
100
|
+
const actionable = plan.filter((entry) => entry.action === 'archive');
|
|
101
|
+
if (flags['dry-run']) {
|
|
102
|
+
const report = { taskId: task.id, dryRun: true, plan };
|
|
103
|
+
if (flags.json)
|
|
104
|
+
return this.log(JSON.stringify(report, null, 2));
|
|
105
|
+
return this.report(plan, []);
|
|
106
|
+
}
|
|
107
|
+
const results = [];
|
|
108
|
+
for (const entry of actionable) {
|
|
109
|
+
try {
|
|
110
|
+
const asset = await (0, task_asset_upload_1.uploadTaskAssetFile)({
|
|
111
|
+
taskId: task.id,
|
|
112
|
+
filePath: entry.filePath,
|
|
113
|
+
role: 'deliverable',
|
|
114
|
+
ledger: {
|
|
115
|
+
identity: entry.identity,
|
|
116
|
+
title: entry.title,
|
|
117
|
+
expectationIds: entry.expectationIds,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
results.push({ identity: entry.identity, ok: true, attachmentId: asset.id });
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
results.push({
|
|
124
|
+
identity: entry.identity,
|
|
125
|
+
ok: false,
|
|
126
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (flags.json) {
|
|
131
|
+
return this.log(JSON.stringify({ taskId: task.id, plan, results }, null, 2));
|
|
132
|
+
}
|
|
133
|
+
this.report(plan, results);
|
|
134
|
+
if (results.some((entry) => !entry.ok)) {
|
|
135
|
+
this.error(`${results.filter((entry) => !entry.ok).length} Deliverable(s) failed to archive`, {
|
|
136
|
+
exit: 1,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
report(plan, results) {
|
|
141
|
+
const byIdentity = new Map(results.map((entry) => [entry.identity, entry]));
|
|
142
|
+
for (const entry of plan) {
|
|
143
|
+
const outcome = byIdentity.get(entry.identity);
|
|
144
|
+
if (entry.action === 'archive' && !outcome) {
|
|
145
|
+
this.log(`would archive ${entry.identity} (${entry.filePath})`);
|
|
146
|
+
}
|
|
147
|
+
else if (outcome?.ok) {
|
|
148
|
+
this.log(`archived ${entry.identity} → ${outcome.attachmentId}`);
|
|
149
|
+
}
|
|
150
|
+
else if (outcome) {
|
|
151
|
+
this.log(`FAILED ${entry.identity} — ${outcome.reason}`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.log(`skipped ${entry.identity} — ${entry.reason}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!plan.length)
|
|
158
|
+
this.log('No Deliverables recorded.');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.default = TasksDeliverableArchive;
|
|
162
|
+
/**
|
|
163
|
+
* One row's verdict. Every `skip` carries the reason it was skipped — the
|
|
164
|
+
* whole point of the command is that a partial backfill says which part.
|
|
165
|
+
*/
|
|
166
|
+
function classify(row, maxBytes) {
|
|
167
|
+
const identity = row.identity || row.location || row.title || '';
|
|
168
|
+
const base = {
|
|
169
|
+
linkId: row.linkId,
|
|
170
|
+
identity,
|
|
171
|
+
title: row.title,
|
|
172
|
+
expectationIds: row.expectationIds,
|
|
173
|
+
action: 'skip',
|
|
174
|
+
};
|
|
175
|
+
if (row.managedContentRef) {
|
|
176
|
+
return { ...base, reason: 'already archived' };
|
|
177
|
+
}
|
|
178
|
+
if (!identity) {
|
|
179
|
+
return { ...base, reason: 'no coordinate to resolve' };
|
|
180
|
+
}
|
|
181
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(row.location || identity)) {
|
|
182
|
+
return { ...base, reason: 'remote locator — nothing local to archive' };
|
|
183
|
+
}
|
|
184
|
+
for (const candidate of [row.location, identity]) {
|
|
185
|
+
if (!candidate)
|
|
186
|
+
continue;
|
|
187
|
+
let stat;
|
|
188
|
+
try {
|
|
189
|
+
stat = fs.statSync(candidate);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (!stat.isFile())
|
|
195
|
+
continue;
|
|
196
|
+
if (stat.size > maxBytes) {
|
|
197
|
+
return {
|
|
198
|
+
...base,
|
|
199
|
+
reason: `${path.basename(candidate)} is ${stat.size} bytes, over the ${maxBytes} limit`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { ...base, action: 'archive', filePath: candidate };
|
|
203
|
+
}
|
|
204
|
+
return { ...base, reason: 'no readable local file at this coordinate' };
|
|
205
|
+
}
|
|
@@ -21,6 +21,9 @@ class TasksLabelsDetach extends base_command_1.BaseCommand {
|
|
|
21
21
|
static flags = {
|
|
22
22
|
json: core_1.Flags.boolean({ description: 'Output the updated task as JSON' }),
|
|
23
23
|
'label-id': core_1.Flags.string({
|
|
24
|
+
// Same alias `attach` carries: `--label` is what `spaces labels
|
|
25
|
+
// remove` takes, and the two directions should spell one flag alike.
|
|
26
|
+
aliases: ['label'],
|
|
24
27
|
description: 'Label to detach — id, or a name from `skrr labels list --applicable-to task` (repeatable)',
|
|
25
28
|
multiple: true,
|
|
26
29
|
required: true,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Ask the lightweight model which of the DECLARED labels fit this task —
|
|
4
|
+
* `POST /api/tasks/:taskId/labels/suggest`, the on-demand half of the
|
|
5
|
+
* create-time `_labelGuidance` hint. The server keeps the suggestion off the
|
|
6
|
+
* task-create path (the hottest write in the product); this command is how a
|
|
7
|
+
* caller pays for one suggestion when it actually wants it.
|
|
8
|
+
*
|
|
9
|
+
* Same contract as create: the model may only CHOOSE from the declared
|
|
10
|
+
* vocabulary, a label the task already wears is never suggested, and a
|
|
11
|
+
* suggestion is a proposal, not a write — attach is still the caller's
|
|
12
|
+
* decision (`tasks labels attach --label <id>`).
|
|
13
|
+
*/
|
|
14
|
+
export default class TasksLabelsSuggest extends BaseCommand {
|
|
15
|
+
static description: string;
|
|
16
|
+
static examples: string[];
|
|
17
|
+
static args: {
|
|
18
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
19
|
+
};
|
|
20
|
+
static flags: {
|
|
21
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|