@indigoai-us/hq-cli 5.309.0 → 5.309.1
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 +13 -0
- package/dist/command-catalog.generated.d.ts +4 -1
- package/dist/command-catalog.generated.js +5 -1
- package/dist/commands/agents.js +6 -0
- package/dist/commands/core-checkpoint-gate-setting.d.ts +0 -10
- package/dist/commands/core-checkpoint-gate-setting.js +3 -3
- package/dist/commands/core-ontology.d.ts +1 -9
- package/dist/commands/core-ontology.js +4 -4
- package/dist/commands/core-policy.d.ts +0 -3
- package/dist/commands/core-policy.js +3 -3
- package/dist/commands/files.js +1 -1
- package/dist/commands/index-cmd.js +1 -1
- package/dist/commands/integrations-api.d.ts +9 -4
- package/dist/commands/integrations-api.js +9 -6
- package/dist/commands/integrations-manage.js +11 -3
- package/dist/commands/integrations.d.ts +8 -0
- package/dist/commands/integrations.js +83 -0
- package/dist/commands/lanes-checks.d.ts +0 -2
- package/dist/commands/lanes-checks.js +2 -2
- package/dist/commands/lanes.d.ts +0 -11
- package/dist/commands/lanes.js +6 -6
- package/dist/commands/mcp-registration.d.ts +5 -11
- package/dist/commands/mcp-registration.js +2 -6
- package/dist/lib/core-utils/sentry-report.d.ts +5 -11
- package/dist/lib/core-utils/sentry-report.js +2 -2
- package/dist/lib/db/local.d.ts +0 -5
- package/dist/lib/db/local.js +1 -1
- package/dist/lib/db/migrate.d.ts +0 -12
- package/dist/lib/db/migrate.js +5 -5
- package/dist/lib/db/sql.d.ts +0 -10
- package/dist/lib/db/sql.js +4 -8
- package/dist/lib/doctor/checks/codex-wiring.js +1 -33
- package/dist/lib/doctor/checks/grok-wiring.js +1 -34
- package/dist/lib/doctor/deep/effects.js +1 -3
- package/dist/lib/doctor/deep/sandbox.js +1 -3
- package/dist/lib/doctor/fixtures/schema.js +1 -3
- package/dist/lib/doctor/shared.d.ts +8 -0
- package/dist/lib/doctor/shared.js +38 -0
- package/dist/lib/lanes/autopilot.js +6 -4
- package/dist/lib/monitor.d.ts +2 -6
- package/dist/lib/monitor.js +5 -5
- package/dist/lib/report-publish.d.ts +1 -10
- package/dist/lib/report-publish.js +3 -9
- package/dist/lib/search-index/index.d.ts +7 -0
- package/dist/lib/search-index/index.js +21 -2
- package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +5 -0
- package/dist/lib/search-index/qmd-exit-diagnostics.js +40 -0
- package/dist/lib/service-manager/launchd.d.ts +0 -7
- package/dist/lib/service-manager/launchd.js +2 -2
- package/dist/main.js +7 -2
- package/dist/startup-registration.js +9 -1
- package/dist/utils/client-health.d.ts +0 -4
- package/dist/utils/client-health.js +2 -2
- package/dist/utils/feedback-diagnostics.d.ts +2 -1
- package/dist/utils/feedback-log-bundle.d.ts +0 -25
- package/dist/utils/feedback-log-bundle.js +5 -5
- package/dist/utils/feedback-logs.d.ts +4 -38
- package/dist/utils/feedback-logs.js +7 -7
- package/dist/utils/feedback-screenshots.d.ts +0 -1
- package/dist/utils/feedback-screenshots.js +1 -1
- package/dist/utils/install-tree-torn.d.ts +19 -13
- package/dist/utils/install-tree-torn.js +77 -2
- package/dist/utils/local-files-overview.d.ts +0 -6
- package/dist/utils/local-files-overview.js +1 -1
- package/dist/utils/qmd-model-download-error.d.ts +0 -8
- package/dist/utils/qmd-model-download-error.js +1 -1
- package/dist/utils/qmd-query-document-error.d.ts +0 -6
- package/dist/utils/qmd-query-document-error.js +1 -1
- package/dist/utils/scaffold-fast-import-guard.d.ts +0 -1
- package/dist/utils/scaffold-fast-import-guard.js +1 -1
- package/dist/utils/scaffold-sibling-references.d.ts +3 -2
- package/dist/utils/sentry-fingerprint.js +17 -0
- package/dist/utils/version-gate.d.ts +4 -0
- package/dist/utils/version-gate.js +13 -0
- package/package.json +1 -1
|
@@ -242,10 +242,6 @@ export function isCodexInstalled(env) {
|
|
|
242
242
|
export function claudeConfigPath(env) {
|
|
243
243
|
return path.join(env.home, '.claude.json');
|
|
244
244
|
}
|
|
245
|
-
/** `~/.mcp.json` — the project-pinned Claude surface (a symlink on this host). */
|
|
246
|
-
export function mcpJsonPath(env) {
|
|
247
|
-
return path.join(env.home, '.mcp.json');
|
|
248
|
-
}
|
|
249
245
|
/**
|
|
250
246
|
* Built-in JSON {@link ConfigFormat} for the Claude surfaces. Pretty-prints with
|
|
251
247
|
* a trailing newline; an empty doc is `{}`. Parsing the empty string is the
|
|
@@ -368,9 +364,9 @@ export function sanitizeParserMessage(message) {
|
|
|
368
364
|
// Advisory O_EXCL lock (held across read->merge->write).
|
|
369
365
|
// ---------------------------------------------------------------------------
|
|
370
366
|
/** Default stale-lock timeout — a lock older than this whose PID is dead is broken. */
|
|
371
|
-
|
|
367
|
+
const DEFAULT_LOCK_STALE_MS = 30_000;
|
|
372
368
|
/** Default total time to wait for a held lock before giving up. */
|
|
373
|
-
|
|
369
|
+
const DEFAULT_LOCK_WAIT_MS = 10_000;
|
|
374
370
|
/** The lockfile path for a target: `~/.<basename>.hqlock` (a sibling, hidden). */
|
|
375
371
|
export function lockPathFor(target) {
|
|
376
372
|
const dir = path.dirname(target);
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
import * as Sentry from "@sentry/node";
|
|
19
19
|
import type { CaptureContext, SeverityLevel } from "@sentry/node";
|
|
20
20
|
export declare const DEFAULT_SENTRY_REPORT_TIMEOUT_MS = 750;
|
|
21
|
-
export declare const MAX_SENTRY_REPORT_TIMEOUT_MS = 5000;
|
|
22
21
|
export declare const MAX_SENTRY_REPORT_PAYLOAD_BYTES = 2048;
|
|
23
22
|
export declare const MAX_SENTRY_REPORT_METADATA_VALUE_BYTES = 256;
|
|
24
23
|
/**
|
|
@@ -34,11 +33,11 @@ export type HookSequenceEntry = {
|
|
|
34
33
|
event: string;
|
|
35
34
|
ms: number;
|
|
36
35
|
};
|
|
37
|
-
|
|
36
|
+
type HookTimeoutDebugPhaseTiming = {
|
|
38
37
|
phase: string;
|
|
39
38
|
elapsed_ms: number;
|
|
40
39
|
};
|
|
41
|
-
|
|
40
|
+
type HookTimeoutDebugContext = {
|
|
42
41
|
hook_name: string;
|
|
43
42
|
hook_event: string;
|
|
44
43
|
budget_ms: number;
|
|
@@ -52,9 +51,9 @@ export type HookTimeoutDebugContext = {
|
|
|
52
51
|
spawn_ms?: number | "unavailable";
|
|
53
52
|
process_count?: number | "unavailable";
|
|
54
53
|
};
|
|
55
|
-
|
|
54
|
+
type SentryReportMetadataValue = string | number | boolean | HookSequenceEntry[] | HookTimeoutDebugContext;
|
|
56
55
|
export type SentryReportMetadata = Record<string, SentryReportMetadataValue>;
|
|
57
|
-
|
|
56
|
+
type SentryReportEvent = {
|
|
58
57
|
type: string;
|
|
59
58
|
message: string;
|
|
60
59
|
fingerprint: string;
|
|
@@ -102,12 +101,6 @@ export type SentryReportResult = {
|
|
|
102
101
|
export declare function readSentryReportStdin(stdin: AsyncIterable<Buffer | string>): Promise<string | null>;
|
|
103
102
|
/** Unknown metadata is ignored before this cap is evaluated. */
|
|
104
103
|
export declare function exceedsSentryReportMetadataKeyCap(keys: Iterable<string>): boolean;
|
|
105
|
-
/**
|
|
106
|
-
* Parse and validate the closed report schema without touching Sentry. The
|
|
107
|
-
* function intentionally returns an ordinary result instead of throwing so a
|
|
108
|
-
* hook can ignore the CLI exit code without creating an unhandled rejection.
|
|
109
|
-
*/
|
|
110
|
-
export declare function parseSentryReportEvent(stdin: string): SentryReportResult;
|
|
111
104
|
/**
|
|
112
105
|
* Capture one validated Sentry message and wait only for the supplied bounded
|
|
113
106
|
* flush budget. A zero result means the event entered the local transport and
|
|
@@ -117,4 +110,5 @@ export declare function parseSentryReportEvent(stdin: string): SentryReportResul
|
|
|
117
110
|
* transport errors cannot echo event data back to a hook.
|
|
118
111
|
*/
|
|
119
112
|
export declare function reportSentryEvent(stdin: string, options?: SentryReportOptions, dependencies?: SentryReportDependencies): Promise<SentryReportResult>;
|
|
113
|
+
export {};
|
|
120
114
|
//# sourceMappingURL=sentry-report.d.ts.map
|
|
@@ -25,7 +25,7 @@ import { beforeSend } from "../../sentry-before-send.js";
|
|
|
25
25
|
import { resolveLiveRoot } from "../../utils/hq-roots.js";
|
|
26
26
|
import { hookTimeoutDebugContextEnabled } from "./hook-timeout-debug-context-flag.js";
|
|
27
27
|
export const DEFAULT_SENTRY_REPORT_TIMEOUT_MS = 750;
|
|
28
|
-
|
|
28
|
+
const MAX_SENTRY_REPORT_TIMEOUT_MS = 5_000;
|
|
29
29
|
export const MAX_SENTRY_REPORT_PAYLOAD_BYTES = 2_048;
|
|
30
30
|
export const MAX_SENTRY_REPORT_METADATA_VALUE_BYTES = 256;
|
|
31
31
|
const MAX_SENTRY_REPORT_TYPE_BYTES = 64;
|
|
@@ -349,7 +349,7 @@ function invalidInput() {
|
|
|
349
349
|
* function intentionally returns an ordinary result instead of throwing so a
|
|
350
350
|
* hook can ignore the CLI exit code without creating an unhandled rejection.
|
|
351
351
|
*/
|
|
352
|
-
|
|
352
|
+
function parseSentryReportEvent(stdin) {
|
|
353
353
|
if (byteLength(stdin) > MAX_SENTRY_REPORT_PAYLOAD_BYTES)
|
|
354
354
|
return invalidInput();
|
|
355
355
|
let parsed;
|
package/dist/lib/db/local.d.ts
CHANGED
|
@@ -23,11 +23,6 @@ export interface LocalDbStatus {
|
|
|
23
23
|
/** Fingerprint of path for logs that prefer not to echo full home paths. */
|
|
24
24
|
pathFingerprint: string;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Short non-reversible fingerprint of a path (for status display).
|
|
28
|
-
* Not a secret — just avoids dumping full home paths when preferred.
|
|
29
|
-
*/
|
|
30
|
-
export declare function fingerprintPath(filePath: string): string;
|
|
31
26
|
/**
|
|
32
27
|
* Open (and create if missing) the company local vault DB with WAL mode.
|
|
33
28
|
* Idempotent: reopening an existing file does not recreate or wipe it.
|
package/dist/lib/db/local.js
CHANGED
|
@@ -12,7 +12,7 @@ const MIGRATIONS_TABLE = "hq_schema_migrations";
|
|
|
12
12
|
* Short non-reversible fingerprint of a path (for status display).
|
|
13
13
|
* Not a secret — just avoids dumping full home paths when preferred.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
function fingerprintPath(filePath) {
|
|
16
16
|
let h = 2166136261;
|
|
17
17
|
for (let i = 0; i < filePath.length; i++) {
|
|
18
18
|
h ^= filePath.charCodeAt(i);
|
package/dist/lib/db/migrate.d.ts
CHANGED
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
* companies/{company}/db/migrations/*.sql
|
|
6
6
|
* Applied versions are recorded in hq_schema_migrations inside the local DB.
|
|
7
7
|
*/
|
|
8
|
-
import type { LocalDb } from "./local.js";
|
|
9
8
|
import type { LocalDbPathEnv } from "./paths.js";
|
|
10
|
-
export declare const MIGRATIONS_TABLE = "hq_schema_migrations";
|
|
11
9
|
export interface MigrateOptions extends LocalDbPathEnv {
|
|
12
10
|
company: string;
|
|
13
11
|
/**
|
|
@@ -24,16 +22,6 @@ export interface MigrateResult {
|
|
|
24
22
|
head: string | null;
|
|
25
23
|
}
|
|
26
24
|
export declare function resolveMigrationsDir(hqRoot: string, companySlug: string): string;
|
|
27
|
-
/**
|
|
28
|
-
* Ensure migrations directory exists (creates empty dir on first migrate).
|
|
29
|
-
*/
|
|
30
|
-
export declare function ensureMigrationsDir(hqRoot: string, companySlug: string): string;
|
|
31
|
-
/**
|
|
32
|
-
* List pending migration files in lexical/version order (filename sort).
|
|
33
|
-
*/
|
|
34
|
-
export declare function listMigrationFiles(migrationsDir: string): string[];
|
|
35
|
-
export declare function ensureMigrationsLedger(db: LocalDb): void;
|
|
36
|
-
export declare function listAppliedVersions(db: LocalDb): Set<string>;
|
|
37
25
|
/**
|
|
38
26
|
* Apply pending migrations. On failure, does not mark the failed file applied.
|
|
39
27
|
*/
|
package/dist/lib/db/migrate.js
CHANGED
|
@@ -9,7 +9,7 @@ import fs from "node:fs";
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { openLocalDb, readMigrationHead } from "./local.js";
|
|
11
11
|
import { normalizeCompanySlugForLocalDb } from "./paths.js";
|
|
12
|
-
|
|
12
|
+
const MIGRATIONS_TABLE = "hq_schema_migrations";
|
|
13
13
|
export function resolveMigrationsDir(hqRoot, companySlug) {
|
|
14
14
|
const slug = normalizeCompanySlugForLocalDb(companySlug);
|
|
15
15
|
return path.join(hqRoot, "companies", slug, "db", "migrations");
|
|
@@ -17,7 +17,7 @@ export function resolveMigrationsDir(hqRoot, companySlug) {
|
|
|
17
17
|
/**
|
|
18
18
|
* Ensure migrations directory exists (creates empty dir on first migrate).
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
function ensureMigrationsDir(hqRoot, companySlug) {
|
|
21
21
|
const dir = resolveMigrationsDir(hqRoot, companySlug);
|
|
22
22
|
fs.mkdirSync(dir, { recursive: true });
|
|
23
23
|
return dir;
|
|
@@ -25,7 +25,7 @@ export function ensureMigrationsDir(hqRoot, companySlug) {
|
|
|
25
25
|
/**
|
|
26
26
|
* List pending migration files in lexical/version order (filename sort).
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
function listMigrationFiles(migrationsDir) {
|
|
29
29
|
if (!fs.existsSync(migrationsDir))
|
|
30
30
|
return [];
|
|
31
31
|
return fs
|
|
@@ -33,7 +33,7 @@ export function listMigrationFiles(migrationsDir) {
|
|
|
33
33
|
.filter((f) => f.endsWith(".sql"))
|
|
34
34
|
.sort((a, b) => a.localeCompare(b, "en"));
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
function ensureMigrationsLedger(db) {
|
|
37
37
|
db.exec(`
|
|
38
38
|
CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (
|
|
39
39
|
version TEXT PRIMARY KEY NOT NULL,
|
|
@@ -41,7 +41,7 @@ export function ensureMigrationsLedger(db) {
|
|
|
41
41
|
);
|
|
42
42
|
`);
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
function listAppliedVersions(db) {
|
|
45
45
|
ensureMigrationsLedger(db);
|
|
46
46
|
const rows = db
|
|
47
47
|
.prepare(`SELECT version FROM ${MIGRATIONS_TABLE} ORDER BY version`)
|
package/dist/lib/db/sql.d.ts
CHANGED
|
@@ -27,14 +27,6 @@ export interface SqlRunResult {
|
|
|
27
27
|
changes: number;
|
|
28
28
|
readonly: boolean;
|
|
29
29
|
}
|
|
30
|
-
export declare function stripSqlNoise(sql: string): string;
|
|
31
|
-
export declare function isWriteSql(sql: string): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Statements that must never run via `hq db sql`, even with --write.
|
|
34
|
-
* ATTACH/DETACH would let a company-scoped session open another company's
|
|
35
|
-
* vault.db by absolute path (category-1 isolation).
|
|
36
|
-
*/
|
|
37
|
-
export declare function assertSqlAllowed(sql: string): void;
|
|
38
30
|
/**
|
|
39
31
|
* Resolve which file path to open, enforcing company isolation by default.
|
|
40
32
|
*/
|
|
@@ -44,6 +36,4 @@ export declare function resolveSqlDbPath(opts: SqlRunOptions): string;
|
|
|
44
36
|
*/
|
|
45
37
|
export declare function runLocalSql(opts: SqlRunOptions): SqlRunResult;
|
|
46
38
|
export declare function formatSqlResult(result: SqlRunResult, format?: "jsonl" | "table"): string;
|
|
47
|
-
/** Test helper: company dir for isolation assertions. */
|
|
48
|
-
export declare function companyLocalDbDir(company: string, env?: LocalDbPathEnv): string;
|
|
49
39
|
//# sourceMappingURL=sql.d.ts.map
|
package/dist/lib/db/sql.js
CHANGED
|
@@ -7,17 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import Database from "better-sqlite3";
|
|
9
9
|
import { openLocalDb } from "./local.js";
|
|
10
|
-
import { normalizeCompanySlugForLocalDb,
|
|
10
|
+
import { normalizeCompanySlugForLocalDb, resolveLocalDbPath, } from "./paths.js";
|
|
11
11
|
const WRITE_PATTERN = /^\s*(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|ALTER|TRUNCATE|REINDEX|VACUUM|BEGIN|COMMIT|ROLLBACK)\b/i;
|
|
12
12
|
/** Always forbidden — opens other files/DBs and breaks company path isolation. */
|
|
13
13
|
const FORBIDDEN_SQL_PATTERN = /\b(ATTACH|DETACH|LOAD_EXTENSION)\b/i;
|
|
14
|
-
|
|
14
|
+
function stripSqlNoise(sql) {
|
|
15
15
|
return sql
|
|
16
16
|
.replace(/^\s*--[^\n]*\n/gm, "")
|
|
17
17
|
.replace(/^\s*\/\*[\s\S]*?\*\//gm, "")
|
|
18
18
|
.trim();
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
function isWriteSql(sql) {
|
|
21
21
|
return WRITE_PATTERN.test(stripSqlNoise(sql));
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -25,7 +25,7 @@ export function isWriteSql(sql) {
|
|
|
25
25
|
* ATTACH/DETACH would let a company-scoped session open another company's
|
|
26
26
|
* vault.db by absolute path (category-1 isolation).
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
function assertSqlAllowed(sql) {
|
|
29
29
|
const stripped = stripSqlNoise(sql);
|
|
30
30
|
if (FORBIDDEN_SQL_PATTERN.test(stripped)) {
|
|
31
31
|
throw new Error("ATTACH/DETACH/LOAD_EXTENSION are not allowed via hq db sql (tenant isolation); use the company-canonical local path only");
|
|
@@ -122,8 +122,4 @@ export function formatSqlResult(result, format = "jsonl") {
|
|
|
122
122
|
.join("\n");
|
|
123
123
|
return body ? `${header}\n${body}` : header;
|
|
124
124
|
}
|
|
125
|
-
/** Test helper: company dir for isolation assertions. */
|
|
126
|
-
export function companyLocalDbDir(company, env) {
|
|
127
|
-
return resolveLocalDbDir(company, env);
|
|
128
|
-
}
|
|
129
125
|
//# sourceMappingURL=sql.js.map
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
import * as fs from "node:fs";
|
|
43
43
|
import * as path from "node:path";
|
|
44
44
|
import { parse as parseToml } from "smol-toml";
|
|
45
|
+
import { collectCommands, fileState } from "../shared.js";
|
|
45
46
|
import { ALLOWED_DIVERGENCE_RELPATH, loadAllowedDivergence, } from "../allowed-divergence.js";
|
|
46
47
|
/** Basename of the single-adapter script the current architecture routes to. */
|
|
47
48
|
const CODEX_ADAPTER_BASENAME = "hq-codex-hook-adapter.sh";
|
|
@@ -549,44 +550,11 @@ function extractBraceBlock(source, from) {
|
|
|
549
550
|
return source.slice(open + 1);
|
|
550
551
|
}
|
|
551
552
|
// --- shared low-level helpers --------------------------------------------------
|
|
552
|
-
/** Collect every `command` string from a `{hooks:{Event:[{hooks:[…]}]}}` doc. */
|
|
553
|
-
function collectCommands(parsed) {
|
|
554
|
-
const commands = [];
|
|
555
|
-
if (!parsed || typeof parsed !== "object")
|
|
556
|
-
return commands;
|
|
557
|
-
const hooks = parsed.hooks;
|
|
558
|
-
if (!hooks || typeof hooks !== "object")
|
|
559
|
-
return commands;
|
|
560
|
-
for (const entries of Object.values(hooks)) {
|
|
561
|
-
if (!Array.isArray(entries))
|
|
562
|
-
continue;
|
|
563
|
-
for (const entry of entries) {
|
|
564
|
-
const inner = entry?.hooks;
|
|
565
|
-
if (!Array.isArray(inner))
|
|
566
|
-
continue;
|
|
567
|
-
for (const hook of inner) {
|
|
568
|
-
const command = hook?.command;
|
|
569
|
-
if (typeof command === "string")
|
|
570
|
-
commands.push(command);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
return commands;
|
|
575
|
-
}
|
|
576
553
|
function resolvePath(hqRoot, target) {
|
|
577
554
|
if (!target)
|
|
578
555
|
return null;
|
|
579
556
|
return path.isAbsolute(target) ? target : path.resolve(hqRoot, target);
|
|
580
557
|
}
|
|
581
|
-
function fileState(target) {
|
|
582
|
-
try {
|
|
583
|
-
const stat = fs.statSync(target);
|
|
584
|
-
return { present: stat.isFile(), executable: (stat.mode & 0o111) !== 0 };
|
|
585
|
-
}
|
|
586
|
-
catch {
|
|
587
|
-
return { present: false, executable: false };
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
558
|
function filesEqual(a, b) {
|
|
591
559
|
try {
|
|
592
560
|
return fs.readFileSync(a).equals(fs.readFileSync(b));
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import * as fs from "node:fs";
|
|
23
23
|
import * as os from "node:os";
|
|
24
24
|
import * as path from "node:path";
|
|
25
|
+
import { collectCommands, fileState } from "../shared.js";
|
|
25
26
|
/** The command a user runs to install the user-global Grok bridge. */
|
|
26
27
|
export const GROK_TRUST_REMEDIATION = "bash core/scripts/grok-trust.sh";
|
|
27
28
|
/** Files that grok-trust.sh installs into `~/.grok/hooks/` for the bridge. */
|
|
@@ -149,38 +150,4 @@ function bridgeInstalled(bridgeDir) {
|
|
|
149
150
|
}
|
|
150
151
|
return false;
|
|
151
152
|
}
|
|
152
|
-
// --- shared low-level helpers --------------------------------------------------
|
|
153
|
-
/** Collect every `command` string from a `{hooks:{Event:[{hooks:[…]}]}}` doc. */
|
|
154
|
-
function collectCommands(parsed) {
|
|
155
|
-
const commands = [];
|
|
156
|
-
if (!parsed || typeof parsed !== "object")
|
|
157
|
-
return commands;
|
|
158
|
-
const hooks = parsed.hooks;
|
|
159
|
-
if (!hooks || typeof hooks !== "object")
|
|
160
|
-
return commands;
|
|
161
|
-
for (const entries of Object.values(hooks)) {
|
|
162
|
-
if (!Array.isArray(entries))
|
|
163
|
-
continue;
|
|
164
|
-
for (const entry of entries) {
|
|
165
|
-
const inner = entry?.hooks;
|
|
166
|
-
if (!Array.isArray(inner))
|
|
167
|
-
continue;
|
|
168
|
-
for (const hook of inner) {
|
|
169
|
-
const command = hook?.command;
|
|
170
|
-
if (typeof command === "string")
|
|
171
|
-
commands.push(command);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return commands;
|
|
176
|
-
}
|
|
177
|
-
function fileState(target) {
|
|
178
|
-
try {
|
|
179
|
-
const stat = fs.statSync(target);
|
|
180
|
-
return { present: stat.isFile(), executable: (stat.mode & 0o111) !== 0 };
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
return { present: false, executable: false };
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
153
|
//# sourceMappingURL=grok-wiring.js.map
|
|
@@ -36,6 +36,7 @@ import { spawnSync } from "node:child_process";
|
|
|
36
36
|
import { createHash } from "node:crypto";
|
|
37
37
|
import * as fs from "node:fs";
|
|
38
38
|
import * as path from "node:path";
|
|
39
|
+
import { isRecord } from "../shared.js";
|
|
39
40
|
/**
|
|
40
41
|
* Parse a fixture case's `effects:` field into a list of {@link
|
|
41
42
|
* EffectExpectation}. Returns the list, or an error string naming what was
|
|
@@ -223,7 +224,4 @@ function hashFile(abs) {
|
|
|
223
224
|
return null;
|
|
224
225
|
}
|
|
225
226
|
}
|
|
226
|
-
function isRecord(value) {
|
|
227
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
228
|
-
}
|
|
229
227
|
//# sourceMappingURL=effects.js.map
|
|
@@ -39,6 +39,7 @@ import * as fs from "node:fs";
|
|
|
39
39
|
import * as os from "node:os";
|
|
40
40
|
import * as path from "node:path";
|
|
41
41
|
import * as yaml from "js-yaml";
|
|
42
|
+
import { isRecord } from "../shared.js";
|
|
42
43
|
import { classifyCaseStatus, looksLikeFixture, } from "../fixtures/schema.js";
|
|
43
44
|
import { HOOK_TESTS_RELDIR, registeredHookIds } from "../fixtures/discover.js";
|
|
44
45
|
import { isSideEffectingHookId } from "./classify.js";
|
|
@@ -566,7 +567,4 @@ function oneLine(text) {
|
|
|
566
567
|
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
567
568
|
return collapsed.length > 200 ? `${collapsed.slice(0, 197)}…` : collapsed;
|
|
568
569
|
}
|
|
569
|
-
function isRecord(value) {
|
|
570
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
571
|
-
}
|
|
572
570
|
//# sourceMappingURL=sandbox.js.map
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
* module owns only the classification semantics, so both the doctor and its
|
|
28
28
|
* tests agree on what a case outcome means.
|
|
29
29
|
*/
|
|
30
|
+
import { isRecord } from "../shared.js";
|
|
30
31
|
/**
|
|
31
32
|
* Every fixture schema version this build of the CLI can interpret. A fixture
|
|
32
33
|
* declaring a version outside this set is reported UNKNOWN, never PASS — see
|
|
@@ -242,7 +243,4 @@ export function classifyCaseStatus(met, expectedFailure) {
|
|
|
242
243
|
return met ? "WARN" : "KNOWN-DEFECT";
|
|
243
244
|
return met ? "PASS" : "FAIL";
|
|
244
245
|
}
|
|
245
|
-
function isRecord(value) {
|
|
246
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
247
|
-
}
|
|
248
246
|
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Collect every `command` string from a `{hooks:{Event:[{hooks:[…]}]}}` doc. */
|
|
2
|
+
export declare function collectCommands(parsed: unknown): string[];
|
|
3
|
+
export declare function fileState(target: string): {
|
|
4
|
+
present: boolean;
|
|
5
|
+
executable: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
8
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
/** Collect every `command` string from a `{hooks:{Event:[{hooks:[…]}]}}` doc. */
|
|
3
|
+
export function collectCommands(parsed) {
|
|
4
|
+
const commands = [];
|
|
5
|
+
if (!parsed || typeof parsed !== "object")
|
|
6
|
+
return commands;
|
|
7
|
+
const hooks = parsed.hooks;
|
|
8
|
+
if (!hooks || typeof hooks !== "object")
|
|
9
|
+
return commands;
|
|
10
|
+
for (const entries of Object.values(hooks)) {
|
|
11
|
+
if (!Array.isArray(entries))
|
|
12
|
+
continue;
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const inner = entry?.hooks;
|
|
15
|
+
if (!Array.isArray(inner))
|
|
16
|
+
continue;
|
|
17
|
+
for (const hook of inner) {
|
|
18
|
+
const command = hook?.command;
|
|
19
|
+
if (typeof command === "string")
|
|
20
|
+
commands.push(command);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return commands;
|
|
25
|
+
}
|
|
26
|
+
export function fileState(target) {
|
|
27
|
+
try {
|
|
28
|
+
const stat = fs.statSync(target);
|
|
29
|
+
return { present: stat.isFile(), executable: (stat.mode & 0o111) !== 0 };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { present: false, executable: false };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function isRecord(value) {
|
|
36
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -3,6 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import { laneRunsOnHost } from "./admission.js";
|
|
4
4
|
import { appendDropboxMessage } from "./dropbox.js";
|
|
5
5
|
import { LanesError } from "./errors.js";
|
|
6
|
+
import { resolveLaneCompany } from "./lane-company.js";
|
|
6
7
|
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
7
8
|
import { readAllLanes } from "./store.js";
|
|
8
9
|
export const LEAD_AUTOPILOT_FLAG = "lanes.lead-autopilot";
|
|
@@ -418,7 +419,8 @@ async function runLeadAutopilotPassUnlocked(input) {
|
|
|
418
419
|
result.skipped.push({ lead_lane: registered.lane, reason: "lead_lane_missing" });
|
|
419
420
|
continue;
|
|
420
421
|
}
|
|
421
|
-
|
|
422
|
+
const company = resolveLaneCompany(hqRoot, lead).company;
|
|
423
|
+
if (!company) {
|
|
422
424
|
result.skipped.push({ lead_lane: lead.lane_id, reason: "lead_company_unresolved" });
|
|
423
425
|
continue;
|
|
424
426
|
}
|
|
@@ -433,16 +435,16 @@ async function runLeadAutopilotPassUnlocked(input) {
|
|
|
433
435
|
}
|
|
434
436
|
let stateChanged = false;
|
|
435
437
|
try {
|
|
436
|
-
const enabled = await (input.readFlag ?? readLanesRegistryFlag)(LEAD_AUTOPILOT_FLAG, { company
|
|
438
|
+
const enabled = await (input.readFlag ?? readLanesRegistryFlag)(LEAD_AUTOPILOT_FLAG, { company });
|
|
437
439
|
if (!enabled) {
|
|
438
440
|
result.skipped.push({ lead_lane: lead.lane_id, reason: "flag_off" });
|
|
439
441
|
continue;
|
|
440
442
|
}
|
|
441
|
-
const status = readStatus(hqRoot, registered.status,
|
|
443
|
+
const status = readStatus(hqRoot, registered.status, company.slug);
|
|
442
444
|
const statusUpdatedAt = typeof status.updated_at === "string" && Number.isFinite(Date.parse(status.updated_at))
|
|
443
445
|
? new Date(Date.parse(status.updated_at)).toISOString()
|
|
444
446
|
: undefined;
|
|
445
|
-
const stories = projectStories(hqRoot, registered.prd,
|
|
447
|
+
const stories = projectStories(hqRoot, registered.prd, company.slug, lead.project_id);
|
|
446
448
|
const children = lanes.filter((lane) => lane.senior.kind === "lane" && lane.senior.id === lead.lane_id);
|
|
447
449
|
const planned = planLeadAutopilotWakes({
|
|
448
450
|
lead,
|
package/dist/lib/monitor.d.ts
CHANGED
|
@@ -4,15 +4,12 @@ export declare const MONITOR_FLAG = "monitor.enabled";
|
|
|
4
4
|
export declare const MONITOR_FLAG_DEFAULT = false;
|
|
5
5
|
export declare const MONITOR_DEFAULT_TIMEOUT_MS: number;
|
|
6
6
|
export declare const MONITOR_DEFAULT_CHECKIN_MS: number;
|
|
7
|
-
export declare const MONITOR_PROMPT_CACHE_TTL_MS: number;
|
|
8
7
|
export declare const MONITOR_BATCH_WINDOW_MS = 200;
|
|
9
8
|
export declare const MONITOR_POLL_INTERVAL_MS = 1000;
|
|
10
9
|
export declare const MONITOR_RATE_WINDOW_MS = 10000;
|
|
11
10
|
/** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
|
|
12
11
|
export declare const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
|
|
13
12
|
export declare const MONITOR_MAX_FLOOD_WINDOWS = 3;
|
|
14
|
-
export declare const MONITOR_LOCK_STALE_MS = 30000;
|
|
15
|
-
export declare const MONITOR_MAX_TIMER_DELAY_MS = 2147000000;
|
|
16
13
|
export type MonitorTarget = {
|
|
17
14
|
kind: "lane";
|
|
18
15
|
laneId: string;
|
|
@@ -38,7 +35,7 @@ export interface NearestMonitorRuntime {
|
|
|
38
35
|
export interface MonitorRuntimeIdentity extends NearestMonitorRuntime {
|
|
39
36
|
starttime: number;
|
|
40
37
|
}
|
|
41
|
-
|
|
38
|
+
interface MonitorSessionOwner {
|
|
42
39
|
pid: number;
|
|
43
40
|
starttime: number | null;
|
|
44
41
|
}
|
|
@@ -107,7 +104,6 @@ export interface MonitorCheckinResult {
|
|
|
107
104
|
/** This guard is first in monitor start so a conflicting invocation has no side effects. */
|
|
108
105
|
export declare function assertMonitorTimeoutCompatibility(persistent: boolean, timeoutProvided: boolean): void;
|
|
109
106
|
export declare function parseMonitorDuration(value: string, kind: "timeout" | "checkin"): number;
|
|
110
|
-
export declare function assertMonitorSessionId(sessionId: string): void;
|
|
111
107
|
export declare function parseMonitorTarget(value: string): MonitorTarget;
|
|
112
108
|
export declare function monitorTargetKey(target: MonitorTarget): string;
|
|
113
109
|
export declare function detectMonitorTarget(options: DetectMonitorTargetOptions): MonitorTarget;
|
|
@@ -119,7 +115,6 @@ export declare function findNearestMonitorRuntime(options: {
|
|
|
119
115
|
export declare function monitorSessionDir(hqRoot: string, provider: LaneProvider, sessionId: string): string;
|
|
120
116
|
export declare function monitorSessionHasActiveMarkers(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
121
117
|
export declare function monitorSessionHasActiveMarkerForOwner(hqRoot: string, provider: LaneProvider, sessionId: string, owner: MonitorRuntimeIdentity): boolean;
|
|
122
|
-
export declare function monitorSessionHasInboxFile(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
123
118
|
export declare function monitorSessionInboxHasEvents(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
124
119
|
export declare function monitorSessionHasWork(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
|
|
125
120
|
export declare function monitorDir(hqRoot: string, monitorId: string): string;
|
|
@@ -150,4 +145,5 @@ export declare function recordMonitorTargetDeliveryAtPath(activityPath: string,
|
|
|
150
145
|
export declare function formatElapsed(ms: number): string;
|
|
151
146
|
export declare function runMonitorCheckinTick(hqRoot: string, targetKey: string, deps: MonitorCheckinDeps): Promise<MonitorCheckinResult>;
|
|
152
147
|
export declare function readMonitorPidLiveness(pid: number | null, starttime: number | null, readStarttime?: (pid: number) => number | null): boolean;
|
|
148
|
+
export {};
|
|
153
149
|
//# sourceMappingURL=monitor.d.ts.map
|
package/dist/lib/monitor.js
CHANGED
|
@@ -9,15 +9,15 @@ export const MONITOR_FLAG = "monitor.enabled";
|
|
|
9
9
|
export const MONITOR_FLAG_DEFAULT = false;
|
|
10
10
|
export const MONITOR_DEFAULT_TIMEOUT_MS = 5 * 60_000;
|
|
11
11
|
export const MONITOR_DEFAULT_CHECKIN_MS = 55 * 60_000;
|
|
12
|
-
|
|
12
|
+
const MONITOR_PROMPT_CACHE_TTL_MS = 60 * 60_000;
|
|
13
13
|
export const MONITOR_BATCH_WINDOW_MS = 200;
|
|
14
14
|
export const MONITOR_POLL_INTERVAL_MS = 1_000;
|
|
15
15
|
export const MONITOR_RATE_WINDOW_MS = 10_000;
|
|
16
16
|
/** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
|
|
17
17
|
export const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
|
|
18
18
|
export const MONITOR_MAX_FLOOD_WINDOWS = 3;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const MONITOR_LOCK_STALE_MS = 30_000;
|
|
20
|
+
const MONITOR_MAX_TIMER_DELAY_MS = 2_147_000_000;
|
|
21
21
|
const SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
22
22
|
const SAFE_LANE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
23
23
|
const RUNTIME_ENV = {
|
|
@@ -59,7 +59,7 @@ function assertLaneTargetId(laneId) {
|
|
|
59
59
|
throw monitorError("monitor_target_invalid", `Invalid lane target ${JSON.stringify(laneId)}.`, { lane_id: laneId });
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
function assertMonitorSessionId(sessionId) {
|
|
63
63
|
if (!SESSION_ID_RE.test(sessionId)) {
|
|
64
64
|
throw monitorError("monitor_session_id_invalid", "Session ids must contain only letters, numbers, underscores, or hyphens and be 1–128 characters long.", { session_id: sessionId });
|
|
65
65
|
}
|
|
@@ -154,7 +154,7 @@ export function monitorSessionHasActiveMarkerForOwner(hqRoot, provider, sessionI
|
|
|
154
154
|
&& markerOwner.starttime === owner.starttime;
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
function monitorSessionHasInboxFile(hqRoot, provider, sessionId) {
|
|
158
158
|
return fs.existsSync(path.join(monitorSessionDir(hqRoot, provider, sessionId), "dropbox", "inbox.jsonl"));
|
|
159
159
|
}
|
|
160
160
|
export function monitorSessionInboxHasEvents(hqRoot, provider, sessionId) {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/** Mirrors the deploy skill's static-report guardrails. */
|
|
2
|
-
export declare const REPORT_SOURCE_MAX_BYTES: number;
|
|
3
|
-
export declare const REPORT_BUNDLE_MAX_BYTES: number;
|
|
4
|
-
export declare const REPORT_SOURCE_MAX_FILES = 100;
|
|
5
1
|
export declare const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
|
|
6
|
-
|
|
2
|
+
type ReportLastRun = {
|
|
7
3
|
at: string;
|
|
8
4
|
status: "running" | "succeeded" | "failed";
|
|
9
5
|
reason?: string;
|
|
@@ -175,10 +171,5 @@ type BuiltTarball = {
|
|
|
175
171
|
};
|
|
176
172
|
/** hq-deploy static payload format: index.html stays at the archive root. */
|
|
177
173
|
export declare function buildReportTarball(files: StaticFile[]): BuiltTarball;
|
|
178
|
-
/** Isolated test helper for creating a compliant report source. */
|
|
179
|
-
export declare function makeReportFixture(html: string): {
|
|
180
|
-
directory: string;
|
|
181
|
-
cleanup: () => void;
|
|
182
|
-
};
|
|
183
174
|
export {};
|
|
184
175
|
//# sourceMappingURL=report-publish.d.ts.map
|
|
@@ -13,9 +13,9 @@ import { gzipSync } from "node:zlib";
|
|
|
13
13
|
import { REPORT_PREVIEW_FILE } from "./report-snapshot.js";
|
|
14
14
|
import { loadUpdateReportRunbook } from "./report-templates.js";
|
|
15
15
|
/** Mirrors the deploy skill's static-report guardrails. */
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const REPORT_SOURCE_MAX_BYTES = 25 * 1024 * 1024;
|
|
17
|
+
const REPORT_BUNDLE_MAX_BYTES = 10 * 1024 * 1024;
|
|
18
|
+
const REPORT_SOURCE_MAX_FILES = 100;
|
|
19
19
|
export const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
|
|
20
20
|
/**
|
|
21
21
|
* Write the files exactly as they will be published, protected index.html
|
|
@@ -418,10 +418,4 @@ function writeOctal(buffer, value, offset, length) {
|
|
|
418
418
|
buffer.write(value.toString(8).padStart(length - 1, "0").slice(-length + 1), offset, length - 1, "ascii");
|
|
419
419
|
buffer[offset + length - 1] = 0;
|
|
420
420
|
}
|
|
421
|
-
/** Isolated test helper for creating a compliant report source. */
|
|
422
|
-
export function makeReportFixture(html) {
|
|
423
|
-
const directory = fs.mkdtempSync(path.join(os.tmpdir(), "hq-report-test-"));
|
|
424
|
-
fs.writeFileSync(path.join(directory, "index.html"), html);
|
|
425
|
-
return { directory, cleanup: () => fs.rmSync(directory, { recursive: true, force: true }) };
|
|
426
|
-
}
|
|
427
421
|
//# sourceMappingURL=report-publish.js.map
|
|
@@ -11,6 +11,7 @@ export type QmdProcessResult = {
|
|
|
11
11
|
*/
|
|
12
12
|
signal?: NodeJS.Signals | string | null;
|
|
13
13
|
};
|
|
14
|
+
export type QmdUpdateEntryPath = 'index-sync';
|
|
14
15
|
export type QmdProcessRunner = (bin: string, args: string[], options: {
|
|
15
16
|
cwd?: string;
|
|
16
17
|
env?: NodeJS.ProcessEnv;
|
|
@@ -113,6 +114,10 @@ export declare class QmdExitError extends Error {
|
|
|
113
114
|
readonly stdout: string;
|
|
114
115
|
readonly stderr: string;
|
|
115
116
|
name: string;
|
|
117
|
+
/** Safe route labels for telemetry; raw qmd streams remain local to the error. */
|
|
118
|
+
entryPath?: QmdUpdateEntryPath;
|
|
119
|
+
/** Present only when the invoked executable is the bundled qmd. */
|
|
120
|
+
qmdVersion?: string;
|
|
116
121
|
constructor(message: string, args: string[], status: number | null, stdout: string, stderr: string);
|
|
117
122
|
}
|
|
118
123
|
export declare class QmdCollectionMissingError extends QmdExitError {
|
|
@@ -507,6 +512,8 @@ export type ResolveQmdInvocationOptions = {
|
|
|
507
512
|
export declare function resolveQmdInvocation(options?: ResolveQmdInvocationOptions): QmdInvocation;
|
|
508
513
|
export type RunQmdOptions = {
|
|
509
514
|
bin?: string;
|
|
515
|
+
/** Source of an update failure, used only for bounded Sentry tags. */
|
|
516
|
+
entryPath?: QmdUpdateEntryPath;
|
|
510
517
|
cwd?: string;
|
|
511
518
|
env?: NodeJS.ProcessEnv;
|
|
512
519
|
runner?: QmdProcessRunner;
|