@gajae-code/coding-agent 0.4.5 → 0.5.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 +62 -0
- package/dist/types/async/job-manager.d.ts +26 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/list-models.d.ts +6 -0
- package/dist/types/commands/gc.d.ts +26 -0
- package/dist/types/commands/harness.d.ts +3 -0
- package/dist/types/config/file-lock-gc.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +7 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -2
- package/dist/types/config/model-profiles.d.ts +7 -0
- package/dist/types/config/model-registry.d.ts +3 -0
- package/dist/types/config/model-resolver.d.ts +2 -0
- package/dist/types/config/models-config-schema.d.ts +30 -0
- package/dist/types/config/settings-schema.d.ts +4 -3
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/defaults/gjc/extensions/grok-build/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
- package/dist/types/defaults/gjc-grok-cli.d.ts +5 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +103 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +112 -0
- package/dist/types/gjc-runtime/gc-render.d.ts +6 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +134 -0
- package/dist/types/gjc-runtime/ledger-event-renderer.d.ts +68 -0
- package/dist/types/gjc-runtime/team-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -1
- package/dist/types/gjc-runtime/tmux-common.d.ts +14 -0
- package/dist/types/gjc-runtime/tmux-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +13 -0
- package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
- package/dist/types/harness-control-plane/owner.d.ts +8 -1
- package/dist/types/harness-control-plane/receipt-spool.d.ts +19 -0
- package/dist/types/harness-control-plane/state-machine.d.ts +6 -1
- package/dist/types/harness-control-plane/storage.d.ts +20 -0
- package/dist/types/harness-control-plane/types.d.ts +4 -0
- package/dist/types/hindsight/mental-models.d.ts +5 -5
- package/dist/types/modes/components/hook-selector.d.ts +7 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -12
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +2 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +16 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +4 -1
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +13 -0
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +2 -0
- package/dist/types/sdk.d.ts +5 -0
- package/dist/types/session/agent-session.d.ts +3 -1
- package/dist/types/session/blob-store.d.ts +59 -4
- package/dist/types/session/session-manager.d.ts +24 -6
- package/dist/types/session/streaming-output.d.ts +3 -2
- package/dist/types/session/tool-choice-queue.d.ts +6 -0
- package/dist/types/skill-state/workflow-hud.d.ts +14 -0
- package/dist/types/task/receipt.d.ts +1 -0
- package/dist/types/task/types.d.ts +7 -0
- package/dist/types/thinking-metadata.d.ts +16 -0
- package/dist/types/thinking.d.ts +3 -12
- package/dist/types/tools/ask.d.ts +15 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/resolve.d.ts +0 -10
- package/dist/types/tools/subagent.d.ts +6 -0
- package/dist/types/utils/tool-choice.d.ts +14 -1
- package/package.json +7 -7
- package/src/async/job-manager.ts +52 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/list-models.ts +13 -1
- package/src/cli.ts +9 -4
- package/src/commands/gc.ts +22 -0
- package/src/commands/harness.ts +43 -5
- package/src/commands/launch.ts +2 -2
- package/src/commands/session.ts +3 -1
- package/src/config/file-lock-gc.ts +181 -0
- package/src/config/file-lock.ts +14 -0
- package/src/config/model-profile-activation.ts +15 -3
- package/src/config/model-profiles.ts +264 -56
- package/src/config/model-resolver.ts +9 -6
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +6 -3
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/server.ts +513 -26
- package/src/cursor.ts +16 -2
- package/src/defaults/gjc/agent.models.grok-cli.yml +36 -0
- package/src/defaults/gjc/extensions/grok-build/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-build/package.json +7 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +39 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/package.json +8 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +131 -113
- package/src/defaults/gjc/skills/deep-interview/lateral-review-panel.md +49 -0
- package/src/defaults/gjc/skills/team/SKILL.md +3 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +8 -2
- package/src/defaults/gjc-defaults.ts +7 -0
- package/src/defaults/gjc-grok-cli.ts +22 -0
- package/src/export/html/index.ts +13 -9
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +417 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +18 -26
- package/src/gjc-runtime/deep-interview-state.ts +324 -0
- package/src/gjc-runtime/gc-render.ts +70 -0
- package/src/gjc-runtime/gc-runtime.ts +403 -0
- package/src/gjc-runtime/ledger-event-renderer.ts +164 -0
- package/src/gjc-runtime/ralplan-runtime.ts +58 -7
- package/src/gjc-runtime/state-renderer.ts +12 -3
- package/src/gjc-runtime/state-runtime.ts +46 -29
- package/src/gjc-runtime/team-gc.ts +49 -0
- package/src/gjc-runtime/team-runtime.ts +211 -8
- package/src/gjc-runtime/tmux-common.ts +29 -0
- package/src/gjc-runtime/tmux-gc.ts +176 -0
- package/src/gjc-runtime/tmux-sessions.ts +68 -12
- package/src/gjc-runtime/ultragoal-runtime.ts +517 -41
- package/src/gjc-runtime/workflow-manifest.generated.json +27 -1
- package/src/gjc-runtime/workflow-manifest.ts +16 -1
- package/src/harness-control-plane/gc-adapter.ts +184 -0
- package/src/harness-control-plane/owner.ts +89 -27
- package/src/harness-control-plane/receipt-spool.ts +128 -0
- package/src/harness-control-plane/state-machine.ts +27 -6
- package/src/harness-control-plane/storage.ts +93 -0
- package/src/harness-control-plane/types.ts +4 -0
- package/src/hindsight/mental-models.ts +17 -16
- package/src/internal-urls/docs-index.generated.ts +14 -8
- package/src/main.ts +7 -2
- package/src/modes/components/assistant-message.ts +26 -14
- package/src/modes/components/diff.ts +97 -0
- package/src/modes/components/hook-selector.ts +19 -0
- package/src/modes/components/model-selector.ts +370 -181
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/components/tool-execution.ts +30 -13
- package/src/modes/controllers/command-controller.ts +25 -6
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/selector-controller.ts +34 -42
- package/src/modes/rpc/rpc-client.ts +3 -2
- package/src/modes/rpc/rpc-mode.ts +187 -39
- package/src/modes/rpc/rpc-types.ts +5 -2
- package/src/modes/shared/agent-wire/command-dispatch.ts +279 -257
- package/src/modes/shared/agent-wire/command-validation.ts +11 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +30 -1
- package/src/modes/shared/agent-wire/session-registry.ts +109 -0
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +24 -0
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +23 -3
- package/src/modes/shared/agent-wire/unattended-session.ts +16 -1
- package/src/sdk.ts +46 -5
- package/src/secrets/obfuscator.ts +102 -27
- package/src/session/agent-session.ts +179 -25
- package/src/session/blob-store.ts +148 -6
- package/src/session/session-manager.ts +311 -60
- package/src/session/streaming-output.ts +185 -122
- package/src/session/tool-choice-queue.ts +23 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +7 -1
- package/src/skill-state/workflow-hud.ts +106 -10
- package/src/slash-commands/builtin-registry.ts +3 -2
- package/src/task/executor.ts +78 -6
- package/src/task/receipt.ts +5 -0
- package/src/task/render.ts +21 -1
- package/src/task/types.ts +8 -0
- package/src/thinking-metadata.ts +51 -0
- package/src/thinking.ts +26 -46
- package/src/tools/ask.ts +56 -1
- package/src/tools/bash.ts +1 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/job.ts +3 -2
- package/src/tools/monitor.ts +36 -1
- package/src/tools/resolve.ts +93 -18
- package/src/tools/subagent-render.ts +9 -0
- package/src/tools/subagent.ts +26 -2
- package/src/utils/edit-mode.ts +1 -1
- package/src/utils/tool-choice.ts +45 -16
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type DeepInterviewEstablishedFact, type DeepInterviewRoundRecord, type DeepInterviewStateEnvelope, type DeepInterviewTriggerMetadata } from "./deep-interview-state";
|
|
2
|
+
export * from "./deep-interview-state";
|
|
3
|
+
/**
|
|
4
|
+
* Runtime-owned deep-interview round recorder (conflict-aware scoring support).
|
|
5
|
+
*
|
|
6
|
+
* Ownership boundary (per the approved consensus plan): this module owns durable
|
|
7
|
+
* round-record semantics — stable identity, append-or-merge, lifecycle, compact
|
|
8
|
+
* reads, replay detection, and the pure scored-transition validator. Callers such
|
|
9
|
+
* as the `ask` tool only resolve an answer and invoke these helpers; they never
|
|
10
|
+
* compute state paths, merge records, or write `.gjc` files directly. All writes
|
|
11
|
+
* go through the sanctioned state-writer (`writeWorkflowEnvelopeAtomic`).
|
|
12
|
+
*/
|
|
13
|
+
export interface DeepInterviewAnswerInput {
|
|
14
|
+
interviewId?: string;
|
|
15
|
+
round: number;
|
|
16
|
+
round_id?: string;
|
|
17
|
+
questionId?: string;
|
|
18
|
+
questionText: string;
|
|
19
|
+
component?: string;
|
|
20
|
+
dimension?: string;
|
|
21
|
+
ambiguity?: number;
|
|
22
|
+
selectedOptions?: string[];
|
|
23
|
+
customInput?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface DeepInterviewScoringInput {
|
|
26
|
+
interviewId?: string;
|
|
27
|
+
round: number;
|
|
28
|
+
round_id?: string;
|
|
29
|
+
questionId?: string;
|
|
30
|
+
scores: Record<string, number>;
|
|
31
|
+
ambiguity: number;
|
|
32
|
+
triggers?: DeepInterviewTriggerMetadata[];
|
|
33
|
+
}
|
|
34
|
+
export type AppendOrMergeAction = "created" | "noop" | "replaced";
|
|
35
|
+
export interface AppendOrMergeResult {
|
|
36
|
+
rounds: DeepInterviewRoundRecord[];
|
|
37
|
+
action: AppendOrMergeAction;
|
|
38
|
+
record: DeepInterviewRoundRecord;
|
|
39
|
+
}
|
|
40
|
+
export interface DeepInterviewCompactState {
|
|
41
|
+
threshold?: number;
|
|
42
|
+
threshold_source?: string;
|
|
43
|
+
current_ambiguity?: number;
|
|
44
|
+
topology_summary?: {
|
|
45
|
+
active: number;
|
|
46
|
+
deferred: number;
|
|
47
|
+
components: string[];
|
|
48
|
+
};
|
|
49
|
+
established_facts: DeepInterviewEstablishedFact[];
|
|
50
|
+
unresolved_triggers: DeepInterviewTriggerMetadata[];
|
|
51
|
+
recent_scored_rounds: DeepInterviewRoundRecord[];
|
|
52
|
+
pending_shells: DeepInterviewRoundRecord[];
|
|
53
|
+
}
|
|
54
|
+
export interface TransitionValidationResult {
|
|
55
|
+
ok: boolean;
|
|
56
|
+
violations: string[];
|
|
57
|
+
}
|
|
58
|
+
export declare function buildAnswerShell(input: DeepInterviewAnswerInput, now?: string): DeepInterviewRoundRecord;
|
|
59
|
+
/**
|
|
60
|
+
* Append-or-merge by `round_key`. Exactly one record per key:
|
|
61
|
+
* - no existing record -> append (`created`);
|
|
62
|
+
* - identical question_hash + answer_hash -> deterministic no-op (`noop`);
|
|
63
|
+
* - same key, different hashes -> deterministic replacement of the prior shell
|
|
64
|
+
* (`replaced`); the prior answer for that key is superseded and lifecycle resets.
|
|
65
|
+
*/
|
|
66
|
+
export declare function appendOrMergeRound(rounds: readonly DeepInterviewRoundRecord[], shell: DeepInterviewRoundRecord): AppendOrMergeResult;
|
|
67
|
+
/**
|
|
68
|
+
* Merge scoring output into the existing record for the derived key, transitioning
|
|
69
|
+
* it to `scored`. Never appends a second record for the same key; if no shell exists
|
|
70
|
+
* yet (scoring without a prior ask), a scored record is created so data is not lost.
|
|
71
|
+
*/
|
|
72
|
+
export declare function enrichRoundWithScoring(rounds: readonly DeepInterviewRoundRecord[], input: DeepInterviewScoringInput, now?: string): {
|
|
73
|
+
rounds: DeepInterviewRoundRecord[];
|
|
74
|
+
record: DeepInterviewRoundRecord;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Bidirectional invariant: if `next` carries an `active` trigger, the affected
|
|
78
|
+
* dimension must not improve and overall ambiguity must rise vs the prior scored
|
|
79
|
+
* round. `disputed`/`unresolved` triggers are exempt but must carry a rationale.
|
|
80
|
+
*/
|
|
81
|
+
export declare function validateDeepInterviewScoredTransition(prior: DeepInterviewRoundRecord | undefined, next: DeepInterviewRoundRecord): TransitionValidationResult;
|
|
82
|
+
/** Back-compat wrapper: normalize a deep-interview envelope to its canonical nested shape. */
|
|
83
|
+
export declare function ensureDeepInterviewStateShape(value: unknown): DeepInterviewStateEnvelope;
|
|
84
|
+
export declare function projectCompactState(value: unknown, options?: {
|
|
85
|
+
lastN?: number;
|
|
86
|
+
}): DeepInterviewCompactState;
|
|
87
|
+
/** Record an `answered` shell for one round (append-or-merge by durable key). */
|
|
88
|
+
export declare function appendOrMergeDeepInterviewRound(cwd: string, statePath: string, input: DeepInterviewAnswerInput, options?: {
|
|
89
|
+
sessionId?: string;
|
|
90
|
+
}): Promise<{
|
|
91
|
+
action: AppendOrMergeAction;
|
|
92
|
+
record: DeepInterviewRoundRecord;
|
|
93
|
+
}>;
|
|
94
|
+
/** Merge scoring output into the same round record, transitioning to `scored`. */
|
|
95
|
+
export declare function enrichDeepInterviewRoundScoring(cwd: string, statePath: string, input: DeepInterviewScoringInput, options?: {
|
|
96
|
+
sessionId?: string;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
record: DeepInterviewRoundRecord;
|
|
99
|
+
}>;
|
|
100
|
+
/** Compact projection so callers read a slice instead of the full transcript. */
|
|
101
|
+
export declare function readDeepInterviewStateCompact(statePath: string, options?: {
|
|
102
|
+
lastN?: number;
|
|
103
|
+
}): Promise<DeepInterviewCompactState>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./deep-interview-recorder";
|
|
1
2
|
/**
|
|
2
3
|
* Native implementation of `gjc deep-interview`.
|
|
3
4
|
*
|
|
@@ -12,6 +13,7 @@ export interface DeepInterviewCommandResult {
|
|
|
12
13
|
stdout?: string;
|
|
13
14
|
stderr?: string;
|
|
14
15
|
}
|
|
16
|
+
export declare function deepInterviewStatePath(cwd: string, sessionId: string | undefined): string;
|
|
15
17
|
export interface ResolvedDeepInterviewSpecWriteArgs {
|
|
16
18
|
stage: "final";
|
|
17
19
|
slug: string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, dependency-free foundation for deep-interview state shape.
|
|
3
|
+
*
|
|
4
|
+
* Ownership boundary (per the approved consensus plan): this leaf module owns the
|
|
5
|
+
* canonical persisted shape (interview data nested under `state`), durable round
|
|
6
|
+
* identity/hashing, lossless legacy normalization, and the deep-interview-specific
|
|
7
|
+
* envelope/round merge used by every writer (`deep-interview-recorder`,
|
|
8
|
+
* `state-runtime` write/reconcile, seed, and handoff). It MUST NOT import the
|
|
9
|
+
* active-state, state-writer, CLI runtime, or filesystem so it stays cycle-free and
|
|
10
|
+
* trivially testable.
|
|
11
|
+
*/
|
|
12
|
+
export type DeepInterviewRoundLifecycle = "answered" | "pending_scoring" | "scored";
|
|
13
|
+
export type DeepInterviewTriggerKind = "A" | "B" | "C" | "D";
|
|
14
|
+
/** `active` triggers must satisfy the bidirectional invariant; disputed/unresolved are exempt with rationale. */
|
|
15
|
+
export type DeepInterviewTriggerStatus = "active" | "disputed" | "unresolved";
|
|
16
|
+
export interface DeepInterviewEstablishedFact {
|
|
17
|
+
id: string;
|
|
18
|
+
statement: string;
|
|
19
|
+
round: number;
|
|
20
|
+
component?: string;
|
|
21
|
+
dimension?: string;
|
|
22
|
+
evidence?: string;
|
|
23
|
+
disputed: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface DeepInterviewTriggerMetadata {
|
|
26
|
+
kind: DeepInterviewTriggerKind;
|
|
27
|
+
name: string;
|
|
28
|
+
status: DeepInterviewTriggerStatus;
|
|
29
|
+
component: string;
|
|
30
|
+
dimension: string;
|
|
31
|
+
priorDimensionScore?: number;
|
|
32
|
+
newDimensionScore?: number;
|
|
33
|
+
priorAmbiguity?: number;
|
|
34
|
+
newAmbiguity?: number;
|
|
35
|
+
evidence?: string;
|
|
36
|
+
contradictedFactId?: string;
|
|
37
|
+
/** Required when status is `disputed` or `unresolved` to exempt the invariant. */
|
|
38
|
+
rationale?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface DeepInterviewRoundRecord {
|
|
41
|
+
round_key: string;
|
|
42
|
+
round_id?: string;
|
|
43
|
+
round: number;
|
|
44
|
+
question_id?: string;
|
|
45
|
+
question_text?: string;
|
|
46
|
+
question_hash: string;
|
|
47
|
+
answer_hash: string;
|
|
48
|
+
selected_options?: string[];
|
|
49
|
+
custom_input?: string;
|
|
50
|
+
component?: string;
|
|
51
|
+
dimension?: string;
|
|
52
|
+
ambiguity_at_ask?: number;
|
|
53
|
+
lifecycle: DeepInterviewRoundLifecycle;
|
|
54
|
+
answered_at: string;
|
|
55
|
+
scored_at?: string;
|
|
56
|
+
scores?: Record<string, number>;
|
|
57
|
+
ambiguity?: number;
|
|
58
|
+
triggers?: DeepInterviewTriggerMetadata[];
|
|
59
|
+
}
|
|
60
|
+
export interface DeepInterviewStateEnvelope {
|
|
61
|
+
threshold?: number;
|
|
62
|
+
threshold_source?: string;
|
|
63
|
+
state?: Record<string, unknown>;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
export declare function hashContent(value: string): string;
|
|
67
|
+
export declare function questionHash(questionText: string): string;
|
|
68
|
+
export declare function answerHash(selectedOptions: string[] | undefined, customInput: string | undefined): string;
|
|
69
|
+
/**
|
|
70
|
+
* Durable round identity. Prefer `interview_id + round_id`; fall back to
|
|
71
|
+
* `interview_id + round + question.id` when no caller-supplied `round_id` exists.
|
|
72
|
+
*/
|
|
73
|
+
export declare function deriveRoundKey(interviewId: string | undefined, input: {
|
|
74
|
+
round_id?: string;
|
|
75
|
+
round: number;
|
|
76
|
+
questionId?: string;
|
|
77
|
+
}): string;
|
|
78
|
+
/**
|
|
79
|
+
* Canonicalize a deep-interview envelope: interview data nested under `state`,
|
|
80
|
+
* legacy flattened fields hoisted in losslessly, transcript duplicates removed
|
|
81
|
+
* from the top level, and `rounds`/`established_facts` guaranteed to be arrays.
|
|
82
|
+
*
|
|
83
|
+
* Idempotent: a canonical envelope is returned unchanged in shape. Never deletes
|
|
84
|
+
* unknown envelope or nested fields, and never mutates the input.
|
|
85
|
+
*/
|
|
86
|
+
export declare function normalizeDeepInterviewEnvelope(value: unknown): DeepInterviewStateEnvelope;
|
|
87
|
+
/**
|
|
88
|
+
* Lossless, idempotent merge of two round arrays.
|
|
89
|
+
*
|
|
90
|
+
* - Records sharing a durable key (`round_key`, or synthesized from
|
|
91
|
+
* `round_id`/`question_id`) merge into one, preferring scored over answered.
|
|
92
|
+
* - Records without any durable identity are preserved verbatim; an exact
|
|
93
|
+
* duplicate is skipped so repeated writes stay idempotent, but distinct records
|
|
94
|
+
* are never collapsed.
|
|
95
|
+
*
|
|
96
|
+
* Deliberate refinement of the approved plan: rather than mutating opaque legacy
|
|
97
|
+
* records with synthetic `legacy:<index>` keys, they are preserved verbatim with
|
|
98
|
+
* exact-duplicate dedupe. This satisfies the plan's intent (lossless, idempotent,
|
|
99
|
+
* never collapse distinct rounds) without rewriting user-supplied round objects,
|
|
100
|
+
* and keeps free-form extension preservation intact. Recorder-produced records
|
|
101
|
+
* always carry a `round_key`, so the synthetic path is unnecessary in practice.
|
|
102
|
+
*/
|
|
103
|
+
export declare function mergeDeepInterviewRounds(existing: readonly Record<string, unknown>[], incoming: readonly Record<string, unknown>[]): Record<string, unknown>[];
|
|
104
|
+
/**
|
|
105
|
+
* Deep-interview-specific envelope merge. Unlike the generic shallow null-delete
|
|
106
|
+
* merge, this keeps interview data nested under `state`, never deletes `state`,
|
|
107
|
+
* and merges `rounds` losslessly by durable key so a partial write (e.g. a
|
|
108
|
+
* scoring update) cannot drop recorder-written transcript history.
|
|
109
|
+
*/
|
|
110
|
+
export declare function mergeDeepInterviewEnvelope(existing: unknown, incoming: unknown, options?: {
|
|
111
|
+
replace?: boolean;
|
|
112
|
+
}): DeepInterviewStateEnvelope;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text rendering for `gjc gc` reports. JSON output is produced directly in
|
|
3
|
+
* `gc-runtime.ts`; this module owns the human-readable grouped report.
|
|
4
|
+
*/
|
|
5
|
+
import type { GcReport } from "./gc-runtime";
|
|
6
|
+
export declare function buildGcReportText(report: GcReport): string;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gjc gc` runtime — a global, liveness-only, dry-run-by-default garbage
|
|
3
|
+
* collector for stale GJC session/PID records.
|
|
4
|
+
*
|
|
5
|
+
* Design (see .gjc/plans/ralplan/2026-06-13-1347-954f/pending-approval.md):
|
|
6
|
+
* - This module is an ORCHESTRATOR only. It owns the shared PID probe, the
|
|
7
|
+
* report/exit-code policy, and text/JSON rendering. It must NOT parse private
|
|
8
|
+
* store layouts directly; every store is reached through an injectable
|
|
9
|
+
* `GcStoreAdapter` that lives next to its store owner.
|
|
10
|
+
* - Liveness-only and fail-closed: only `ESRCH` (no such process) is `dead`
|
|
11
|
+
* (removable). `process.kill(pid, 0)` success, `EPERM`, and any unknown probe
|
|
12
|
+
* error all mean KEEP — a live process is never signalled or killed.
|
|
13
|
+
* - Dry-run by default: nothing is deleted unless `--prune`/`--force`.
|
|
14
|
+
*/
|
|
15
|
+
export type GcStore = "harness_leases" | "team_workers" | "file_locks" | "tmux_sessions" | "registry_entries";
|
|
16
|
+
export declare const GC_STORES: readonly GcStore[];
|
|
17
|
+
/** Why a probed pid is kept instead of treated as dead. */
|
|
18
|
+
export type GcPidKeepReason = "alive" | "eperm" | "unknown";
|
|
19
|
+
export interface GcPidProbeResult {
|
|
20
|
+
/** `dead` only on ESRCH; `keep` for alive/eperm/unknown (fail-closed). */
|
|
21
|
+
status: "dead" | "keep";
|
|
22
|
+
reason?: GcPidKeepReason;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Single shared liveness contract threaded through every classifier + prune path. */
|
|
26
|
+
export type GcPidProbe = (pid: number) => GcPidProbeResult;
|
|
27
|
+
export type GcPidStatus = "dead" | "alive" | "eperm" | "unknown" | "none";
|
|
28
|
+
export type GcAction = "none" | "would_remove" | "removed" | "remove_failed" | "skipped";
|
|
29
|
+
export interface GcRecord {
|
|
30
|
+
store: GcStore;
|
|
31
|
+
/** Stable identifier: session id, lock dir path, worker id, tmux name, registry session id. */
|
|
32
|
+
id: string;
|
|
33
|
+
path?: string;
|
|
34
|
+
root?: string;
|
|
35
|
+
pid?: number;
|
|
36
|
+
pid_status?: GcPidStatus;
|
|
37
|
+
/** Store-specific classification label (e.g. "dead", "live", "unclassified", "terminal_lifecycle"). */
|
|
38
|
+
status: string;
|
|
39
|
+
stale: boolean;
|
|
40
|
+
removable: boolean;
|
|
41
|
+
action: GcAction;
|
|
42
|
+
reason: string;
|
|
43
|
+
detail?: string;
|
|
44
|
+
error?: string;
|
|
45
|
+
removed?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface GcError {
|
|
48
|
+
store: GcStore;
|
|
49
|
+
scope: string;
|
|
50
|
+
message: string;
|
|
51
|
+
}
|
|
52
|
+
export interface GcCollectResult {
|
|
53
|
+
records: GcRecord[];
|
|
54
|
+
errors: GcError[];
|
|
55
|
+
}
|
|
56
|
+
export interface GcPruneOutcome {
|
|
57
|
+
removed: boolean;
|
|
58
|
+
error?: string;
|
|
59
|
+
/** Set when a removable record was skipped at prune time (e.g. TOCTOU became live). */
|
|
60
|
+
skipped?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface GcContext {
|
|
63
|
+
probe: GcPidProbe;
|
|
64
|
+
force: boolean;
|
|
65
|
+
env: NodeJS.ProcessEnv;
|
|
66
|
+
cwd: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A store-owned GC adapter. `collect` discovers + classifies (using the shared
|
|
70
|
+
* probe) without mutating anything. `prune` removes a single record, and MUST
|
|
71
|
+
* re-validate / re-probe immediately before any destructive action.
|
|
72
|
+
*/
|
|
73
|
+
export interface GcStoreAdapter {
|
|
74
|
+
store: GcStore;
|
|
75
|
+
collect(ctx: GcContext): Promise<GcCollectResult>;
|
|
76
|
+
prune(record: GcRecord, ctx: GcContext): Promise<GcPruneOutcome>;
|
|
77
|
+
}
|
|
78
|
+
export interface GcCounts {
|
|
79
|
+
discovered: number;
|
|
80
|
+
stale: number;
|
|
81
|
+
alive: number;
|
|
82
|
+
eperm: number;
|
|
83
|
+
unknown: number;
|
|
84
|
+
terminal_lifecycle: number;
|
|
85
|
+
unclassified: number;
|
|
86
|
+
would_remove: number;
|
|
87
|
+
removed: number;
|
|
88
|
+
failed: number;
|
|
89
|
+
errors: number;
|
|
90
|
+
by_store: Record<GcStore, {
|
|
91
|
+
discovered: number;
|
|
92
|
+
stale: number;
|
|
93
|
+
would_remove: number;
|
|
94
|
+
removed: number;
|
|
95
|
+
failed: number;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
export interface GcReport {
|
|
99
|
+
dry_run: boolean;
|
|
100
|
+
stores: Record<GcStore, GcRecord[]>;
|
|
101
|
+
counts: GcCounts;
|
|
102
|
+
errors: GcError[];
|
|
103
|
+
}
|
|
104
|
+
export interface GcRunResult {
|
|
105
|
+
stdout: string;
|
|
106
|
+
stderr: string;
|
|
107
|
+
status: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The shared, fail-closed PID probe. ESRCH => dead/removable; success => alive;
|
|
111
|
+
* EPERM => kept (owned by another user); any other error => kept as unknown.
|
|
112
|
+
*/
|
|
113
|
+
export declare const gcPidProbe: GcPidProbe;
|
|
114
|
+
/** Map a `GcPidProbe` onto the harness lease probe shape (`"alive"|"dead"|"eperm"`). */
|
|
115
|
+
export declare function gcProbeToLeasePidStatus(probe: GcPidProbe): (pid: number) => "alive" | "dead" | "eperm";
|
|
116
|
+
/** Translate a probe result into a record-friendly pid status label. */
|
|
117
|
+
export declare function gcPidStatusLabel(result: GcPidProbeResult): Exclude<GcPidStatus, "none">;
|
|
118
|
+
/**
|
|
119
|
+
* Collect every store's records (catching hard discovery errors per adapter),
|
|
120
|
+
* then optionally prune removable records with per-record revalidation.
|
|
121
|
+
*/
|
|
122
|
+
export declare function collectGcReport(adapters: GcStoreAdapter[], ctx: GcContext, prune: boolean): Promise<GcReport>;
|
|
123
|
+
/**
|
|
124
|
+
* Exit-code policy:
|
|
125
|
+
* - usage/parse error => 2
|
|
126
|
+
* - hard discovery errors => 1 (both modes)
|
|
127
|
+
* - prune mode with a failed intended removal => 1
|
|
128
|
+
* - otherwise => 0
|
|
129
|
+
*/
|
|
130
|
+
export declare function computeExitCode(report: GcReport): number;
|
|
131
|
+
export declare function runGjcGcCommand(argv: string[], cwd?: string, env?: NodeJS.ProcessEnv, adapters?: GcStoreAdapter[]): Promise<GcRunResult>;
|
|
132
|
+
export declare function gcHelpText(): string;
|
|
133
|
+
/** Lazily assemble the real store adapters (kept lazy to avoid import cycles). */
|
|
134
|
+
export declare function defaultGcAdapters(): Promise<GcStoreAdapter[]>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure parse + summarize for ledger-backed skill observability.
|
|
3
|
+
*
|
|
4
|
+
* Workflow progress for ultragoal/ralplan cannot be observed via subagent tool
|
|
5
|
+
* events (those skills persist through `bash`-backed `gjc` CLI calls whose tool
|
|
6
|
+
* `details` carry no structured payload). The durable source of truth is the
|
|
7
|
+
* append-only ledgers:
|
|
8
|
+
* - ultragoal: `.gjc/ultragoal/ledger.jsonl`
|
|
9
|
+
* - ralplan: `.gjc/plans/ralplan/<run-id>/index.jsonl`
|
|
10
|
+
*
|
|
11
|
+
* This module is I/O-free: callers read the files and pass lines or already-parsed
|
|
12
|
+
* rows. It feeds the compact HUD chip builders in `skill-state/workflow-hud.ts`
|
|
13
|
+
* via the runtime sync paths. Display-string helpers stay theme-free.
|
|
14
|
+
*/
|
|
15
|
+
/** Minimal projection of an ultragoal ledger row used for the HUD chip. */
|
|
16
|
+
export interface UltragoalLedgerEventLite {
|
|
17
|
+
/** Normalized from the row's `event` field, or `type` for reconcile rows. */
|
|
18
|
+
event: string;
|
|
19
|
+
goalId?: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
timestamp?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Coerce an already-parsed ledger row into the lite shape. Accepts both the
|
|
25
|
+
* `event`-keyed vocabulary (plan_created, goal_started, goal_checkpointed,
|
|
26
|
+
* steering_accepted/rejected, review_blockers_recorded) and the `type`-keyed
|
|
27
|
+
* reconcile-failure row (`type: "reconcile_failed"`). Returns undefined when no
|
|
28
|
+
* event/type discriminator is present.
|
|
29
|
+
*/
|
|
30
|
+
export declare function coerceUltragoalLedgerEvent(row: Record<string, unknown>): UltragoalLedgerEventLite | undefined;
|
|
31
|
+
/** Parse a single ultragoal ledger JSONL line; undefined for blank/malformed lines. */
|
|
32
|
+
export declare function parseUltragoalLedgerLine(line: string): UltragoalLedgerEventLite | undefined;
|
|
33
|
+
/** The most recent event, or undefined when the ledger is empty. */
|
|
34
|
+
export declare function latestUltragoalLedgerEvent(events: readonly UltragoalLedgerEventLite[]): UltragoalLedgerEventLite | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Best-effort latest event from raw ledger text: parses line-by-line and skips
|
|
37
|
+
* blank/malformed rows so a torn or hand-edited ledger never throws on the HUD
|
|
38
|
+
* path. Strict receipt consumers should keep using the validating reader.
|
|
39
|
+
*/
|
|
40
|
+
export declare function latestUltragoalLedgerEventFromText(text: string): UltragoalLedgerEventLite | undefined;
|
|
41
|
+
/** Minimal projection of a ralplan `index.jsonl` row. */
|
|
42
|
+
export interface RalplanIndexRow {
|
|
43
|
+
stage: string;
|
|
44
|
+
stageN?: number;
|
|
45
|
+
}
|
|
46
|
+
/** Parse a single ralplan index JSONL line; undefined for blank/malformed lines. */
|
|
47
|
+
export declare function parseRalplanIndexLine(line: string): RalplanIndexRow | undefined;
|
|
48
|
+
export interface RalplanIndexSummary {
|
|
49
|
+
/** Number of consensus iterations (planner/revision boundaries), >= 0. */
|
|
50
|
+
iteration: number;
|
|
51
|
+
/** Stage names present in the current (latest) iteration, in append order. */
|
|
52
|
+
currentStages: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Derive iteration count and current-iteration stage presence from index rows.
|
|
56
|
+
*
|
|
57
|
+
* `stage_n` is NOT used as the iteration key: it is stored verbatim per row and a
|
|
58
|
+
* single planner/architect/critic pass can span multiple stage_n values. Instead,
|
|
59
|
+
* a `planner` or `revision` row opens a new iteration and subsequent rows attach
|
|
60
|
+
* to it. No verdict is derived here (index rows carry none).
|
|
61
|
+
*/
|
|
62
|
+
export declare function summarizeRalplanIndex(rows: readonly RalplanIndexRow[]): RalplanIndexSummary;
|
|
63
|
+
/**
|
|
64
|
+
* Compact, theme-free presence string for the ralplan `stages` chip, e.g.
|
|
65
|
+
* `P·A·C`. Collapses past `cap` with a "… N more" suffix. Returns undefined when
|
|
66
|
+
* there are no stages.
|
|
67
|
+
*/
|
|
68
|
+
export declare function formatRalplanStagePresence(stages: readonly string[], cap?: number): string | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GC adapter for team workers (`.gjc/state/team/<name>/workers/<id>/` heartbeat
|
|
3
|
+
* + lifecycle). Liveness-only: numeric PID status dominates lifecycle/heartbeat
|
|
4
|
+
* signals.
|
|
5
|
+
*/
|
|
6
|
+
import type { GcStoreAdapter } from "./gc-runtime";
|
|
7
|
+
export declare const teamWorkersGcAdapter: GcStoreAdapter;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { WorkflowHudSummary } from "../skill-state/active-state";
|
|
2
|
+
import type { GcPidProbe, GcRecord } from "./gc-runtime";
|
|
2
3
|
export type GjcTeamPhase = "starting" | "running" | "awaiting_integration" | "complete" | "failed" | "cancelled";
|
|
3
4
|
export type GjcTeamTaskStatus = "pending" | "blocked" | "in_progress" | "completed" | "failed";
|
|
4
5
|
export type GjcWorkerStatusState = "idle" | "working" | "blocked" | "done" | "failed" | "draining" | "unknown";
|
|
@@ -272,10 +273,13 @@ export interface GjcWorkerIntegrationAttemptRequestResult {
|
|
|
272
273
|
}
|
|
273
274
|
export declare const GJC_TEAM_API_OPERATIONS: readonly ["send-message", "broadcast", "mailbox-list", "mailbox-mark-delivered", "mailbox-mark-notified", "notification-list", "notification-read", "notification-replay", "notification-mark-pane-attempt", "worker-startup-ack", "create-task", "read-task", "list-tasks", "update-task", "claim-task", "transition-task-status", "transition-task", "release-task-claim", "read-config", "read-manifest", "read-worker-status", "update-worker-status", "read-worker-heartbeat", "recover-stale-claims", "update-worker-heartbeat", "write-worker-inbox", "write-worker-identity", "append-event", "read-events", "read-traces", "await-event", "write-shutdown-request", "read-shutdown-ack", "read-monitor-snapshot", "write-monitor-snapshot", "read-task-approval", "write-task-approval"];
|
|
274
275
|
export declare function resolveGjcTeamStateRoot(cwd?: string, env?: NodeJS.ProcessEnv): string;
|
|
276
|
+
/** @internal */
|
|
277
|
+
export declare function listTeamWorkerGcRecords(teamRoot: string, probe: GcPidProbe): Promise<GcRecord[]>;
|
|
278
|
+
/** @internal */
|
|
279
|
+
export declare function pruneTeamWorkerGcRecord(record: GcRecord, probe: GcPidProbe): Promise<boolean>;
|
|
275
280
|
export declare function persistGjcTeamModeStateSummary(snapshot: GjcTeamSnapshot, cwd?: string): Promise<void>;
|
|
276
281
|
export declare function recoverGjcTeamStaleClaims(teamName: string, cwd?: string, env?: NodeJS.ProcessEnv): Promise<GjcTeamLivenessRecoveryResult>;
|
|
277
282
|
type GjcTeamTaskMetadataInput = Partial<Pick<GjcTeamTask, "owner" | "lane" | "required_role" | "allowed_roles" | "depends_on" | "blocked_by">>;
|
|
278
|
-
export declare function resolveGjcTmuxCommand(env?: NodeJS.ProcessEnv): string;
|
|
279
283
|
export declare function resolveGjcWorkerCommand(cwd?: string, env?: NodeJS.ProcessEnv): string;
|
|
280
284
|
export type GjcWorkerCheckpointClassification = {
|
|
281
285
|
kind: "clean";
|
|
@@ -21,6 +21,20 @@ export interface TmuxCommandResult {
|
|
|
21
21
|
export type TmuxCommandRunner = (args: string[]) => TmuxCommandResult;
|
|
22
22
|
export declare function envDisabled(value: string | undefined): boolean;
|
|
23
23
|
export declare function resolveGjcTmuxCommand(env?: NodeJS.ProcessEnv): string;
|
|
24
|
+
/**
|
|
25
|
+
* Build the exact-session target for tmux *option* commands
|
|
26
|
+
* (`show-options` / `set-option`) and `display-message -t`.
|
|
27
|
+
*
|
|
28
|
+
* Session-scoped commands such as `kill-session` / `attach-session` resolve a
|
|
29
|
+
* bare exact target (`=NAME`), but tmux 3.6a refuses to resolve a bare `=NAME`
|
|
30
|
+
* for option/display commands. Appending the empty window separator (`=NAME:`)
|
|
31
|
+
* keeps the exact-session match while giving tmux the window-qualified target
|
|
32
|
+
* those commands require. See gajae-code#580.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildGjcTmuxExactOptionTarget(sessionName: string): string;
|
|
35
|
+
export declare const GJC_TMUX_UNTAGGED_REASON = "gjc_tmux_session_untagged";
|
|
36
|
+
export declare function buildGjcTmuxUntaggedSessionHint(tmuxCommand: string): string;
|
|
37
|
+
export declare function buildGjcTmuxUntaggedSessionError(sessionName: string, tmuxCommand: string): string;
|
|
24
38
|
export declare function sanitizeTmuxToken(value: string): string;
|
|
25
39
|
export declare function buildGjcTmuxSessionSlug(value: string): string;
|
|
26
40
|
export declare function buildGjcTmuxSessionName(env?: NodeJS.ProcessEnv, context?: {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GC adapter for gjc-tagged tmux sessions. Stale iff `@gjc-project` path is gone
|
|
3
|
+
* OR `@gjc-branch` has no live git worktree. Removal is a spec-authorized
|
|
4
|
+
* destructive `kill-session`, gated by exact-target re-read + revalidation.
|
|
5
|
+
*/
|
|
6
|
+
import type { GcStoreAdapter } from "./gc-runtime";
|
|
7
|
+
export declare const tmuxSessionsGcAdapter: GcStoreAdapter;
|
|
@@ -9,9 +9,22 @@ export interface GjcTmuxSessionStatus {
|
|
|
9
9
|
branchSlug?: string;
|
|
10
10
|
project?: string;
|
|
11
11
|
}
|
|
12
|
+
export interface GjcTmuxSessionTagsForGc {
|
|
13
|
+
profile?: string;
|
|
14
|
+
project?: string;
|
|
15
|
+
branch?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface GjcTmuxSessionsForGc {
|
|
18
|
+
tagged: GjcTmuxSessionStatus[];
|
|
19
|
+
untagged: string[];
|
|
20
|
+
}
|
|
12
21
|
export declare function listGjcTmuxSessions(env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus[];
|
|
22
|
+
/** @internal */
|
|
23
|
+
export declare function listTmuxSessionsForGc(env?: NodeJS.ProcessEnv): GjcTmuxSessionsForGc;
|
|
13
24
|
export declare function findGjcTmuxSessionByBranch(branch: string, env?: NodeJS.ProcessEnv, project?: string | null): GjcTmuxSessionStatus | undefined;
|
|
14
25
|
export declare function statusGjcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
|
|
15
26
|
export declare function createGjcTmuxSession(env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
|
|
27
|
+
/** @internal */
|
|
28
|
+
export declare function readTmuxSessionTagsForGc(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionTagsForGc;
|
|
16
29
|
export declare function removeGjcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
|
|
17
30
|
export declare function attachGjcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): never;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Stateless `gjc harness` CLI calls reach the owner via {@link resolveOwner} + the endpoint.
|
|
12
12
|
*/
|
|
13
13
|
import { type FinalizeChecks, type ValidationCommandSpec } from "./finalize";
|
|
14
|
-
import type
|
|
14
|
+
import { type HarnessRpc } from "./rpc-adapter";
|
|
15
15
|
import { type SessionLease } from "./session-lease";
|
|
16
16
|
export interface OwnerOptions {
|
|
17
17
|
root: string;
|
|
@@ -44,3 +44,10 @@ export interface ResolvedOwner {
|
|
|
44
44
|
}
|
|
45
45
|
/** Determine whether a live owner currently holds the session (for CLI routing). */
|
|
46
46
|
export declare function resolveOwner(root: string, sessionId: string): Promise<ResolvedOwner>;
|
|
47
|
+
/**
|
|
48
|
+
* Owner liveness for verbs that do not route to the owner (e.g. `classify`): a routable owner
|
|
49
|
+
* has a live lease and a socket endpoint. This is the same lease/socket probe `observe` uses to
|
|
50
|
+
* decide routing, so non-routing verbs derive `ownerLive` consistently instead of assuming the
|
|
51
|
+
* owner is gone (which would misclassify a live owner as vanished/restart-clean).
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveOwnerLive(root: string, sessionId: string): Promise<boolean>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReceiptEnvelope } from "./receipts";
|
|
2
|
+
export declare const RECEIPT_SPOOL_DIR_ENV = "GJC_RECEIPT_SPOOL_DIR";
|
|
3
|
+
export declare const RECEIPT_SPOOL_FILENAME = "spool.jsonl";
|
|
4
|
+
export declare const RECEIPT_SPOOL_CURSOR_WIDTH = 12;
|
|
5
|
+
export interface ReceiptSpoolRecord {
|
|
6
|
+
cursor: string;
|
|
7
|
+
envelope: ReceiptEnvelope<unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface ReceiptSpoolAppendResult {
|
|
10
|
+
cursor: string;
|
|
11
|
+
path: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function withReceiptSpoolDir<T>(spoolDir: string, fn: () => Promise<T>): Promise<T>;
|
|
14
|
+
export declare function resolveReceiptSpoolDir(env?: NodeJS.ProcessEnv): string | undefined;
|
|
15
|
+
export declare function receiptSpoolPath(spoolDir: string): string;
|
|
16
|
+
export declare function formatReceiptSpoolCursor(cursor: bigint): string;
|
|
17
|
+
export declare function readHighestReceiptSpoolCursor(spoolDir: string): Promise<bigint>;
|
|
18
|
+
export declare function appendReceiptToSpool(spoolDir: string, envelope: ReceiptEnvelope<unknown>): Promise<ReceiptSpoolAppendResult>;
|
|
19
|
+
export declare function appendReceiptToConfiguredSpool(envelope: ReceiptEnvelope<unknown>, env?: NodeJS.ProcessEnv): Promise<ReceiptSpoolAppendResult | undefined>;
|
|
@@ -9,11 +9,16 @@ import type { HarnessLifecycle, NextAllowedAction, PrimitiveResponse, SessionSta
|
|
|
9
9
|
export declare function isTerminal(lifecycle: HarnessLifecycle): boolean;
|
|
10
10
|
export declare function canTransition(from: HarnessLifecycle, to: HarnessLifecycle): boolean;
|
|
11
11
|
export declare function assertTransition(from: HarnessLifecycle, to: HarnessLifecycle): void;
|
|
12
|
+
export interface NextAllowedActionsOptions {
|
|
13
|
+
/** Additional live-owner/RPC readiness gate for submit, e.g. rpc-not-idle. */
|
|
14
|
+
submitUnavailableReason?: string | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function submitUnavailableReason(lifecycle: HarnessLifecycle, ownerLive: boolean, gateReason?: string | null): string | null;
|
|
12
17
|
/**
|
|
13
18
|
* Derive the permitted next actions for a session given its lifecycle and whether
|
|
14
19
|
* a live owner currently holds the lease.
|
|
15
20
|
*/
|
|
16
|
-
export declare function nextAllowedActions(lifecycle: HarnessLifecycle, ownerLive: boolean): NextAllowedAction[];
|
|
21
|
+
export declare function nextAllowedActions(lifecycle: HarnessLifecycle, ownerLive: boolean, options?: NextAllowedActionsOptions): NextAllowedAction[];
|
|
17
22
|
export declare function buildStateView(state: SessionState, ownerLive: boolean): SessionStateView;
|
|
18
23
|
/** Build the universal contract response carried by every primitive. */
|
|
19
24
|
export declare function buildResponse<E extends Record<string, unknown>>(state: SessionState, ownerLive: boolean, evidence: E, ok?: boolean): PrimitiveResponse<E>;
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import type { EventEnvelope, ReceiptFamily, SessionState } from "./types";
|
|
2
|
+
interface HarnessRootRegistryEntry {
|
|
3
|
+
root: string;
|
|
4
|
+
updatedAt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface HarnessRootRegistryForGc {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
roots: HarnessRootRegistryEntry[];
|
|
9
|
+
}
|
|
10
|
+
export interface HarnessRootRegistryListingForGc {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
file: string;
|
|
13
|
+
roots: HarnessRootRegistryEntry[];
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
2
16
|
interface ResolveHarnessSessionRootOptions {
|
|
3
17
|
expectedWorkspace?: string;
|
|
4
18
|
}
|
|
5
19
|
export declare function canonicalWorkspacePath(workspace: string): string;
|
|
20
|
+
/** @internal */
|
|
21
|
+
export declare function listHarnessRootRegistriesForGc(env?: NodeJS.ProcessEnv): Promise<HarnessRootRegistryListingForGc[]>;
|
|
22
|
+
/** @internal */
|
|
23
|
+
export declare function rewriteHarnessRootRegistryForGc(file: string, registry: HarnessRootRegistryForGc): Promise<void>;
|
|
24
|
+
/** @internal */
|
|
25
|
+
export declare function removeHarnessRootRegistryFileForGc(file: string): Promise<void>;
|
|
6
26
|
export declare const MAX_UNIX_SOCKET_PATH_BYTES = 100;
|
|
7
27
|
export declare function controlSocketPath(root: string, sessionId: string, env?: NodeJS.ProcessEnv): string;
|
|
8
28
|
export declare class StorageError extends Error {
|
|
@@ -138,6 +138,10 @@ export interface Observation {
|
|
|
138
138
|
rpcLive?: boolean;
|
|
139
139
|
/** ISO timestamp of the most recent RPC frame the owner observed, if any. */
|
|
140
140
|
rpcLastFrameAt?: string | null;
|
|
141
|
+
/** True only when owner/rpc/lifecycle gates indicate a prompt can be submitted now. */
|
|
142
|
+
readyForSubmit?: boolean;
|
|
143
|
+
/** Present when readyForSubmit is false; mirrors submit's nextAllowedActions reason. */
|
|
144
|
+
submitUnavailableReason?: string | null;
|
|
141
145
|
}
|
|
142
146
|
/** Input to the deterministic recovery classifier. */
|
|
143
147
|
export interface ClassifyInput {
|
|
@@ -108,12 +108,12 @@ export declare function summarizeMentalModel(model: MentalModelSummary): string;
|
|
|
108
108
|
* snapshot only; the diff is computed locally for display purposes.
|
|
109
109
|
*
|
|
110
110
|
* This is intentionally minimal — for "what changed" at a glance, not for a
|
|
111
|
-
* full structural diff. Each side is capped at `MAX_LCS_LINES` lines
|
|
112
|
-
* the
|
|
113
|
-
*
|
|
114
|
-
*
|
|
111
|
+
* full structural diff. Each side is capped at `MAX_LCS_LINES` lines before
|
|
112
|
+
* the Hunt-Szymanski LCS pass so a long curated model can never hang the TUI;
|
|
113
|
+
* output is then capped at `maxLines` so the rendered diff stays readable. The
|
|
114
|
+
* cap is signalled inline.
|
|
115
115
|
*/
|
|
116
|
-
/** Hard cap on input line count per side before LCS. Keeps
|
|
116
|
+
/** Hard cap on input line count per side before LCS. Keeps worst-case repeated-line matching bounded. */
|
|
117
117
|
export declare const MAX_LCS_LINES = 1000;
|
|
118
118
|
export declare function diffMentalModelContent(previous: string | null, current: string, maxLines?: number): string;
|
|
119
119
|
/** Awaited only by the first-turn race in `beforeAgentStartPrompt`. */
|