@indigoai-us/hq-cli 5.345.155 → 5.345.159
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 +289 -0
- package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +110 -2
- package/assets/scaffold/core/scripts/rebuild-projects-index.sh +101 -5
- package/assets/scaffold/core/scripts/worktree.sh +4 -0
- package/dist/command-catalog.generated.d.ts +536 -7
- package/dist/command-catalog.generated.js +676 -24
- package/dist/command-registration-plan.d.ts +18 -0
- package/dist/command-registration-plan.js +4 -0
- package/dist/commands/_patterns.d.ts +17 -0
- package/dist/commands/_patterns.js +22 -0
- package/dist/commands/agent-inbox.js +2 -2
- package/dist/commands/agent-kit.js +8 -6
- package/dist/commands/bot.js +7 -4
- package/dist/commands/channel-suggest.d.ts +56 -0
- package/dist/commands/channel-suggest.js +170 -0
- package/dist/commands/channels.js +7 -1
- package/dist/commands/cloud.d.ts +45 -0
- package/dist/commands/cloud.js +150 -10
- package/dist/commands/company.js +4 -3
- package/dist/commands/core-checkpoint-native.d.ts +18 -0
- package/dist/commands/core-checkpoint-native.js +67 -2
- package/dist/commands/core-pipeline-driver-native.d.ts +12 -1
- package/dist/commands/core-pipeline-driver-native.js +131 -5
- package/dist/commands/core.js +13 -1
- package/dist/commands/crm.js +83 -6
- package/dist/commands/deploy-access.d.ts +33 -0
- package/dist/commands/deploy-access.js +322 -0
- package/dist/commands/dm-attach.d.ts +106 -0
- package/dist/commands/dm-attach.js +184 -0
- package/dist/commands/dm.d.ts +37 -0
- package/dist/commands/dm.js +172 -10
- package/dist/commands/feedback-show.d.ts +40 -0
- package/dist/commands/feedback-show.js +261 -0
- package/dist/commands/feedback.d.ts +21 -0
- package/dist/commands/feedback.js +152 -2
- package/dist/commands/files-browse.d.ts +16 -0
- package/dist/commands/files-browse.js +52 -1
- package/dist/commands/files.d.ts +24 -0
- package/dist/commands/files.js +52 -1
- package/dist/commands/integrations-connect.js +7 -3
- package/dist/commands/integrations-core.d.ts +13 -1
- package/dist/commands/integrations-core.js +49 -4
- package/dist/commands/integrations.js +4 -2
- package/dist/commands/lanes-accounts.js +16 -1
- package/dist/commands/lanes-loop.js +14 -4
- package/dist/commands/lanes-message.js +6 -4
- package/dist/commands/lanes-resume.js +36 -13
- package/dist/commands/lanes-shared.d.ts +5 -0
- package/dist/commands/lanes-shared.js +13 -3
- package/dist/commands/lanes-watch.js +1 -0
- package/dist/commands/lanes.d.ts +20 -1
- package/dist/commands/lanes.js +201 -51
- package/dist/commands/mesh.js +149 -1
- package/dist/commands/monitor.d.ts +1 -0
- package/dist/commands/monitor.js +4 -1
- package/dist/commands/repo.d.ts +41 -0
- package/dist/commands/repo.js +331 -0
- package/dist/commands/scan.d.ts +3 -1
- package/dist/commands/scan.js +7 -3
- package/dist/commands/secrets.d.ts +37 -0
- package/dist/commands/secrets.js +185 -16
- package/dist/commands/signals.js +17 -5
- package/dist/commands/staff/listings.d.ts +41 -0
- package/dist/commands/staff/listings.js +160 -0
- package/dist/commands/staff/reset-test-account.d.ts +3 -2
- package/dist/commands/staff/reset-test-account.js +4 -3
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +2629 -1036
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-state.d.ts +7 -0
- package/dist/lib/agent-kit/inbox-state.js +5 -1
- package/dist/lib/agent-kit/mcp/tools.js +2 -1
- package/dist/lib/agent-kit/run/inbox.js +2 -1
- package/dist/lib/agent-kit/wake-secrets.d.ts +7 -0
- package/dist/lib/agent-kit/wake-secrets.js +32 -0
- package/dist/lib/agent-kit/wake.d.ts +4 -0
- package/dist/lib/agent-kit/wake.js +49 -3
- package/dist/lib/bot/inflight.d.ts +7 -1
- package/dist/lib/bot/inflight.js +10 -2
- package/dist/lib/bot/prompt.js +3 -0
- package/dist/lib/bot/run.js +72 -20
- package/dist/lib/bot/session.d.ts +14 -0
- package/dist/lib/bot/session.js +70 -0
- package/dist/lib/capacity/collectors/claude-oauth.d.ts +6 -0
- package/dist/lib/capacity/collectors/claude-oauth.js +12 -0
- package/dist/lib/capacity/lane-login.d.ts +6 -0
- package/dist/lib/capacity/lane-login.js +5 -0
- package/dist/lib/core-utils/worktree.js +2 -0
- package/dist/lib/daemon/exit-cause.d.ts +43 -0
- package/dist/lib/daemon/exit-cause.js +88 -0
- package/dist/lib/daemon/handoff.d.ts +2 -0
- package/dist/lib/daemon/handoff.js +6 -1
- package/dist/lib/daemon/hq-child-bootstrap.mjs +20 -3
- package/dist/lib/daemon/paths.d.ts +2 -0
- package/dist/lib/daemon/paths.js +1 -0
- package/dist/lib/daemon/run.js +13 -0
- package/dist/lib/daemon/supervisor.d.ts +54 -1
- package/dist/lib/daemon/supervisor.js +297 -21
- package/dist/lib/daemon/unit-holds.d.ts +22 -0
- package/dist/lib/daemon/unit-holds.js +86 -0
- package/dist/lib/doctor/checks/sync-health.d.ts +9 -0
- package/dist/lib/doctor/checks/sync-health.js +66 -1
- package/dist/lib/doctor/company-resolution-state.d.ts +30 -0
- package/dist/lib/doctor/company-resolution-state.js +89 -0
- package/dist/lib/doctor/fix/apply.d.ts +36 -6
- package/dist/lib/doctor/fix/apply.js +128 -12
- package/dist/lib/doctor/types.d.ts +1 -1
- package/dist/lib/doctor/types.js +1 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/hook-engine/resolve.js +6 -2
- package/dist/lib/index-render/company-knowledge.d.ts +1 -1
- package/dist/lib/index-render/company-knowledge.js +4 -5
- package/dist/lib/index-render/index.js +44 -3
- package/dist/lib/index-render/projects.d.ts +1 -1
- package/dist/lib/index-render/projects.js +5 -5
- package/dist/lib/lanes/account-company.d.ts +28 -0
- package/dist/lib/lanes/account-company.js +53 -0
- package/dist/lib/lanes/accounts.d.ts +22 -3
- package/dist/lib/lanes/accounts.js +38 -2
- package/dist/lib/lanes/claude-balance.d.ts +6 -1
- package/dist/lib/lanes/claude-balance.js +6 -1
- package/dist/lib/lanes/claude-credential.d.ts +78 -0
- package/dist/lib/lanes/claude-credential.js +163 -0
- package/dist/lib/lanes/compaction.d.ts +2 -0
- package/dist/lib/lanes/compaction.js +9 -0
- package/dist/lib/lanes/config.js +6 -0
- package/dist/lib/lanes/envelope-repair-dispatch.js +2 -1
- package/dist/lib/lanes/hooks-install.js +2 -1
- package/dist/lib/lanes/host-capacity.d.ts +2 -0
- package/dist/lib/lanes/host-capacity.js +1 -0
- package/dist/lib/lanes/keep-alive.d.ts +1 -1
- package/dist/lib/lanes/keep-alive.js +3 -1
- package/dist/lib/lanes/links.js +10 -4
- package/dist/lib/lanes/loop.js +16 -1
- package/dist/lib/lanes/node-binary.d.ts +17 -0
- package/dist/lib/lanes/node-binary.js +30 -0
- package/dist/lib/lanes/outpost-dispatch.d.ts +2 -1
- package/dist/lib/lanes/outpost-dispatch.js +1 -0
- package/dist/lib/lanes/reconcile.js +4 -0
- package/dist/lib/lanes/remote-control-lane.js +2 -0
- package/dist/lib/lanes/spawn.d.ts +3 -0
- package/dist/lib/lanes/spawn.js +119 -9
- package/dist/lib/lanes/store.d.ts +6 -0
- package/dist/lib/lanes/store.js +107 -18
- package/dist/lib/lanes/types.d.ts +2 -0
- package/dist/lib/lanes/watch.js +28 -5
- package/dist/lib/lanes/watcher-main.js +4 -3
- package/dist/lib/lanes/watcher.d.ts +4 -0
- package/dist/lib/lanes/watcher.js +110 -21
- package/dist/lib/mesh/api.d.ts +32 -0
- package/dist/lib/mesh/api.js +75 -0
- package/dist/lib/secret-scan/detect.js +9 -0
- package/dist/lib/secret-scan/repo-config.d.ts +41 -0
- package/dist/lib/secret-scan/repo-config.js +237 -0
- package/dist/lib/secret-scan/rules.d.ts +7 -1
- package/dist/lib/secret-scan/rules.js +3 -1
- package/dist/lib/secret-scan/staged.d.ts +5 -0
- package/dist/lib/secret-scan/staged.js +19 -2
- package/dist/lib/secret-scan/types.d.ts +2 -0
- package/dist/lib/sync/server-owned-local-only.d.ts +29 -0
- package/dist/lib/sync/server-owned-local-only.js +75 -0
- package/dist/sentry-before-send.js +1 -0
- package/dist/utils/access-denied-hint.js +6 -0
- package/dist/utils/client-health.d.ts +34 -0
- package/dist/utils/client-health.js +96 -3
- package/dist/utils/package-use-lease.js +27 -9
- package/dist/utils/version-gate.d.ts +7 -0
- package/dist/utils/version-gate.js +66 -0
- package/package.json +8 -8
|
@@ -400,6 +400,12 @@ export declare const REGISTRATION_PLAN: readonly [{
|
|
|
400
400
|
readonly parent: "program";
|
|
401
401
|
readonly module: "./commands/mcp-status.js";
|
|
402
402
|
readonly exportName: "registerMcpCommand";
|
|
403
|
+
}, {
|
|
404
|
+
readonly type: "registrar";
|
|
405
|
+
readonly root: "repo";
|
|
406
|
+
readonly parent: "program";
|
|
407
|
+
readonly module: "./commands/repo.js";
|
|
408
|
+
readonly exportName: "registerRepoCommand";
|
|
403
409
|
}, {
|
|
404
410
|
readonly type: "registrar";
|
|
405
411
|
readonly root: "crm";
|
|
@@ -533,6 +539,12 @@ export declare const REGISTRATION_PLAN: readonly [{
|
|
|
533
539
|
readonly parent: "deploy";
|
|
534
540
|
readonly module: "./commands/deploy-list.js";
|
|
535
541
|
readonly exportName: "registerDeployListCommand";
|
|
542
|
+
}, {
|
|
543
|
+
readonly type: "registrar";
|
|
544
|
+
readonly root: "deploy";
|
|
545
|
+
readonly parent: "deploy";
|
|
546
|
+
readonly module: "./commands/deploy-access.js";
|
|
547
|
+
readonly exportName: "registerDeployAccessCommand";
|
|
536
548
|
}, {
|
|
537
549
|
readonly type: "group";
|
|
538
550
|
readonly root: "staff";
|
|
@@ -551,6 +563,12 @@ export declare const REGISTRATION_PLAN: readonly [{
|
|
|
551
563
|
readonly parent: "staff";
|
|
552
564
|
readonly module: "./commands/staff/test-account.js";
|
|
553
565
|
readonly exportName: "registerTestAccountCommand";
|
|
566
|
+
}, {
|
|
567
|
+
readonly type: "registrar";
|
|
568
|
+
readonly root: "staff";
|
|
569
|
+
readonly parent: "staff";
|
|
570
|
+
readonly module: "./commands/staff/listings.js";
|
|
571
|
+
readonly exportName: "registerListingsCommand";
|
|
554
572
|
}];
|
|
555
573
|
export declare function registerAllCommands(program: Command): Promise<void>;
|
|
556
574
|
export declare function registerCommandRoot(program: Command, root: string): Promise<boolean>;
|
|
@@ -69,6 +69,7 @@ export const REGISTRATION_PLAN = [
|
|
|
69
69
|
{ type: "registrar", root: "reindex", parent: "program", module: "./commands/reindex.js", exportName: "registerReindexCommand" },
|
|
70
70
|
{ type: "registrar", root: "rescue", parent: "program", module: "./commands/rescue.js", exportName: "registerRescueCommand" },
|
|
71
71
|
{ type: "registrar", root: "mcp", parent: "program", module: "./commands/mcp-status.js", exportName: "registerMcpCommand" },
|
|
72
|
+
{ type: "registrar", root: "repo", parent: "program", module: "./commands/repo.js", exportName: "registerRepoCommand" },
|
|
72
73
|
{ type: "registrar", root: "crm", parent: "program", module: "./commands/crm.js", exportName: "registerCrmCommand" },
|
|
73
74
|
{ type: "registrar", root: "company", parent: "program", module: "./commands/company.js", exportName: "registerCompanyCommand" },
|
|
74
75
|
{ type: "registrar", root: "agents", parent: "program", module: "./commands/agents.js", exportName: "registerAgentsCommand" },
|
|
@@ -91,12 +92,15 @@ export const REGISTRATION_PLAN = [
|
|
|
91
92
|
{ type: "group", root: "deploy", id: "deploy", name: "deploy", description: "Manage deployments in hq-deploy" },
|
|
92
93
|
{ type: "registrar", root: "deploy", parent: "deploy", module: "./commands/deploy-comments.js", exportName: "registerDeployCommentsCommand" },
|
|
93
94
|
{ type: "registrar", root: "deploy", parent: "deploy", module: "./commands/deploy-list.js", exportName: "registerDeployListCommand" },
|
|
95
|
+
{ type: "registrar", root: "deploy", parent: "deploy", module: "./commands/deploy-access.js", exportName: "registerDeployAccessCommand" },
|
|
94
96
|
// onboarding-test-accounts US-007 — super-admin staff CLI wrappers over the
|
|
95
97
|
// hq-pro admin surface. New wrappers land under this group; the reset
|
|
96
98
|
// command mirrors POST /v1/admin/test-account/reset.
|
|
97
99
|
{ type: "group", root: "staff", id: "staff", name: "staff", description: "Staff-only commands (super-admin required)" },
|
|
98
100
|
{ type: "registrar", root: "staff", parent: "staff", module: "./commands/staff/reset-test-account.js", exportName: "registerResetTestAccountCommand" },
|
|
99
101
|
{ type: "registrar", root: "staff", parent: "staff", module: "./commands/staff/test-account.js", exportName: "registerTestAccountCommand" },
|
|
102
|
+
// Marketplace moderation: queue / approve / reject over /v1/moderation.
|
|
103
|
+
{ type: "registrar", root: "staff", parent: "staff", module: "./commands/staff/listings.js", exportName: "registerListingsCommand" },
|
|
100
104
|
];
|
|
101
105
|
async function executePlan(program, steps) {
|
|
102
106
|
const parents = new Map([["program", program]]);
|
|
@@ -7,6 +7,23 @@ export declare const EMAIL_PATTERN: RegExp;
|
|
|
7
7
|
* grantee slot on the wire.
|
|
8
8
|
*/
|
|
9
9
|
export declare const OUTPOST_UID_PATTERN: RegExp;
|
|
10
|
+
/**
|
|
11
|
+
* A fleet agent uid: `agt_` plus a 26-character Crockford ULID, upper-case,
|
|
12
|
+
* the same shape as OUTPOST_UID_PATTERN. A typo (wrong length, lower-case,
|
|
13
|
+
* or a letter outside the Crockford alphabet: I, L, O, U) fails locally.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AGENT_UID_PATTERN: RegExp;
|
|
16
|
+
/**
|
|
17
|
+
* The machine email a fleet agent signs in with:
|
|
18
|
+
* `agt-<ulid>@agents.getindigo.ai`, lower-cased. The CLI sends this email as
|
|
19
|
+
* the grantee; hq-pro canonicalizes it onto the agent's `agt_…` principal
|
|
20
|
+
* when the agent is an active member of the company.
|
|
21
|
+
*/
|
|
22
|
+
export declare function agentMachineEmail(agentUid: string): string;
|
|
23
|
+
/** Matches a fleet agent machine email; group 1 is the lower-case ULID. */
|
|
24
|
+
export declare const AGENT_MACHINE_EMAIL_PATTERN: RegExp;
|
|
25
|
+
/** The `agt_…` uid behind a machine email, or null when it is not one. */
|
|
26
|
+
export declare function agentUidFromMachineEmail(email: string): string | null;
|
|
10
27
|
/**
|
|
11
28
|
* Keep an ACL pattern exactly as the caller supplied it.
|
|
12
29
|
*
|
|
@@ -7,6 +7,28 @@ export const EMAIL_PATTERN = /^[^\s]+@[^\s]+$/;
|
|
|
7
7
|
* grantee slot on the wire.
|
|
8
8
|
*/
|
|
9
9
|
export const OUTPOST_UID_PATTERN = /^out_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
10
|
+
/**
|
|
11
|
+
* A fleet agent uid: `agt_` plus a 26-character Crockford ULID, upper-case,
|
|
12
|
+
* the same shape as OUTPOST_UID_PATTERN. A typo (wrong length, lower-case,
|
|
13
|
+
* or a letter outside the Crockford alphabet: I, L, O, U) fails locally.
|
|
14
|
+
*/
|
|
15
|
+
export const AGENT_UID_PATTERN = /^agt_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
16
|
+
/**
|
|
17
|
+
* The machine email a fleet agent signs in with:
|
|
18
|
+
* `agt-<ulid>@agents.getindigo.ai`, lower-cased. The CLI sends this email as
|
|
19
|
+
* the grantee; hq-pro canonicalizes it onto the agent's `agt_…` principal
|
|
20
|
+
* when the agent is an active member of the company.
|
|
21
|
+
*/
|
|
22
|
+
export function agentMachineEmail(agentUid) {
|
|
23
|
+
return `agt-${agentUid.slice(4).toLowerCase()}@agents.getindigo.ai`;
|
|
24
|
+
}
|
|
25
|
+
/** Matches a fleet agent machine email; group 1 is the lower-case ULID. */
|
|
26
|
+
export const AGENT_MACHINE_EMAIL_PATTERN = /^agt-([0-9a-hjkmnp-tv-z]{26})@agents\.getindigo\.ai$/i;
|
|
27
|
+
/** The `agt_…` uid behind a machine email, or null when it is not one. */
|
|
28
|
+
export function agentUidFromMachineEmail(email) {
|
|
29
|
+
const m = AGENT_MACHINE_EMAIL_PATTERN.exec(email.trim());
|
|
30
|
+
return m ? `agt_${m[1].toUpperCase()}` : null;
|
|
31
|
+
}
|
|
10
32
|
/**
|
|
11
33
|
* Keep an ACL pattern exactly as the caller supplied it.
|
|
12
34
|
*
|
|
@@ -26,7 +26,7 @@ export function registerAgentInboxCommand(agent) {
|
|
|
26
26
|
// Merged with the server, never the local mirror alone: a dead kit
|
|
27
27
|
// poller would otherwise make this command answer confidently with
|
|
28
28
|
// yesterday's mail and no sign anything was wrong.
|
|
29
|
-
const { entries, note } = await mergeAgentInbox(paths, async () => {
|
|
29
|
+
const { entries, note, source } = await mergeAgentInbox(paths, async () => {
|
|
30
30
|
const token = await ensureCognitoToken({ tokenSource: "machine", interactive: false });
|
|
31
31
|
const res = await vaultApiFetch({
|
|
32
32
|
token,
|
|
@@ -39,7 +39,7 @@ export function registerAgentInboxCommand(agent) {
|
|
|
39
39
|
.filter((e) => opts.all || !done.has(e.id))
|
|
40
40
|
.map((e) => summarizeInboxEntry(redactAgentInboxItem(e), done.has(e.id)));
|
|
41
41
|
if (opts.json) {
|
|
42
|
-
console.log(JSON.stringify({ count: rows.length, messages: rows, ...(note ? { note } : {}) }, null, 2));
|
|
42
|
+
console.log(JSON.stringify({ count: rows.length, source, messages: rows, ...(note ? { note } : {}) }, null, 2));
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
if (note)
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* output in ~/.hq-agent/logs/kit.log). Logs: ~/.hq-agent/logs/<service>.log. Skills:
|
|
18
18
|
* ~/.hq-agent/skills/<name>/SKILL.md.
|
|
19
19
|
*/
|
|
20
|
+
import { createWakeSecretResolver } from "../lib/agent-kit/wake-secrets.js";
|
|
20
21
|
import chalk from "chalk";
|
|
21
22
|
import * as fs from "node:fs";
|
|
22
23
|
import * as os from "node:os";
|
|
@@ -37,7 +38,7 @@ import { serviceLogPath } from "../lib/agent-kit/paths.js";
|
|
|
37
38
|
import { runResidentCommandWithPackageLease } from "../utils/resident-package-preload.js";
|
|
38
39
|
import { spawn } from "node:child_process";
|
|
39
40
|
import { pendingInbox } from "../lib/agent-kit/inbox-state.js";
|
|
40
|
-
import { buildWakeNotice, clearWakeConfig, currentWakeState, DEFAULT_WAKE_RETRY_MS, describeWake, fireWake, readWakeConfig, validateWakeUrl, writeWakeConfig, } from "../lib/agent-kit/wake.js";
|
|
41
|
+
import { parseHeaderSecrets, buildWakeNotice, clearWakeConfig, currentWakeState, DEFAULT_WAKE_RETRY_MS, describeWake, fireWake, readWakeConfig, validateWakeUrl, writeWakeConfig, } from "../lib/agent-kit/wake.js";
|
|
41
42
|
import { runSyncLoop } from "../lib/agent-kit/run/sync.js";
|
|
42
43
|
import { resolveHqBinary, resolveNodeBinary, } from "../lib/mesh/live/daemon/install.js";
|
|
43
44
|
import { installServices, servicesStatus, uninstallServices, } from "../lib/service-manager/index.js";
|
|
@@ -380,6 +381,7 @@ export function registerAgentKitCommand(agent) {
|
|
|
380
381
|
.description("POST a notice to a webhook URL (e.g. a Grok Bot routine webhook) when mail is pending. Prefer --stdin so the URL stays out of shell history")
|
|
381
382
|
.option("--stdin", "Read the URL from stdin")
|
|
382
383
|
.option("--retry-minutes <n>", "Re-wake while items stay pending (default 10, minimum 1)")
|
|
384
|
+
.option("--header-secret <Header=SECRET>", "Send a header using a stored company secret (repeatable; value resolved at wake time)", (value, previous) => [...previous, value], [])
|
|
383
385
|
.action(async (url, opts) => {
|
|
384
386
|
try {
|
|
385
387
|
const paths = agentKitPaths(os.homedir(), process.env);
|
|
@@ -393,7 +395,8 @@ export function registerAgentKitCommand(agent) {
|
|
|
393
395
|
}
|
|
394
396
|
if (!raw)
|
|
395
397
|
throw new Error("Provide the URL as an argument or with --stdin");
|
|
396
|
-
const
|
|
398
|
+
const headerSecrets = parseHeaderSecrets(opts.headerSecret);
|
|
399
|
+
const config = { kind: "url", url: validateWakeUrl(raw), retryMs: retryMsFrom(opts.retryMinutes), ...(Object.keys(headerSecrets).length ? { headerSecrets } : {}) };
|
|
397
400
|
writeWakeConfig(paths, config);
|
|
398
401
|
console.log(chalk.green(`Wake set: ${describeWake(config)}`));
|
|
399
402
|
console.log("Test it: hq agent kit wake test");
|
|
@@ -450,15 +453,14 @@ export function registerAgentKitCommand(agent) {
|
|
|
450
453
|
.description("Fire the wake once now with the current pending count")
|
|
451
454
|
.action(async () => {
|
|
452
455
|
try {
|
|
453
|
-
const
|
|
454
|
-
const creds =
|
|
455
|
-
ensureKitDirs(paths);
|
|
456
|
+
const runtime = buildKitRuntime("inbox");
|
|
457
|
+
const { paths, creds } = runtime;
|
|
456
458
|
const config = readWakeConfig(paths);
|
|
457
459
|
if (!config)
|
|
458
460
|
throw new Error("No wake configured. Run hq agent kit wake set-url --stdin (or set-command).");
|
|
459
461
|
const log = createKitLogger(paths, "wake", { echo: false });
|
|
460
462
|
const ids = pendingInbox(paths).map((e) => e.id);
|
|
461
|
-
const result = await fireWake(config, buildWakeNotice(creds.entityUid, "test", ids, new Date()), { paths, agentUid: creds.entityUid, log });
|
|
463
|
+
const result = await fireWake(config, buildWakeNotice(creds.entityUid, "test", ids, new Date()), { paths, agentUid: creds.entityUid, log, resolveHeaderSecrets: createWakeSecretResolver(creds.companySlug, runtime.getToken, creds.apiBaseUrl) });
|
|
462
464
|
console.log(result.ok ? chalk.green(result.detail) : chalk.red(result.detail));
|
|
463
465
|
if (!result.ok)
|
|
464
466
|
process.exit(1);
|
package/dist/commands/bot.js
CHANGED
|
@@ -44,7 +44,7 @@ import { DEFAULT_COGNITO, ensureCognitoToken, resolveDefaultHqRoot, } from "../u
|
|
|
44
44
|
import { peekHqApiKey } from "../utils/resolve-vault-credential.js";
|
|
45
45
|
import { getCompanyUid, resolveCallerPersonUid } from "../utils/vault-api.js";
|
|
46
46
|
import { resolveHqBinary } from "../lib/mesh/live/daemon/install.js";
|
|
47
|
-
import { askDaemonToStart, askDaemonToStop, daemonOwnsProcess, daemonSupervises, daemonWillSupervise, handOffInstallHere, } from "../lib/daemon/handoff.js";
|
|
47
|
+
import { askDaemonToStart, askDaemonToStop, daemonOwnsProcess, daemonHoldReason, daemonSupervises, daemonWillSupervise, handOffInstallHere, } from "../lib/daemon/handoff.js";
|
|
48
48
|
import { daemonPaths } from "../lib/daemon/paths.js";
|
|
49
49
|
import { launchdLabel } from "../lib/bot/paths.js";
|
|
50
50
|
import { isAncestorProcess } from "../lib/bot/self-process.js";
|
|
@@ -286,9 +286,11 @@ async function startBot(name, dir, config, output, extra = {}) {
|
|
|
286
286
|
const d = botDaemonStatus(paths, daemonDeps());
|
|
287
287
|
const hqDaemon = daemonPaths();
|
|
288
288
|
let how;
|
|
289
|
+
let supervised = false;
|
|
289
290
|
// A bot created since the daemon last read its plan is the daemon's too,
|
|
290
291
|
// unless its own LaunchAgent runs it.
|
|
291
292
|
if (daemonSupervises(hqDaemon, `bots:${name}`) || (!d.installed && daemonWillSupervise(hqDaemon, `bots:${name}`))) {
|
|
293
|
+
supervised = true;
|
|
292
294
|
// `hq daemon` runs this bot; starting a copy here would run it twice.
|
|
293
295
|
const before = readBotStatus(dir);
|
|
294
296
|
if (before && isPidAlive(before.pid) && before.state === "running") {
|
|
@@ -322,18 +324,19 @@ async function startBot(name, dir, config, output, extra = {}) {
|
|
|
322
324
|
return !!s && s.state === "running" && isPidAlive(s.pid);
|
|
323
325
|
}, 15_000);
|
|
324
326
|
const status = readBotStatus(dir);
|
|
327
|
+
const lastError = (!running && supervised ? daemonHoldReason(hqDaemon, `bots:${name}`) : null) ?? status?.lastError ?? null;
|
|
325
328
|
if (output === "silent")
|
|
326
329
|
return { running, how };
|
|
327
330
|
if (output === "json") {
|
|
328
|
-
console.log(JSON.stringify({ ok: running, name, ...extra, running, how, state: status?.state ?? "unknown", pid: status?.pid ?? null, lastError
|
|
331
|
+
console.log(JSON.stringify({ ok: running, name, ...extra, running, how, state: status?.state ?? "unknown", pid: status?.pid ?? null, lastError }, null, 2));
|
|
329
332
|
return { running, how };
|
|
330
333
|
}
|
|
331
334
|
if (running)
|
|
332
335
|
console.log(chalk.green(`${name} is running`) + chalk.dim(` (${how})`));
|
|
333
336
|
else {
|
|
334
337
|
console.log(chalk.yellow(`${name} did not report running within 15s`) + chalk.dim(` (${how})`));
|
|
335
|
-
if (
|
|
336
|
-
console.log(chalk.dim(` last error: ${
|
|
338
|
+
if (lastError)
|
|
339
|
+
console.log(chalk.dim(` last error: ${lastError}`));
|
|
337
340
|
console.log(chalk.dim(` logs: hq bot logs ${name}`));
|
|
338
341
|
}
|
|
339
342
|
return { running, how };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Near-match suggestions for a channel name that resolved to nothing.
|
|
3
|
+
*
|
|
4
|
+
* `hq dm channel <name>`, `hq dm <channel> "msg"`, `hq channels members` and
|
|
5
|
+
* `hq files share --channel` all resolve a channel by exact slug or display
|
|
6
|
+
* name. When that misses, the user usually typed something close to a real
|
|
7
|
+
* channel (for example "desktop-agent-coordination" for the project channel
|
|
8
|
+
* "project-desktop-agent-creation-1331ed7f"). This module ranks the caller's
|
|
9
|
+
* channels against the typed name so the error can list the closest few.
|
|
10
|
+
*
|
|
11
|
+
* Pure: no I/O, so it is unit-testable.
|
|
12
|
+
*/
|
|
13
|
+
/** The fields the ranker reads. Structurally compatible with ChannelSummary. */
|
|
14
|
+
export interface SuggestableChannel {
|
|
15
|
+
channelId: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
slug?: string;
|
|
18
|
+
scope?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ChannelSuggestion {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
}
|
|
24
|
+
/** Most suggestions an error ever lists. */
|
|
25
|
+
export declare const MAX_CHANNEL_SUGGESTIONS = 3;
|
|
26
|
+
/**
|
|
27
|
+
* Tokens used for comparison. Drops a leading "project" token and a trailing
|
|
28
|
+
* 8-hex id, which every project channel carries and which would otherwise
|
|
29
|
+
* dominate the comparison. Falls back to the raw tokens when stripping would
|
|
30
|
+
* leave nothing (a channel literally named "project").
|
|
31
|
+
*/
|
|
32
|
+
export declare function comparableTokens(value: string): string[];
|
|
33
|
+
/** Levenshtein distance over code points (so astral characters count once). */
|
|
34
|
+
export declare function editDistance(a: string, b: string): number;
|
|
35
|
+
/**
|
|
36
|
+
* Rank the caller's channels against a name that matched nothing and return
|
|
37
|
+
* up to `max` close ones, best first. Group DMs are unnamed and cannot be
|
|
38
|
+
* addressed by name, so they are never suggested. Each channel is compared by
|
|
39
|
+
* both its slug and its display name; the better score wins.
|
|
40
|
+
*/
|
|
41
|
+
export declare function suggestChannels(channels: readonly SuggestableChannel[], query: string, max?: number): ChannelSuggestion[];
|
|
42
|
+
/**
|
|
43
|
+
* Append a "Did you mean" block to a not-found message. Returns the message
|
|
44
|
+
* unchanged when there are no suggestions.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withChannelSuggestions(message: string, suggestions: readonly ChannelSuggestion[]): string;
|
|
47
|
+
/**
|
|
48
|
+
* Thrown by channel resolvers when a name or id matches nothing. Carries the
|
|
49
|
+
* near-match suggestions so a --json caller can emit them structurally.
|
|
50
|
+
*/
|
|
51
|
+
export declare class ChannelNotFoundError extends Error {
|
|
52
|
+
readonly baseMessage: string;
|
|
53
|
+
readonly suggestions: ChannelSuggestion[];
|
|
54
|
+
constructor(baseMessage: string, suggestions: ChannelSuggestion[]);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=channel-suggest.d.ts.map
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Near-match suggestions for a channel name that resolved to nothing.
|
|
3
|
+
*
|
|
4
|
+
* `hq dm channel <name>`, `hq dm <channel> "msg"`, `hq channels members` and
|
|
5
|
+
* `hq files share --channel` all resolve a channel by exact slug or display
|
|
6
|
+
* name. When that misses, the user usually typed something close to a real
|
|
7
|
+
* channel (for example "desktop-agent-coordination" for the project channel
|
|
8
|
+
* "project-desktop-agent-creation-1331ed7f"). This module ranks the caller's
|
|
9
|
+
* channels against the typed name so the error can list the closest few.
|
|
10
|
+
*
|
|
11
|
+
* Pure: no I/O, so it is unit-testable.
|
|
12
|
+
*/
|
|
13
|
+
/** Most suggestions an error ever lists. */
|
|
14
|
+
export const MAX_CHANNEL_SUGGESTIONS = 3;
|
|
15
|
+
/**
|
|
16
|
+
* Comparison strings are capped so a very long name cannot make the edit
|
|
17
|
+
* distance (quadratic) expensive across a large channel list.
|
|
18
|
+
*/
|
|
19
|
+
const MAX_COMPARE_LENGTH = 64;
|
|
20
|
+
/** Lowercase, Unicode-normalised tokens split on '-', '_' and whitespace. */
|
|
21
|
+
function rawTokens(value) {
|
|
22
|
+
return value
|
|
23
|
+
.normalize("NFKC")
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.trim()
|
|
26
|
+
.replace(/^#/, "")
|
|
27
|
+
.split(/[\s_-]+/u)
|
|
28
|
+
.filter((token) => token.length > 0);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Tokens used for comparison. Drops a leading "project" token and a trailing
|
|
32
|
+
* 8-hex id, which every project channel carries and which would otherwise
|
|
33
|
+
* dominate the comparison. Falls back to the raw tokens when stripping would
|
|
34
|
+
* leave nothing (a channel literally named "project").
|
|
35
|
+
*/
|
|
36
|
+
export function comparableTokens(value) {
|
|
37
|
+
const tokens = rawTokens(value);
|
|
38
|
+
let stripped = tokens;
|
|
39
|
+
if (stripped[0] === "project")
|
|
40
|
+
stripped = stripped.slice(1);
|
|
41
|
+
const last = stripped[stripped.length - 1];
|
|
42
|
+
if (last !== undefined && /^[0-9a-f]{8}$/.test(last)) {
|
|
43
|
+
stripped = stripped.slice(0, -1);
|
|
44
|
+
}
|
|
45
|
+
return stripped.length > 0 ? stripped : tokens;
|
|
46
|
+
}
|
|
47
|
+
function sharedPrefixLength(a, b) {
|
|
48
|
+
const max = Math.min(a.length, b.length);
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < max && a[i] === b[i])
|
|
51
|
+
i += 1;
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
/** Levenshtein distance over code points (so astral characters count once). */
|
|
55
|
+
export function editDistance(a, b) {
|
|
56
|
+
const left = Array.from(a);
|
|
57
|
+
const right = Array.from(b);
|
|
58
|
+
if (left.length === 0)
|
|
59
|
+
return right.length;
|
|
60
|
+
if (right.length === 0)
|
|
61
|
+
return left.length;
|
|
62
|
+
let previous = Array.from({ length: right.length + 1 }, (_, j) => j);
|
|
63
|
+
for (let i = 1; i <= left.length; i += 1) {
|
|
64
|
+
const current = [i];
|
|
65
|
+
for (let j = 1; j <= right.length; j += 1) {
|
|
66
|
+
const cost = left[i - 1] === right[j - 1] ? 0 : 1;
|
|
67
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + cost);
|
|
68
|
+
}
|
|
69
|
+
previous = current;
|
|
70
|
+
}
|
|
71
|
+
return previous[right.length];
|
|
72
|
+
}
|
|
73
|
+
function toComparable(value) {
|
|
74
|
+
const tokens = comparableTokens(value);
|
|
75
|
+
return {
|
|
76
|
+
tokens: new Set(tokens),
|
|
77
|
+
joined: Array.from(tokens.join("-")).slice(0, MAX_COMPARE_LENGTH).join(""),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Similarity in [0, 1], or 0 when the two are not close enough to suggest.
|
|
82
|
+
* A candidate qualifies when it shares a token, shares a prefix of at least
|
|
83
|
+
* three characters, or is within 40% edit distance of the query.
|
|
84
|
+
*/
|
|
85
|
+
function similarity(query, candidate) {
|
|
86
|
+
if (!query.joined || !candidate.joined)
|
|
87
|
+
return 0;
|
|
88
|
+
let shared = 0;
|
|
89
|
+
for (const token of query.tokens)
|
|
90
|
+
if (candidate.tokens.has(token))
|
|
91
|
+
shared += 1;
|
|
92
|
+
const union = query.tokens.size + candidate.tokens.size - shared;
|
|
93
|
+
const tokenScore = union > 0 ? shared / union : 0;
|
|
94
|
+
const prefix = sharedPrefixLength(query.joined, candidate.joined);
|
|
95
|
+
const longest = Math.max(Array.from(query.joined).length, Array.from(candidate.joined).length);
|
|
96
|
+
const prefixScore = longest > 0 ? prefix / longest : 0;
|
|
97
|
+
const editScore = longest > 0
|
|
98
|
+
? 1 - editDistance(query.joined, candidate.joined) / longest
|
|
99
|
+
: 0;
|
|
100
|
+
const close = shared > 0 || prefix >= 3 || editScore >= 0.6;
|
|
101
|
+
if (!close)
|
|
102
|
+
return 0;
|
|
103
|
+
return 0.5 * tokenScore + 0.2 * prefixScore + 0.3 * editScore;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Rank the caller's channels against a name that matched nothing and return
|
|
107
|
+
* up to `max` close ones, best first. Group DMs are unnamed and cannot be
|
|
108
|
+
* addressed by name, so they are never suggested. Each channel is compared by
|
|
109
|
+
* both its slug and its display name; the better score wins.
|
|
110
|
+
*/
|
|
111
|
+
export function suggestChannels(channels, query, max = MAX_CHANNEL_SUGGESTIONS) {
|
|
112
|
+
if (max <= 0)
|
|
113
|
+
return [];
|
|
114
|
+
const target = toComparable(query);
|
|
115
|
+
if (!target.joined)
|
|
116
|
+
return [];
|
|
117
|
+
const scored = [];
|
|
118
|
+
for (const channel of channels) {
|
|
119
|
+
if (channel.scope === "group")
|
|
120
|
+
continue;
|
|
121
|
+
const slug = channel.slug?.trim() ?? "";
|
|
122
|
+
const name = channel.name?.trim() ?? "";
|
|
123
|
+
if (!slug && !name)
|
|
124
|
+
continue;
|
|
125
|
+
const score = Math.max(slug ? similarity(target, toComparable(slug)) : 0, name ? similarity(target, toComparable(name)) : 0);
|
|
126
|
+
if (score <= 0)
|
|
127
|
+
continue;
|
|
128
|
+
scored.push({
|
|
129
|
+
suggestion: { id: channel.channelId, name: slug || name },
|
|
130
|
+
score,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
scored.sort((a, b) => b.score - a.score ||
|
|
134
|
+
a.suggestion.name.localeCompare(b.suggestion.name) ||
|
|
135
|
+
a.suggestion.id.localeCompare(b.suggestion.id));
|
|
136
|
+
return scored.slice(0, max).map((entry) => entry.suggestion);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Strip control and bidi-override characters so a server-supplied name cannot
|
|
140
|
+
* drive the terminal or visually reorder the line.
|
|
141
|
+
*/
|
|
142
|
+
function printable(value) {
|
|
143
|
+
// eslint-disable-next-line no-control-regex
|
|
144
|
+
return value.replace(/[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "");
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Append a "Did you mean" block to a not-found message. Returns the message
|
|
148
|
+
* unchanged when there are no suggestions.
|
|
149
|
+
*/
|
|
150
|
+
export function withChannelSuggestions(message, suggestions) {
|
|
151
|
+
if (suggestions.length === 0)
|
|
152
|
+
return message;
|
|
153
|
+
const lines = suggestions.map((s) => ` ${printable(s.name)} (${printable(s.id)})`);
|
|
154
|
+
return `${message}\nDid you mean:\n${lines.join("\n")}`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Thrown by channel resolvers when a name or id matches nothing. Carries the
|
|
158
|
+
* near-match suggestions so a --json caller can emit them structurally.
|
|
159
|
+
*/
|
|
160
|
+
export class ChannelNotFoundError extends Error {
|
|
161
|
+
baseMessage;
|
|
162
|
+
suggestions;
|
|
163
|
+
constructor(baseMessage, suggestions) {
|
|
164
|
+
super(withChannelSuggestions(baseMessage, suggestions));
|
|
165
|
+
this.name = "ChannelNotFoundError";
|
|
166
|
+
this.baseMessage = baseMessage;
|
|
167
|
+
this.suggestions = suggestions;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=channel-suggest.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
3
3
|
import { vaultApiFetch } from "../utils/vault-api.js";
|
|
4
|
+
import { suggestChannels, withChannelSuggestions } from "./channel-suggest.js";
|
|
4
5
|
import { callerFromToken, channelSlug, fetchChannelMembers, fetchChannels, matchChannelsByName, } from "./dm.js";
|
|
5
6
|
/**
|
|
6
7
|
* Human label for a channel row. Named channels (personal/company) show their
|
|
@@ -189,7 +190,12 @@ async function runChannelsMembers(channelName, opts) {
|
|
|
189
190
|
const channels = await fetchChannels(token);
|
|
190
191
|
const matches = matchChannelsByName(channels, channelName);
|
|
191
192
|
if (matches.length === 0) {
|
|
192
|
-
|
|
193
|
+
const message = `No channel named '${channelName}' — run \`hq channels\` to see your channels.`;
|
|
194
|
+
const suggestions = suggestChannels(channels, channelName);
|
|
195
|
+
if (opts.json) {
|
|
196
|
+
console.log(JSON.stringify({ ok: false, error: message, suggestions }, null, 2));
|
|
197
|
+
}
|
|
198
|
+
console.error(chalk.red(withChannelSuggestions(message, suggestions)));
|
|
193
199
|
process.exit(1);
|
|
194
200
|
}
|
|
195
201
|
if (matches.length > 1) {
|
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -69,6 +69,32 @@ export declare function scopeExcludedExitCode(count: number): 0 | 1;
|
|
|
69
69
|
export declare function scopeExcludedWarning(count: number): string | null;
|
|
70
70
|
/** Actionable recovery for files refused because the vault baseline is stale. */
|
|
71
71
|
export declare function staleUploadRefusalLines(count: number, paths?: readonly string[]): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Upload-failure fields newer hq-cloud ShareResult carries. Read through
|
|
74
|
+
* readUploadFailures so this CLI also builds against a release without them.
|
|
75
|
+
*/
|
|
76
|
+
export interface UploadFailureCounts {
|
|
77
|
+
filesUploadFailed?: number;
|
|
78
|
+
uploadFailedPaths?: string[];
|
|
79
|
+
}
|
|
80
|
+
export declare function readUploadFailures(result: object): {
|
|
81
|
+
count: number;
|
|
82
|
+
paths: string[];
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Files the vault accepted in the plan but refused or failed at upload
|
|
86
|
+
* (feedback_943456f4). Without these lines a push that uploaded nothing
|
|
87
|
+
* printed "✓ Pushed 0" and exited 0.
|
|
88
|
+
*/
|
|
89
|
+
export declare function uploadFailedLines(count: number, paths?: readonly string[]): string[];
|
|
90
|
+
/**
|
|
91
|
+
* share() option that turns a user-named path an ignore rule drops into an
|
|
92
|
+
* "unreachable path" error instead of a silent 0-file success
|
|
93
|
+
* (feedback_63bfc302, feedback_8c294805). Spread as a plain record so this
|
|
94
|
+
* builds against an hq-cloud release whose ShareOptions predates the field;
|
|
95
|
+
* older releases ignore it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function namedPathShareOptions(userNamedPaths: boolean): Record<string, boolean>;
|
|
72
98
|
/**
|
|
73
99
|
* Optional detail line listing the effective write prefixes when a push
|
|
74
100
|
* dropped files — helps debug ACL vs scope-excluded mismatches (feedback_7e9c535e).
|
|
@@ -241,6 +267,8 @@ export interface ShareCallResult {
|
|
|
241
267
|
filesExcludedByScope: number;
|
|
242
268
|
filesRefusedStale?: number;
|
|
243
269
|
filesRefusedStalePaths?: string[];
|
|
270
|
+
filesUploadFailed?: number;
|
|
271
|
+
uploadFailedPaths?: string[];
|
|
244
272
|
conflictPaths: string[];
|
|
245
273
|
aborted: boolean;
|
|
246
274
|
/** Files this leg's plan limit refused; absent or null when none were. */
|
|
@@ -286,6 +314,8 @@ export interface PushAllResult {
|
|
|
286
314
|
filesExcludedByScope: number;
|
|
287
315
|
filesRefusedStale?: number;
|
|
288
316
|
filesRefusedStalePaths?: string[];
|
|
317
|
+
filesUploadFailed?: number;
|
|
318
|
+
uploadFailedPaths?: string[];
|
|
289
319
|
errors: Array<{
|
|
290
320
|
company: string;
|
|
291
321
|
message: string;
|
|
@@ -418,4 +448,19 @@ export declare function printReadOnlyLocalOnly(hqRoot: string, journals: Readonl
|
|
|
418
448
|
files?: Record<string, unknown>;
|
|
419
449
|
};
|
|
420
450
|
}>, log?: (line: string) => void): number;
|
|
451
|
+
/**
|
|
452
|
+
* `hq sync status`: list local files under server-owned folders (sources/,
|
|
453
|
+
* signals/, ontology/ outside entities/) that are not in the sync journal.
|
|
454
|
+
* The server pipeline writes these folders; a client push refuses them and
|
|
455
|
+
* the recurring runner skips them quietly, so a file written locally there
|
|
456
|
+
* never reaches the vault and `pendingFiles: 0` still reports a clean tree
|
|
457
|
+
* (feedback_0414d71c). Uses only the journals already loaded, with no
|
|
458
|
+
* network calls. Prints nothing when nothing applies.
|
|
459
|
+
*/
|
|
460
|
+
export declare function printServerOwnedLocalOnly(hqRoot: string, journals: ReadonlyArray<{
|
|
461
|
+
slug: string;
|
|
462
|
+
journal: {
|
|
463
|
+
files?: Record<string, unknown>;
|
|
464
|
+
};
|
|
465
|
+
}>, log?: (line: string) => void): number;
|
|
421
466
|
//# sourceMappingURL=cloud.d.ts.map
|