@indigoai-us/hq-cli 5.121.1 → 5.121.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/command-catalog.generated.d.ts +32 -1
- package/dist/command-catalog.generated.js +41 -1
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/cloud-demote.js +3 -2
- package/dist/commands/cloud-provision.d.ts +11 -0
- package/dist/commands/cloud-provision.js +25 -0
- package/dist/commands/cloud-retire.d.ts +51 -0
- package/dist/commands/cloud-retire.js +154 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.121.2] — 2026-09-18
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `hq cloud retire company <slug>` soft-tombstones a cloud company (owner
|
|
10
|
+
only, confirm unless `--yes`) so `hq cloud demote company` can run without
|
|
11
|
+
`--propagate-deletes`. Vault files stay; local folders are not touched.
|
|
12
|
+
|
|
5
13
|
## [5.121.1] — 2026-09-18
|
|
6
14
|
|
|
7
15
|
### Fixed
|
|
@@ -722,6 +722,37 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
722
722
|
}];
|
|
723
723
|
readonly subcommands: readonly [];
|
|
724
724
|
}];
|
|
725
|
+
}, {
|
|
726
|
+
readonly name: "retire";
|
|
727
|
+
readonly description: "Soft-tombstone a cloud-backed company (owner only)";
|
|
728
|
+
readonly aliases: readonly [];
|
|
729
|
+
readonly hidden: false;
|
|
730
|
+
readonly usage: "[options] [command]";
|
|
731
|
+
readonly arguments: readonly [];
|
|
732
|
+
readonly options: readonly [];
|
|
733
|
+
readonly subcommands: readonly [{
|
|
734
|
+
readonly name: "company";
|
|
735
|
+
readonly description: "Soft-tombstone a cloud company so `hq cloud demote company` can run. Does not delete vault files or local folders. Prompts unless --yes.";
|
|
736
|
+
readonly aliases: readonly [];
|
|
737
|
+
readonly hidden: false;
|
|
738
|
+
readonly usage: "[options] <slug>";
|
|
739
|
+
readonly arguments: readonly [{
|
|
740
|
+
readonly name: "slug";
|
|
741
|
+
readonly required: true;
|
|
742
|
+
readonly variadic: false;
|
|
743
|
+
}];
|
|
744
|
+
readonly options: readonly [{
|
|
745
|
+
readonly flags: "--hq-root <path>";
|
|
746
|
+
readonly description: "Local HQ tree root (default: <runtime-path>)";
|
|
747
|
+
}, {
|
|
748
|
+
readonly flags: "--vault-api-url <url>";
|
|
749
|
+
readonly description: "Vault API URL (default: https://hqapi.hq.computer)";
|
|
750
|
+
}, {
|
|
751
|
+
readonly flags: "-y, --yes";
|
|
752
|
+
readonly description: "Skip the confirmation prompt (for scripts)";
|
|
753
|
+
}];
|
|
754
|
+
readonly subcommands: readonly [];
|
|
755
|
+
}];
|
|
725
756
|
}, {
|
|
726
757
|
readonly name: "demote";
|
|
727
758
|
readonly description: "Demote a cloud-backed entity back to local-only";
|
|
@@ -732,7 +763,7 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
732
763
|
readonly options: readonly [];
|
|
733
764
|
readonly subcommands: readonly [{
|
|
734
765
|
readonly name: "company";
|
|
735
|
-
readonly description: "Demote a cloud-backed company to local-only after the cloud entity has been soft-tombstoned
|
|
766
|
+
readonly description: "Demote a cloud-backed company to local-only after the cloud entity has been soft-tombstoned (`hq cloud retire company` or hq-console). Removes .hq/config.json, flips company.yaml `cloud: false`, and strips the manifest cloud refs.";
|
|
736
767
|
readonly aliases: readonly [];
|
|
737
768
|
readonly hidden: false;
|
|
738
769
|
readonly usage: "[options] <slug>";
|
|
@@ -924,6 +924,46 @@ export const COMMAND_CATALOG = [
|
|
|
924
924
|
}
|
|
925
925
|
]
|
|
926
926
|
},
|
|
927
|
+
{
|
|
928
|
+
"name": "retire",
|
|
929
|
+
"description": "Soft-tombstone a cloud-backed company (owner only)",
|
|
930
|
+
"aliases": [],
|
|
931
|
+
"hidden": false,
|
|
932
|
+
"usage": "[options] [command]",
|
|
933
|
+
"arguments": [],
|
|
934
|
+
"options": [],
|
|
935
|
+
"subcommands": [
|
|
936
|
+
{
|
|
937
|
+
"name": "company",
|
|
938
|
+
"description": "Soft-tombstone a cloud company so `hq cloud demote company` can run. Does not delete vault files or local folders. Prompts unless --yes.",
|
|
939
|
+
"aliases": [],
|
|
940
|
+
"hidden": false,
|
|
941
|
+
"usage": "[options] <slug>",
|
|
942
|
+
"arguments": [
|
|
943
|
+
{
|
|
944
|
+
"name": "slug",
|
|
945
|
+
"required": true,
|
|
946
|
+
"variadic": false
|
|
947
|
+
}
|
|
948
|
+
],
|
|
949
|
+
"options": [
|
|
950
|
+
{
|
|
951
|
+
"flags": "--hq-root <path>",
|
|
952
|
+
"description": "Local HQ tree root (default: <runtime-path>)"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
"flags": "--vault-api-url <url>",
|
|
956
|
+
"description": "Vault API URL (default: https://hqapi.hq.computer)"
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
"flags": "-y, --yes",
|
|
960
|
+
"description": "Skip the confirmation prompt (for scripts)"
|
|
961
|
+
}
|
|
962
|
+
],
|
|
963
|
+
"subcommands": []
|
|
964
|
+
}
|
|
965
|
+
]
|
|
966
|
+
},
|
|
927
967
|
{
|
|
928
968
|
"name": "demote",
|
|
929
969
|
"description": "Demote a cloud-backed entity back to local-only",
|
|
@@ -935,7 +975,7 @@ export const COMMAND_CATALOG = [
|
|
|
935
975
|
"subcommands": [
|
|
936
976
|
{
|
|
937
977
|
"name": "company",
|
|
938
|
-
"description": "Demote a cloud-backed company to local-only after the cloud entity has been soft-tombstoned
|
|
978
|
+
"description": "Demote a cloud-backed company to local-only after the cloud entity has been soft-tombstoned (`hq cloud retire company` or hq-console). Removes .hq/config.json, flips company.yaml `cloud: false`, and strips the manifest cloud refs.",
|
|
939
979
|
"aliases": [],
|
|
940
980
|
"hidden": false,
|
|
941
981
|
"usage": "[options] <slug>",
|
|
@@ -141,6 +141,12 @@ export declare const REGISTRATION_PLAN: readonly [{
|
|
|
141
141
|
readonly parent: "cloud";
|
|
142
142
|
readonly module: "./commands/cloud-provision.js";
|
|
143
143
|
readonly exportName: "registerCloudProvisionCommands";
|
|
144
|
+
}, {
|
|
145
|
+
readonly type: "registrar";
|
|
146
|
+
readonly root: "cloud";
|
|
147
|
+
readonly parent: "cloud";
|
|
148
|
+
readonly module: "./commands/cloud-retire.js";
|
|
149
|
+
readonly exportName: "registerCloudRetireCommands";
|
|
144
150
|
}, {
|
|
145
151
|
readonly type: "registrar";
|
|
146
152
|
readonly root: "cloud";
|
|
@@ -26,6 +26,7 @@ export const REGISTRATION_PLAN = [
|
|
|
26
26
|
{ type: "registrar", root: "sync", parent: "sync", module: "./commands/sync-manifest.js", exportName: "registerSyncManifestCommand" },
|
|
27
27
|
{ type: "group", root: "cloud", id: "cloud", name: "cloud", description: "Cloud commands — provision entities and manage cloud-backed companies" },
|
|
28
28
|
{ type: "registrar", root: "cloud", parent: "cloud", module: "./commands/cloud-provision.js", exportName: "registerCloudProvisionCommands" },
|
|
29
|
+
{ type: "registrar", root: "cloud", parent: "cloud", module: "./commands/cloud-retire.js", exportName: "registerCloudRetireCommands" },
|
|
29
30
|
{ type: "registrar", root: "cloud", parent: "cloud", module: "./commands/cloud-demote.js", exportName: "registerCloudDemoteCommands" },
|
|
30
31
|
{ type: "registrar", root: "team-sync", parent: "program", module: "./commands/team-sync.js", exportName: "registerTeamSyncCommand" },
|
|
31
32
|
{ type: "registrar", root: "login", parent: "program", module: "./commands/login.js", exportName: "registerLoginCommand" },
|
|
@@ -160,8 +160,9 @@ export function registerCloudDemoteCommands(program) {
|
|
|
160
160
|
demoteCmd
|
|
161
161
|
.command("company")
|
|
162
162
|
.description("Demote a cloud-backed company to local-only after the cloud entity " +
|
|
163
|
-
"has been soft-tombstoned
|
|
164
|
-
"flips company.yaml `cloud: false`, and
|
|
163
|
+
"has been soft-tombstoned (`hq cloud retire company` or hq-console). " +
|
|
164
|
+
"Removes .hq/config.json, flips company.yaml `cloud: false`, and " +
|
|
165
|
+
"strips the manifest cloud refs.")
|
|
165
166
|
.argument("<slug>", "Company slug")
|
|
166
167
|
.option("--hq-root <path>", `Local HQ tree root (default: ${DEFAULT_HQ_ROOT})`, DEFAULT_HQ_ROOT)
|
|
167
168
|
.option("--vault-api-url <url>", `Vault API URL (default: ${DEFAULT_VAULT_API_URL})`, DEFAULT_VAULT_API_URL)
|
|
@@ -38,6 +38,8 @@ export interface VaultEntity {
|
|
|
38
38
|
kmsKeyId?: string | null;
|
|
39
39
|
status?: string;
|
|
40
40
|
ownerUid?: string;
|
|
41
|
+
/** Set by hq-pro after a soft tombstone. Absent on live companies. */
|
|
42
|
+
deleted?: boolean;
|
|
41
43
|
}
|
|
42
44
|
/** Per-company `.hq/config.json` schema (matches AppBar `provision.rs::CompanyConfig`). */
|
|
43
45
|
export interface CompanyConfig {
|
|
@@ -142,6 +144,15 @@ export interface VaultClient {
|
|
|
142
144
|
name: string;
|
|
143
145
|
ownerUid?: string;
|
|
144
146
|
}): Promise<VaultEntity>;
|
|
147
|
+
/**
|
|
148
|
+
* Soft-tombstone a company (`DELETE /entity/{uid}`). Owner-only. Leaves the
|
|
149
|
+
* row, S3 bucket, KMS key, and memberships intact. Idempotent on an already
|
|
150
|
+
* deleted company. Used by `hq cloud retire company`.
|
|
151
|
+
*/
|
|
152
|
+
softDeleteCompany(uid: string): Promise<{
|
|
153
|
+
deleted: true;
|
|
154
|
+
uid: string;
|
|
155
|
+
}>;
|
|
145
156
|
}
|
|
146
157
|
/** Custom error class so the CLI runner can map to exit codes. */
|
|
147
158
|
export declare class ProvisionError extends Error {
|
|
@@ -364,6 +364,31 @@ export function createDefaultVaultClient(apiUrl, accessToken) {
|
|
|
364
364
|
}
|
|
365
365
|
return data.entity;
|
|
366
366
|
},
|
|
367
|
+
async softDeleteCompany(uid) {
|
|
368
|
+
const url = `${apiUrl.replace(/\/$/, "")}/entity/${encodeURIComponent(uid)}`;
|
|
369
|
+
const res = await fetch(url, { method: "DELETE", headers });
|
|
370
|
+
if (res.status === 403) {
|
|
371
|
+
const body = await safeBody(res);
|
|
372
|
+
throw new ProvisionError(2, `Refusing to retire '${uid}': only the company owner can soft-tombstone it. ${body}`);
|
|
373
|
+
}
|
|
374
|
+
if (res.status === 404) {
|
|
375
|
+
const body = await safeBody(res);
|
|
376
|
+
throw new ProvisionError(2, `Vault DELETE /entity/${uid} failed: not found — ${body}`);
|
|
377
|
+
}
|
|
378
|
+
if (res.status === 400) {
|
|
379
|
+
const body = await safeBody(res);
|
|
380
|
+
throw new ProvisionError(2, `Vault DELETE /entity/${uid} failed: ${res.status} ${res.statusText} — ${body}`);
|
|
381
|
+
}
|
|
382
|
+
if (!res.ok) {
|
|
383
|
+
const body = await safeBody(res);
|
|
384
|
+
throw new ProvisionError(1, `Vault DELETE /entity/${uid} failed: ${res.status} ${res.statusText} — ${body}`);
|
|
385
|
+
}
|
|
386
|
+
const data = (await res.json());
|
|
387
|
+
if (data.deleted !== true || typeof data.uid !== "string") {
|
|
388
|
+
throw new ProvisionError(1, `Vault DELETE /entity/${uid} returned ${res.status} with no deleted confirmation`);
|
|
389
|
+
}
|
|
390
|
+
return { deleted: true, uid: data.uid };
|
|
391
|
+
},
|
|
367
392
|
};
|
|
368
393
|
}
|
|
369
394
|
async function safeBody(res) {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq cloud retire company <slug>` — soft-tombstone a cloud company so
|
|
3
|
+
* `hq cloud demote company` can run without `--propagate-deletes`.
|
|
4
|
+
*
|
|
5
|
+
* Console equivalent: Settings → Delete company (`DELETE /entity/{uid}`).
|
|
6
|
+
* Owner-only. The entity row, S3 bucket, KMS key, and memberships stay;
|
|
7
|
+
* `/membership/me` stops listing the company. Local files are not touched —
|
|
8
|
+
* demote is the follow-up that flips the local tree back to local-only.
|
|
9
|
+
*
|
|
10
|
+
* Confirm step is on by default (`[y/N]`). `--yes` skips it for scripts.
|
|
11
|
+
* A non-TTY stdin without `--yes` refuses rather than hanging.
|
|
12
|
+
*
|
|
13
|
+
* Exit codes (mirrors cloud-provision / cloud-demote):
|
|
14
|
+
* 0 — success, already tombstoned, or the operator cancelled.
|
|
15
|
+
* 1 — vault HTTP failure (auth/network/5xx).
|
|
16
|
+
* 2 — validation (bad slug, no entity, not owner, missing confirm).
|
|
17
|
+
*/
|
|
18
|
+
import { Command } from "commander";
|
|
19
|
+
import { type VaultClient } from "./cloud-provision.js";
|
|
20
|
+
/** Final stdout JSON shape. */
|
|
21
|
+
export interface RetireResult {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
company_slug: string;
|
|
24
|
+
cloud_uid: string | null;
|
|
25
|
+
/** True when hq-pro already had deleted=true (no DELETE sent). */
|
|
26
|
+
already_deleted: boolean;
|
|
27
|
+
cancelled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface RetireCompanyOptions {
|
|
30
|
+
slug: string;
|
|
31
|
+
hqRoot: string;
|
|
32
|
+
vaultApiUrl: string;
|
|
33
|
+
/** Skip the interactive confirmation prompt. */
|
|
34
|
+
yes?: boolean;
|
|
35
|
+
vaultClient?: VaultClient;
|
|
36
|
+
resolveAccessToken?: () => Promise<string>;
|
|
37
|
+
confirm?: (question: string) => Promise<boolean>;
|
|
38
|
+
stdinIsTTY?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export declare function defaultConfirm(question: string): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Read `companyUid` from `companies/<slug>/.hq/config.json` when the by-slug
|
|
43
|
+
* lookup misses (a tombstoned company is filtered from that route).
|
|
44
|
+
*/
|
|
45
|
+
export declare function readLocalCompanyUid(hqRoot: string, slug: string): string | null;
|
|
46
|
+
export declare function retireCompany(options: RetireCompanyOptions): Promise<RetireResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Register `retire company <slug>` under the `cloud` command group.
|
|
49
|
+
*/
|
|
50
|
+
export declare function registerCloudRetireCommands(program: Command): void;
|
|
51
|
+
//# sourceMappingURL=cloud-retire.d.ts.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq cloud retire company <slug>` — soft-tombstone a cloud company so
|
|
3
|
+
* `hq cloud demote company` can run without `--propagate-deletes`.
|
|
4
|
+
*
|
|
5
|
+
* Console equivalent: Settings → Delete company (`DELETE /entity/{uid}`).
|
|
6
|
+
* Owner-only. The entity row, S3 bucket, KMS key, and memberships stay;
|
|
7
|
+
* `/membership/me` stops listing the company. Local files are not touched —
|
|
8
|
+
* demote is the follow-up that flips the local tree back to local-only.
|
|
9
|
+
*
|
|
10
|
+
* Confirm step is on by default (`[y/N]`). `--yes` skips it for scripts.
|
|
11
|
+
* A non-TTY stdin without `--yes` refuses rather than hanging.
|
|
12
|
+
*
|
|
13
|
+
* Exit codes (mirrors cloud-provision / cloud-demote):
|
|
14
|
+
* 0 — success, already tombstoned, or the operator cancelled.
|
|
15
|
+
* 1 — vault HTTP failure (auth/network/5xx).
|
|
16
|
+
* 2 — validation (bad slug, no entity, not owner, missing confirm).
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
|
+
import * as readline from "node:readline";
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
import { ProvisionError, companyConfigPath, createDefaultVaultClient, validateSlug, } from "./cloud-provision.js";
|
|
22
|
+
import { DEFAULT_HQ_ROOT, DEFAULT_VAULT_API_URL, ensureCognitoToken, } from "../utils/cognito-session.js";
|
|
23
|
+
export function defaultConfirm(question) {
|
|
24
|
+
const rl = readline.createInterface({
|
|
25
|
+
input: process.stdin,
|
|
26
|
+
output: process.stdout,
|
|
27
|
+
});
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
30
|
+
rl.close();
|
|
31
|
+
resolve(/^y(es)?$/i.test(answer.trim()));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read `companyUid` from `companies/<slug>/.hq/config.json` when the by-slug
|
|
37
|
+
* lookup misses (a tombstoned company is filtered from that route).
|
|
38
|
+
*/
|
|
39
|
+
export function readLocalCompanyUid(hqRoot, slug) {
|
|
40
|
+
const cPath = companyConfigPath(hqRoot, slug);
|
|
41
|
+
if (!fs.existsSync(cPath))
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(fs.readFileSync(cPath, "utf-8"));
|
|
45
|
+
return typeof parsed.companyUid === "string" && parsed.companyUid.length > 0
|
|
46
|
+
? parsed.companyUid
|
|
47
|
+
: null;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export async function retireCompany(options) {
|
|
54
|
+
validateSlug(options.slug);
|
|
55
|
+
const accessToken = options.resolveAccessToken
|
|
56
|
+
? await options.resolveAccessToken()
|
|
57
|
+
: await ensureCognitoToken();
|
|
58
|
+
const client = options.vaultClient ??
|
|
59
|
+
createDefaultVaultClient(options.vaultApiUrl, accessToken);
|
|
60
|
+
let entity;
|
|
61
|
+
try {
|
|
62
|
+
entity = await client.findCompanyBySlug(options.slug);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err instanceof ProvisionError)
|
|
66
|
+
throw err;
|
|
67
|
+
throw new ProvisionError(1, `Vault GET by-slug failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
+
}
|
|
69
|
+
if (entity?.deleted === true) {
|
|
70
|
+
return {
|
|
71
|
+
ok: true,
|
|
72
|
+
company_slug: options.slug,
|
|
73
|
+
cloud_uid: entity.uid,
|
|
74
|
+
already_deleted: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const uid = entity?.uid ?? readLocalCompanyUid(options.hqRoot, options.slug);
|
|
78
|
+
if (!uid) {
|
|
79
|
+
throw new ProvisionError(2, `Refusing to retire '${options.slug}': no cloud entity found.`);
|
|
80
|
+
}
|
|
81
|
+
if (options.yes !== true) {
|
|
82
|
+
const tty = options.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
83
|
+
if (!tty) {
|
|
84
|
+
throw new ProvisionError(2, `Refusing to retire '${options.slug}' without confirmation. Re-run with --yes.`);
|
|
85
|
+
}
|
|
86
|
+
const confirm = options.confirm ?? defaultConfirm;
|
|
87
|
+
const ok = await confirm(`Soft-tombstone cloud company '${options.slug}' (${uid})? ` +
|
|
88
|
+
`It will disappear from every member's picker. Vault files stay. ` +
|
|
89
|
+
`Then run: hq cloud demote company ${options.slug}`);
|
|
90
|
+
if (!ok) {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
company_slug: options.slug,
|
|
94
|
+
cloud_uid: uid,
|
|
95
|
+
already_deleted: false,
|
|
96
|
+
cancelled: true,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
await client.softDeleteCompany(uid);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err instanceof ProvisionError)
|
|
105
|
+
throw err;
|
|
106
|
+
throw new ProvisionError(1, `Vault DELETE /entity/${uid} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
ok: true,
|
|
110
|
+
company_slug: options.slug,
|
|
111
|
+
cloud_uid: uid,
|
|
112
|
+
already_deleted: false,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Register `retire company <slug>` under the `cloud` command group.
|
|
117
|
+
*/
|
|
118
|
+
export function registerCloudRetireCommands(program) {
|
|
119
|
+
const retireCmd = program
|
|
120
|
+
.command("retire")
|
|
121
|
+
.description("Soft-tombstone a cloud-backed company (owner only)");
|
|
122
|
+
retireCmd
|
|
123
|
+
.command("company")
|
|
124
|
+
.description("Soft-tombstone a cloud company so `hq cloud demote company` can run. " +
|
|
125
|
+
"Does not delete vault files or local folders. Prompts unless --yes.")
|
|
126
|
+
.argument("<slug>", "Company slug")
|
|
127
|
+
.option("--hq-root <path>", `Local HQ tree root (default: ${DEFAULT_HQ_ROOT})`, DEFAULT_HQ_ROOT)
|
|
128
|
+
.option("--vault-api-url <url>", `Vault API URL (default: ${DEFAULT_VAULT_API_URL})`, DEFAULT_VAULT_API_URL)
|
|
129
|
+
.option("-y, --yes", "Skip the confirmation prompt (for scripts)")
|
|
130
|
+
.action(async (slug, options) => {
|
|
131
|
+
try {
|
|
132
|
+
const result = await retireCompany({
|
|
133
|
+
slug,
|
|
134
|
+
hqRoot: options.hqRoot,
|
|
135
|
+
vaultApiUrl: options.vaultApiUrl,
|
|
136
|
+
yes: options.yes,
|
|
137
|
+
});
|
|
138
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
139
|
+
if (result.cancelled) {
|
|
140
|
+
process.stderr.write(chalk.dim("[hq cloud retire] Cancelled — nothing was tombstoned.\n"));
|
|
141
|
+
}
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (err instanceof ProvisionError) {
|
|
146
|
+
process.stderr.write(chalk.red(`[hq cloud retire] ${err.message}\n`));
|
|
147
|
+
process.exit(err.code);
|
|
148
|
+
}
|
|
149
|
+
process.stderr.write(chalk.red(`[hq cloud retire] Unexpected error: ${err instanceof Error ? err.message : String(err)}\n`));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=cloud-retire.js.map
|