@keb-org/consol 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +265 -2
- package/dist/consol.d.ts +36 -0
- package/dist/errors.d.ts +29 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +815 -0
- package/dist/index.mjs +5 -0
- package/dist/stdio.d.ts +120 -0
- package/dist/transport.d.ts +38 -0
- package/dist/types.d.ts +395 -0
- package/dist/vault.d.ts +180 -0
- package/package.json +58 -4
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Thin ESM wrapper over the one CommonJS implementation: import and require share every class,
|
|
2
|
+
// so instanceof and ConsolError.is() agree. Types come from index.d.ts for both.
|
|
3
|
+
import sdk from "./index.js";
|
|
4
|
+
|
|
5
|
+
export const { Consol, ConsolError, Vault, createVault, openVault, httpStatus, sliceUtf8 } = sdk;
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type CallOptions, type Context, type Transport } from "./transport";
|
|
2
|
+
import type { Reply } from "./types";
|
|
3
|
+
/** Bound of the kept stderr tail and of any one line, in UTF-8 bytes. */
|
|
4
|
+
export declare const STDERR_TAIL_BYTES = 4096;
|
|
5
|
+
/** Any OpenAI-shaped `/embeddings` endpoint; without it recall stays lexical-only. */
|
|
6
|
+
export interface EmbeddingOptions {
|
|
7
|
+
url: string;
|
|
8
|
+
/** Omit for endpoints that take no key. */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
model: string;
|
|
11
|
+
dims?: number;
|
|
12
|
+
queryPrefix?: string;
|
|
13
|
+
batchSize?: number;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Jev advice (experimental). */
|
|
17
|
+
export interface JevOptions {
|
|
18
|
+
url?: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
model?: string;
|
|
21
|
+
/** `false` turns automatic triage off. */
|
|
22
|
+
auto?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* What starts the `consol stdio` child. Options become the child's environment (never argv);
|
|
26
|
+
* inherited CONSOL_* and RUST_LOG are stripped first and `env` is applied last.
|
|
27
|
+
*/
|
|
28
|
+
export interface EngineOptions {
|
|
29
|
+
/** Database URL: PostgreSQL with pgvector, or CockroachDB. Without it this process's `CONSOL_DB_URL` applies; the child needs one. */
|
|
30
|
+
db?: string;
|
|
31
|
+
embedding?: EmbeddingOptions;
|
|
32
|
+
jev?: JevOptions;
|
|
33
|
+
/** Explicit binary; otherwise CONSOL_BIN, the platform package, then PATH. */
|
|
34
|
+
binaryPath?: string;
|
|
35
|
+
env?: Record<string, string>;
|
|
36
|
+
/** Default per-call deadline in ms (300000); 0 disables it. */
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
/** Receives each child stderr line. Without it lines are only kept for error messages. */
|
|
39
|
+
onLog?: (line: string) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare function engineEnv(o: EngineOptions): Record<string, string>;
|
|
42
|
+
export interface StdioOptions extends EngineOptions {
|
|
43
|
+
/** `--vault PATH` or `--vault-root ROOT`. */
|
|
44
|
+
location: ["--vault" | "--vault-root", string];
|
|
45
|
+
/** After the ready line: create (first start only) or open this vault. A restart always opens. */
|
|
46
|
+
boot?: {
|
|
47
|
+
vault: string;
|
|
48
|
+
create: boolean;
|
|
49
|
+
};
|
|
50
|
+
/** The SDK version the child's major.minor must match. */
|
|
51
|
+
sdkVersion: string;
|
|
52
|
+
}
|
|
53
|
+
export interface BinaryResolution {
|
|
54
|
+
path: string;
|
|
55
|
+
attempts: string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Explicit path authoritative (missing file fails here), then CONSOL_BIN authoritative, then the
|
|
59
|
+
* platform package resolved relative to this SDK file, then PATH. CONSOL_BIN is read only here,
|
|
60
|
+
* never sent to the child.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveBinary(explicit?: string): BinaryResolution;
|
|
63
|
+
/** Child env: host minus ALL CONSOL_* and RUST_LOG, then options, then explicit env last. */
|
|
64
|
+
export declare function childEnv(base?: Record<string, string>, extra?: Record<string, string>): Record<string, string>;
|
|
65
|
+
/** The last STDERR_TAIL_BYTES bytes of `text`, cut on a character boundary. */
|
|
66
|
+
export declare function lastBytes(text: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* One `consol stdio` child speaking JSON lines (docs W-wire): a ready line, then `{id, op, ...}`
|
|
69
|
+
* frames answered by `{id, reply}` lines in any order. Stdin EOF ends the child gracefully.
|
|
70
|
+
*/
|
|
71
|
+
export declare class StdioTransport implements Transport {
|
|
72
|
+
private readonly opts;
|
|
73
|
+
private readonly attempts;
|
|
74
|
+
private readonly binary;
|
|
75
|
+
private readonly timeoutMs;
|
|
76
|
+
private child;
|
|
77
|
+
private reader;
|
|
78
|
+
private generation;
|
|
79
|
+
private nextId;
|
|
80
|
+
private pending;
|
|
81
|
+
private starting;
|
|
82
|
+
/** After the first successful start, every restart opens the vault instead of creating it. */
|
|
83
|
+
private started;
|
|
84
|
+
private closed;
|
|
85
|
+
private closing;
|
|
86
|
+
private stderrTail;
|
|
87
|
+
private stderrTailBytes;
|
|
88
|
+
version: string | null;
|
|
89
|
+
constructor(opts: StdioOptions);
|
|
90
|
+
private decoder;
|
|
91
|
+
private stderrPartial;
|
|
92
|
+
private onStderr;
|
|
93
|
+
private flushStderr;
|
|
94
|
+
private pushLine;
|
|
95
|
+
private tailText;
|
|
96
|
+
/**
|
|
97
|
+
* Idle children are unref'd so a forgotten close() never keeps Node or Bun alive. Only the process
|
|
98
|
+
* handle toggles (its stdio is unref'd once at spawn): Bun cannot unref a stream again once ref'd.
|
|
99
|
+
*/
|
|
100
|
+
private updateRef;
|
|
101
|
+
private onDeath;
|
|
102
|
+
/**
|
|
103
|
+
* Final and idempotent: in-flight calls reject now, later calls with `closed`. Every close()
|
|
104
|
+
* returns the same promise, settled once the child has exited.
|
|
105
|
+
*/
|
|
106
|
+
close(): Promise<void>;
|
|
107
|
+
private shutdown;
|
|
108
|
+
/** Starts the child and waits for its ready line, unless one is running or starting already. */
|
|
109
|
+
start(): Promise<void>;
|
|
110
|
+
private spawn;
|
|
111
|
+
private onLine;
|
|
112
|
+
/** Waits for the answer to `id`, writing `frame` first unless it is null (the ready line). */
|
|
113
|
+
private call;
|
|
114
|
+
/** One frame; after a crash the next call starts the child once more. Never retried. */
|
|
115
|
+
private send;
|
|
116
|
+
/** Runs one envelope under `ctx`. The reply is returned untouched, tool errors included. */
|
|
117
|
+
handle(body: unknown, ctx: Context, options?: CallOptions): Promise<Reply>;
|
|
118
|
+
/** Create or open a vault by name; a refusal arrives as the reply's `vault_exists` / `vault_not_found`. */
|
|
119
|
+
vaultOp(op: "create_vault" | "open_vault", vault: string, options?: CallOptions): Promise<Reply>;
|
|
120
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Reply } from "./types";
|
|
2
|
+
export declare const DEFAULT_TIMEOUT_MS = 300000;
|
|
3
|
+
export interface CallOptions {
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
/** Per-call deadline in ms; 0 disables it. Defaults to the vault's `timeoutMs`. */
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
/** What a backend knows about the caller; it comes from the developer's own auth, never from a request. */
|
|
9
|
+
export interface Context {
|
|
10
|
+
/** Vaults the caller may use; `null` means any vault, on purpose. */
|
|
11
|
+
vaults: string[] | null;
|
|
12
|
+
/** Pins the agent; the request cannot name another one. */
|
|
13
|
+
agent?: string | null;
|
|
14
|
+
}
|
|
15
|
+
/** One way to move an envelope: a stdio child or HTTP. Internal: only Vault and Consol are public. */
|
|
16
|
+
export interface Transport {
|
|
17
|
+
/** Server version of the last reply; null before the first. */
|
|
18
|
+
readonly version: string | null;
|
|
19
|
+
handle(body: unknown, ctx: Context, options?: CallOptions): Promise<Reply>;
|
|
20
|
+
/** Final and idempotent. */
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/** A deadline is a non-negative integer of ms; 0 disables it. */
|
|
24
|
+
export declare function deadline(ms: number | undefined, fallback: number): number;
|
|
25
|
+
/** Server major.minor must equal the SDK's; returns the server version. */
|
|
26
|
+
export declare function checkVersion(got: unknown, sdk: string): string;
|
|
27
|
+
/** POSTs the envelope to `url`; the caller's headers are the backend's auth. Stateless. */
|
|
28
|
+
export declare class HttpTransport implements Transport {
|
|
29
|
+
private readonly url;
|
|
30
|
+
private readonly headers;
|
|
31
|
+
private readonly timeoutMs;
|
|
32
|
+
private readonly sdkVersion;
|
|
33
|
+
version: string | null;
|
|
34
|
+
private readonly closed;
|
|
35
|
+
constructor(url: string, headers: Record<string, string>, timeoutMs: number, sdkVersion: string);
|
|
36
|
+
handle(body: unknown, _ctx: Context, options?: CallOptions): Promise<Reply>;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import type { ConsolErrorCode } from "./errors";
|
|
2
|
+
/** Open enum: autocompletes the known values and still accepts future ones. */
|
|
3
|
+
type Open<T extends string> = T | (string & {});
|
|
4
|
+
/**
|
|
5
|
+
* The wire reply, the same on every transport. `text` is rendered for an LLM, `result` is the
|
|
6
|
+
* contract payload (receipt fields next to `error` for a failed reflection-bound write). Tool
|
|
7
|
+
* errors are replies with `error`, never exceptions.
|
|
8
|
+
*/
|
|
9
|
+
export interface Reply {
|
|
10
|
+
version: string;
|
|
11
|
+
/** Guidance for an LLM; absent when there is none. Note Markdown is not here: it is inline in `result`. */
|
|
12
|
+
text?: string;
|
|
13
|
+
result?: unknown;
|
|
14
|
+
error?: ToolError;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Structured tool error (contract section 4); failed reflect entries carry the same shape. */
|
|
18
|
+
export interface ToolError {
|
|
19
|
+
code: ConsolErrorCode;
|
|
20
|
+
retryable: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
/** Input at fault as a path, e.g. `decisions[2].temporal.evidence[0]`; only when one input is to blame. */
|
|
23
|
+
field?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Part of a successful call that could not be done; an empty list means nothing was degraded. */
|
|
26
|
+
export interface Unavailable {
|
|
27
|
+
code: Open<"source_invalid" | "embedding_unavailable" | "index_unavailable" | "relationships_incomplete">;
|
|
28
|
+
count?: number;
|
|
29
|
+
}
|
|
30
|
+
/** Note status: `active`, an authored status such as `archived`, or a computed one. */
|
|
31
|
+
export type Status = Open<"active" | "archived" | "superseded" | "expired" | "not_yet_valid" | "empty_validity" | "invalid_validity">;
|
|
32
|
+
/** UTF-8 byte offsets `[start, end)` into the source text, not JS string indices. */
|
|
33
|
+
export type ByteRange = [number, number];
|
|
34
|
+
/** Consolidation level of a note; it says nothing about truth or trust. */
|
|
35
|
+
export type Scope = "records" | "episodic" | "semantic" | "skills" | "core";
|
|
36
|
+
/** Exact note version; pass `content_version` back as `expected_version` so writes never clobber unseen edits. */
|
|
37
|
+
export interface SourceRef {
|
|
38
|
+
id: string;
|
|
39
|
+
owner: string;
|
|
40
|
+
content_version: string;
|
|
41
|
+
/** Present only when the server could hash the note's review dependencies too. */
|
|
42
|
+
review_version?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Link kinds (open); bare `[[x]]` links are `wikilink` (or `hub_member` inside a hub). */
|
|
45
|
+
export type RelationshipKind = Open<"derives" | "causes" | "contradicts" | "questions" | "wikilink" | "hub_member">;
|
|
46
|
+
/** Recorded link, never a truth vote; statuses and validity bounds tell whether each endpoint is current. */
|
|
47
|
+
export interface Relationship {
|
|
48
|
+
kind: RelationshipKind;
|
|
49
|
+
direction: "outgoing" | "incoming" | "contextual";
|
|
50
|
+
owner_source: SourceRef;
|
|
51
|
+
src: string;
|
|
52
|
+
dst: string;
|
|
53
|
+
src_source: SourceRef;
|
|
54
|
+
dst_source: SourceRef;
|
|
55
|
+
owner_status: Status;
|
|
56
|
+
src_status: Status;
|
|
57
|
+
dst_status: Status;
|
|
58
|
+
owner_valid_from_ms: number | null;
|
|
59
|
+
owner_valid_to_ms: number | null;
|
|
60
|
+
src_valid_from_ms: number | null;
|
|
61
|
+
src_valid_to_ms: number | null;
|
|
62
|
+
dst_valid_from_ms: number | null;
|
|
63
|
+
dst_valid_to_ms: number | null;
|
|
64
|
+
reasons?: string[];
|
|
65
|
+
}
|
|
66
|
+
/** `read` payload; `text` is the complete file, byte for byte, frontmatter included. */
|
|
67
|
+
export interface ReadResult {
|
|
68
|
+
text: string;
|
|
69
|
+
source: SourceRef;
|
|
70
|
+
source_path: string;
|
|
71
|
+
scope: Scope;
|
|
72
|
+
status: Status;
|
|
73
|
+
valid_from_ms: number | null;
|
|
74
|
+
valid_to_ms: number | null;
|
|
75
|
+
/** One page of 16; pass `continuation` back to read the next page (null on the last). */
|
|
76
|
+
relationships: Relationship[];
|
|
77
|
+
continuation: string | null;
|
|
78
|
+
unavailable: Unavailable[];
|
|
79
|
+
}
|
|
80
|
+
/** Retrieval arm (open); `linked` cards were pulled in by a contradiction or tension link. */
|
|
81
|
+
export type RecallRetrieval = Open<"exact" | "ledger" | "facet" | "fused" | "relaxed" | "linked">;
|
|
82
|
+
/** `text` is exactly the bytes at `byte_range` of the note version in `source.content_version`. */
|
|
83
|
+
export interface SourceExcerpt {
|
|
84
|
+
byte_range: ByteRange;
|
|
85
|
+
text: string;
|
|
86
|
+
heading_context?: string;
|
|
87
|
+
speaker_date_context?: string;
|
|
88
|
+
}
|
|
89
|
+
/** A search lead, not proof: read the source before relying on or editing it. */
|
|
90
|
+
export interface RecallCard {
|
|
91
|
+
source: SourceRef;
|
|
92
|
+
scope: Scope;
|
|
93
|
+
status: Status;
|
|
94
|
+
retrieval: RecallRetrieval;
|
|
95
|
+
tier: "full" | "lead" | "id" | "linked";
|
|
96
|
+
matched_passages: number;
|
|
97
|
+
valid_from_ms: number | null;
|
|
98
|
+
valid_to_ms: number | null;
|
|
99
|
+
/** When the event happened, from the note's leading `[Date: …]` line; null when unknown. */
|
|
100
|
+
observed_ms: number | null;
|
|
101
|
+
summary?: string;
|
|
102
|
+
excerpts?: SourceExcerpt[];
|
|
103
|
+
relationships?: Relationship[];
|
|
104
|
+
linked_via?: string;
|
|
105
|
+
compact?: boolean;
|
|
106
|
+
}
|
|
107
|
+
/** Every `jev`, `jev_triage` and `jev_advisory` field is experimental: present only with Jev configured. */
|
|
108
|
+
export type Experimental = Record<string, unknown>;
|
|
109
|
+
/** `recall` payload: at most `limit` cards, linked companions included. */
|
|
110
|
+
export interface RecallResult {
|
|
111
|
+
/**
|
|
112
|
+
* The progressive disclosure as a model reads it: full cards with excerpts, lead and id cards,
|
|
113
|
+
* the question's intent block and the hints. `candidates` are the same cards as data.
|
|
114
|
+
*/
|
|
115
|
+
text: string;
|
|
116
|
+
candidates: RecallCard[];
|
|
117
|
+
/** True when more matched cards or companions were omitted. */
|
|
118
|
+
truncated: boolean;
|
|
119
|
+
unavailable: Unavailable[];
|
|
120
|
+
jev?: Experimental;
|
|
121
|
+
}
|
|
122
|
+
/** Similar note worth inspecting after a write; similarity is never agreement. */
|
|
123
|
+
export interface AffectedDoc {
|
|
124
|
+
id: string;
|
|
125
|
+
source_path: string;
|
|
126
|
+
similarity: number;
|
|
127
|
+
valid_to_ms: number | null;
|
|
128
|
+
}
|
|
129
|
+
/** Notes sharing an entity with the written note. */
|
|
130
|
+
export interface EntityAffectedGroup {
|
|
131
|
+
entity: string;
|
|
132
|
+
docs: AffectedDoc[];
|
|
133
|
+
}
|
|
134
|
+
/** `remember` receipt; a reflection-bound write adds `reflection_write` to this same shape. */
|
|
135
|
+
export interface RememberResult {
|
|
136
|
+
changed: boolean;
|
|
137
|
+
indexed: boolean;
|
|
138
|
+
/** Present when publication is known. */
|
|
139
|
+
source?: SourceRef;
|
|
140
|
+
source_path?: string;
|
|
141
|
+
/** Parsed validity bounds, echoed. */
|
|
142
|
+
valid_from_ms: number | null;
|
|
143
|
+
valid_to_ms: number | null;
|
|
144
|
+
invalidated_dependents: string[];
|
|
145
|
+
affected: AffectedDoc[];
|
|
146
|
+
entity_affected: EntityAffectedGroup[];
|
|
147
|
+
unavailable: Unavailable[];
|
|
148
|
+
/** Outcome of a reflection-bound write (and of the resume form). */
|
|
149
|
+
reflection_write?: WriteOutcome;
|
|
150
|
+
jev?: Experimental;
|
|
151
|
+
}
|
|
152
|
+
/** `remove` receipt: the note is archived, its body stays readable and editable. */
|
|
153
|
+
export interface RemoveResult {
|
|
154
|
+
changed: boolean;
|
|
155
|
+
indexed: boolean;
|
|
156
|
+
source?: SourceRef;
|
|
157
|
+
source_path?: string;
|
|
158
|
+
/** Validity bounds of the archived version. */
|
|
159
|
+
valid_from_ms: number | null;
|
|
160
|
+
valid_to_ms: number | null;
|
|
161
|
+
invalidated_dependents: string[];
|
|
162
|
+
unavailable: Unavailable[];
|
|
163
|
+
reflection_write?: WriteOutcome;
|
|
164
|
+
jev?: Experimental;
|
|
165
|
+
}
|
|
166
|
+
/** Durable state of a reflection-bound write (open); only `succeeded` published bytes. */
|
|
167
|
+
export type WriteState = Open<"pending" | "succeeded" | "conflicted" | "abandoned">;
|
|
168
|
+
/** Why a reflection write has not succeeded yet (open); resume or abandon it explicitly. */
|
|
169
|
+
export type WriteFailureCode = Open<"source_conflict" | "basis_changed" | "index_pending" | "publication_pending" | "receipt_pending">;
|
|
170
|
+
/** Proof of a published reflection write. */
|
|
171
|
+
export interface WriteReceipt {
|
|
172
|
+
operation: "remember" | "remove";
|
|
173
|
+
source_path: string;
|
|
174
|
+
before: SourceRef | null;
|
|
175
|
+
after: SourceRef;
|
|
176
|
+
indexed: boolean;
|
|
177
|
+
}
|
|
178
|
+
/** Recorded reason a write was abandoned; `inspected: null` means the target was absent. */
|
|
179
|
+
export interface WriteResolution {
|
|
180
|
+
inspected: SourceRef | null;
|
|
181
|
+
reason: string;
|
|
182
|
+
}
|
|
183
|
+
/** Outcome of one reflection-bound write; a write never completes the work by itself. */
|
|
184
|
+
export interface WriteOutcome {
|
|
185
|
+
work_id: string;
|
|
186
|
+
action_key: string;
|
|
187
|
+
state: WriteState;
|
|
188
|
+
/** True for a replayed terminal outcome: it describes history, not the current source. */
|
|
189
|
+
historical: boolean;
|
|
190
|
+
saved: boolean | null;
|
|
191
|
+
indexed: boolean;
|
|
192
|
+
receipt: WriteReceipt | null;
|
|
193
|
+
resolution: WriteResolution | null;
|
|
194
|
+
failure_code: WriteFailureCode | null;
|
|
195
|
+
}
|
|
196
|
+
/** Queue state of a work item; only an accepted decision completes it. */
|
|
197
|
+
export type WorkStatus = "pending" | "completed" | "blocked" | "retryable" | "stale";
|
|
198
|
+
/** Pair found through a link authored in `owner`. */
|
|
199
|
+
export interface AuthoredLead {
|
|
200
|
+
route: "authored";
|
|
201
|
+
owner: SourceRef;
|
|
202
|
+
src: string;
|
|
203
|
+
dst: string;
|
|
204
|
+
relation: "derives" | "causes" | "contradicts" | "questions" | "hub_member";
|
|
205
|
+
}
|
|
206
|
+
/** Pair found through a shared facet value. */
|
|
207
|
+
export interface SharedFacetLead {
|
|
208
|
+
route: "shared_facet";
|
|
209
|
+
value: string;
|
|
210
|
+
}
|
|
211
|
+
/** Pair found through a shared numeric value. */
|
|
212
|
+
export interface SharedNumericLead {
|
|
213
|
+
route: "shared_numeric";
|
|
214
|
+
value: string;
|
|
215
|
+
}
|
|
216
|
+
/** Pair found through embedding similarity (embeddings on only). */
|
|
217
|
+
export interface SemanticLead {
|
|
218
|
+
route: "semantic";
|
|
219
|
+
probe: SourceRef;
|
|
220
|
+
target: SourceRef;
|
|
221
|
+
entity_hash: string;
|
|
222
|
+
projection_hash: string;
|
|
223
|
+
fingerprint: string;
|
|
224
|
+
score: number;
|
|
225
|
+
}
|
|
226
|
+
/** Discovery witness of a pair; one witness, not an exhaustive list or a truth judgment. */
|
|
227
|
+
export type PairLead = AuthoredLead | SharedFacetLead | SharedNumericLead | SemanticLead;
|
|
228
|
+
/** Hub witness; `target` is null when a new hub would be formed. Unstable: checked against Rust source only. */
|
|
229
|
+
export interface HubLead {
|
|
230
|
+
route: "hub";
|
|
231
|
+
target: string | null;
|
|
232
|
+
members: string[];
|
|
233
|
+
witness: string;
|
|
234
|
+
coverage: string[];
|
|
235
|
+
constraint: string | null;
|
|
236
|
+
}
|
|
237
|
+
/** Promotion witness. Unstable: checked against Rust source only. */
|
|
238
|
+
export interface PromotionLead {
|
|
239
|
+
route: "promotion";
|
|
240
|
+
entity: string;
|
|
241
|
+
scope: "skills" | "core";
|
|
242
|
+
existing: string[];
|
|
243
|
+
}
|
|
244
|
+
/** Sources a work item was judged on; the basis hash binds decisions to exactly these versions. */
|
|
245
|
+
export interface WorkBasis<L> {
|
|
246
|
+
subjects: SourceRef[];
|
|
247
|
+
sources: SourceRef[];
|
|
248
|
+
lead: L;
|
|
249
|
+
}
|
|
250
|
+
/** Shared by every work kind, so they stay readable before narrowing on `kind`. */
|
|
251
|
+
export interface WorkBase {
|
|
252
|
+
work_id: string;
|
|
253
|
+
basis_hash: string;
|
|
254
|
+
status: WorkStatus;
|
|
255
|
+
}
|
|
256
|
+
/** Review one note; source work carries no lead. */
|
|
257
|
+
export interface SourceWork extends WorkBase {
|
|
258
|
+
kind: "source";
|
|
259
|
+
basis: {
|
|
260
|
+
subjects: SourceRef[];
|
|
261
|
+
sources: SourceRef[];
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/** Compare two notes. */
|
|
265
|
+
export interface PairWork extends WorkBase {
|
|
266
|
+
kind: "pair";
|
|
267
|
+
basis: WorkBasis<PairLead>;
|
|
268
|
+
}
|
|
269
|
+
/** Form, attach to or bridge a hub. Unstable: checked against Rust source only. */
|
|
270
|
+
export interface HubWork extends WorkBase {
|
|
271
|
+
kind: "hub_attachment" | "hub_formation" | "hub_bridge";
|
|
272
|
+
basis: WorkBasis<HubLead>;
|
|
273
|
+
}
|
|
274
|
+
/** Promote recurring knowledge to skills/core. Unstable: checked against Rust source only. */
|
|
275
|
+
export interface PromotionWork extends WorkBase {
|
|
276
|
+
kind: "promotion";
|
|
277
|
+
basis: WorkBasis<PromotionLead>;
|
|
278
|
+
}
|
|
279
|
+
/** A delivered work item, discriminated on `kind`. */
|
|
280
|
+
export type ReflectionWork = SourceWork | PairWork | HubWork | PromotionWork;
|
|
281
|
+
/** Markdown block of a delivered source, as a suggested excerpt boundary. */
|
|
282
|
+
export interface CandidateBlock {
|
|
283
|
+
byte_range: ByteRange;
|
|
284
|
+
heading_context: string | null;
|
|
285
|
+
speaker_date_context: string | null;
|
|
286
|
+
}
|
|
287
|
+
/** A delivered source: `text` is its complete original Markdown (inline in the reply). */
|
|
288
|
+
export interface DeliveredSource {
|
|
289
|
+
source: SourceRef;
|
|
290
|
+
text: string;
|
|
291
|
+
byte_range: ByteRange;
|
|
292
|
+
/** Suggested body spans, not a replacement for inspection. */
|
|
293
|
+
candidate_blocks: CandidateBlock[];
|
|
294
|
+
}
|
|
295
|
+
/** Work delivered with every source body; deliver, write and decide are separate steps. */
|
|
296
|
+
export interface CompleteDelivery {
|
|
297
|
+
work: ReflectionWork;
|
|
298
|
+
sources: DeliveredSource[];
|
|
299
|
+
complete: true;
|
|
300
|
+
jev_advisory?: Experimental;
|
|
301
|
+
}
|
|
302
|
+
/** Work or a requested source that could not be delivered this call; the call itself succeeded. */
|
|
303
|
+
export interface FailedDelivery {
|
|
304
|
+
/** Present when the work is known. */
|
|
305
|
+
work_id?: string;
|
|
306
|
+
/** Present for a requested source (`ids` mode). */
|
|
307
|
+
requested_id?: string;
|
|
308
|
+
complete: false;
|
|
309
|
+
error: ToolError;
|
|
310
|
+
}
|
|
311
|
+
/** One entry of `reflect().deliveries`; narrow on `complete`. */
|
|
312
|
+
export type ReflectDelivery = CompleteDelivery | FailedDelivery;
|
|
313
|
+
/** Allowed `disposition` values of a source decision. */
|
|
314
|
+
export type SourceDisposition = "synthesize" | "connect" | "archive" | "retained_raw" | "blocked" | "retryable_error" | "stale";
|
|
315
|
+
/** Allowed `disposition` values of a pair decision. */
|
|
316
|
+
export type PairDisposition = "linked" | "no_relation" | "unresolved" | "blocked" | "retryable_error" | "stale";
|
|
317
|
+
/** Allowed `disposition` values of a hub or promotion decision. */
|
|
318
|
+
export type ConsolidationDisposition = "applied" | "reused" | "rejected" | "retained_raw" | "blocked" | "retryable_error" | "stale";
|
|
319
|
+
/** Accepted source/pair/hub/promotion decision; `status` echoes the disposition. */
|
|
320
|
+
export interface AcceptedDecision {
|
|
321
|
+
work_id: string;
|
|
322
|
+
accepted: true;
|
|
323
|
+
status: SourceDisposition | PairDisposition | ConsolidationDisposition;
|
|
324
|
+
}
|
|
325
|
+
/** Accepted `abandon_write`; the resulting outcome is in `writes`. */
|
|
326
|
+
export interface AcceptedAbandon {
|
|
327
|
+
work_id: string;
|
|
328
|
+
action_key: string;
|
|
329
|
+
accepted: true;
|
|
330
|
+
}
|
|
331
|
+
/** Failed decision; the call still succeeds and later decisions still run. */
|
|
332
|
+
export interface RejectedDecision {
|
|
333
|
+
work_id: string;
|
|
334
|
+
accepted: false;
|
|
335
|
+
error: ToolError;
|
|
336
|
+
}
|
|
337
|
+
/** One entry of `reflect().decisions`, in submission order. */
|
|
338
|
+
export type DecisionReceipt = AcceptedDecision | AcceptedAbandon | RejectedDecision;
|
|
339
|
+
/** Discovery lanes in the order the server reports them. */
|
|
340
|
+
export type ReflectionLane = "source" | "semantic_pairs" | "structural_pairs" | "hubs" | "promotions";
|
|
341
|
+
/** Progress of one discovery page. */
|
|
342
|
+
export interface LaneCoverage {
|
|
343
|
+
exhausted: boolean;
|
|
344
|
+
processed: number;
|
|
345
|
+
blocked: number;
|
|
346
|
+
retryable: number;
|
|
347
|
+
}
|
|
348
|
+
/** Source lane progress; `validation_complete` covers re-checks of earlier work. */
|
|
349
|
+
export interface SourceLaneCoverage extends LaneCoverage {
|
|
350
|
+
validation_complete: boolean;
|
|
351
|
+
}
|
|
352
|
+
/** Lane report of a discovery call; `current_complete` is set only when completion could be checked. */
|
|
353
|
+
export type DiscoveryLane = {
|
|
354
|
+
lane: "source";
|
|
355
|
+
coverage: SourceLaneCoverage;
|
|
356
|
+
current_complete?: boolean;
|
|
357
|
+
} | {
|
|
358
|
+
lane: "structural_pairs" | "semantic_pairs" | "hubs" | "promotions";
|
|
359
|
+
coverage: LaneCoverage;
|
|
360
|
+
current_complete?: boolean;
|
|
361
|
+
} | {
|
|
362
|
+
lane: ReflectionLane;
|
|
363
|
+
exhausted: false;
|
|
364
|
+
error: ToolError;
|
|
365
|
+
current_complete?: boolean;
|
|
366
|
+
};
|
|
367
|
+
/** Queue counters; `done` is true only when every lane is exhausted and nothing is open. */
|
|
368
|
+
export interface ReflectCounters {
|
|
369
|
+
pending: number;
|
|
370
|
+
blocked: number;
|
|
371
|
+
retryable: number;
|
|
372
|
+
unresolved_writes: number;
|
|
373
|
+
done: boolean;
|
|
374
|
+
}
|
|
375
|
+
/** `reflect` payload for every mode; unused sections are empty. Check `counters.done` before assuming nothing is left. */
|
|
376
|
+
export interface ReflectResult {
|
|
377
|
+
deliveries: ReflectDelivery[];
|
|
378
|
+
decisions: DecisionReceipt[];
|
|
379
|
+
writes: WriteOutcome[];
|
|
380
|
+
/** Lanes are filled by discovery (no targets) only. */
|
|
381
|
+
discovery: {
|
|
382
|
+
completion_checked: boolean;
|
|
383
|
+
lanes: DiscoveryLane[];
|
|
384
|
+
};
|
|
385
|
+
counters: ReflectCounters;
|
|
386
|
+
jev?: Experimental;
|
|
387
|
+
jev_triage?: Experimental;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Slice a string by UTF-8 byte offsets, not JS string indices. Validates bounds
|
|
391
|
+
* and character boundaries. Contract byte ranges always point into the text returned
|
|
392
|
+
* by the server, so valid ranges never fail.
|
|
393
|
+
*/
|
|
394
|
+
export declare function sliceUtf8(text: string, start: number, end: number): string;
|
|
395
|
+
export {};
|