@indigoai-us/hq-cli 5.225.0 → 5.227.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 +47 -1
- package/dist/command-catalog.generated.d.ts +100 -0
- package/dist/command-catalog.generated.js +128 -0
- package/dist/command-registration-plan.d.ts +18 -0
- package/dist/command-registration-plan.js +6 -0
- package/dist/commands/agent-enroll.d.ts +2 -0
- package/dist/commands/agent-enroll.js +17 -2
- package/dist/commands/cloud.d.ts +10 -0
- package/dist/commands/cloud.js +52 -47
- package/dist/commands/lanes-checks.d.ts +2 -0
- package/dist/commands/lanes-checks.js +13 -11
- package/dist/commands/lanes-import.d.ts +1 -0
- package/dist/commands/lanes-import.js +12 -11
- package/dist/commands/lanes-report.js +21 -14
- package/dist/commands/lanes-tracker.d.ts +1 -0
- package/dist/commands/lanes-tracker.js +39 -31
- package/dist/commands/lanes.d.ts +8 -0
- package/dist/commands/lanes.js +818 -314
- package/dist/commands/staff/reset-test-account.d.ts +110 -0
- package/dist/commands/staff/reset-test-account.js +268 -0
- package/dist/commands/staff/test-account.d.ts +51 -0
- package/dist/commands/staff/test-account.js +196 -0
- package/dist/lib/checkpoint-ontology/plan.d.ts +4 -6
- package/dist/lib/checkpoint-ontology/plan.js +8 -26
- package/dist/lib/doctor/client-health-flag-token.d.ts +15 -0
- package/dist/lib/doctor/client-health-flag-token.js +66 -0
- package/dist/lib/doctor/client-health-reason-codes-flag.d.ts +1 -0
- package/dist/lib/doctor/client-health-reason-codes-flag.js +16 -5
- package/dist/lib/doctor/client-health-sentry-flag.d.ts +1 -0
- package/dist/lib/doctor/client-health-sentry-flag.js +17 -6
- package/dist/lib/lanes/dropbox.d.ts +9 -0
- package/dist/lib/lanes/dropbox.js +70 -1
- package/dist/lib/lanes/reconcile.d.ts +4 -0
- package/dist/lib/lanes/reconcile.js +28 -0
- package/dist/lib/lanes/store.js +9 -1
- package/dist/lib/lanes/tracker-mesh-questions.d.ts +54 -0
- package/dist/lib/lanes/tracker-mesh-questions.js +138 -0
- package/dist/lib/lanes/tracker-mesh.d.ts +19 -0
- package/dist/lib/lanes/tracker-mesh.js +228 -0
- package/dist/lib/lanes/tracker-store.d.ts +13 -2
- package/dist/lib/lanes/tracker-store.js +1 -1
- package/dist/lib/lanes/types.d.ts +4 -0
- package/dist/lib/lanes/watcher-main.js +16 -0
- package/dist/lib/lanes/watcher.d.ts +4 -1
- package/dist/lib/lanes/watcher.js +77 -3
- package/dist/utils/cognito-session.d.ts +8 -0
- package/dist/utils/cognito-session.js +198 -3
- package/dist/utils/upload-author.d.ts +15 -0
- package/dist/utils/upload-author.js +39 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.227.0] — 2026-09-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `hq lanes tracker`, `checks`, `import`, and `report` use the Work Mesh tracker
|
|
10
|
+
store when `lanes.tracker-mesh` is enabled. Company questions are indexed and
|
|
11
|
+
shared across hosts; reconcile polls for remote answers, wakes the owning lane,
|
|
12
|
+
and stamps delivery once.
|
|
13
|
+
|
|
14
|
+
## [5.226.0] — 2026-09-26
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `hq staff reset-test-account <email>` wipes a designated test account through
|
|
19
|
+
the hq-pro admin API. Defaults to a dry-run that lists what would be deleted;
|
|
20
|
+
`--execute` prompts for the typed email confirmation before wiping, and
|
|
21
|
+
`--yes` skips the prompt. Refuses to run for callers whose stored email is
|
|
22
|
+
not on the staff list.
|
|
23
|
+
- `hq staff test-account add|remove|list` manages the designated-test-account
|
|
24
|
+
registry through the same admin API. `add` and `remove` require staff
|
|
25
|
+
callers; `list` returns the current registry entries.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `hq lanes message` now probes the worker PID and start time before queueing.
|
|
30
|
+
Watcher and reconcile recover accepted inbox messages through the same
|
|
31
|
+
resume path after classifying an exited worker; undrained messages on done,
|
|
32
|
+
killed, retired, or superseded lanes are archived as undeliverable.
|
|
33
|
+
- Failed queued-message recovery restores unaccepted claims to the inbox and
|
|
34
|
+
records the failure. Recovery also sees leftover draining and inflight files,
|
|
35
|
+
and synchronous classification shares watcher ownership to prevent duplicate
|
|
36
|
+
repair and resume work.
|
|
37
|
+
- `hq agent enroll --name <bot>` now works on a computer where a person is signed in. It enrolls into `~/.hq-agent/<bot>/` and refuses only if that folder already holds an agent. Before, it refused because of the person's login and told you to pass `--name`, which you already had. Enrolling with no name on such a computer (the default local folder) had the same bug.
|
|
38
|
+
- Pushes made as an agent now record the agent as the uploader. Before, on a computer where a person was also signed in, the files were stamped with the person's email and id.
|
|
39
|
+
- When the server refuses some paths in a push (for example, another member's file in a private folder `foo/`), the warning now says the server refused them, in `hq sync push`, `hq sync now` and `hq sync push --all`. Before, it said the files were outside your write access and to ask an admin for a grant.
|
|
40
|
+
|
|
5
41
|
## [5.225.0] — 2026-09-26
|
|
6
42
|
|
|
7
43
|
### Changed
|
|
@@ -20,7 +56,13 @@
|
|
|
20
56
|
|
|
21
57
|
### Fixed
|
|
22
58
|
|
|
23
|
-
- When `hq daemon pin-hq-cloud` names a version that is not installed yet, the
|
|
59
|
+
- When `hq daemon pin-hq-cloud` names a version that is not installed yet, the
|
|
60
|
+
daemon keeps running the newest installed hq-cloud instead of falling back
|
|
61
|
+
to the older copy bundled with the CLI, and logs a warning naming the
|
|
62
|
+
missing version. The updater then installs the pinned version and the
|
|
63
|
+
daemon switches to it. Before, a pin that did not match the installed copy
|
|
64
|
+
silently ran the bundled copy, which on one outpost meant a months-old sync
|
|
65
|
+
runner without recent fixes.
|
|
24
66
|
|
|
25
67
|
## [5.223.0] — 2026-09-26
|
|
26
68
|
|
|
@@ -34,6 +76,10 @@
|
|
|
34
76
|
shares one local account probe across matching lanes per poll. Quota and
|
|
35
77
|
model failures keep their existing account-selection path and reason.
|
|
36
78
|
|
|
79
|
+
- Client-health flag checks refresh expired person identity and use machine
|
|
80
|
+
identity when available. Identity refresh has a separate bound, and failed
|
|
81
|
+
lookups keep the existing doctor fallback path.
|
|
82
|
+
|
|
37
83
|
## [5.222.0] — 2026-09-26
|
|
38
84
|
|
|
39
85
|
- Checkpoint ontology, behind `checkpoint.ontology.multi-writer` (off by
|
|
@@ -7069,6 +7069,9 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
7069
7069
|
}, {
|
|
7070
7070
|
readonly flags: "--company <slug>";
|
|
7071
7071
|
readonly description: "Select the company by slug";
|
|
7072
|
+
}, {
|
|
7073
|
+
readonly flags: "--question <id>";
|
|
7074
|
+
readonly description: "Answered owner question authorizing this approval";
|
|
7072
7075
|
}, {
|
|
7073
7076
|
readonly flags: "--json";
|
|
7074
7077
|
readonly description: "JSON on stdout (always)";
|
|
@@ -7145,6 +7148,9 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
7145
7148
|
}, {
|
|
7146
7149
|
readonly flags: "--company <slug>";
|
|
7147
7150
|
readonly description: "Select the company by slug";
|
|
7151
|
+
}, {
|
|
7152
|
+
readonly flags: "--question <id>";
|
|
7153
|
+
readonly description: "Answered owner question authorizing this approval";
|
|
7148
7154
|
}, {
|
|
7149
7155
|
readonly flags: "--json";
|
|
7150
7156
|
readonly description: "JSON on stdout (always)";
|
|
@@ -7961,6 +7967,22 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
7961
7967
|
readonly description: "JSON on stdout (always)";
|
|
7962
7968
|
}];
|
|
7963
7969
|
readonly subcommands: readonly [];
|
|
7970
|
+
}, {
|
|
7971
|
+
readonly name: "_recover-queued-messages";
|
|
7972
|
+
readonly description: "";
|
|
7973
|
+
readonly aliases: readonly [];
|
|
7974
|
+
readonly hidden: true;
|
|
7975
|
+
readonly usage: "[options] <lane-id>";
|
|
7976
|
+
readonly arguments: readonly [{
|
|
7977
|
+
readonly name: "lane-id";
|
|
7978
|
+
readonly required: true;
|
|
7979
|
+
readonly variadic: false;
|
|
7980
|
+
}];
|
|
7981
|
+
readonly options: readonly [{
|
|
7982
|
+
readonly flags: "--json";
|
|
7983
|
+
readonly description: "JSON on stdout (always)";
|
|
7984
|
+
}];
|
|
7985
|
+
readonly subcommands: readonly [];
|
|
7964
7986
|
}, {
|
|
7965
7987
|
readonly name: "_monitor-message";
|
|
7966
7988
|
readonly description: "";
|
|
@@ -9490,5 +9512,83 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
9490
9512
|
}];
|
|
9491
9513
|
readonly subcommands: readonly [];
|
|
9492
9514
|
}];
|
|
9515
|
+
}, {
|
|
9516
|
+
readonly name: "staff";
|
|
9517
|
+
readonly description: "Staff-only commands (super-admin required)";
|
|
9518
|
+
readonly aliases: readonly [];
|
|
9519
|
+
readonly hidden: false;
|
|
9520
|
+
readonly usage: "[options] [command]";
|
|
9521
|
+
readonly arguments: readonly [];
|
|
9522
|
+
readonly options: readonly [];
|
|
9523
|
+
readonly subcommands: readonly [{
|
|
9524
|
+
readonly name: "reset-test-account";
|
|
9525
|
+
readonly description: "Reset a designated real-email test account (dry-run by default). Wraps POST /v1/admin/test-account/reset — super-admin only.";
|
|
9526
|
+
readonly aliases: readonly [];
|
|
9527
|
+
readonly hidden: false;
|
|
9528
|
+
readonly usage: "[options] <email>";
|
|
9529
|
+
readonly arguments: readonly [{
|
|
9530
|
+
readonly name: "email";
|
|
9531
|
+
readonly required: true;
|
|
9532
|
+
readonly variadic: false;
|
|
9533
|
+
}];
|
|
9534
|
+
readonly options: readonly [{
|
|
9535
|
+
readonly flags: "--execute";
|
|
9536
|
+
readonly description: "Actually delete artifacts. Prompts for a typed-email confirmation.";
|
|
9537
|
+
}, {
|
|
9538
|
+
readonly flags: "-y, --yes";
|
|
9539
|
+
readonly description: "Skip the typed-email confirmation prompt (still sends confirmEmail).";
|
|
9540
|
+
}];
|
|
9541
|
+
readonly subcommands: readonly [];
|
|
9542
|
+
}, {
|
|
9543
|
+
readonly name: "test-account";
|
|
9544
|
+
readonly description: "Manage the designated test-account registry (super-admin only). Wraps /v1/admin/test-account-registry.";
|
|
9545
|
+
readonly aliases: readonly [];
|
|
9546
|
+
readonly hidden: false;
|
|
9547
|
+
readonly usage: "[options] [command]";
|
|
9548
|
+
readonly arguments: readonly [];
|
|
9549
|
+
readonly options: readonly [];
|
|
9550
|
+
readonly subcommands: readonly [{
|
|
9551
|
+
readonly name: "add";
|
|
9552
|
+
readonly description: "Add an email to the registry so `hq staff reset-test-account` will sweep it.";
|
|
9553
|
+
readonly aliases: readonly [];
|
|
9554
|
+
readonly hidden: false;
|
|
9555
|
+
readonly usage: "[options] <email>";
|
|
9556
|
+
readonly arguments: readonly [{
|
|
9557
|
+
readonly name: "email";
|
|
9558
|
+
readonly required: true;
|
|
9559
|
+
readonly variadic: false;
|
|
9560
|
+
}];
|
|
9561
|
+
readonly options: readonly [{
|
|
9562
|
+
readonly flags: "--note <text>";
|
|
9563
|
+
readonly description: "Short reason recorded on the row";
|
|
9564
|
+
}];
|
|
9565
|
+
readonly subcommands: readonly [];
|
|
9566
|
+
}, {
|
|
9567
|
+
readonly name: "remove";
|
|
9568
|
+
readonly description: "Soft-delete a registry entry (row stays with active: false).";
|
|
9569
|
+
readonly aliases: readonly [];
|
|
9570
|
+
readonly hidden: false;
|
|
9571
|
+
readonly usage: "[options] <email>";
|
|
9572
|
+
readonly arguments: readonly [{
|
|
9573
|
+
readonly name: "email";
|
|
9574
|
+
readonly required: true;
|
|
9575
|
+
readonly variadic: false;
|
|
9576
|
+
}];
|
|
9577
|
+
readonly options: readonly [];
|
|
9578
|
+
readonly subcommands: readonly [];
|
|
9579
|
+
}, {
|
|
9580
|
+
readonly name: "list";
|
|
9581
|
+
readonly description: "List active registry entries.";
|
|
9582
|
+
readonly aliases: readonly [];
|
|
9583
|
+
readonly hidden: false;
|
|
9584
|
+
readonly usage: "[options]";
|
|
9585
|
+
readonly arguments: readonly [];
|
|
9586
|
+
readonly options: readonly [{
|
|
9587
|
+
readonly flags: "--include-inactive";
|
|
9588
|
+
readonly description: "Also list soft-deleted rows (active: false).";
|
|
9589
|
+
}];
|
|
9590
|
+
readonly subcommands: readonly [];
|
|
9591
|
+
}];
|
|
9592
|
+
}];
|
|
9493
9593
|
}];
|
|
9494
9594
|
//# sourceMappingURL=command-catalog.generated.d.ts.map
|
|
@@ -9137,6 +9137,10 @@ export const COMMAND_CATALOG = [
|
|
|
9137
9137
|
"flags": "--company <slug>",
|
|
9138
9138
|
"description": "Select the company by slug"
|
|
9139
9139
|
},
|
|
9140
|
+
{
|
|
9141
|
+
"flags": "--question <id>",
|
|
9142
|
+
"description": "Answered owner question authorizing this approval"
|
|
9143
|
+
},
|
|
9140
9144
|
{
|
|
9141
9145
|
"flags": "--json",
|
|
9142
9146
|
"description": "JSON on stdout (always)"
|
|
@@ -9235,6 +9239,10 @@ export const COMMAND_CATALOG = [
|
|
|
9235
9239
|
"flags": "--company <slug>",
|
|
9236
9240
|
"description": "Select the company by slug"
|
|
9237
9241
|
},
|
|
9242
|
+
{
|
|
9243
|
+
"flags": "--question <id>",
|
|
9244
|
+
"description": "Answered owner question authorizing this approval"
|
|
9245
|
+
},
|
|
9238
9246
|
{
|
|
9239
9247
|
"flags": "--json",
|
|
9240
9248
|
"description": "JSON on stdout (always)"
|
|
@@ -10296,6 +10304,27 @@ export const COMMAND_CATALOG = [
|
|
|
10296
10304
|
],
|
|
10297
10305
|
"subcommands": []
|
|
10298
10306
|
},
|
|
10307
|
+
{
|
|
10308
|
+
"name": "_recover-queued-messages",
|
|
10309
|
+
"description": "",
|
|
10310
|
+
"aliases": [],
|
|
10311
|
+
"hidden": true,
|
|
10312
|
+
"usage": "[options] <lane-id>",
|
|
10313
|
+
"arguments": [
|
|
10314
|
+
{
|
|
10315
|
+
"name": "lane-id",
|
|
10316
|
+
"required": true,
|
|
10317
|
+
"variadic": false
|
|
10318
|
+
}
|
|
10319
|
+
],
|
|
10320
|
+
"options": [
|
|
10321
|
+
{
|
|
10322
|
+
"flags": "--json",
|
|
10323
|
+
"description": "JSON on stdout (always)"
|
|
10324
|
+
}
|
|
10325
|
+
],
|
|
10326
|
+
"subcommands": []
|
|
10327
|
+
},
|
|
10299
10328
|
{
|
|
10300
10329
|
"name": "_monitor-message",
|
|
10301
10330
|
"description": "",
|
|
@@ -12273,6 +12302,105 @@ export const COMMAND_CATALOG = [
|
|
|
12273
12302
|
"subcommands": []
|
|
12274
12303
|
}
|
|
12275
12304
|
]
|
|
12305
|
+
},
|
|
12306
|
+
{
|
|
12307
|
+
"name": "staff",
|
|
12308
|
+
"description": "Staff-only commands (super-admin required)",
|
|
12309
|
+
"aliases": [],
|
|
12310
|
+
"hidden": false,
|
|
12311
|
+
"usage": "[options] [command]",
|
|
12312
|
+
"arguments": [],
|
|
12313
|
+
"options": [],
|
|
12314
|
+
"subcommands": [
|
|
12315
|
+
{
|
|
12316
|
+
"name": "reset-test-account",
|
|
12317
|
+
"description": "Reset a designated real-email test account (dry-run by default). Wraps POST /v1/admin/test-account/reset — super-admin only.",
|
|
12318
|
+
"aliases": [],
|
|
12319
|
+
"hidden": false,
|
|
12320
|
+
"usage": "[options] <email>",
|
|
12321
|
+
"arguments": [
|
|
12322
|
+
{
|
|
12323
|
+
"name": "email",
|
|
12324
|
+
"required": true,
|
|
12325
|
+
"variadic": false
|
|
12326
|
+
}
|
|
12327
|
+
],
|
|
12328
|
+
"options": [
|
|
12329
|
+
{
|
|
12330
|
+
"flags": "--execute",
|
|
12331
|
+
"description": "Actually delete artifacts. Prompts for a typed-email confirmation."
|
|
12332
|
+
},
|
|
12333
|
+
{
|
|
12334
|
+
"flags": "-y, --yes",
|
|
12335
|
+
"description": "Skip the typed-email confirmation prompt (still sends confirmEmail)."
|
|
12336
|
+
}
|
|
12337
|
+
],
|
|
12338
|
+
"subcommands": []
|
|
12339
|
+
},
|
|
12340
|
+
{
|
|
12341
|
+
"name": "test-account",
|
|
12342
|
+
"description": "Manage the designated test-account registry (super-admin only). Wraps /v1/admin/test-account-registry.",
|
|
12343
|
+
"aliases": [],
|
|
12344
|
+
"hidden": false,
|
|
12345
|
+
"usage": "[options] [command]",
|
|
12346
|
+
"arguments": [],
|
|
12347
|
+
"options": [],
|
|
12348
|
+
"subcommands": [
|
|
12349
|
+
{
|
|
12350
|
+
"name": "add",
|
|
12351
|
+
"description": "Add an email to the registry so `hq staff reset-test-account` will sweep it.",
|
|
12352
|
+
"aliases": [],
|
|
12353
|
+
"hidden": false,
|
|
12354
|
+
"usage": "[options] <email>",
|
|
12355
|
+
"arguments": [
|
|
12356
|
+
{
|
|
12357
|
+
"name": "email",
|
|
12358
|
+
"required": true,
|
|
12359
|
+
"variadic": false
|
|
12360
|
+
}
|
|
12361
|
+
],
|
|
12362
|
+
"options": [
|
|
12363
|
+
{
|
|
12364
|
+
"flags": "--note <text>",
|
|
12365
|
+
"description": "Short reason recorded on the row"
|
|
12366
|
+
}
|
|
12367
|
+
],
|
|
12368
|
+
"subcommands": []
|
|
12369
|
+
},
|
|
12370
|
+
{
|
|
12371
|
+
"name": "remove",
|
|
12372
|
+
"description": "Soft-delete a registry entry (row stays with active: false).",
|
|
12373
|
+
"aliases": [],
|
|
12374
|
+
"hidden": false,
|
|
12375
|
+
"usage": "[options] <email>",
|
|
12376
|
+
"arguments": [
|
|
12377
|
+
{
|
|
12378
|
+
"name": "email",
|
|
12379
|
+
"required": true,
|
|
12380
|
+
"variadic": false
|
|
12381
|
+
}
|
|
12382
|
+
],
|
|
12383
|
+
"options": [],
|
|
12384
|
+
"subcommands": []
|
|
12385
|
+
},
|
|
12386
|
+
{
|
|
12387
|
+
"name": "list",
|
|
12388
|
+
"description": "List active registry entries.",
|
|
12389
|
+
"aliases": [],
|
|
12390
|
+
"hidden": false,
|
|
12391
|
+
"usage": "[options]",
|
|
12392
|
+
"arguments": [],
|
|
12393
|
+
"options": [
|
|
12394
|
+
{
|
|
12395
|
+
"flags": "--include-inactive",
|
|
12396
|
+
"description": "Also list soft-deleted rows (active: false)."
|
|
12397
|
+
}
|
|
12398
|
+
],
|
|
12399
|
+
"subcommands": []
|
|
12400
|
+
}
|
|
12401
|
+
]
|
|
12402
|
+
}
|
|
12403
|
+
]
|
|
12276
12404
|
}
|
|
12277
12405
|
];
|
|
12278
12406
|
//# sourceMappingURL=command-catalog.generated.js.map
|
|
@@ -432,6 +432,24 @@ export declare const REGISTRATION_PLAN: readonly [{
|
|
|
432
432
|
readonly parent: "program";
|
|
433
433
|
readonly module: "./commands/report.js";
|
|
434
434
|
readonly exportName: "registerReportCommand";
|
|
435
|
+
}, {
|
|
436
|
+
readonly type: "group";
|
|
437
|
+
readonly root: "staff";
|
|
438
|
+
readonly id: "staff";
|
|
439
|
+
readonly name: "staff";
|
|
440
|
+
readonly description: "Staff-only commands (super-admin required)";
|
|
441
|
+
}, {
|
|
442
|
+
readonly type: "registrar";
|
|
443
|
+
readonly root: "staff";
|
|
444
|
+
readonly parent: "staff";
|
|
445
|
+
readonly module: "./commands/staff/reset-test-account.js";
|
|
446
|
+
readonly exportName: "registerResetTestAccountCommand";
|
|
447
|
+
}, {
|
|
448
|
+
readonly type: "registrar";
|
|
449
|
+
readonly root: "staff";
|
|
450
|
+
readonly parent: "staff";
|
|
451
|
+
readonly module: "./commands/staff/test-account.js";
|
|
452
|
+
readonly exportName: "registerTestAccountCommand";
|
|
435
453
|
}];
|
|
436
454
|
export declare function registerAllCommands(program: Command): Promise<void>;
|
|
437
455
|
export declare function registerCommandRoot(program: Command, root: string): Promise<boolean>;
|
|
@@ -74,6 +74,12 @@ export const REGISTRATION_PLAN = [
|
|
|
74
74
|
{ type: "registrar", root: "daemon", parent: "program", module: "./commands/daemon.js", exportName: "registerDaemonCommand", hidden: true },
|
|
75
75
|
{ type: "registrar", root: "bot", parent: "program", module: "./commands/bot.js", exportName: "registerBotCommand" },
|
|
76
76
|
{ type: "registrar", root: "report", parent: "program", module: "./commands/report.js", exportName: "registerReportCommand" },
|
|
77
|
+
// onboarding-test-accounts US-007 — super-admin staff CLI wrappers over the
|
|
78
|
+
// hq-pro admin surface. New wrappers land under this group; the reset
|
|
79
|
+
// command mirrors POST /v1/admin/test-account/reset.
|
|
80
|
+
{ type: "group", root: "staff", id: "staff", name: "staff", description: "Staff-only commands (super-admin required)" },
|
|
81
|
+
{ type: "registrar", root: "staff", parent: "staff", module: "./commands/staff/reset-test-account.js", exportName: "registerResetTestAccountCommand" },
|
|
82
|
+
{ type: "registrar", root: "staff", parent: "staff", module: "./commands/staff/test-account.js", exportName: "registerTestAccountCommand" },
|
|
77
83
|
];
|
|
78
84
|
async function executePlan(program, steps) {
|
|
79
85
|
const parents = new Map([["program", program]]);
|
|
@@ -87,6 +87,8 @@ export interface EnrollDeps {
|
|
|
87
87
|
env?: NodeJS.ProcessEnv;
|
|
88
88
|
hostInfo?: HostInfo;
|
|
89
89
|
generateKeyPair?: typeof generateHostKeyPair;
|
|
90
|
+
/** Home directory the enroll target resolves under (defaults to os.homedir()). */
|
|
91
|
+
home?: string;
|
|
90
92
|
}
|
|
91
93
|
export interface EnrollOptions {
|
|
92
94
|
code: string;
|
|
@@ -59,6 +59,17 @@ export function detectExistingIdentity(paths, env = process.env) {
|
|
|
59
59
|
}
|
|
60
60
|
return { kind: "none" };
|
|
61
61
|
}
|
|
62
|
+
/** Machine identity already enrolled in a local agent directory, if any. */
|
|
63
|
+
function existingLocalIdentity(paths) {
|
|
64
|
+
if (!machineCredsFileExists(paths))
|
|
65
|
+
return { kind: "none" };
|
|
66
|
+
const existing = readExternalMachineCreds(paths);
|
|
67
|
+
return {
|
|
68
|
+
kind: "machine",
|
|
69
|
+
file: paths.machineCredsPath,
|
|
70
|
+
...(existing ? { agentUid: existing.entityUid } : {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
62
73
|
export function refusalMessage(existing) {
|
|
63
74
|
switch (existing.kind) {
|
|
64
75
|
case "none":
|
|
@@ -221,7 +232,7 @@ export async function enrollHost(opts, deps = {}) {
|
|
|
221
232
|
const env = deps.env ?? process.env;
|
|
222
233
|
const target = deps.paths
|
|
223
234
|
? { paths: deps.paths, local: false }
|
|
224
|
-
: resolveEnrollTarget({ name: opts.name, replace: opts.replace }, env);
|
|
235
|
+
: resolveEnrollTarget({ name: opts.name, replace: opts.replace }, env, deps.home);
|
|
225
236
|
const paths = target.paths;
|
|
226
237
|
const doFetch = deps.fetch ?? fetch;
|
|
227
238
|
const apiBaseUrl = (opts.apiBaseUrl ?? env.HQ_VAULT_API_URL ?? DEFAULT_VAULT_API_URL).replace(/\/+$/, "");
|
|
@@ -229,7 +240,11 @@ export async function enrollHost(opts, deps = {}) {
|
|
|
229
240
|
if (!isWellFormedEnrollmentCode(code)) {
|
|
230
241
|
throw new EnrollError(`Enrollment code must be 24 base32 characters (shown as XXXX-XXXX-XXXX-XXXX-XXXX-XXXX); got ${code.length}.`);
|
|
231
242
|
}
|
|
232
|
-
|
|
243
|
+
// A local target sits in its own ~/.hq-agent/<name>/ beside the person's
|
|
244
|
+
// login by design, so only an identity already in that directory blocks it.
|
|
245
|
+
const existing = target.local
|
|
246
|
+
? existingLocalIdentity(paths)
|
|
247
|
+
: detectExistingIdentity(paths, env);
|
|
233
248
|
const refusal = refusalMessage(existing);
|
|
234
249
|
if (refusal && !opts.replace)
|
|
235
250
|
throw new EnrollError(refusal);
|
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -61,6 +61,14 @@ export declare function scopeExcludedWarning(count: number): string | null;
|
|
|
61
61
|
* dropped files — helps debug ACL vs scope-excluded mismatches (feedback_7e9c535e).
|
|
62
62
|
*/
|
|
63
63
|
export declare function scopeExcludedPrefixDetail(prefixSet: readonly string[] | undefined): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Every warning line for a push that dropped files, shared by `push`, `now`
|
|
66
|
+
* and `push --all`. With a client prefix scope the files fell outside the
|
|
67
|
+
* caller's write prefixes; without one (prefixSet undefined) the server
|
|
68
|
+
* refused them path by path — typically another member's child in a private
|
|
69
|
+
* folder foo/ — and grant advice would point the reader the wrong way.
|
|
70
|
+
*/
|
|
71
|
+
export declare function scopeExcludedLines(count: number, prefixSet: readonly string[] | undefined): string[];
|
|
64
72
|
/**
|
|
65
73
|
* Bound foreground waits for a watcher/manual sync that currently owns the
|
|
66
74
|
* per-root operation lock. The cloud engine reads this environment value on
|
|
@@ -231,6 +239,8 @@ export interface PushAllOptions {
|
|
|
231
239
|
export interface PushAllRow {
|
|
232
240
|
slug: string;
|
|
233
241
|
result?: ShareCallResult;
|
|
242
|
+
/** Client write-prefix scope this push ran under; undefined = none applied. */
|
|
243
|
+
prefixSet?: readonly string[];
|
|
234
244
|
error?: string;
|
|
235
245
|
}
|
|
236
246
|
export interface PushAllResult {
|
package/dist/commands/cloud.js
CHANGED
|
@@ -16,8 +16,9 @@ import { isAccessDeniedError, accessDeniedKeyOf, formatAccessDenied, } from "../
|
|
|
16
16
|
import chalk from "chalk";
|
|
17
17
|
import * as fs from "fs";
|
|
18
18
|
import * as path from "path";
|
|
19
|
-
import { share, sync, getStateDir, listJournals,
|
|
19
|
+
import { share, sync, getStateDir, listJournals, VaultClient, computePersonalVaultPaths, PERSONAL_VAULT_JOURNAL_SLUG, resolvePullScope, syncDoctor, } from "@indigoai-us/hq-cloud";
|
|
20
20
|
import { DEFAULT_HQ_ROOT, ensureCognitoToken, buildVaultConfig, } from "../utils/cognito-session.js";
|
|
21
|
+
import { resolveUploadAuthor } from "../utils/upload-author.js";
|
|
21
22
|
import { companyFolderExceedsThreshold, emitNarrowHint, isStrictRefusal, resolveBannerLevel, resolveNarrowHintPresentationLevel, resolveNarrowHintMinBytes, } from "../lib/narrow-hint-banner.js";
|
|
22
23
|
import { beginSyncHealthReport, } from "../utils/client-health.js";
|
|
23
24
|
/**
|
|
@@ -115,11 +116,39 @@ export function scopeExcludedWarning(count) {
|
|
|
115
116
|
* dropped files — helps debug ACL vs scope-excluded mismatches (feedback_7e9c535e).
|
|
116
117
|
*/
|
|
117
118
|
export function scopeExcludedPrefixDetail(prefixSet) {
|
|
118
|
-
|
|
119
|
+
// No client-side prefix scope applied: the server refused the paths one by
|
|
120
|
+
// one, and scopeExcludedLines' primary line already says so.
|
|
121
|
+
if (prefixSet === undefined)
|
|
122
|
+
return null;
|
|
123
|
+
if (prefixSet.length === 0) {
|
|
119
124
|
return " Granted write prefixes: (none — shared-mode membership with no explicit grants)";
|
|
120
125
|
}
|
|
121
126
|
return ` Granted write prefixes: ${prefixSet.join(", ")}`;
|
|
122
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Every warning line for a push that dropped files, shared by `push`, `now`
|
|
130
|
+
* and `push --all`. With a client prefix scope the files fell outside the
|
|
131
|
+
* caller's write prefixes; without one (prefixSet undefined) the server
|
|
132
|
+
* refused them path by path — typically another member's child in a private
|
|
133
|
+
* folder foo/ — and grant advice would point the reader the wrong way.
|
|
134
|
+
*/
|
|
135
|
+
export function scopeExcludedLines(count, prefixSet) {
|
|
136
|
+
if (count <= 0)
|
|
137
|
+
return [];
|
|
138
|
+
if (prefixSet === undefined) {
|
|
139
|
+
return [
|
|
140
|
+
`⚠ ${count} file(s) were NOT uploaded — the server refused them. ` +
|
|
141
|
+
`A common cause is a file someone else created in a private folder ` +
|
|
142
|
+
`(foo/): only its creator can change it. They were skipped, not ` +
|
|
143
|
+
`synced. Re-run with --json to list them.`,
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
const lines = [scopeExcludedWarning(count)];
|
|
147
|
+
const detail = scopeExcludedPrefixDetail(prefixSet);
|
|
148
|
+
if (detail)
|
|
149
|
+
lines.push(detail);
|
|
150
|
+
return lines;
|
|
151
|
+
}
|
|
123
152
|
/**
|
|
124
153
|
* Resolve the `propagateDeletePolicy` for share() calls.
|
|
125
154
|
*
|
|
@@ -445,7 +474,13 @@ export async function pushAll(options, deps) {
|
|
|
445
474
|
result.bytesUploaded += r.bytesUploaded;
|
|
446
475
|
result.filesDeleted += r.filesDeleted;
|
|
447
476
|
result.filesExcludedByScope += r.filesExcludedByScope;
|
|
448
|
-
result.perCompany.push({
|
|
477
|
+
result.perCompany.push({
|
|
478
|
+
slug: entry.slug,
|
|
479
|
+
result: r,
|
|
480
|
+
...(entry.shareOptions.prefixSet !== undefined
|
|
481
|
+
? { prefixSet: entry.shareOptions.prefixSet }
|
|
482
|
+
: {}),
|
|
483
|
+
});
|
|
449
484
|
}
|
|
450
485
|
catch (err) {
|
|
451
486
|
const message = formatSyncFailure(err);
|
|
@@ -803,7 +838,7 @@ export function registerCloudCommands(program) {
|
|
|
803
838
|
// every row renders `—`. Resolved best-effort from the cached
|
|
804
839
|
// idToken — pre-vended `--creds-from-stdin` paths still get author
|
|
805
840
|
// attribution as long as the caller is logged in locally.
|
|
806
|
-
const author =
|
|
841
|
+
const author = resolveUploadAuthor();
|
|
807
842
|
let pushPrefixSet;
|
|
808
843
|
if (!personalMode && scopeVaultConfig) {
|
|
809
844
|
const scopeClient = new VaultClient(scopeVaultConfig);
|
|
@@ -850,10 +885,9 @@ export function registerCloudCommands(program) {
|
|
|
850
885
|
if (result.filesExcludedByScope > 0) {
|
|
851
886
|
log(chalk.yellow(`\n⚠ Pushed ${result.filesUploaded} file(s) (${formatBytes(result.bytesUploaded)}, ` +
|
|
852
887
|
`${result.filesSkipped} skipped, ${result.filesExcludedByScope} scope-excluded)`));
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
log(chalk.yellow(prefixDetail));
|
|
888
|
+
for (const line of scopeExcludedLines(result.filesExcludedByScope, pushPrefixSet)) {
|
|
889
|
+
log(chalk.yellow(line));
|
|
890
|
+
}
|
|
857
891
|
}
|
|
858
892
|
else {
|
|
859
893
|
log(chalk.green(`\n✓ Pushed ${result.filesUploaded} file(s) (${formatBytes(result.bytesUploaded)}, ${result.filesSkipped} skipped)`));
|
|
@@ -1342,7 +1376,7 @@ async function runPushAll(hqRoot, message, onConflict, skipPersonal) {
|
|
|
1342
1376
|
const accessToken = await ensureCognitoToken();
|
|
1343
1377
|
const vaultConfig = buildVaultConfig(accessToken);
|
|
1344
1378
|
const realClient = new VaultClient(vaultConfig);
|
|
1345
|
-
const author =
|
|
1379
|
+
const author = resolveUploadAuthor();
|
|
1346
1380
|
const adapter = {
|
|
1347
1381
|
listMyMemberships: () => realClient.listMyMemberships(),
|
|
1348
1382
|
listPersonEntities: () => realClient.entity.listByType("person"),
|
|
@@ -1420,8 +1454,11 @@ async function runPushAll(hqRoot, message, onConflict, skipPersonal) {
|
|
|
1420
1454
|
console.log(errored > 0 || result.filesExcludedByScope > 0
|
|
1421
1455
|
? chalk.yellow(summary)
|
|
1422
1456
|
: chalk.green(summary));
|
|
1423
|
-
|
|
1424
|
-
|
|
1457
|
+
for (const row of result.perCompany) {
|
|
1458
|
+
const excluded = row.result?.filesExcludedByScope ?? 0;
|
|
1459
|
+
for (const line of scopeExcludedLines(excluded, row.prefixSet)) {
|
|
1460
|
+
console.log(chalk.yellow(`${row.slug}: ${line}`));
|
|
1461
|
+
}
|
|
1425
1462
|
}
|
|
1426
1463
|
if (errored > 0)
|
|
1427
1464
|
throw new SyncExitError(1);
|
|
@@ -1434,7 +1471,7 @@ async function runNowSingle(hqRoot, company, personal, message, onConflict, mode
|
|
|
1434
1471
|
try {
|
|
1435
1472
|
const accessToken = await ensureCognitoToken();
|
|
1436
1473
|
const vaultConfig = buildVaultConfig(accessToken);
|
|
1437
|
-
const author =
|
|
1474
|
+
const author = resolveUploadAuthor();
|
|
1438
1475
|
// Resolve the target. For --personal, look up the canonical person and
|
|
1439
1476
|
// route paths/journal through personalMode. Otherwise use the company arg
|
|
1440
1477
|
// (or fall back to the active company inside share()/sync()).
|
|
@@ -1499,10 +1536,9 @@ async function runNowSingle(hqRoot, company, personal, message, onConflict, mode
|
|
|
1499
1536
|
`${pushResult.filesDeleted} deleted, ${pushResult.filesExcludedByScope} scope-excluded` +
|
|
1500
1537
|
(pushResult.aborted ? " — aborted" : ""));
|
|
1501
1538
|
if (pushResult.filesExcludedByScope > 0) {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
console.log(chalk.yellow(prefixDetail));
|
|
1539
|
+
for (const line of scopeExcludedLines(pushResult.filesExcludedByScope, nowPushPrefixSet)) {
|
|
1540
|
+
console.log(chalk.yellow(line));
|
|
1541
|
+
}
|
|
1506
1542
|
}
|
|
1507
1543
|
if (pushResult.aborted) {
|
|
1508
1544
|
console.log(chalk.yellow("\n⚠ Sync now aborted on push leg; pull skipped."));
|
|
@@ -1689,35 +1725,4 @@ async function readAllStdin() {
|
|
|
1689
1725
|
}
|
|
1690
1726
|
return Buffer.concat(chunks).toString("utf8");
|
|
1691
1727
|
}
|
|
1692
|
-
/**
|
|
1693
|
-
* Resolve the syncing user's `UploadAuthor` (sub + email) from the cached
|
|
1694
|
-
* Cognito idToken. Returns `undefined` when no tokens are cached or the
|
|
1695
|
-
* token is missing the required claims — share() then skips the metadata
|
|
1696
|
-
* stamp gracefully (not an error).
|
|
1697
|
-
*
|
|
1698
|
-
* We deliberately decode the JWT here instead of verifying it: Cognito
|
|
1699
|
-
* already verified at issuance, and we only use the public claims to
|
|
1700
|
-
* label the upload's S3 user metadata (no auth decision rides on it).
|
|
1701
|
-
*/
|
|
1702
|
-
function resolveUploadAuthorFromCache() {
|
|
1703
|
-
const tokens = loadCachedTokens();
|
|
1704
|
-
if (!tokens?.idToken)
|
|
1705
|
-
return undefined;
|
|
1706
|
-
const parts = tokens.idToken.split(".");
|
|
1707
|
-
if (parts.length !== 3)
|
|
1708
|
-
return undefined;
|
|
1709
|
-
try {
|
|
1710
|
-
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
1711
|
-
const padded = payload + "=".repeat((4 - (payload.length % 4)) % 4);
|
|
1712
|
-
const json = Buffer.from(padded, "base64").toString("utf-8");
|
|
1713
|
-
const claims = JSON.parse(json);
|
|
1714
|
-
if (claims.sub && claims.email) {
|
|
1715
|
-
return { userSub: claims.sub, email: claims.email };
|
|
1716
|
-
}
|
|
1717
|
-
return undefined;
|
|
1718
|
-
}
|
|
1719
|
-
catch {
|
|
1720
|
-
return undefined;
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
1728
|
//# sourceMappingURL=cloud.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import { type TrackerKind, type TrackerRecord } from "../lib/lanes/tracker-store.js";
|
|
3
|
+
import type { TrackerStore } from "../lib/lanes/tracker-store.js";
|
|
3
4
|
import type { LaneCompanyRef, QuestionRecord } from "../lib/lanes/types.js";
|
|
4
5
|
export interface LaneChecksDeps {
|
|
5
6
|
hqRoot: () => string;
|
|
@@ -7,6 +8,7 @@ export interface LaneChecksDeps {
|
|
|
7
8
|
trackerEnabled: (company: LaneCompanyRef) => boolean | Promise<boolean>;
|
|
8
9
|
trackerMeshEnabled: (company: LaneCompanyRef) => boolean | Promise<boolean>;
|
|
9
10
|
now: () => Date;
|
|
11
|
+
meshStore?: (company: LaneCompanyRef, projectId: string) => TrackerStore;
|
|
10
12
|
}
|
|
11
13
|
type WrapHandler = <Args extends unknown[]>(action: (...args: Args) => Promise<void>) => (...args: Args) => Promise<void>;
|
|
12
14
|
export interface ProjectMapping {
|