@indigoai-us/hq-cli 5.52.0 → 5.53.0
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 +18 -0
- package/dist/commands/company.d.ts +3 -0
- package/dist/commands/company.js +82 -0
- package/dist/commands/crm.d.ts +3 -0
- package/dist/commands/crm.js +162 -0
- package/dist/commands/files.d.ts +2 -0
- package/dist/commands/files.js +41 -13
- package/dist/index.js +11 -2
- package/package.json +1 -1
- package/src/commands/company.test.ts +177 -0
- package/src/commands/company.ts +132 -0
- package/src/commands/crm.test.ts +179 -0
- package/src/commands/crm.ts +236 -0
- package/src/commands/files-delete.test.ts +84 -0
- package/src/commands/files.ts +54 -13
- package/src/index.ts +11 -0
package/src/commands/files.ts
CHANGED
|
@@ -468,21 +468,39 @@ export function registerFilesCommand(program: Command): Command {
|
|
|
468
468
|
files
|
|
469
469
|
.command("delete <prefix>")
|
|
470
470
|
.description(
|
|
471
|
-
"Delete vault objects under a prefix (bounded + scoped). Always previews the exact count first; prompts for confirmation unless --yes.",
|
|
471
|
+
"Delete vault objects under a prefix (bounded + scoped). Always previews the exact count first; prompts for confirmation unless --yes. Use --personal to target your own personal vault instead of a company.",
|
|
472
472
|
)
|
|
473
473
|
.option(
|
|
474
474
|
"--dry-run",
|
|
475
475
|
"List what WOULD be deleted without deleting anything",
|
|
476
476
|
)
|
|
477
|
+
.option(
|
|
478
|
+
"--personal",
|
|
479
|
+
"Target your own personal vault instead of a company vault (mutually exclusive with --company)",
|
|
480
|
+
)
|
|
477
481
|
.option("-y, --yes", "Skip the confirmation prompt (for scripts)")
|
|
478
482
|
.action(
|
|
479
|
-
async (
|
|
483
|
+
async (
|
|
484
|
+
prefix: string,
|
|
485
|
+
opts: { dryRun?: boolean; yes?: boolean; personal?: boolean },
|
|
486
|
+
) => {
|
|
480
487
|
try {
|
|
488
|
+
const companySlug = files.opts().company as string | undefined;
|
|
489
|
+
const personal = opts.personal === true;
|
|
490
|
+
if (personal && companySlug) {
|
|
491
|
+
console.error(
|
|
492
|
+
chalk.red(
|
|
493
|
+
"Pass either --personal or --company, not both.",
|
|
494
|
+
),
|
|
495
|
+
);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
481
498
|
await runFilesDelete({
|
|
482
499
|
prefix,
|
|
483
500
|
dryRun: opts.dryRun === true,
|
|
484
501
|
yes: opts.yes === true,
|
|
485
|
-
|
|
502
|
+
personal,
|
|
503
|
+
companySlug,
|
|
486
504
|
});
|
|
487
505
|
} catch (err) {
|
|
488
506
|
console.error(
|
|
@@ -783,10 +801,16 @@ function realConfirm(message: string): Promise<boolean> {
|
|
|
783
801
|
/**
|
|
784
802
|
* POST /v1/files/delete. Throws FilesDeleteHttpError on any non-2xx so the one
|
|
785
803
|
* caller renders a single consistent error path.
|
|
804
|
+
*
|
|
805
|
+
* Scope is EITHER a company vault (`companyUid` set) OR the caller's personal
|
|
806
|
+
* vault (`personal: true`). For the personal case the server resolves the target
|
|
807
|
+
* person + bucket from the authenticated caller — we send NO uid, just the
|
|
808
|
+
* `personal` flag — so there is nothing for the client to get wrong or spoof.
|
|
786
809
|
*/
|
|
787
810
|
async function callDeleteEndpoint(params: {
|
|
788
811
|
token: string;
|
|
789
|
-
companyUid
|
|
812
|
+
companyUid?: string;
|
|
813
|
+
personal?: boolean;
|
|
790
814
|
prefix: string;
|
|
791
815
|
dryRun: boolean;
|
|
792
816
|
}): Promise<FilesDeleteResponse> {
|
|
@@ -794,11 +818,17 @@ async function callDeleteEndpoint(params: {
|
|
|
794
818
|
token: params.token,
|
|
795
819
|
path: "/v1/files/delete",
|
|
796
820
|
method: "POST",
|
|
797
|
-
body:
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
821
|
+
body: params.personal
|
|
822
|
+
? {
|
|
823
|
+
personal: true,
|
|
824
|
+
prefix: params.prefix,
|
|
825
|
+
dryRun: params.dryRun,
|
|
826
|
+
}
|
|
827
|
+
: {
|
|
828
|
+
company: params.companyUid,
|
|
829
|
+
prefix: params.prefix,
|
|
830
|
+
dryRun: params.dryRun,
|
|
831
|
+
},
|
|
802
832
|
});
|
|
803
833
|
if (!res.ok) {
|
|
804
834
|
const body = (await res.json().catch(() => ({}))) as Record<string, string>;
|
|
@@ -815,6 +845,8 @@ interface RunFilesDeleteParams {
|
|
|
815
845
|
prefix: string;
|
|
816
846
|
dryRun: boolean;
|
|
817
847
|
yes: boolean;
|
|
848
|
+
/** Target the caller's personal vault instead of a company vault. */
|
|
849
|
+
personal?: boolean;
|
|
818
850
|
companySlug: string | undefined;
|
|
819
851
|
}
|
|
820
852
|
|
|
@@ -896,7 +928,14 @@ export async function runFilesDelete(
|
|
|
896
928
|
}
|
|
897
929
|
|
|
898
930
|
const token = await ensureCognitoToken();
|
|
899
|
-
|
|
931
|
+
// Personal scope resolves the vault server-side from the caller's identity —
|
|
932
|
+
// no company to look up. Company scope resolves the companyUid as before.
|
|
933
|
+
const companyUid = params.personal
|
|
934
|
+
? undefined
|
|
935
|
+
: await getCompanyUid(token, params.companySlug);
|
|
936
|
+
const scopeArgs = params.personal
|
|
937
|
+
? { personal: true as const }
|
|
938
|
+
: { companyUid };
|
|
900
939
|
|
|
901
940
|
// 1. Always preview first — this is how we print the EXACT key count before
|
|
902
941
|
// deleting anything (and the whole behavior of --dry-run).
|
|
@@ -904,7 +943,7 @@ export async function runFilesDelete(
|
|
|
904
943
|
try {
|
|
905
944
|
preview = await callDeleteEndpoint({
|
|
906
945
|
token,
|
|
907
|
-
|
|
946
|
+
...scopeArgs,
|
|
908
947
|
prefix: normalized,
|
|
909
948
|
dryRun: true,
|
|
910
949
|
});
|
|
@@ -956,7 +995,9 @@ export async function runFilesDelete(
|
|
|
956
995
|
|
|
957
996
|
if (!params.yes) {
|
|
958
997
|
const ok = await confirm(
|
|
959
|
-
|
|
998
|
+
params.personal
|
|
999
|
+
? `Delete ${preview.matched} ${noun}? This removes them from your personal vault.`
|
|
1000
|
+
: `Delete ${preview.matched} ${noun}? This removes them from the shared vault for everyone.`,
|
|
960
1001
|
);
|
|
961
1002
|
if (!ok) {
|
|
962
1003
|
console.log(chalk.dim("Aborted — nothing was deleted."));
|
|
@@ -969,7 +1010,7 @@ export async function runFilesDelete(
|
|
|
969
1010
|
try {
|
|
970
1011
|
result = await callDeleteEndpoint({
|
|
971
1012
|
token,
|
|
972
|
-
|
|
1013
|
+
...scopeArgs,
|
|
973
1014
|
prefix: normalized,
|
|
974
1015
|
dryRun: false,
|
|
975
1016
|
});
|
package/src/index.ts
CHANGED
|
@@ -48,6 +48,8 @@ import { registerSignalsCommand } from "./commands/signals.js";
|
|
|
48
48
|
import { registerReindexCommand } from "./commands/reindex.js";
|
|
49
49
|
import { registerRescueCommand } from "./commands/rescue.js";
|
|
50
50
|
import { registerMcpCommand } from "./commands/mcp-status.js";
|
|
51
|
+
import { registerCrmCommand } from "./commands/crm.js";
|
|
52
|
+
import { registerCompanyCommand } from "./commands/company.js";
|
|
51
53
|
import { sanitizeArgv } from "./utils/feedback-diagnostics.js";
|
|
52
54
|
import { environmentalFsErrorMessage } from "./utils/environmental-error.js";
|
|
53
55
|
import { isEpipe } from "./utils/epipe.js";
|
|
@@ -214,6 +216,15 @@ registerRescueCommand(program);
|
|
|
214
216
|
// off the configs, NOT linkStatus), with secret-redacted output + `--json`.
|
|
215
217
|
registerMcpCommand(program);
|
|
216
218
|
|
|
219
|
+
// Native CRM entity upsert (subcommand group — `hq crm entity upsert`). Wraps
|
|
220
|
+
// POST /crm/entities (the ontology write gate) so an authenticated company
|
|
221
|
+
// member can create/update canonical CRM entities in the company vault.
|
|
222
|
+
registerCrmCommand(program);
|
|
223
|
+
|
|
224
|
+
// Company settings (subcommand group — `hq company settings set`). Owner-only
|
|
225
|
+
// toggles for crmEnabled / ontologyEnabled via PUT /company-settings.
|
|
226
|
+
registerCompanyCommand(program);
|
|
227
|
+
|
|
217
228
|
(async () => {
|
|
218
229
|
try {
|
|
219
230
|
Sentry.addBreadcrumb({
|