@gajae-code/coding-agent 0.14.2-nightly.20260818150120.32333814007.gd49c40a6c3c0 → 0.14.2
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 +24 -0
- package/dist/types/cli/crash-cli.d.ts +12 -0
- package/dist/types/commands/crash.d.ts +3 -2
- package/dist/types/commands/ralplan.d.ts +3 -0
- package/dist/types/config/settings-schema.d.ts +19 -0
- package/dist/types/crash/index-store.d.ts +6 -0
- package/dist/types/crash/upstream/dsn.d.ts +22 -0
- package/dist/types/crash/upstream/envelope.d.ts +38 -0
- package/dist/types/crash/upstream/relay.d.ts +138 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +16 -0
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/sdk/broker/broker.d.ts +8 -0
- package/dist/types/sdk/broker/discovery.d.ts +1 -0
- package/dist/types/sdk/bus/notification-service.d.ts +2 -10
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/session/provider-safety-stop-hint.d.ts +79 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/tools/ask.d.ts +8 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/utils/herdr-pane.d.ts +18 -5
- package/package.json +7 -7
- package/src/cli/config-cli.ts +67 -0
- package/src/cli/crash-cli.ts +36 -0
- package/src/commands/crash.ts +12 -6
- package/src/commands/ralplan.ts +23 -3
- package/src/config/model-registry.ts +48 -17
- package/src/config/settings-schema.ts +22 -0
- package/src/config/settings.ts +13 -2
- package/src/crash/index-store.ts +52 -2
- package/src/crash/upstream/dsn.ts +89 -0
- package/src/crash/upstream/envelope.ts +152 -0
- package/src/crash/upstream/relay.ts +451 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +10 -9
- package/src/extensibility/runtime-skill-discovery.ts +35 -0
- package/src/gjc-runtime/ralplan-runtime.ts +243 -41
- package/src/gjc-runtime/team-runtime.ts +7 -1
- package/src/internal-urls/docs-index.generated.ts +4 -3
- package/src/modes/components/assistant-message.ts +24 -0
- package/src/modes/controllers/event-controller.ts +1 -0
- package/src/modes/interactive-mode.ts +23 -0
- package/src/modes/print-mode.ts +5 -0
- package/src/modes/utils/ui-helpers.ts +2 -0
- package/src/prompts/agent-fragments/ralplan-persistence.md +2 -2
- package/src/sdk/broker/broker.ts +115 -14
- package/src/sdk/broker/discovery.ts +19 -2
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +36 -3
- package/src/sdk/bus/notification-service.ts +126 -30
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/session.ts +7 -0
- package/src/session/agent-session.ts +43 -10
- package/src/session/blob-store.ts +10 -1
- package/src/session/provider-safety-stop-hint.ts +187 -0
- package/src/session/session-manager.ts +121 -10
- package/src/tools/ask-contract.ts +70 -1
- package/src/tools/ask.ts +8 -0
- package/src/tools/descriptors.test.ts +72 -0
- package/src/tools/index.ts +2 -0
- package/src/tools/subagent.ts +9 -0
- package/src/utils/herdr-pane.ts +250 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.14.2] - 2026-08-20
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Added an opt-in crash upstream relay for cross-install aggregation. Handled tool errors are captured and relayed to a configurable Sentry upstream; relayed-upstream state transitions are journaled and indexed; and the relay is hardened across the trust boundary (no unsigned provenance), delivery watermarks (no replay races), egress and durability (bounded queues, LRU-bounded handled dedupe, restored fatal-occurrence journaling), and recovery/provenance paths closed by exact-head review. The generated config schema was regenerated after the global-only relay settings. Off by default; enabling requires explicit operator opt-in.
|
|
9
|
+
- Added a manual-switch hint after provider safety stops: when a provider halts a turn for a safety reason, the session now surfaces that the operator can switch models/providers manually instead of leaving the stop unexplained (#4650, #4653).
|
|
10
|
+
- Shift+Tab effort cycling now wins over profile suffixes, and operator-intent effort is distinguished from model-default appends, so explicit effort choices are no longer silently overridden at restore time (#4695, #4700).
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Fixed worker runtime state under `.gjc/state` being swept into leader-repository auto-checkpoints during team runs; checkpoint classification now excludes it (#4603).
|
|
14
|
+
- Fixed ralplan explicit-target worktree handling end to end: runs bind to the explicit `--worktree-root` instead of fragmenting by writer cwd, a trailing `--worktree-root` with no operand is rejected, HEAD objects are verified and explicit-target writes contained, mutation fails closed on review findings, and `.gjc` is confined before migration and fails closed without procfs.
|
|
15
|
+
- Fixed SDK broker liveness (#4704): a broker that stops publishing while its process stays alive is now terminated; the retained broker heartbeat and watchdog observation run off the JS thread; shutdown and observation no longer hold the retained writer lock; stale watchdog observations are fenced during teardown; startup admission reopens after authority recheck; and retained work is fenced across broker restarts.
|
|
16
|
+
- Fixed agent steering losing or racing user input: a steer that interrupts an in-flight tool is delivered, the remaining abort-race gaps in steer-after-tool-interrupt are closed, and a live subagent await ends when user steering arrives instead of hanging.
|
|
17
|
+
- Fixed rotating agent environment credentials not being reloaded and hardened the rotation path so concurrent readers never observe a partially written credential set.
|
|
18
|
+
- Fixed the config CLI reporting success when a setting was not durably saved, and made retargeted CLI persistence fail closed instead of writing to an unintended target.
|
|
19
|
+
- Fixed session robustness: a fatal resident blob now names the session and leaves a record; the corrupted-sentinel lane the strict check walked past is closed; and the transition materialize lane is bound and the dead invalid-ref guard dropped.
|
|
20
|
+
- Fixed notification/herdr integration: recovery no longer re-quarantines native exchange debris, debris cleanup binds to native identity, pane authority binds to process identity so a nested gjc cannot release its parent pane's agent authority, and the native lint gate is satisfied.
|
|
21
|
+
- Fixed `/usage` not surfacing cached usage for API-key credentials in `getCachedUsageReport` (#4686), and made the account-inventory usage tests hermetic on credential-free hosts (#4663).
|
|
22
|
+
- Fixed the auth gateway rejecting explicit `null` fields on openai-chat requests (#4667).
|
|
23
|
+
- Fixed Grok Build turns stalling by giving the provider the same 300s idle window other long-turn providers use.
|
|
24
|
+
- Fixed skill discovery ignoring `skills.customDirectories`; configured directories are now scanned (#4713).
|
|
25
|
+
- Fixed the escaped-non-ASCII em-dash exemption applying beyond display-only tools (#4627).
|
|
26
|
+
- Fixed deep-interview Round 0 ask calls omitting required intent metadata, which produced HTTP 400 rejections on strict providers (#4651).
|
|
27
|
+
- Fixed SDK terminal-in-progress prompt submissions being dropped past the delivery TTL.
|
|
28
|
+
- Fixed postmortem tests writing into the real crash store; they now isolate into a fresh store.
|
|
5
29
|
## [0.14.1] - 2026-08-18
|
|
6
30
|
- Fixed a resident-cache demotion aborting the turn it was supposed to rescue. The demotion is the salvage that runs *because* the cache already failed, so it materializes a store that is by definition missing blobs — yet it was the one materialize call site that never passed `missingPolicy`, inheriting the fail-closed default. It therefore threw `ResidentBlobMissingError` on the very entry it existed to rescue, the transition never committed, the store stayed broken, and every later turn repeated the same throw out of the `message_end` handler. That handler only `logger.warn`s, so the operator saw a bare `Operation aborted` with every pending tool marked `Tool execution was aborted.` and nothing naming a cache, a blob, or an errno — permanently, until the session was restarted. The salvage now substitutes the same placeholder the persistence path already uses, which never emits a `blob:sha256:` ref, so the invariant the fail-closed policy protects is preserved while the session stays usable. Unrecoverable substitutions are counted in `residentBlobPlaceholderCount` and logged once each with their kind, hash, and the demotion's errno, so silent content loss is visible rather than inferred.
|
|
7
31
|
- Fixed the resident-cache GC reaping the cache of a *running* session, which made long-lived sessions abort every turn with an unexplained `Operation aborted`. The owner lease stores a process start time purely to detect PID reuse, and derived it from `ps -o lstart=` — a zoneless local wall clock rendered from `/etc/localtime` by `ps`, then bound to a zone by `Date.parse` in the reading runtime. Those are two independent zone resolutions: pinning `LC_ALL`/`LANG` stabilized the *format* but not the *instant*, so a reader whose runtime resolved UTC while `ps` rendered UTC+9 computed a start time nine hours off for the same live PID, declared the owner reused, and deleted its instance directory. Observed in the wild: a test process reaped the live instance directories of two running sessions in the same sweep (captured at 32,400,000 ms of skew, exactly the host offset). Each victim then lost the externalized bodies of its large `edit` snapshots, and every later turn died materializing them. The probe now pins `TZ=UTC` on the `ps` child and parses the render explicitly as GMT, so the value is absolute in any reader; leases carry `startTimeBasis: "utc"`, and a lease written before the pin leaves reuse unproven instead of stale, so upgrading cannot reap a live owner once on the way through.
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
* `crash/report.ts`, which is the part that carries the consent contract and is
|
|
6
6
|
* therefore tested against stubbed boundaries.
|
|
7
7
|
*/
|
|
8
|
+
import type { Settings } from "../config/settings";
|
|
8
9
|
import { type CrashReportOutcome } from "../crash/report";
|
|
10
|
+
import { type CrashRelayOutcome } from "../crash/upstream/relay";
|
|
9
11
|
export declare function runCrashReportCommand(): Promise<CrashReportOutcome>;
|
|
10
12
|
export declare function runCrashListCommand(json: boolean): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Batch-relay every due signature to the configured upstream.
|
|
15
|
+
*
|
|
16
|
+
* The startup relay is silent and best-effort; this is the loud form, so a
|
|
17
|
+
* refusal is reported as a refusal instead of being swallowed. It shares the
|
|
18
|
+
* same gate: with `crashReport.upstream` off, it explains that and exits
|
|
19
|
+
* non-zero rather than quietly doing nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function crashRelayExitCode(outcome: CrashRelayOutcome): number;
|
|
22
|
+
export declare function runCrashRelayCommand(settings: Settings): Promise<void>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `gjc crash` — inspect local crash signatures and file an assisted, fully
|
|
3
|
-
* consented bug report.
|
|
4
|
-
* digest-confirmed confirmation for that exact invocation
|
|
3
|
+
* consented bug report. `gjc crash report` requires an explicit,
|
|
4
|
+
* digest-confirmed confirmation for that exact invocation; `gjc crash relay`
|
|
5
|
+
* uses separately configured standing consent.
|
|
5
6
|
*/
|
|
6
7
|
import { Command } from "@gajae-code/utils/cli";
|
|
7
8
|
export default class Crash extends Command {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { Command } from "@gajae-code/utils/cli";
|
|
2
|
+
import { type RalplanCommandResult } from "../gjc-runtime/ralplan-runtime";
|
|
3
|
+
/** Public CLI path: validate --worktree-root before any settings migration, then dispatch. */
|
|
4
|
+
export declare function runRalplanCliCommand(args: string[], cwd: string): Promise<RalplanCommandResult>;
|
|
2
5
|
export default class Ralplan extends Command {
|
|
3
6
|
static description: string;
|
|
4
7
|
static strict: boolean;
|
|
@@ -1841,6 +1841,25 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
1841
1841
|
readonly description: "At interactive startup, show one rate-limited line when unreported crash signatures exist. Reads local state only; nothing is ever transmitted without the explicit consent flow in `gjc crash report`.";
|
|
1842
1842
|
};
|
|
1843
1843
|
};
|
|
1844
|
+
readonly "crashReport.upstream": {
|
|
1845
|
+
readonly type: "enum";
|
|
1846
|
+
readonly values: readonly ["off", "sentry"];
|
|
1847
|
+
readonly default: "off";
|
|
1848
|
+
readonly ui: {
|
|
1849
|
+
readonly tab: "interaction";
|
|
1850
|
+
readonly label: "Crash Report Upstream (Global)";
|
|
1851
|
+
readonly description: "Global-only opt-in to transmit sanitized crash signatures to an aggregation service for cross-install counting. Off sends nothing. Only fields approved by `sanitizeExternalCrashV1` are sent; prompt text, source code, file contents, and credentials are excluded.";
|
|
1852
|
+
};
|
|
1853
|
+
};
|
|
1854
|
+
readonly "crashReport.upstreamDsn": {
|
|
1855
|
+
readonly type: "string";
|
|
1856
|
+
readonly default: "";
|
|
1857
|
+
readonly ui: {
|
|
1858
|
+
readonly tab: "interaction";
|
|
1859
|
+
readonly label: "Crash Report Upstream DSN (Global)";
|
|
1860
|
+
readonly description: "Global-only Sentry DSN for the opted-in upstream; ignored while Crash Report Upstream is off, and no default destination exists. Only fields approved by `sanitizeExternalCrashV1` are sent; prompt text, source code, file contents, and credentials are excluded.";
|
|
1861
|
+
};
|
|
1862
|
+
};
|
|
1844
1863
|
readonly collapseChangelog: {
|
|
1845
1864
|
readonly type: "boolean";
|
|
1846
1865
|
readonly default: false;
|
|
@@ -21,9 +21,15 @@ export interface CrashSignatureEntry {
|
|
|
21
21
|
firstSeen: number;
|
|
22
22
|
lastSeen: number;
|
|
23
23
|
lastRecordId: string;
|
|
24
|
+
/** Journal-append-order occurrence id, independent of display-time `lastSeen`. */
|
|
25
|
+
lastAppendRecordId?: string;
|
|
24
26
|
reportedAt?: number;
|
|
25
27
|
reportedIssueUrl?: string;
|
|
26
28
|
acknowledgedAt?: number;
|
|
29
|
+
/** Epoch ms this signature was last accepted by the configured upstream. */
|
|
30
|
+
relayedAt?: number;
|
|
31
|
+
/** Occurrence record represented by the durable upstream watermark. */
|
|
32
|
+
relayedRecordId?: string;
|
|
27
33
|
/** Issues this install already "+1"ed, so re-invocations cannot spam comments. */
|
|
28
34
|
commentedIssues?: string[];
|
|
29
35
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentry DSNs are configuration, but accepting a malformed one can turn an
|
|
3
|
+
* opt-in crash relay into an unexpected network destination. Keep parsing
|
|
4
|
+
* deliberately narrow and reconstruct public-key-bearing forms only at the
|
|
5
|
+
* envelope boundary.
|
|
6
|
+
*/
|
|
7
|
+
export interface SentryDsn {
|
|
8
|
+
readonly publicKey: string;
|
|
9
|
+
readonly host: string;
|
|
10
|
+
readonly projectId: string;
|
|
11
|
+
readonly envelopeUrl: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse only the public-key DSN form used by the relay. Secrets, query values,
|
|
15
|
+
* fragments, and plaintext public destinations are all refused before a URL is
|
|
16
|
+
* ever retained as a network target.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseSentryDsn(raw: string): SentryDsn | undefined;
|
|
19
|
+
/** Reconstruct the DSN required in the envelope header, nowhere else. */
|
|
20
|
+
export declare function toDsnString(dsn: SentryDsn): string;
|
|
21
|
+
/** Omit the public key from diagnostics so configuration can be logged safely. */
|
|
22
|
+
export declare function redactDsn(dsn: SentryDsn): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type SentryDsn } from "./dsn";
|
|
2
|
+
export interface CrashEventFrame {
|
|
3
|
+
readonly filename: string;
|
|
4
|
+
readonly function: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BuildCrashEnvelopeInput {
|
|
7
|
+
readonly eventId: string;
|
|
8
|
+
readonly fingerprint: string;
|
|
9
|
+
readonly errorName: string;
|
|
10
|
+
readonly messageClass: string;
|
|
11
|
+
readonly frames: readonly CrashEventFrame[];
|
|
12
|
+
readonly firstSeen: number;
|
|
13
|
+
readonly lastSeen: number;
|
|
14
|
+
readonly lifetimeCount: number;
|
|
15
|
+
readonly release: string;
|
|
16
|
+
readonly platform: string;
|
|
17
|
+
readonly bunVersion: string;
|
|
18
|
+
readonly dsn: SentryDsn;
|
|
19
|
+
/** Upstream severity. Defaults to `fatal`; handled tool failures use `error`. */
|
|
20
|
+
readonly level?: "fatal" | "error";
|
|
21
|
+
}
|
|
22
|
+
export type BuildCrashEnvelopeResult = {
|
|
23
|
+
ok: true;
|
|
24
|
+
body: string;
|
|
25
|
+
eventId: string;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: string;
|
|
29
|
+
};
|
|
30
|
+
/** Create Sentry's required lowercase 128-bit event identifier. */
|
|
31
|
+
export declare function newSentryEventId(): string;
|
|
32
|
+
/** Build the exact auth header used for the hand-rolled envelope POST. */
|
|
33
|
+
export declare function sentryAuthHeader(dsn: SentryDsn, clientVersion: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Build a three-line event envelope. Sanitization failures and oversize output
|
|
36
|
+
* refuse the complete event: JSON must never be truncated into a new payload.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildCrashEnvelope(input: BuildCrashEnvelopeInput): BuildCrashEnvelopeResult;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in crash relay to a Sentry-compatible upstream.
|
|
3
|
+
*
|
|
4
|
+
* This is a **second, separate** egress channel from `gjc crash report`. The
|
|
5
|
+
* issue flow keeps its per-invocation, digest-confirmed consent boundary; this
|
|
6
|
+
* one is gated by configuration instead, and is therefore deliberately much
|
|
7
|
+
* narrower in what it can ever emit:
|
|
8
|
+
*
|
|
9
|
+
* 1. `crashReport.upstream` must be `sentry`. The default is `off`, and while
|
|
10
|
+
* it is off this module performs no IO at all — not even a state read.
|
|
11
|
+
* 2. An operator must supply a DSN. No DSN literal is compiled into the binary,
|
|
12
|
+
* so a build has no destination to fall back to; an unset DSN is a hard stop
|
|
13
|
+
* and never means "use ours".
|
|
14
|
+
* 3. Every crash-derived byte must pass `sanitizeExternalCrashV1`. A refusal
|
|
15
|
+
* drops that signature entirely. There is no less-sanitized fallback path.
|
|
16
|
+
*
|
|
17
|
+
* The relay never runs on the fatal path. A crashing process still does exactly
|
|
18
|
+
* one `O_APPEND` write and dies; relaying happens at the *next* startup, after
|
|
19
|
+
* compaction, where blocking and failing are both safe.
|
|
20
|
+
*/
|
|
21
|
+
import { type CrashSignatureView, type CrashStatePaths } from "../index-store";
|
|
22
|
+
import { type SentryDsn } from "./dsn";
|
|
23
|
+
/** Trusted environment variable form of the DSN, for CI and one-off runs. */
|
|
24
|
+
export declare const CRASH_UPSTREAM_DSN_ENV = "GJC_CRASH_SENTRY_DSN";
|
|
25
|
+
export interface CrashRelayConfig {
|
|
26
|
+
readonly upstream: "off" | "sentry";
|
|
27
|
+
readonly dsn: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The only settings surface the relay is allowed to read.
|
|
31
|
+
*
|
|
32
|
+
* `Settings.get` merges project `.gjc` configuration into the answer, so using
|
|
33
|
+
* it here would let merely opening a repository turn the relay on and choose
|
|
34
|
+
* its destination — an untrusted checkout could redirect crash signatures that
|
|
35
|
+
* were recorded long before it was cloned. Both keys are therefore read from
|
|
36
|
+
* the user/global layer only, which is exactly what `getGlobal` documents
|
|
37
|
+
* itself for.
|
|
38
|
+
*/
|
|
39
|
+
export interface TrustedRelaySettings {
|
|
40
|
+
getGlobal(path: "crashReport.upstream" | "crashReport.upstreamDsn"): unknown;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the relay configuration from the trusted layer.
|
|
44
|
+
*
|
|
45
|
+
* The values are re-validated rather than trusted by type. `getGlobal` reports
|
|
46
|
+
* whatever the hand-editable global config file holds, and it returns
|
|
47
|
+
* `undefined` instead of a schema default, so anything that is not literally
|
|
48
|
+
* `"sentry"` lands on `off` and anything that is not a string lands on an empty
|
|
49
|
+
* DSN. Both absent and malformed therefore fail closed.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readTrustedRelayConfig(settings: TrustedRelaySettings): CrashRelayConfig;
|
|
52
|
+
/**
|
|
53
|
+
* The exact shape the relay uses. Narrower than `typeof fetch` on purpose: the
|
|
54
|
+
* relay only ever issues one POST to a known URL, and depending on the full
|
|
55
|
+
* runtime signature (Bun adds `preconnect`) would force every caller and test
|
|
56
|
+
* double to fake surface this module never touches.
|
|
57
|
+
*/
|
|
58
|
+
export type CrashRelayFetch = (url: string, init: RequestInit) => Promise<Response>;
|
|
59
|
+
export type CrashRelaySkip = "disabled" | "no-dsn" | "invalid-dsn" | "nothing-to-relay";
|
|
60
|
+
export type CrashRelayOutcome = {
|
|
61
|
+
readonly status: "skipped";
|
|
62
|
+
readonly reason: CrashRelaySkip;
|
|
63
|
+
} | {
|
|
64
|
+
readonly status: "ran";
|
|
65
|
+
/** Signatures the upstream accepted and that are now stamped `relayedAt`. */
|
|
66
|
+
readonly sent: number;
|
|
67
|
+
/** Signatures dropped because the sanitizer refused a field. */
|
|
68
|
+
readonly refused: number;
|
|
69
|
+
/** Signatures the upstream rejected or that failed in transport. */
|
|
70
|
+
readonly failed: number;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Severity of the store being relayed.
|
|
74
|
+
*
|
|
75
|
+
* Fatal crashes and handled tool failures live in separate files on purpose --
|
|
76
|
+
* handled errors are high-volume and would otherwise evict the rare, precious
|
|
77
|
+
* fatal records from a shared cap. They are relayed through the same code with
|
|
78
|
+
* the same egress contract, and differ upstream only by `level`, so a single
|
|
79
|
+
* project can hold both without the noisy class drowning the signal.
|
|
80
|
+
*/
|
|
81
|
+
export type CrashRelaySeverity = "fatal" | "error";
|
|
82
|
+
export interface CrashRelayOptions {
|
|
83
|
+
readonly config: CrashRelayConfig;
|
|
84
|
+
readonly paths?: CrashStatePaths;
|
|
85
|
+
readonly handledPaths?: CrashStatePaths;
|
|
86
|
+
readonly severity?: CrashRelaySeverity;
|
|
87
|
+
readonly env?: Record<string, string | undefined>;
|
|
88
|
+
readonly fetchImpl?: CrashRelayFetch;
|
|
89
|
+
readonly now?: () => number;
|
|
90
|
+
readonly maxPerRun?: number;
|
|
91
|
+
readonly platform?: string;
|
|
92
|
+
readonly release?: string;
|
|
93
|
+
readonly bunVersion?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the destination. Explicit config wins over the environment so a
|
|
97
|
+
* machine-wide export cannot silently redirect a configured install.
|
|
98
|
+
*/
|
|
99
|
+
export declare function resolveRelayDsn(config: CrashRelayConfig, env?: Record<string, string | undefined>): {
|
|
100
|
+
ok: true;
|
|
101
|
+
dsn: SentryDsn;
|
|
102
|
+
} | {
|
|
103
|
+
ok: false;
|
|
104
|
+
reason: CrashRelaySkip;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* A signature is due when new journal-append-order occurrences exist after the
|
|
108
|
+
* last durable watermark. `lastSeen` is display-time only and must not hide a
|
|
109
|
+
* backdated occurrence. Legacy indexes that only have `relayedAt` stay covered
|
|
110
|
+
* when that wall-clock stamp still covers `lastSeen`. After a downgrade that
|
|
111
|
+
* advanced `relayedAt` without rewriting `relayedRecordId`, the same lastSeen
|
|
112
|
+
* coverage applies only when the latest append is also the lastSeen record.
|
|
113
|
+
*/
|
|
114
|
+
export declare function isRelayDue(signature: CrashSignatureView): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Automatic relay stores use the normal XDG state location only when the XDG
|
|
117
|
+
* value came from a trusted environment. `dirs.ts` rejects checkout `.env`
|
|
118
|
+
* declarations before resolving these paths, including dotenv-expanded values.
|
|
119
|
+
*/
|
|
120
|
+
export declare function resolveTrustedRelayStatePaths(): CrashStatePaths;
|
|
121
|
+
export declare function resolveTrustedHandledRelayStatePaths(): CrashStatePaths;
|
|
122
|
+
/**
|
|
123
|
+
* Relay every due signature once. Never throws: a broken upstream, an offline
|
|
124
|
+
* machine or a corrupt crash log must not be able to take down startup.
|
|
125
|
+
*/
|
|
126
|
+
export declare function relayCrashSignatures(options: CrashRelayOptions): Promise<CrashRelayOutcome>;
|
|
127
|
+
/** Paths of the handled-error store. Never XDG: a supplied directory is joined directly. */
|
|
128
|
+
export declare function resolveHandledErrorStatePaths(agentDir?: string): CrashStatePaths;
|
|
129
|
+
/**
|
|
130
|
+
* Relay both stores in one pass.
|
|
131
|
+
*
|
|
132
|
+
* Fatal crashes go first: they are rarer and more valuable, so when the
|
|
133
|
+
* per-run cap binds they must not be starved by a noisy handled-error class.
|
|
134
|
+
* The cap is shared across both stores. The gate is evaluated once by the
|
|
135
|
+
* first call, and a skip there means the same skip applies to the second, so
|
|
136
|
+
* `off` still performs no IO at all.
|
|
137
|
+
*/
|
|
138
|
+
export declare function relayAllSignatures(options: CrashRelayOptions): Promise<CrashRelayOutcome>;
|
|
@@ -155,6 +155,22 @@ export declare function resolveRalplanMaxReviewPassesPerLane(cwd: string, agentD
|
|
|
155
155
|
source: string;
|
|
156
156
|
}>;
|
|
157
157
|
export declare function isRalplanArtifactWriteInvocation(args: readonly string[]): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Explicit target-worktree routing (#4693). `--worktree-root <path>` selects the
|
|
160
|
+
* canonical git worktree that owns every ralplan persistence root (run state,
|
|
161
|
+
* stage artifacts, index ledger, HUD state, stuck markers, and review-budget
|
|
162
|
+
* accounting) regardless of the writer process's ambient cwd. Without the flag,
|
|
163
|
+
* behavior stays cwd-based. The invoking cwd is retained only for resolving a
|
|
164
|
+
* relative `--artifact` input file.
|
|
165
|
+
*/
|
|
166
|
+
interface RalplanTargetRoot {
|
|
167
|
+
/** Canonical persistence root: the invocation cwd, or the --worktree-root target. */
|
|
168
|
+
root: string;
|
|
169
|
+
/** True when the caller explicitly selected the target via --worktree-root. */
|
|
170
|
+
explicit: boolean;
|
|
171
|
+
}
|
|
172
|
+
export declare function resolveRalplanTargetRoot(args: readonly string[], invocationCwd: string): Promise<RalplanTargetRoot>;
|
|
173
|
+
export declare function assertExplicitTargetGjcNotSymlinked(root: string): Promise<void>;
|
|
158
174
|
export declare function runNativeRalplanCommand(args: string[], cwd?: string, options?: {
|
|
159
175
|
agentDir?: string;
|
|
160
176
|
}): Promise<RalplanCommandResult>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AssistantMessage, ImageContent, Usage } from "@gajae-code/ai/core";
|
|
2
2
|
import { Container } from "@gajae-code/tui";
|
|
3
|
+
import { type ProviderSafetyStopHintSession } from "../../session/provider-safety-stop-hint";
|
|
3
4
|
interface AssistantMessageUpdateOptions {
|
|
4
5
|
streaming?: boolean;
|
|
5
6
|
}
|
|
@@ -11,7 +12,8 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
11
12
|
private hideThinkingBlock;
|
|
12
13
|
private readonly onImageUpdate?;
|
|
13
14
|
private readonly onVisibleMutation?;
|
|
14
|
-
|
|
15
|
+
private readonly hintSession?;
|
|
16
|
+
constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, viewportAnchorId?: string, onVisibleMutation?: (() => void) | undefined, hintSession?: ProviderSafetyStopHintSession | undefined);
|
|
15
17
|
invalidate(): void;
|
|
16
18
|
setHideThinkingBlock(hide: boolean): void;
|
|
17
19
|
setToolResultImages(toolCallId: string, images: ImageContent[]): void;
|
|
@@ -233,6 +233,14 @@ export declare function setTerminalPersistenceHookForTest(broker: Broker, hook:
|
|
|
233
233
|
export declare function setAmbiguityGraceForTest(broker: Broker, graceMs: number | undefined): void;
|
|
234
234
|
/** Test-only hook for shortening the startup lock-artifact reap bound. */
|
|
235
235
|
export declare function setLockArtifactGraceForTest(broker: Broker, graceMs: number | undefined): void;
|
|
236
|
+
/** Test-only hook for shortening the bounded liveness deadline. */
|
|
237
|
+
export declare function setLivenessGraceForTest(broker: Broker, graceMs: number | undefined): void;
|
|
238
|
+
/**
|
|
239
|
+
* Test-only hook for stalling the heartbeat write, reproducing a publication tick
|
|
240
|
+
* whose awaited IO does not settle. Clearing it releases the stalled tick the way
|
|
241
|
+
* recovered IO would, instead of abandoning it forever.
|
|
242
|
+
*/
|
|
243
|
+
export declare function setHeartbeatStallForTest(broker: Broker, stalled: boolean): void;
|
|
236
244
|
/** Test-only hook for forcing the observation the publication watchdog sees. */
|
|
237
245
|
export declare function setPublicationObservationForTest(broker: Broker, observation: BrokerPublicationObservation | undefined): void;
|
|
238
246
|
export {};
|
|
@@ -3,6 +3,7 @@ import { SDK_STATE_VERSION } from "./state-version";
|
|
|
3
3
|
export type BrokerPublicationObservation = "owned" | "absent" | "replaced" | "ambiguous";
|
|
4
4
|
export interface RetainedBrokerDiscovery {
|
|
5
5
|
observe(): BrokerPublicationObservation;
|
|
6
|
+
observeAsync(): Promise<BrokerPublicationObservation>;
|
|
6
7
|
heartbeat(heartbeatAt: number): Promise<boolean>;
|
|
7
8
|
close(): void;
|
|
8
9
|
}
|
|
@@ -51,16 +51,6 @@ export interface NotificationExactUnlinkResult {
|
|
|
51
51
|
export declare function readNotificationEndpointFile(file: string): Promise<NotificationEndpointFile>;
|
|
52
52
|
/** Bump when the native exact-deletion identity contract changes. */
|
|
53
53
|
export declare const NATIVE_PATH_IDENTITY_CONTRACT_VERSION = 1;
|
|
54
|
-
/**
|
|
55
|
-
* Remove exactly the inspected regular file.
|
|
56
|
-
*
|
|
57
|
-
* Intermediate directory symlinks (e.g. multi-account layouts that share
|
|
58
|
-
* `notifications/` via a directory symlink) are resolved before the native
|
|
59
|
-
* no-follow unlink. Only the parent path is canonicalized; the final basename
|
|
60
|
-
* is rejoined so native exact_unlink still applies AT_SYMLINK_NOFOLLOW to the
|
|
61
|
-
* final path component at mutation time. A final-component file symlink stays
|
|
62
|
-
* `reparse_point` (including TOCTOU replacement after JS preflight).
|
|
63
|
-
*/
|
|
64
54
|
export declare function exactUnlinkNotificationFile(file: string, identity: NotificationEndpointFileIdentity, quarantineName: string): NotificationExactUnlinkResult;
|
|
65
55
|
/** Minimal filesystem surface the service needs; injectable for tests. */
|
|
66
56
|
export interface NotificationServiceFs {
|
|
@@ -68,6 +58,8 @@ export interface NotificationServiceFs {
|
|
|
68
58
|
readFile(file: string, encoding: "utf8"): Promise<string>;
|
|
69
59
|
readEndpointFile(file: string): Promise<NotificationEndpointFile>;
|
|
70
60
|
exactUnlink(file: string, identity: NotificationEndpointFileIdentity): Promise<NotificationExactUnlinkResult>;
|
|
61
|
+
/** Identity-bound direct unlink reserved for inert exchange debris. */
|
|
62
|
+
unlinkExact(file: string, identity: NotificationEndpointFileIdentity): Promise<NotificationExactUnlinkResult>;
|
|
71
63
|
unlink(file: string): Promise<void>;
|
|
72
64
|
writeFile?(file: string, data: string, opts?: WriteFileOptions): Promise<void>;
|
|
73
65
|
stat?(file: string): Promise<{
|
|
@@ -269,7 +269,7 @@ export declare const SDK_LIFECYCLE_ROUTER_PROTOCOL_VERSION = 1;
|
|
|
269
269
|
* Generation 169 delivers every ring-positioned session event live through the
|
|
270
270
|
* bounded, capability-gated directed subscriber leg used by replay.
|
|
271
271
|
*/
|
|
272
|
-
export declare const DAEMON_GENERATION =
|
|
272
|
+
export declare const DAEMON_GENERATION = 171;
|
|
273
273
|
/**
|
|
274
274
|
* Serving-compatibility boundary for daemon lifecycle requests. Epoch 7
|
|
275
275
|
* requires durable publication receipts and acknowledged attachment dispatch,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AssistantMessage, Model } from "@gajae-code/ai/core";
|
|
2
|
+
import { type ModelSelectorValue } from "../config/model-selector-value";
|
|
3
|
+
/**
|
|
4
|
+
* Normalize a model selector for display: strip ANSI escape sequences and
|
|
5
|
+
* control characters, remove Unicode format characters, replace tabs with
|
|
6
|
+
* spaces, and bound the width. One shared implementation so the TUI render and
|
|
7
|
+
* the print-mode stderr render interpolate the identical safe value (#4653
|
|
8
|
+
* review: centralize selector sanitization instead of leaving each surface to
|
|
9
|
+
* bound itself).
|
|
10
|
+
*/
|
|
11
|
+
export declare function sanitizeModelSelectorForDisplay(selector: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Session capabilities the hint resolver reads. Everything is optional so
|
|
14
|
+
* lightweight host/test contexts without model plumbing degrade to the static
|
|
15
|
+
* guidance instead of throwing.
|
|
16
|
+
*/
|
|
17
|
+
export interface ProviderSafetyStopHintSession {
|
|
18
|
+
getConfiguredModelChainState?(role: string): {
|
|
19
|
+
entries: readonly string[];
|
|
20
|
+
origin: string;
|
|
21
|
+
identity?: string;
|
|
22
|
+
explicitHead: boolean;
|
|
23
|
+
} | undefined;
|
|
24
|
+
settings?: {
|
|
25
|
+
getModelRole?(role: string): ModelSelectorValue | undefined;
|
|
26
|
+
};
|
|
27
|
+
getAvailableModels?(): Model[];
|
|
28
|
+
}
|
|
29
|
+
/** Whether an assistant message terminated as a provider safety stop (typed or legacy-persisted). */
|
|
30
|
+
export declare function isProviderSafetyStop(message: AssistantMessage): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The `provider/id` identity of the model that produced an assistant message.
|
|
33
|
+
* The message's own `provider`/`model` fields are the authoritative identity of
|
|
34
|
+
* the refusing attempt (they survive model switches after the error).
|
|
35
|
+
*/
|
|
36
|
+
export declare function refusingModelSelector(message: AssistantMessage): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a safe, valid alternate model selector from the default role's
|
|
39
|
+
* configured chain — one that is NOT the model that refused. Presentation-only:
|
|
40
|
+
* reads configured intent, dispatches nothing, and mutates nothing (#4650).
|
|
41
|
+
*
|
|
42
|
+
* An entry is named only when the authoritative model selector resolver accepts
|
|
43
|
+
* it (`resolveSelector` with `allowInvalidThinkingSelectorFallback: false`, so
|
|
44
|
+
* malformed suffixes like `:bogus` fail closed while route-suffixed IDs keep
|
|
45
|
+
* their exact-ID semantics) AND the concrete model it resolves to differs from
|
|
46
|
+
* the refuser.
|
|
47
|
+
*
|
|
48
|
+
* The returned selector is RECONSTRUCTED from the resolved model — always
|
|
49
|
+
* `provider/id` qualified, never the original entry (#4653 review: the hint
|
|
50
|
+
* resolver runs without usage-preference context, so a bare/fuzzy/glob entry
|
|
51
|
+
* that resolves here can paste-resolve differently under the real `/model`
|
|
52
|
+
* command's usage-preference context; a provider-qualified selector pins the
|
|
53
|
+
* advertised command to exactly the model that was validated). Only a thinking
|
|
54
|
+
* suffix that itself validated is carried over, so the suggested command is one
|
|
55
|
+
* the resolver parses with identical semantics.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveSafetyStopAlternateSelector(refuserSelector: string | undefined, chain: ModelSelectorValue | readonly string[] | undefined, availableModels: readonly Model[]): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Bounded guidance shown after a provider safety stop: the failure is
|
|
60
|
+
* model-specific, the context need not be discarded, and the session continues
|
|
61
|
+
* after a manual switch. The configured alternate and the canonical manual
|
|
62
|
+
* switch command are named only when a validated alternate was resolved; the
|
|
63
|
+
* hint never claims the alternate is guaranteed to accept the same context.
|
|
64
|
+
*/
|
|
65
|
+
export declare function formatProviderSafetyStopHint(alternateSelector: string | undefined): string;
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the hint to display for a terminal provider safety stop, against the
|
|
68
|
+
* session's current configured default chain and available catalog. Returns a
|
|
69
|
+
* hint string for safety stops (static guidance when no valid alternate can be
|
|
70
|
+
* named) and `undefined` for every other error kind, so unrelated errors keep
|
|
71
|
+
* their existing rendering untouched.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveProviderSafetyStopHint(message: AssistantMessage, session: ProviderSafetyStopHintSession | undefined): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Compose the display error line for a provider safety stop: the provider's own
|
|
76
|
+
* refusal text is always retained verbatim, with the hint appended on a new
|
|
77
|
+
* line. Returns `undefined` for non-safety-stop errors.
|
|
78
|
+
*/
|
|
79
|
+
export declare function formatProviderSafetyStopDisplayError(message: AssistantMessage, alternateSelector: string | undefined): string | undefined;
|
|
@@ -210,6 +210,14 @@ export declare function transferSessionMessageIdentity(source: AgentMessage[], t
|
|
|
210
210
|
export interface ThinkingLevelChangeEntry extends SessionEntryBase {
|
|
211
211
|
type: "thinking_level_change";
|
|
212
212
|
thinkingLevel?: string | null;
|
|
213
|
+
/**
|
|
214
|
+
* True only when an operator effort surface (`setThinkingLevelForControl`,
|
|
215
|
+
* Shift+Tab `cycleThinkingLevel`) recorded this entry. Model-driven appends
|
|
216
|
+
* (model-switch `defaultLevel`, temporary model switches, context clears,
|
|
217
|
+
* re-applies after model cycling) leave it unset so `getThinkingScopeForControl`
|
|
218
|
+
* never mints session scope without operator effort intent (issue #4695).
|
|
219
|
+
*/
|
|
220
|
+
operatorIntent?: boolean;
|
|
213
221
|
}
|
|
214
222
|
export interface ModelChangeEntry extends SessionEntryBase {
|
|
215
223
|
type: "model_change";
|
|
@@ -955,6 +963,14 @@ interface ResidentBlobSentinel {
|
|
|
955
963
|
ref: string;
|
|
956
964
|
}
|
|
957
965
|
export declare function residentBlobSentinelForTests(kind: ResidentBlobKind, ref: string): ResidentBlobSentinel;
|
|
966
|
+
export declare function assertResidentReferencesResolvableForTests(entries: readonly FileEntry[], textStore: BlobStore, imageStore?: BlobStore, binding?: {
|
|
967
|
+
sessionId?: string;
|
|
968
|
+
sessionFile?: string;
|
|
969
|
+
}): void;
|
|
970
|
+
export declare function materializeResidentEntriesThrowingForTests<T>(entries: T[], textStore: BlobStore, imageStore?: BlobStore, binding?: {
|
|
971
|
+
sessionId?: string;
|
|
972
|
+
sessionFile?: string;
|
|
973
|
+
}): T[];
|
|
958
974
|
export declare function materializeResidentEntriesForPersistenceForTests<T>(entries: T[], textStore: BlobStore, imageStore?: BlobStore): T[];
|
|
959
975
|
/** Get recent sessions for display in welcome screen */
|
|
960
976
|
export declare function getRecentSessions(sessionDir: string, limit?: number, storage?: SessionStorage): Promise<RecentSessionInfo[]>;
|
|
@@ -1277,7 +1293,7 @@ export declare class SessionManager {
|
|
|
1277
1293
|
*/
|
|
1278
1294
|
appendMessage(message: Message | CustomMessage | HookMessage | BashExecutionMessage | PythonExecutionMessage | FileMentionMessage): string;
|
|
1279
1295
|
/** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */
|
|
1280
|
-
appendThinkingLevelChange(thinkingLevel?: string): string;
|
|
1296
|
+
appendThinkingLevelChange(thinkingLevel?: string, operatorIntent?: boolean): string;
|
|
1281
1297
|
appendServiceTierChange(serviceTier: ServiceTier | null): string;
|
|
1282
1298
|
/** Append a mode change as child of current leaf, then advance leaf. Returns entry id. */
|
|
1283
1299
|
appendModeChange(mode: string, data?: Record<string, unknown>): string;
|
|
@@ -87,6 +87,14 @@ export declare class AskTool implements AgentTool<AskParametersSchema, AskToolDe
|
|
|
87
87
|
readonly rawArgumentValidation: (arguments_: Record<string, unknown>) => RawArgumentValidationResult;
|
|
88
88
|
readonly strict = true;
|
|
89
89
|
readonly loadMode = "discoverable";
|
|
90
|
+
/**
|
|
91
|
+
* The only ask argument fields rendered to the user as display text: the
|
|
92
|
+
* question wording and the option labels. Everything else — ids,
|
|
93
|
+
* deep-interview metadata (intent contracts/reviews, references), workflow
|
|
94
|
+
* gate metadata — is structured or durable and stays subject to the
|
|
95
|
+
* fail-closed escaped-non-ASCII rejection even after the resample budget.
|
|
96
|
+
*/
|
|
97
|
+
readonly displaySafeEscapedArgFields: readonly ["questions.question", "questions.options.label"];
|
|
90
98
|
constructor(session: ToolSession);
|
|
91
99
|
static createIf(session: ToolSession): AskTool | null;
|
|
92
100
|
execute(_toolCallId: string, params: AskParams, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<AskToolDetails>, context?: AgentToolContext): Promise<AgentToolResult<AskToolDetails>>;
|
|
@@ -172,6 +172,8 @@ export interface ToolSession {
|
|
|
172
172
|
requestForegroundBashBackground?: () => boolean;
|
|
173
173
|
/** Get the session-owned or inherited async job manager. */
|
|
174
174
|
getAsyncJobManager?: () => AsyncJobManager | undefined;
|
|
175
|
+
/** Resolves when the session queues user steering (or `signal` aborts) without consuming it; wait-style tools use this to end their observation early. */
|
|
176
|
+
waitForUserSteering?: (signal: AbortSignal) => Promise<void>;
|
|
175
177
|
/** Get session ID */
|
|
176
178
|
getSessionId?: () => string | null;
|
|
177
179
|
/** Get credential-selection session identity. */
|
|
@@ -11,6 +11,13 @@ export interface HerdrReportProcess {
|
|
|
11
11
|
export interface HerdrReporterOptions {
|
|
12
12
|
env?: NodeJS.ProcessEnv;
|
|
13
13
|
which?: (command: string) => string | null;
|
|
14
|
+
/** Identity written into the ownership marker. Injectable so the nested-process
|
|
15
|
+
* case is testable without actually forking. */
|
|
16
|
+
pid?: number;
|
|
17
|
+
/** OS process incarnation probe, injectable for PID-reuse and recovery tests. */
|
|
18
|
+
processIncarnation?: (pid: number) => string | undefined;
|
|
19
|
+
/** Process liveness/incarnation probe, injectable for cross-platform recovery tests. */
|
|
20
|
+
processProbe?: (pid: number) => HerdrProcessProbe;
|
|
14
21
|
spawn?: (command: string[], options: {
|
|
15
22
|
env: NodeJS.ProcessEnv;
|
|
16
23
|
stdin: "ignore";
|
|
@@ -18,6 +25,14 @@ export interface HerdrReporterOptions {
|
|
|
18
25
|
stderr: "ignore";
|
|
19
26
|
}) => HerdrReportProcess;
|
|
20
27
|
}
|
|
28
|
+
export type HerdrProcessProbe = {
|
|
29
|
+
state: "live";
|
|
30
|
+
incarnation: string;
|
|
31
|
+
} | {
|
|
32
|
+
state: "absent";
|
|
33
|
+
} | {
|
|
34
|
+
state: "unverifiable";
|
|
35
|
+
};
|
|
21
36
|
/** Session event shape consumed by the reporter. Narrow on purpose: the state
|
|
22
37
|
* machine is driven only by lifecycle transitions, never by message content. */
|
|
23
38
|
export interface HerdrSessionEvent {
|
|
@@ -41,6 +56,9 @@ export interface HerdrReporter {
|
|
|
41
56
|
* unverified path scavenged from an install layout is a command this process
|
|
42
57
|
* would execute, and PATH/`HERDR_BIN_PATH` are the trust boundary Herdr itself
|
|
43
58
|
* documents.
|
|
59
|
+
*
|
|
60
|
+
* Also returns null when an ancestor gjc already owns this pane, so a nested
|
|
61
|
+
* invocation reports nothing at all.
|
|
44
62
|
*/
|
|
45
63
|
export declare function resolveHerdrPaneEnvironment(options?: HerdrReporterOptions): HerdrPaneEnvironment | null;
|
|
46
64
|
/** Build the argv for a state report. Exported for tests. */
|
|
@@ -63,11 +81,6 @@ export declare function buildHerdrClearTitleArgs(paneId: string, seq: number): s
|
|
|
63
81
|
* instead of flickering to a placeholder during startup or a rename.
|
|
64
82
|
*/
|
|
65
83
|
export declare function syncHerdrPaneTitle(sessionName: string | undefined, options?: HerdrReporterOptions): void;
|
|
66
|
-
/**
|
|
67
|
-
* Create a reporter bound to a pane. `subscribe` supplies the session event
|
|
68
|
-
* stream and is parameterized so the state machine is testable without a live
|
|
69
|
-
* session.
|
|
70
|
-
*/
|
|
71
84
|
export declare function createHerdrReporter(paneEnv: HerdrPaneEnvironment, subscribe: (listener: (event: HerdrSessionEvent) => void) => () => void, options?: HerdrReporterOptions): HerdrReporter;
|
|
72
85
|
/**
|
|
73
86
|
* Install the Herdr reporter for a running session. No-op outside a Herdr pane.
|