@indigoai-us/hq-cli 5.345.6 → 5.345.8
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 +14 -0
- package/dist/commands/__fixtures__/make-tar.d.ts +2 -10
- package/dist/commands/__fixtures__/make-tar.js +2 -2
- package/dist/commands/agent-enroll.d.ts +2 -3
- package/dist/commands/agent-enroll.js +2 -2
- package/dist/commands/mcp-status.d.ts +4 -3
- package/dist/commands/reindex.d.ts +0 -6
- package/dist/commands/reindex.js +1 -1
- package/dist/commands/safe-extract.d.ts +2 -17
- package/dist/commands/safe-extract.js +2 -2
- package/dist/commands/search.d.ts +2 -1
- package/dist/lazy-commands.d.ts +0 -6
- package/dist/lazy-commands.js +1 -1
- package/dist/lib/agent-kit/run/inbox.js +29 -3
- package/dist/lib/daemon/supervisor.d.ts +1 -0
- package/dist/lib/daemon/supervisor.js +97 -12
- package/dist/lib/doctor/__testing__/fake-hq-tree.d.ts +8 -9
- package/dist/lib/doctor/__testing__/fake-hq-tree.js +1 -1
- package/dist/lib/doctor/checks/runtime-probe.d.ts +0 -21
- package/dist/lib/doctor/checks/runtime-probe.js +4 -4
- package/dist/lib/doctor/checks/sync-health.d.ts +2 -3
- package/dist/lib/doctor/checks/sync-health.js +1 -1
- package/dist/lib/doctor/compat.d.ts +2 -1
- package/dist/lib/doctor/deep/classify.d.ts +2 -1
- package/dist/lib/doctor/fix/backup.d.ts +0 -8
- package/dist/lib/doctor/fix/backup.js +2 -2
- package/dist/lib/doctor/fixtures/discover.d.ts +2 -10
- package/dist/lib/doctor/fixtures/discover.js +1 -1
- package/dist/lib/lanes/autopilot.d.ts +2 -17
- package/dist/lib/lanes/autopilot.js +8 -8
- package/dist/lib/lanes/flag-keys.d.ts +2 -0
- package/dist/lib/lanes/flag-keys.js +2 -0
- package/dist/lib/lanes/keep-alive.d.ts +2 -0
- package/dist/lib/lanes/keep-alive.js +9 -0
- package/dist/lib/lanes/reconcile.js +44 -27
- package/dist/lib/lanes/spawn.js +2 -0
- package/dist/lib/lanes/tracker-report.d.ts +16 -15
- package/dist/lib/lanes/wait.d.ts +2 -5
- package/dist/lib/lanes/wait.js +3 -3
- package/dist/lib/local-tree-diff.d.ts +3 -2
- package/dist/lib/search-index/background.d.ts +0 -2
- package/dist/lib/search-index/background.js +1 -1
- package/dist/lib/search-index/index.d.ts +0 -19
- package/dist/lib/search-index/index.js +2 -2
- package/dist/main.d.ts +3 -0
- package/dist/main.js +126 -12
- package/dist/types.d.ts +3 -3
- package/dist/utils/client-health-contract.d.ts +14 -17
- package/dist/utils/client-health-contract.js +11 -11
- package/dist/utils/self-update.d.ts +2 -0
- package/dist/utils/self-update.js +37 -7
- package/package.json +1 -1
|
@@ -47,27 +47,6 @@ export declare const RUNTIME_PROBE_PREFIX = "hooks.runtime";
|
|
|
47
47
|
* `check-hq-hooks.sh` (`LEDGER_DIR="$HQ_ROOT/workspace/orchestrator/policy-trigger-state"`).
|
|
48
48
|
*/
|
|
49
49
|
export declare const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trigger-state";
|
|
50
|
-
/** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
|
|
51
|
-
export declare const REQUIRED_HOOK_EVENTS: readonly ["SessionStart", "PreToolUse"];
|
|
52
|
-
/**
|
|
53
|
-
* Default runtime marker path an agents-v2 (hq-fleet) box writes its runtime mode
|
|
54
|
-
* to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
|
|
55
|
-
* `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
|
|
56
|
-
*/
|
|
57
|
-
export declare const HQ_RUNTIME_MARKER_DEFAULT = "/var/lib/hq-agent/runtime.json";
|
|
58
|
-
/**
|
|
59
|
-
* Path (relative to the HQ root) of the on-box agents-v2 hook adapter. Its
|
|
60
|
-
* presence under the tree is one of the two signals that the runtime is
|
|
61
|
-
* agents-v2, mirroring `hq_runtime_mode` in `check-hq-hooks.sh`.
|
|
62
|
-
*/
|
|
63
|
-
export declare const AGENTS_V2_ADAPTER_RELPATH = ".agents-v2-hooks/hq-agents-v2-hook-adapter.sh";
|
|
64
|
-
/**
|
|
65
|
-
* Default hours a policy-trigger ledger may age and still evidence a live
|
|
66
|
-
* agents-v2 turn when no exact session id is given. Overridable via
|
|
67
|
-
* `HQ_V2_LEDGER_MAX_AGE_HOURS`, matching the shell's
|
|
68
|
-
* `HQ_V2_LEDGER_MAX_AGE_HOURS="${HQ_V2_LEDGER_MAX_AGE_HOURS:-24}"`.
|
|
69
|
-
*/
|
|
70
|
-
export declare const HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT = 24;
|
|
71
50
|
/** Whether the ledger was found. Mirrors the script's `present`/`missing`. */
|
|
72
51
|
export type LedgerState = "present" | "missing";
|
|
73
52
|
/** Options for {@link reproduceCheckHqHooks}. */
|
|
@@ -51,26 +51,26 @@ export const RUNTIME_PROBE_PREFIX = "hooks.runtime";
|
|
|
51
51
|
*/
|
|
52
52
|
export const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trigger-state";
|
|
53
53
|
/** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
|
|
54
|
-
|
|
54
|
+
const REQUIRED_HOOK_EVENTS = ["SessionStart", "PreToolUse"];
|
|
55
55
|
/**
|
|
56
56
|
* Default runtime marker path an agents-v2 (hq-fleet) box writes its runtime mode
|
|
57
57
|
* to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
|
|
58
58
|
* `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
const HQ_RUNTIME_MARKER_DEFAULT = "/var/lib/hq-agent/runtime.json";
|
|
61
61
|
/**
|
|
62
62
|
* Path (relative to the HQ root) of the on-box agents-v2 hook adapter. Its
|
|
63
63
|
* presence under the tree is one of the two signals that the runtime is
|
|
64
64
|
* agents-v2, mirroring `hq_runtime_mode` in `check-hq-hooks.sh`.
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
const AGENTS_V2_ADAPTER_RELPATH = ".agents-v2-hooks/hq-agents-v2-hook-adapter.sh";
|
|
67
67
|
/**
|
|
68
68
|
* Default hours a policy-trigger ledger may age and still evidence a live
|
|
69
69
|
* agents-v2 turn when no exact session id is given. Overridable via
|
|
70
70
|
* `HQ_V2_LEDGER_MAX_AGE_HOURS`, matching the shell's
|
|
71
71
|
* `HQ_V2_LEDGER_MAX_AGE_HOURS="${HQ_V2_LEDGER_MAX_AGE_HOURS:-24}"`.
|
|
72
72
|
*/
|
|
73
|
-
|
|
73
|
+
const HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT = 24;
|
|
74
74
|
/**
|
|
75
75
|
* Faithfully reproduce `core/scripts/check-hq-hooks.sh --require-ledger` in
|
|
76
76
|
* TypeScript. The checks, in the script's order:
|
|
@@ -26,8 +26,6 @@
|
|
|
26
26
|
import type { CheckContext, CheckFamily, CheckResult } from "../types.js";
|
|
27
27
|
/** The id of the versions/sync family. */
|
|
28
28
|
export declare const SYNC_FAMILY_ID = "sync";
|
|
29
|
-
/** Human title for grouped output. */
|
|
30
|
-
export declare const SYNC_FAMILY_TITLE = "Versions & sync";
|
|
31
29
|
/**
|
|
32
30
|
* A journal shard older than this is reported stale. Seven days: long enough
|
|
33
31
|
* that a laptop shut over a weekend never warns, short enough that a silently
|
|
@@ -45,7 +43,7 @@ export interface SyncJournalSummary {
|
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
45
|
/** The component versions this family reports. */
|
|
48
|
-
|
|
46
|
+
interface SyncVersionInfo {
|
|
49
47
|
cli: string;
|
|
50
48
|
core: string | null;
|
|
51
49
|
desktop: string | null;
|
|
@@ -128,4 +126,5 @@ export declare function semverGt(a: string, b: string): boolean;
|
|
|
128
126
|
* something — the daemon, the network, the kill switch — is not running.
|
|
129
127
|
*/
|
|
130
128
|
export declare const STALE_MANIFEST_THRESHOLD_MS: number;
|
|
129
|
+
export {};
|
|
131
130
|
//# sourceMappingURL=sync-health.d.ts.map
|
|
@@ -38,7 +38,7 @@ import { readHqVersion } from "../../../utils/pack-contributions.js";
|
|
|
38
38
|
/** The id of the versions/sync family. */
|
|
39
39
|
export const SYNC_FAMILY_ID = "sync";
|
|
40
40
|
/** Human title for grouped output. */
|
|
41
|
-
|
|
41
|
+
const SYNC_FAMILY_TITLE = "Versions & sync";
|
|
42
42
|
/**
|
|
43
43
|
* A journal shard older than this is reported stale. Seven days: long enough
|
|
44
44
|
* that a laptop shut over a weekend never warns, short enough that a silently
|
|
@@ -36,7 +36,7 @@ export declare const CHECK_HQ_HOOKS_FAIL_EXIT = 2;
|
|
|
36
36
|
* `HQ runtime enforcement: …` line. `NOT CHECKED` is the default when
|
|
37
37
|
* `--require-ledger` was not passed (the wrapper prints "ledger: not checked").
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
type RuntimeObservation = "OBSERVED" | "NOT OBSERVED" | "NOT CHECKED";
|
|
40
40
|
/** The verdict the wrapper renders, derived from a scoped `hq doctor` run. */
|
|
41
41
|
export interface CheckHqHooksVerdict {
|
|
42
42
|
/** True iff the wrapper exits 0 (no in-scope failure, ledger observed when required). */
|
|
@@ -82,4 +82,5 @@ export interface DeriveVerdictOptions {
|
|
|
82
82
|
* what lets `compat.test.ts` prove the wrapper and `hq doctor` agree.
|
|
83
83
|
*/
|
|
84
84
|
export declare function deriveCheckHqHooksVerdict(doc: DoctorJsonDocument, options?: DeriveVerdictOptions): CheckHqHooksVerdict;
|
|
85
|
+
export {};
|
|
85
86
|
//# sourceMappingURL=compat.d.ts.map
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import type { HookFixture } from "../fixtures/schema.js";
|
|
27
27
|
/** A hook's deep-test class: verifiable by verdict, or effect-bearing. */
|
|
28
|
-
|
|
28
|
+
type HookClass = "pure-guard" | "side-effecting";
|
|
29
29
|
/**
|
|
30
30
|
* Substrings that mark a hook id as belonging to a side-effecting family. This
|
|
31
31
|
* is the seed set US-009 names — autocommit, checkpoint, journal, reindex — and
|
|
@@ -58,4 +58,5 @@ export declare function classifyFixture(fixture: HookFixture): Classification;
|
|
|
58
58
|
export declare function isPureGuard(fixture: HookFixture): boolean;
|
|
59
59
|
/** Whether a hook id names a side-effecting hook (US-009's execution surface). */
|
|
60
60
|
export declare function isSideEffectingHookId(hookId: string): boolean;
|
|
61
|
+
export {};
|
|
61
62
|
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
* The module is pure filesystem work with an injectable clock, so the applier's
|
|
12
12
|
* tests get a deterministic backup directory name without racing the wall clock.
|
|
13
13
|
*/
|
|
14
|
-
/** Where backups live under the resolved HQ root. */
|
|
15
|
-
export declare const BACKUP_RELDIR: string;
|
|
16
14
|
/** The result of a backup pass. */
|
|
17
15
|
export interface BackupResult {
|
|
18
16
|
/** Absolute path of the timestamped backup directory. */
|
|
@@ -22,12 +20,6 @@ export interface BackupResult {
|
|
|
22
20
|
/** A single shell command that restores every backed-up file in place. */
|
|
23
21
|
restoreCommand: string;
|
|
24
22
|
}
|
|
25
|
-
/**
|
|
26
|
-
* A filesystem-safe backup directory name derived from an instant, e.g.
|
|
27
|
-
* `2026-08-11T08-30-00-000Z`. Colons and dots — illegal or awkward in paths —
|
|
28
|
-
* are replaced with dashes; the value stays sortable and unique per millisecond.
|
|
29
|
-
*/
|
|
30
|
-
export declare function backupTimestamp(now?: Date): string;
|
|
31
23
|
/**
|
|
32
24
|
* Copy each of `relpaths` (relative to `hqRoot`) into a fresh timestamped backup
|
|
33
25
|
* directory, preserving both the relative path structure and the file mode.
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
import * as fs from "node:fs";
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
/** Where backups live under the resolved HQ root. */
|
|
17
|
-
|
|
17
|
+
const BACKUP_RELDIR = path.join("workspace", "doctor", "backups");
|
|
18
18
|
/**
|
|
19
19
|
* A filesystem-safe backup directory name derived from an instant, e.g.
|
|
20
20
|
* `2026-08-11T08-30-00-000Z`. Colons and dots — illegal or awkward in paths —
|
|
21
21
|
* are replaced with dashes; the value stays sortable and unique per millisecond.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
function backupTimestamp(now = new Date()) {
|
|
24
24
|
return now.toISOString().replace(/[:.]/g, "-");
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
@@ -28,8 +28,6 @@ import type { CheckContext, CheckFamily, CheckResult } from "../types.js";
|
|
|
28
28
|
import { type ParsedFixture } from "./schema.js";
|
|
29
29
|
/** Directory, relative to the HQ root, fixtures are discovered from. */
|
|
30
30
|
export declare const HOOK_TESTS_RELDIR: string;
|
|
31
|
-
/** The id of the fixture-coverage family. */
|
|
32
|
-
export declare const FIXTURES_FAMILY_ID = "fixtures";
|
|
33
31
|
/** checkId of the single coverage-ratio result the report surfaces in its summary. */
|
|
34
32
|
export declare const FIXTURE_COVERAGE_CHECK_ID = "hooks.fixtures.coverage";
|
|
35
33
|
/**
|
|
@@ -45,7 +43,7 @@ export declare const FIXTURE_COVERAGE_CHECK_ID = "hooks.fixtures.coverage";
|
|
|
45
43
|
*/
|
|
46
44
|
export declare function registeredHookIds(hqRoot: string): string[];
|
|
47
45
|
/** A fixture file located on disk and validated (or a YAML-load failure). */
|
|
48
|
-
|
|
46
|
+
interface DiscoveredFixture {
|
|
49
47
|
/** Path relative to the HQ root, e.g. `core/hook-tests/block-core-writes.yaml`. */
|
|
50
48
|
relpath: string;
|
|
51
49
|
/** Absolute path on disk. */
|
|
@@ -74,13 +72,6 @@ export interface FixtureDiscovery {
|
|
|
74
72
|
* looksLikeFixture} are validated and reported.
|
|
75
73
|
*/
|
|
76
74
|
export declare function discoverFixtures(hqRoot: string): FixtureDiscovery;
|
|
77
|
-
/** The coverage tally: how many registered hooks have a usable fixture. */
|
|
78
|
-
export interface FixtureCoverage {
|
|
79
|
-
/** Registered hooks with a valid, recognised-version fixture. */
|
|
80
|
-
tested: number;
|
|
81
|
-
/** Registered hooks in total. */
|
|
82
|
-
total: number;
|
|
83
|
-
}
|
|
84
75
|
/**
|
|
85
76
|
* Run the fixture-coverage tier against the resolved tree: enumerate registered
|
|
86
77
|
* hooks, discover fixtures, and emit UNTESTED / WARN / UNKNOWN results plus the
|
|
@@ -93,4 +84,5 @@ export declare function checkFixtureCoverage(context: CheckContext): CheckResult
|
|
|
93
84
|
* registry contract).
|
|
94
85
|
*/
|
|
95
86
|
export declare const fixtureCoverageFamily: CheckFamily;
|
|
87
|
+
export {};
|
|
96
88
|
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -32,7 +32,7 @@ import { looksLikeFixture, parseFixture, SUPPORTED_FIXTURE_SCHEMA_VERSIONS, } fr
|
|
|
32
32
|
/** Directory, relative to the HQ root, fixtures are discovered from. */
|
|
33
33
|
export const HOOK_TESTS_RELDIR = path.join("core", "hook-tests");
|
|
34
34
|
/** The id of the fixture-coverage family. */
|
|
35
|
-
|
|
35
|
+
const FIXTURES_FAMILY_ID = "fixtures";
|
|
36
36
|
/** checkId of the single coverage-ratio result the report surfaces in its summary. */
|
|
37
37
|
export const FIXTURE_COVERAGE_CHECK_ID = "hooks.fixtures.coverage";
|
|
38
38
|
/** A `*.yaml` file in `core/hook-tests/` that is not a fixture and must be skipped. */
|
|
@@ -2,22 +2,7 @@ import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
|
2
2
|
import type { LaneRecord } from "./types.js";
|
|
3
3
|
export declare const LEAD_AUTOPILOT_FLAG = "lanes.lead-autopilot";
|
|
4
4
|
export declare const LEAD_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = "lanes.autopilot-missed-deadline-escalation";
|
|
5
|
-
|
|
6
|
-
export declare const LEAD_AUTOPILOT_NUDGE_REDELIVERY_DELAY_MS: number;
|
|
7
|
-
export declare const LEAD_AUTOPILOT_NUDGE_STATE_RETENTION_MS: number;
|
|
8
|
-
export declare const LEAD_AUTOPILOT_REVIEW_DELAY_MS: number;
|
|
9
|
-
export declare const LEAD_AUTOPILOT_FILL_DELAY_MS: number;
|
|
10
|
-
export declare const LEAD_AUTOPILOT_PROMPT_LOOP = "personal/knowledge/team-lead-operating-loop.md";
|
|
11
|
-
export declare const LEAD_AUTOPILOT_KPI_STALE_AFTER_MINUTES = 55;
|
|
12
|
-
export declare const LEAD_AUTOPILOT_HEADLINE_STALE_AFTER_MINUTES = 55;
|
|
13
|
-
export interface RegisteredLead {
|
|
14
|
-
team: string;
|
|
15
|
-
lane: string;
|
|
16
|
-
host: string;
|
|
17
|
-
status: string;
|
|
18
|
-
prd: string;
|
|
19
|
-
}
|
|
20
|
-
export type AutopilotCondition = "review_finished_worker" | "fill_grant" | "plan_free_slots" | "flat_kpi" | "stale_kpi" | "stale_headline" | "blocker_record_needs_update" | "project_ready_to_close" | "stale_worker_ledger" | "story_without_live_lane" | "missed_deadline";
|
|
5
|
+
type AutopilotCondition = "review_finished_worker" | "fill_grant" | "plan_free_slots" | "flat_kpi" | "stale_kpi" | "stale_headline" | "blocker_record_needs_update" | "project_ready_to_close" | "stale_worker_ledger" | "story_without_live_lane" | "missed_deadline";
|
|
21
6
|
export interface AutopilotWake {
|
|
22
7
|
condition: AutopilotCondition;
|
|
23
8
|
lead_lane: string;
|
|
@@ -29,7 +14,7 @@ export interface AutopilotWake {
|
|
|
29
14
|
/** Headline episode represented inside the KPI batch notice, if any. */
|
|
30
15
|
headline_fingerprint?: string;
|
|
31
16
|
}
|
|
32
|
-
|
|
17
|
+
interface AutopilotKpiStatus {
|
|
33
18
|
lead_lane: string;
|
|
34
19
|
team: string;
|
|
35
20
|
kpi: string;
|
|
@@ -12,15 +12,15 @@ import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
|
12
12
|
import { readAllLanes } from "./store.js";
|
|
13
13
|
export const LEAD_AUTOPILOT_FLAG = "lanes.lead-autopilot";
|
|
14
14
|
export const LEAD_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = LANE_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const LEAD_AUTOPILOT_MISSED_DEADLINE_ESCALATION_DELAY_MS = 60 * 60_000;
|
|
16
|
+
const LEAD_AUTOPILOT_NUDGE_REDELIVERY_DELAY_MS = 30 * 60_000;
|
|
17
|
+
const LEAD_AUTOPILOT_NUDGE_STATE_RETENTION_MS = 24 * 60 * 60_000;
|
|
18
18
|
const LEAD_AUTOPILOT_DELIVERED_ID_RETENTION_MS = 7 * 24 * 60 * 60_000;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
const LEAD_AUTOPILOT_REVIEW_DELAY_MS = 15 * 60_000;
|
|
20
|
+
const LEAD_AUTOPILOT_FILL_DELAY_MS = 15 * 60_000;
|
|
21
|
+
const LEAD_AUTOPILOT_PROMPT_LOOP = "personal/knowledge/team-lead-operating-loop.md";
|
|
22
|
+
const LEAD_AUTOPILOT_KPI_STALE_AFTER_MINUTES = 55;
|
|
23
|
+
const LEAD_AUTOPILOT_HEADLINE_STALE_AFTER_MINUTES = 55;
|
|
24
24
|
const LIVE_STATES = new Set(["running", "queued", "awaiting_input", "blocked"]);
|
|
25
25
|
const OPEN_STORY_STATES = new Set(["todo", "queued", "in_progress", "review", "blocked"]);
|
|
26
26
|
function isOpenProjectStory(story) {
|
|
@@ -16,6 +16,8 @@ export declare const LANE_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = "lanes.aut
|
|
|
16
16
|
export declare const LANE_MESSAGE_ROUTE_OWNER_HOST_FLAG = "lanes.message-route-owner-host";
|
|
17
17
|
/** Enables stale manager-status KPI reporting and one-time lead nudges. */
|
|
18
18
|
export declare const LEAD_AUTOPILOT_KPI_STALENESS_FLAG = "lanes.autopilot-kpi-staleness";
|
|
19
|
+
/** Enables precise scheduling and priority admission for due lead keep-alive wakes. */
|
|
20
|
+
export declare const LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG = "lanes.keep-alive-due-wake-precise";
|
|
19
21
|
/** Enables staleness notices for a registered lead's dashboard headline. */
|
|
20
22
|
export declare const LEAD_AUTOPILOT_HEADLINE_STALENESS_FLAG = "lanes.autopilot-headline-staleness";
|
|
21
23
|
/** Lets an Outpost's autopilot wake leads created on that Outpost, which record a local host. */
|
|
@@ -16,6 +16,8 @@ export const LANE_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = "lanes.autopilot-m
|
|
|
16
16
|
export const LANE_MESSAGE_ROUTE_OWNER_HOST_FLAG = "lanes.message-route-owner-host";
|
|
17
17
|
/** Enables stale manager-status KPI reporting and one-time lead nudges. */
|
|
18
18
|
export const LEAD_AUTOPILOT_KPI_STALENESS_FLAG = "lanes.autopilot-kpi-staleness";
|
|
19
|
+
/** Enables precise scheduling and priority admission for due lead keep-alive wakes. */
|
|
20
|
+
export const LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG = "lanes.keep-alive-due-wake-precise";
|
|
19
21
|
/** Enables staleness notices for a registered lead's dashboard headline. */
|
|
20
22
|
export const LEAD_AUTOPILOT_HEADLINE_STALENESS_FLAG = "lanes.autopilot-headline-staleness";
|
|
21
23
|
/** Lets an Outpost's autopilot wake leads created on that Outpost, which record a local host. */
|
|
@@ -44,6 +44,8 @@ export interface KeepAliveDoneEnvelope {
|
|
|
44
44
|
}
|
|
45
45
|
export type DoneKeepAliveVerdict = "eligible" | "standing_idle" | "story_complete" | "next_check_at";
|
|
46
46
|
export declare function keepAliveNextCheckAtMs(value: unknown, nowMs: number, anchorMs?: number): number | undefined;
|
|
47
|
+
/** Shared due-time decision for pre-admission ordering and the resume path. */
|
|
48
|
+
export declare function dueKeepAliveNextCheckMs(nextCheckMs: number, nowMs: number, anchorMs: number, preciseDueWakeEnabled: boolean): number | undefined;
|
|
47
49
|
/** Shared done-state policy used by watch, reconcile, and the show command. */
|
|
48
50
|
export declare function doneKeepAliveVerdict(lane: Pick<LaneRecord, "keep_alive_standing">, envelope: KeepAliveDoneEnvelope, hasQueuedWork: boolean, options?: {
|
|
49
51
|
hasPendingWork?: boolean;
|
|
@@ -113,6 +113,15 @@ export function keepAliveNextCheckAtMs(value, nowMs, anchorMs = nowMs) {
|
|
|
113
113
|
const capped = Math.min(parsed, stableAnchorMs + LEAD_LANE_KEEP_ALIVE_NEXT_CHECK_MAX_DELAY_MS);
|
|
114
114
|
return capped > nowMs ? capped : undefined;
|
|
115
115
|
}
|
|
116
|
+
/** Shared due-time decision for pre-admission ordering and the resume path. */
|
|
117
|
+
export function dueKeepAliveNextCheckMs(nextCheckMs, nowMs, anchorMs, preciseDueWakeEnabled) {
|
|
118
|
+
if (!Number.isFinite(nextCheckMs) || !Number.isFinite(nowMs) || !Number.isFinite(anchorMs))
|
|
119
|
+
return undefined;
|
|
120
|
+
const capped = Math.min(nextCheckMs, anchorMs + LEAD_LANE_KEEP_ALIVE_NEXT_CHECK_MAX_DELAY_MS);
|
|
121
|
+
if (capped > nowMs || (preciseDueWakeEnabled && capped <= anchorMs))
|
|
122
|
+
return undefined;
|
|
123
|
+
return capped;
|
|
124
|
+
}
|
|
116
125
|
/** Shared done-state policy used by watch, reconcile, and the show command. */
|
|
117
126
|
export function doneKeepAliveVerdict(lane, envelope, hasQueuedWork, options = {}) {
|
|
118
127
|
if (envelope.decision !== "done")
|
|
@@ -22,12 +22,12 @@ import { ANSWERED_QUESTIONS_FILE, armLaneWatcher, envelopeRepairMode, isPidRecor
|
|
|
22
22
|
import { appendCappedHistory, lanesStoreRoot, parseLaneRecord, parseQuestionRecord, readLane, readQuestion, listQuestionIds, updateLane, updateQuestion, } from "./store.js";
|
|
23
23
|
import { applyThrottleDecision, decideAdmission, defaultThrottleDeps, emptyThrottleState, evaluateThrottle, isCpuCheckEnabled, readAvailableMemMb, readThrottleState, resolveCpuBusyFraction, sampleCpuBusyObservation, recordCpuBusyObservation, throttleStatePath, writeThrottleState, } from "./throttle.js";
|
|
24
24
|
import { readLanesRegistryFlag, readLanesRegistryFlagFailOff } from "./registry-flag.js";
|
|
25
|
-
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_LEAD_ADMISSION_PRIORITY_FLAG } from "./flag-keys.js";
|
|
25
|
+
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, LANE_LEAD_ADMISSION_PRIORITY_FLAG, } from "./flag-keys.js";
|
|
26
26
|
import { checkLaneDiskSpace, configuredCodexRolloutHomes, laneDiskAccount, retainCodexRollouts } from "./disk-guard.js";
|
|
27
27
|
import { laneCompanyUidSource, resolveLaneCompany } from "./lane-company.js";
|
|
28
28
|
import { appendDropboxMessage } from "./dropbox.js";
|
|
29
29
|
import { DEFAULT_RUNAWAY_SEARCH_GUARD_CONFIG, listHostProcesses, runRunawayToolGuard, RUNAWAY_TOOL_GUARD_FLAG, } from "./runaway-tool-guard.js";
|
|
30
|
-
import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS,
|
|
30
|
+
import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_GRACE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_RESUME_TEXT, queueLaneTerminalResume, LEAD_LANE_KEEP_ALIVE_INTERRUPTED_RESUME_TEXT, LEAD_LANE_KEEP_ALIVE_MAX_RESUMES, LEAD_LANE_KEEP_ALIVE_RESUME_TEXT, LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, doneKeepAliveVerdict, dueKeepAliveNextCheckMs, hasPendingKeepAliveWork, keepAliveNextCheckAtMs, keepAliveExclusion, loadRetiredLaneIds, leadLaneKeepAliveBackoffMs, undeliveredAnsweredQuestions, } from "./keep-alive.js";
|
|
31
31
|
import { providerSupportsSessionResume } from "./delivery.js";
|
|
32
32
|
import { isIsoDateTime } from "./types.js";
|
|
33
33
|
import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, loadQuotaState, readQuotaSignal, recordAccountQuota, } from "./quota.js";
|
|
@@ -1236,6 +1236,7 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1236
1236
|
const keepAliveFlagByCompany = new Map();
|
|
1237
1237
|
const blockedResumeFlagByCompany = new Map();
|
|
1238
1238
|
const immediateFirstResumeFlagByCompany = new Map();
|
|
1239
|
+
const preciseDueWakeFlagByCompany = new Map();
|
|
1239
1240
|
const supersessionLineageAwareByCompany = new Map();
|
|
1240
1241
|
await Promise.all([...keepAliveFlagCompanies.entries()].map(async ([key, company]) => {
|
|
1241
1242
|
const options = {
|
|
@@ -1246,17 +1247,19 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1246
1247
|
lane.keep_alive === true &&
|
|
1247
1248
|
laneRunsHere(lane, startDeps.host) &&
|
|
1248
1249
|
keepAliveCompanyKey(resolveLaneCompany(hqRoot, lane).company) === key);
|
|
1249
|
-
const [keepAliveEnabled, lineageAware, blockedResumeEnabled, immediateFirstResumeEnabled] = await Promise.all([
|
|
1250
|
+
const [keepAliveEnabled, lineageAware, blockedResumeEnabled, immediateFirstResumeEnabled, preciseDueWakeEnabled] = await Promise.all([
|
|
1250
1251
|
readRegistryFlag(LEAD_LANE_KEEP_ALIVE_FLAG, options),
|
|
1251
1252
|
readRegistryFlag(LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, options),
|
|
1252
1253
|
hasBlockedKeepAliveLane
|
|
1253
1254
|
? readRegistryFlag(LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, options)
|
|
1254
1255
|
: Promise.resolve(false),
|
|
1255
1256
|
readRegistryFlag(LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, options),
|
|
1257
|
+
readRegistryFlag(LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, options),
|
|
1256
1258
|
]);
|
|
1257
1259
|
keepAliveFlagByCompany.set(key, keepAliveEnabled);
|
|
1258
1260
|
blockedResumeFlagByCompany.set(key, blockedResumeEnabled);
|
|
1259
1261
|
immediateFirstResumeFlagByCompany.set(key, immediateFirstResumeEnabled);
|
|
1262
|
+
preciseDueWakeFlagByCompany.set(key, preciseDueWakeEnabled);
|
|
1260
1263
|
supersessionLineageAwareByCompany.set(key, lineageAware);
|
|
1261
1264
|
}));
|
|
1262
1265
|
const admissionThrottleDeps = startDeps.throttleDeps ?? defaultThrottleDeps(startDeps.env ?? process.env);
|
|
@@ -1278,7 +1281,7 @@ export async function runPassBody(hqRoot, deps) {
|
|
|
1278
1281
|
const freshLanes = loadLaneRecords(hqRoot, summary);
|
|
1279
1282
|
const freshQuestions = loadQuestionRecords(hqRoot, summary);
|
|
1280
1283
|
await closeInterruptedDoneStoryWorkers(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, storyCloseEnabledByCompany);
|
|
1281
|
-
const dueKeepAlivesAdmitted = await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, keepAliveFlagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, deps.terminalKeepAliveCandidate, async (laneIds) => {
|
|
1284
|
+
const dueKeepAlivesAdmitted = await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, admissionDeps, now, keepAliveFlagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, preciseDueWakeFlagByCompany, deps.terminalKeepAliveCandidate, async (laneIds) => {
|
|
1282
1285
|
dueKeepAliveLaneIds = new Set(laneIds);
|
|
1283
1286
|
await admitQueued(hqRoot, loadLaneRecords(hqRoot, summary), summary, admissionDeps, now, laneIds);
|
|
1284
1287
|
});
|
|
@@ -2513,7 +2516,7 @@ function appendBlockedKeepAliveHistory(hqRoot, lane, terminalAt, at, reason, dep
|
|
|
2513
2516
|
}),
|
|
2514
2517
|
}), false);
|
|
2515
2518
|
}
|
|
2516
|
-
async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, flagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, terminalKeepAliveCandidate, admitDueCandidates) {
|
|
2519
|
+
async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, flagByCompany, supersessionLineageAwareByCompany, blockedResumeFlagByCompany, immediateFirstResumeFlagByCompany, preciseDueWakeFlagByCompany, terminalKeepAliveCandidate, admitDueCandidates) {
|
|
2517
2520
|
const nowMs = now.getTime();
|
|
2518
2521
|
const nowIso = now.toISOString();
|
|
2519
2522
|
const config = loadLanesConfig(hqRoot);
|
|
@@ -2546,10 +2549,14 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2546
2549
|
continue;
|
|
2547
2550
|
const anchorMs = Date.parse(lane.last_envelope?.at ?? lane.updated_at);
|
|
2548
2551
|
const nextCheckMs = Date.parse(envelope.next_check_at ?? "");
|
|
2549
|
-
if (!Number.isFinite(anchorMs)
|
|
2552
|
+
if (!Number.isFinite(anchorMs))
|
|
2550
2553
|
continue;
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2554
|
+
const companyKey = keepAliveCompanyKey(resolveLaneCompany(hqRoot, lane).company);
|
|
2555
|
+
const preciseDueWakeEnabled = preciseDueWakeFlagByCompany.get(companyKey) === true;
|
|
2556
|
+
// This set only accelerates lanes with an explicit due next-check. Retry
|
|
2557
|
+
// backoff is decided once in the resume path and queuedDueCandidateIds.
|
|
2558
|
+
const dueNextCheckMs = dueKeepAliveNextCheckMs(nextCheckMs, nowMs, anchorMs, preciseDueWakeEnabled);
|
|
2559
|
+
if (dueNextCheckMs !== undefined &&
|
|
2553
2560
|
doneKeepAliveVerdict(lane, envelope, false, { nowMs, nextCheckAnchorMs: anchorMs }) === "eligible")
|
|
2554
2561
|
dueCandidateIds.add(lane.lane_id);
|
|
2555
2562
|
}
|
|
@@ -2939,23 +2946,13 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2939
2946
|
const storedNextMs = resetByHuman
|
|
2940
2947
|
? Number.NaN
|
|
2941
2948
|
: Date.parse(current.keep_alive_next_eligible_at ?? "");
|
|
2942
|
-
|
|
2949
|
+
let nextEligibleMs = Number.isFinite(storedNextMs)
|
|
2943
2950
|
? Math.max(attemptEligibleMs, storedNextMs)
|
|
2944
2951
|
: attemptEligibleMs;
|
|
2945
|
-
if (nowMs < nextEligibleMs) {
|
|
2946
|
-
let skipLane = current;
|
|
2947
|
-
if (resetByHuman && hasKeepAliveProgress(current)) {
|
|
2948
|
-
const clearedProgress = casLaneIf(hqRoot, current.lane_id, (latestLane) => latestLane.version === current.version &&
|
|
2949
|
-
latestLane.state === current.state &&
|
|
2950
|
-
latestLane.keep_alive === true &&
|
|
2951
|
-
latestLane.keep_alive_opted_in_at === current.keep_alive_opted_in_at, (latestLane) => clearedKeepAliveProgress(latestLane), deps.dryRun);
|
|
2952
|
-
skipLane = clearedProgress.record;
|
|
2953
|
-
}
|
|
2954
|
-
recordKeepAliveSkipEvent(hqRoot, skipLane, "backoff", skipLane.version, summary, deps, new Date(nextEligibleMs).toISOString());
|
|
2955
|
-
continue;
|
|
2956
|
-
}
|
|
2957
|
-
const nextEligibleAt = new Date(nowMs + leadLaneKeepAliveBackoffMs(immediateFirstResumeEnabled ? attempt : attempt + 1)).toISOString();
|
|
2958
2952
|
let resumeReason = "backoff";
|
|
2953
|
+
let dueNextCheckMs;
|
|
2954
|
+
const preciseDueWakeEnabled = initialState === "done" &&
|
|
2955
|
+
preciseDueWakeFlagByCompany.get(keepAliveCompanyKey(companyForLane(current))) === true;
|
|
2959
2956
|
if (initialState === "done") {
|
|
2960
2957
|
if (hasPendingKeepAliveWork(hqRoot, current, questions)) {
|
|
2961
2958
|
resumeReason = "pending_work";
|
|
@@ -2965,13 +2962,30 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
2965
2962
|
const nextCheckMs = Date.parse(finalEnvelope?.next_check_at ?? "");
|
|
2966
2963
|
const anchorMs = Date.parse(current.last_envelope?.at ?? current.updated_at);
|
|
2967
2964
|
if (Number.isFinite(nextCheckMs) && Number.isFinite(anchorMs)) {
|
|
2968
|
-
const
|
|
2969
|
-
if (
|
|
2965
|
+
const eligibleNextCheckMs = dueKeepAliveNextCheckMs(nextCheckMs, nowMs, anchorMs, preciseDueWakeEnabled);
|
|
2966
|
+
if (eligibleNextCheckMs !== undefined &&
|
|
2967
|
+
(preciseDueWakeEnabled || eligibleNextCheckMs > nextEligibleMs)) {
|
|
2970
2968
|
resumeReason = "next_check_at_due";
|
|
2969
|
+
dueNextCheckMs = eligibleNextCheckMs;
|
|
2970
|
+
if (preciseDueWakeEnabled)
|
|
2971
|
+
nextEligibleMs = Math.min(nextEligibleMs, eligibleNextCheckMs);
|
|
2971
2972
|
}
|
|
2972
2973
|
}
|
|
2973
2974
|
}
|
|
2974
2975
|
}
|
|
2976
|
+
if (nowMs < nextEligibleMs) {
|
|
2977
|
+
let skipLane = current;
|
|
2978
|
+
if (resetByHuman && hasKeepAliveProgress(current)) {
|
|
2979
|
+
const clearedProgress = casLaneIf(hqRoot, current.lane_id, (latestLane) => latestLane.version === current.version &&
|
|
2980
|
+
latestLane.state === current.state &&
|
|
2981
|
+
latestLane.keep_alive === true &&
|
|
2982
|
+
latestLane.keep_alive_opted_in_at === current.keep_alive_opted_in_at, (latestLane) => clearedKeepAliveProgress(latestLane), deps.dryRun);
|
|
2983
|
+
skipLane = clearedProgress.record;
|
|
2984
|
+
}
|
|
2985
|
+
recordKeepAliveSkipEvent(hqRoot, skipLane, "backoff", skipLane.version, summary, deps, new Date(nextEligibleMs).toISOString());
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const nextEligibleAt = new Date(nowMs + leadLaneKeepAliveBackoffMs(immediateFirstResumeEnabled ? attempt : attempt + 1)).toISOString();
|
|
2975
2989
|
const queuedCount = loadLaneRecords(hqRoot, summary).filter((queuedLane) => queuedLane.state === "queued" &&
|
|
2976
2990
|
queuedLane.provider === current.provider &&
|
|
2977
2991
|
laneRunsHere(queuedLane, deps.host) &&
|
|
@@ -3233,7 +3247,8 @@ async function resumeKeepAlive(hqRoot, lanes, questions, summary, deps, now, fla
|
|
|
3233
3247
|
}
|
|
3234
3248
|
if (!queued.changed)
|
|
3235
3249
|
continue;
|
|
3236
|
-
if (resumeReason === "next_check_at_due"
|
|
3250
|
+
if (resumeReason === "next_check_at_due" ||
|
|
3251
|
+
(preciseDueWakeEnabled && initialState === "done" && nowMs >= nextEligibleMs && dueNextCheckMs === undefined))
|
|
3237
3252
|
queuedDueCandidateIds.add(current.lane_id);
|
|
3238
3253
|
summary.resumed.push({
|
|
3239
3254
|
id: current.lane_id,
|
|
@@ -3478,11 +3493,13 @@ async function runTerminalKeepAliveCandidatePass(hqRoot, lanes, summary, deps, n
|
|
|
3478
3493
|
let keepAliveEnabled;
|
|
3479
3494
|
let lineageAware;
|
|
3480
3495
|
let immediateFirstResumeEnabled;
|
|
3496
|
+
let preciseDueWakeEnabled;
|
|
3481
3497
|
try {
|
|
3482
|
-
[keepAliveEnabled, lineageAware, immediateFirstResumeEnabled] = await Promise.all([
|
|
3498
|
+
[keepAliveEnabled, lineageAware, immediateFirstResumeEnabled, preciseDueWakeEnabled] = await Promise.all([
|
|
3483
3499
|
readFlag(LEAD_LANE_KEEP_ALIVE_FLAG, options),
|
|
3484
3500
|
readFlag(LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, options),
|
|
3485
3501
|
readFlag(LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, options),
|
|
3502
|
+
readFlag(LANE_KEEP_ALIVE_DUE_WAKE_PRECISE_FLAG, options),
|
|
3486
3503
|
]);
|
|
3487
3504
|
}
|
|
3488
3505
|
catch (err) {
|
|
@@ -3497,7 +3514,7 @@ async function runTerminalKeepAliveCandidatePass(hqRoot, lanes, summary, deps, n
|
|
|
3497
3514
|
const current = freshLanes.find((row) => row.lane_id === candidate.laneId);
|
|
3498
3515
|
if (!current || current.version !== candidate.version || current.state !== "done")
|
|
3499
3516
|
return;
|
|
3500
|
-
await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, deps, now, new Map([[keepAliveCompanyKey(company), true]]), new Map([[keepAliveCompanyKey(company), lineageAware]]), new Map(), new Map([[keepAliveCompanyKey(company), immediateFirstResumeEnabled]]), candidate);
|
|
3517
|
+
await resumeKeepAlive(hqRoot, freshLanes, freshQuestions, summary, deps, now, new Map([[keepAliveCompanyKey(company), true]]), new Map([[keepAliveCompanyKey(company), lineageAware]]), new Map(), new Map([[keepAliveCompanyKey(company), immediateFirstResumeEnabled]]), new Map([[keepAliveCompanyKey(company), preciseDueWakeEnabled]]), candidate);
|
|
3501
3518
|
await admitQueued(hqRoot, loadLaneRecords(hqRoot, summary), summary, deps, now, new Set([candidate.laneId]));
|
|
3502
3519
|
});
|
|
3503
3520
|
return summary;
|
package/dist/lib/lanes/spawn.js
CHANGED
|
@@ -2421,6 +2421,8 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
|
2421
2421
|
...(resumeHistoryCaller ? { caller: resumeHistoryCaller } : {}),
|
|
2422
2422
|
}),
|
|
2423
2423
|
}));
|
|
2424
|
+
}
|
|
2425
|
+
if (priorStartRecorded || resume !== undefined) {
|
|
2424
2426
|
appendLaneWorkerResumeEvent({
|
|
2425
2427
|
hqRoot,
|
|
2426
2428
|
laneId: lane.lane_id,
|
|
@@ -3,12 +3,12 @@ import type { QuestionRecord } from "./types.js";
|
|
|
3
3
|
import type { TrackerRecord } from "./tracker-store.js";
|
|
4
4
|
export type ReportStoryStatus = "queued" | "in_progress" | "review" | "done" | "dropped";
|
|
5
5
|
export type ReportAudience = "owner" | "operator" | "lane";
|
|
6
|
-
|
|
6
|
+
type ApprovalState = "proposal" | "approved";
|
|
7
7
|
export interface TrackerReportRecord extends TrackerRecord {
|
|
8
8
|
/** Absolute path of the validated on-disk record; used only in errors. */
|
|
9
9
|
source_path: string;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
interface TrackerReportStory {
|
|
12
12
|
id: string;
|
|
13
13
|
title: string;
|
|
14
14
|
status: ReportStoryStatus;
|
|
@@ -24,18 +24,18 @@ export interface TrackerReportIssue {
|
|
|
24
24
|
record_id?: string;
|
|
25
25
|
question_id?: string;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
interface TrackerReportPullRequest {
|
|
28
28
|
number: string;
|
|
29
29
|
title: string;
|
|
30
30
|
merged_at: string;
|
|
31
31
|
source_path: string;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
interface TrackerReportRelease {
|
|
34
34
|
version: string;
|
|
35
35
|
released_at: string;
|
|
36
36
|
source_path: string;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
interface TrackerReportQuestion {
|
|
39
39
|
record: QuestionRecord;
|
|
40
40
|
/** Loaded through the existing company-checked question body reader. */
|
|
41
41
|
body: QuestionBody;
|
|
@@ -63,22 +63,22 @@ export interface TrackerReportInput {
|
|
|
63
63
|
since_source: "explicit" | "previous_report" | "first_run";
|
|
64
64
|
teams: readonly TrackerReportTeamInput[];
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
interface ReportTimedStory {
|
|
67
67
|
id: string;
|
|
68
68
|
title: string;
|
|
69
69
|
at: string;
|
|
70
70
|
references: string[];
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
interface ReportPullRequest {
|
|
73
73
|
number: string;
|
|
74
74
|
title: string;
|
|
75
75
|
merged_at: string;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
interface ReportRelease {
|
|
78
78
|
version: string;
|
|
79
79
|
released_at: string;
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
interface ReportKpiValue {
|
|
82
82
|
kpi_id: string;
|
|
83
83
|
name: string;
|
|
84
84
|
at: string;
|
|
@@ -86,7 +86,7 @@ export interface ReportKpiValue {
|
|
|
86
86
|
unit: string;
|
|
87
87
|
source: string;
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
interface ReportQuestion {
|
|
90
90
|
question_id: string;
|
|
91
91
|
question: string;
|
|
92
92
|
asked_at: string;
|
|
@@ -99,7 +99,7 @@ export interface ReportQuestion {
|
|
|
99
99
|
answered_by: string;
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
interface ReportBlocker {
|
|
103
103
|
id: string;
|
|
104
104
|
story_id: string;
|
|
105
105
|
what: string;
|
|
@@ -107,7 +107,7 @@ export interface ReportBlocker {
|
|
|
107
107
|
next_step: string;
|
|
108
108
|
opened_at: string;
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
interface ReportDirective {
|
|
111
111
|
id: string;
|
|
112
112
|
text: string;
|
|
113
113
|
date: string;
|
|
@@ -117,7 +117,7 @@ export interface ReportDirective {
|
|
|
117
117
|
at: string;
|
|
118
118
|
}>;
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
interface TrackerOwnerTeamReport {
|
|
121
121
|
team: string;
|
|
122
122
|
project_id: string;
|
|
123
123
|
errors: TrackerReportIssue[];
|
|
@@ -142,7 +142,7 @@ export interface TrackerOwnerReport {
|
|
|
142
142
|
since_source: TrackerReportInput["since_source"];
|
|
143
143
|
teams: TrackerOwnerTeamReport[];
|
|
144
144
|
}
|
|
145
|
-
|
|
145
|
+
interface TrackerTeamKpi {
|
|
146
146
|
id: string;
|
|
147
147
|
name: string;
|
|
148
148
|
definition: string;
|
|
@@ -162,7 +162,7 @@ export interface TrackerTeamKpi {
|
|
|
162
162
|
}>;
|
|
163
163
|
trend: "improving" | "regressing" | "flat" | "insufficient_data";
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
interface TrackerTeamOkr {
|
|
166
166
|
id: string;
|
|
167
167
|
objective: string;
|
|
168
168
|
period: string;
|
|
@@ -200,4 +200,5 @@ export declare function buildTrackerTeamPage(team: TrackerReportTeamInput, compa
|
|
|
200
200
|
export declare function renderTrackerOwnerReportText(report: TrackerOwnerReport): string;
|
|
201
201
|
/** Human-readable team page, with proposal status visible beside each objective and KPI. */
|
|
202
202
|
export declare function renderTrackerTeamPageText(page: TrackerTeamPage): string;
|
|
203
|
+
export {};
|
|
203
204
|
//# sourceMappingURL=tracker-report.d.ts.map
|