@indigoai-us/hq-cli 5.8.3 → 5.8.5

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.
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5f7a9620-b2ba-5186-980c-76df147440f0")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3d902660-a8aa-5671-ab69-21ffc0143c60")}catch(e){}}();
3
3
  import chalk from "chalk";
4
4
  import { ensureCognitoToken } from "../utils/cognito-session.js";
5
5
  import { vaultApiFetch, getCompanyUid } from "./secrets.js";
@@ -33,12 +33,28 @@ export function registerFilesCommand(program) {
33
33
  const token = await ensureCognitoToken();
34
34
  const companySlug = files.opts().company;
35
35
  const companyUid = await getCompanyUid(token, companySlug);
36
- const res = await vaultApiFetch({
36
+ let res = await vaultApiFetch({
37
37
  token,
38
38
  path: `/files/${encodeURIComponent(companyUid)}/acl/grant`,
39
39
  method: "POST",
40
40
  body: { prefix: canonicalPrefix, granteeType, granteeId, permission: opts.permission },
41
41
  });
42
+ // No ACL row exists yet for this prefix. Auto-create one with this
43
+ // grant as its first entry, then report success — saves the caller
44
+ // from needing a separate "create" step.
45
+ let autoCreated = false;
46
+ if (res.status === 404) {
47
+ res = await vaultApiFetch({
48
+ token,
49
+ path: `/files/${encodeURIComponent(companyUid)}/acl`,
50
+ method: "POST",
51
+ body: {
52
+ prefix: canonicalPrefix,
53
+ entries: [{ granteeType, granteeId, permission: opts.permission }],
54
+ },
55
+ });
56
+ autoCreated = res.ok;
57
+ }
42
58
  if (!res.ok) {
43
59
  const body = await res.json().catch(() => ({}));
44
60
  if (res.status === 401) {
@@ -62,8 +78,9 @@ export function registerFilesCommand(program) {
62
78
  process.exit(1);
63
79
  }
64
80
  const data = await res.json();
65
- const printedPrefix = data.acl?.prefix ?? canonicalPrefix;
66
- console.log(chalk.green(`Granted ${opts.permission} on ${printedPrefix} to ${granteeId}`));
81
+ const printedPrefix = data.acl?.path ?? data.acl?.prefix ?? canonicalPrefix;
82
+ const verb = autoCreated ? "Created ACL and granted" : "Granted";
83
+ console.log(chalk.green(`${verb} ${opts.permission} on ${printedPrefix} to ${granteeId}`));
67
84
  }
68
85
  catch (err) {
69
86
  console.error(chalk.red("Error:"), err instanceof Error ? err.message : String(err));
@@ -158,7 +175,8 @@ export function registerFilesCommand(program) {
158
175
  const data = await res.json();
159
176
  const acl = data.acl;
160
177
  const aclStatus = acl.open ? "open" : "restricted";
161
- console.log(chalk.green(`ACL for ${acl.prefix} (${aclStatus})`));
178
+ const aclPrefix = acl.path ?? acl.prefix ?? canonicalPrefix;
179
+ console.log(chalk.green(`ACL for ${aclPrefix} (${aclStatus})`));
162
180
  console.log(`Creator: ${acl.creatorUid}`);
163
181
  if (acl.effectivePermission) {
164
182
  console.log(`Your effective permission: ${acl.effectivePermission}`);
@@ -203,4 +221,4 @@ export function registerFilesCommand(program) {
203
221
  });
204
222
  }
205
223
  //# sourceMappingURL=files.js.map
206
- //# debugId=5f7a9620-b2ba-5186-980c-76df147440f0
224
+ //# debugId=3d902660-a8aa-5671-ab69-21ffc0143c60
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e84b2c37-90d0-559c-ace0-2b08fb69eec5")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="37e6bf57-eabb-58da-874c-57cc39e78d89")}catch(e){}}();
3
3
  import chalk from "chalk";
4
4
  import { ensureCognitoToken } from "../utils/cognito-session.js";
5
5
  import { vaultApiFetch, getCompanyUid } from "./secrets.js";
@@ -30,10 +30,14 @@ export function registerGroupsCommand(program) {
30
30
  .description("Create a new group")
31
31
  .requiredOption("--name <name>", "Human-readable group name")
32
32
  .option("--description <desc>", "Optional description")
33
- .action(async (groupId, opts) => {
33
+ .action(async (rawGroupId, opts) => {
34
34
  try {
35
+ // Auto-prepend `grp_` when the caller passes a bare id (`core` →
36
+ // `grp_core`); the server does the same as a defense-in-depth
37
+ // backstop. The post-prepend form must still match GROUP_ID_PATTERN.
38
+ const groupId = rawGroupId.startsWith("grp_") ? rawGroupId : `grp_${rawGroupId}`;
35
39
  if (!GROUP_ID_PATTERN.test(groupId)) {
36
- console.error(chalk.red(`Invalid group id '${groupId}': must match grp_<alphanumeric>`));
40
+ console.error(chalk.red(`Invalid group id '${rawGroupId}': resulting id '${groupId}' must match grp_<alphanumeric, underscore, hyphen>`));
37
41
  process.exit(1);
38
42
  }
39
43
  const token = await ensureCognitoToken();
@@ -341,4 +345,4 @@ export function registerGroupsCommand(program) {
341
345
  });
342
346
  }
343
347
  //# sourceMappingURL=groups.js.map
344
- //# debugId=e84b2c37-90d0-559c-ace0-2b08fb69eec5
348
+ //# debugId=37e6bf57-eabb-58da-874c-57cc39e78d89
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ const program = new Command();
30
30
  program
31
31
  .name("hq")
32
32
  .description("HQ management CLI — modules, packages, and cloud sync")
33
- .version("5.8.3");
33
+ .version("5.8.5");
34
34
  // Module management subcommand group
35
35
  const modulesCmd = program
36
36
  .command("modules")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.8.3",
3
+ "version": "5.8.5",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -38,13 +38,30 @@ export function registerFilesCommand(program: Command): void {
38
38
  const companySlug = files.opts().company as string | undefined;
39
39
  const companyUid = await getCompanyUid(token, companySlug);
40
40
 
41
- const res = await vaultApiFetch({
41
+ let res = await vaultApiFetch({
42
42
  token,
43
43
  path: `/files/${encodeURIComponent(companyUid)}/acl/grant`,
44
44
  method: "POST",
45
45
  body: { prefix: canonicalPrefix, granteeType, granteeId, permission: opts.permission },
46
46
  });
47
47
 
48
+ // No ACL row exists yet for this prefix. Auto-create one with this
49
+ // grant as its first entry, then report success — saves the caller
50
+ // from needing a separate "create" step.
51
+ let autoCreated = false;
52
+ if (res.status === 404) {
53
+ res = await vaultApiFetch({
54
+ token,
55
+ path: `/files/${encodeURIComponent(companyUid)}/acl`,
56
+ method: "POST",
57
+ body: {
58
+ prefix: canonicalPrefix,
59
+ entries: [{ granteeType, granteeId, permission: opts.permission }],
60
+ },
61
+ });
62
+ autoCreated = res.ok;
63
+ }
64
+
48
65
  if (!res.ok) {
49
66
  const body = await res.json().catch(() => ({})) as Record<string, string>;
50
67
  if (res.status === 401) {
@@ -63,9 +80,10 @@ export function registerFilesCommand(program: Command): void {
63
80
  process.exit(1);
64
81
  }
65
82
 
66
- const data = await res.json() as { acl?: { prefix?: string } };
67
- const printedPrefix = data.acl?.prefix ?? canonicalPrefix;
68
- console.log(chalk.green(`Granted ${opts.permission} on ${printedPrefix} to ${granteeId}`));
83
+ const data = await res.json() as { acl?: { path?: string; prefix?: string } };
84
+ const printedPrefix = data.acl?.path ?? data.acl?.prefix ?? canonicalPrefix;
85
+ const verb = autoCreated ? "Created ACL and granted" : "Granted";
86
+ console.log(chalk.green(`${verb} ${opts.permission} on ${printedPrefix} to ${granteeId}`));
69
87
  } catch (err) {
70
88
  console.error(chalk.red("Error:"), err instanceof Error ? err.message : String(err));
71
89
  process.exit(1);
@@ -162,7 +180,10 @@ export function registerFilesCommand(program: Command): void {
162
180
  acl: {
163
181
  itemType: string;
164
182
  companyUid: string;
165
- prefix: string;
183
+ // Server returns `path` (the FileAcl field name); older builds
184
+ // used `prefix`. Read both so the CLI works against either.
185
+ path?: string;
186
+ prefix?: string;
166
187
  creatorUid: string;
167
188
  open?: boolean;
168
189
  entries: Array<{
@@ -180,8 +201,9 @@ export function registerFilesCommand(program: Command): void {
180
201
 
181
202
  const acl = data.acl;
182
203
  const aclStatus = acl.open ? "open" : "restricted";
204
+ const aclPrefix = acl.path ?? acl.prefix ?? canonicalPrefix;
183
205
 
184
- console.log(chalk.green(`ACL for ${acl.prefix} (${aclStatus})`));
206
+ console.log(chalk.green(`ACL for ${aclPrefix} (${aclStatus})`));
185
207
  console.log(`Creator: ${acl.creatorUid}`);
186
208
  if (acl.effectivePermission) {
187
209
  console.log(`Your effective permission: ${acl.effectivePermission}`);
@@ -36,10 +36,14 @@ export function registerGroupsCommand(program: Command): void {
36
36
  .description("Create a new group")
37
37
  .requiredOption("--name <name>", "Human-readable group name")
38
38
  .option("--description <desc>", "Optional description")
39
- .action(async (groupId: string, opts: { name: string; description?: string }) => {
39
+ .action(async (rawGroupId: string, opts: { name: string; description?: string }) => {
40
40
  try {
41
+ // Auto-prepend `grp_` when the caller passes a bare id (`core` →
42
+ // `grp_core`); the server does the same as a defense-in-depth
43
+ // backstop. The post-prepend form must still match GROUP_ID_PATTERN.
44
+ const groupId = rawGroupId.startsWith("grp_") ? rawGroupId : `grp_${rawGroupId}`;
41
45
  if (!GROUP_ID_PATTERN.test(groupId)) {
42
- console.error(chalk.red(`Invalid group id '${groupId}': must match grp_<alphanumeric>`));
46
+ console.error(chalk.red(`Invalid group id '${rawGroupId}': resulting id '${groupId}' must match grp_<alphanumeric, underscore, hyphen>`));
43
47
  process.exit(1);
44
48
  }
45
49
 
package/src/index.ts CHANGED
@@ -33,7 +33,7 @@ const program = new Command();
33
33
  program
34
34
  .name("hq")
35
35
  .description("HQ management CLI — modules, packages, and cloud sync")
36
- .version("5.8.3");
36
+ .version("5.8.5");
37
37
 
38
38
  // Module management subcommand group
39
39
  const modulesCmd = program