@jawache/flow 0.1.2 → 0.3.0

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.
@@ -1,6 +1,13 @@
1
1
  import type { LoadResult } from "../language/domain.ts";
2
2
  import { type Facts, type SelectOpts, type SpawnMeta, type TranscriptRef } from "./domain.ts";
3
- /** Where this harness keeps a working directory's conversations. */
3
+ /**
4
+ * Where this harness keeps a working directory's conversations.
5
+ *
6
+ * Under the host's own folder, and `CLAUDE_CONFIG_DIR` moves that folder — the host honours it for
7
+ * the store as it does for settings.json, so a store read from `~/.claude` regardless would be
8
+ * somebody else's. A `home` passed in is taken as the user's home and wins: that is a test naming
9
+ * its own world.
10
+ */
4
11
  export declare function projectDir(cwd: string, home?: string): string;
5
12
  /** One conversation in the store, with everything findable about it without opening it twice. */
6
13
  export interface StoredTranscript {
@@ -1,5 +1,6 @@
1
1
  import { type ExecResult, type FlowConfig, type LoadResult, type Grammar, type Settings, type World } from "../language/domain.ts";
2
- import { type HookEvent, type HookPayload, type HookResult } from "./domain.ts";
2
+ import { type AgentOf } from "../engine/domain.ts";
3
+ import { type CommitScope, type CallRecord, type Change, type Delta, type HookEvent, type HookPayload, type HookResult } from "./domain.ts";
3
4
  /**
4
5
  * Run one command the way a check means it — through a shell, in the repo, hermetically.
5
6
  *
@@ -13,7 +14,7 @@ import { type HookEvent, type HookPayload, type HookResult } from "./domain.ts";
13
14
  * installed refuses the commit instead of passing it. bash answers 127 itself; the only case left
14
15
  * is bash being unspawnable, which is the same fact one level up and is answered the same way.
15
16
  */
16
- export declare function runCommand(command: string, root: string): ExecResult;
17
+ export declare function runCommand(command: string, root: string, env?: Record<string, string | undefined>): ExecResult;
17
18
  /** A file's text, or null when it is not there / not readable. */
18
19
  export declare function readText(root: string, path: string): string | null;
19
20
  /**
@@ -52,16 +53,56 @@ export declare function currentBranch(root: string): string | null;
52
53
  * who is here — and a rule that fires at the gate for a wearer status never showed is the exact
53
54
  * surprise the marker exists to prevent.
54
55
  *
55
- * `agent` is null when the marker is missing, stale or malformed, and then the wearer wears NOTHING
56
- * rather than a guess: there is no transcript and no sidecar out here, so the stored verdict is the
57
- * only truthful answer there can be.
56
+ * `who` is null when the marker is missing, stale or malformed, and then the wearer wears NOTHING
57
+ * rather than a guess: there is no transcript and no hook message out here, so the stored verdict is
58
+ * the only truthful answer there can be.
58
59
  */
59
60
  export declare function wearer(root: string): {
60
61
  readonly branch: string | null;
61
62
  readonly session: string;
62
- readonly agent: string | null;
63
+ readonly who: AgentOf | null;
63
64
  readonly wearing: readonly string[];
64
65
  };
66
+ /**
67
+ * RECORD THE TREE BEFORE A CALL, filed under the host's `tool_use_id`.
68
+ *
69
+ * A snapshot that cannot be taken is RECORDED as a fault rather than skipped, so the after-call rail
70
+ * reports it instead of finding nothing and calling the call clean. `who` is kept beside the tree so
71
+ * a snapshot with no after is readable as a call still in flight, per session and agent.
72
+ */
73
+ export declare function takeSnapshot(root: string, key: string, include: readonly string[], who: {
74
+ readonly session: string;
75
+ readonly agent: string;
76
+ readonly tool: string;
77
+ }): void;
78
+ /**
79
+ * WHAT THE CALL CHANGED: the tree now against the tree its snapshot recorded, path by path, with
80
+ * the content either side, less each path git put there (see `authored`). The before-snapshot is
81
+ * kept — a revert reads from it — until `forget`.
82
+ */
83
+ export declare function observeDelta(root: string, key: string, include: readonly string[]): Delta & {
84
+ readonly before?: string;
85
+ };
86
+ /**
87
+ * PUT CHANGES BACK from the before-snapshot — a changed or removed file to its old content, a file
88
+ * the call created removed. Answers what could not be put back, never throws: a revert that failed
89
+ * is said to the model, loudly, rather than claimed.
90
+ */
91
+ export declare function revertChanges(root: string, tree: string, changes: readonly Change[]): {
92
+ path: string;
93
+ why: string;
94
+ }[];
95
+ /**
96
+ * THE CALL LOG — every snapshot's record, read back: who made each call, when it started, and when
97
+ * it finished if it has. A record that cannot be read is left out; it is somebody's write racing
98
+ * this read, and the next diff reads it whole.
99
+ */
100
+ export declare function callLog(root: string): CallRecord[];
101
+ /**
102
+ * The call is over: its record says when it finished, so a diff still to come can tell it
103
+ * overlapped, and its throwaway indexes go. Records no diff still to come can overlap are dropped.
104
+ */
105
+ export declare function finishSnapshot(root: string, key: string, now?: number): void;
65
106
  /**
66
107
  * The repo the session is standing in — the FOURTH question of §7.
67
108
  *
@@ -76,10 +117,10 @@ export declare function projectRoot(cwd: string): string;
76
117
  * once in the host's settings and fire in every repo the agent visits, so a missing config is the
77
118
  * ordinary case and blocking on it would make flow unusable the moment it was installed.
78
119
  *
79
- * `broken` is the opposite fact and gets the opposite answer: a config file that is THERE and will
80
- * not even import is a guard that cannot run, which is what fail-loud exists for. (A config that
81
- * imports and then will not load is the engine's own path — `load.ok === false` — and refuses with
82
- * the same shape from inside `guard`.)
120
+ * `broken` is the opposite fact and must never be silent: a config file that is THERE and will
121
+ * not even import is a guard that cannot run. The hook rail hands it to `whileBroken`, which lets
122
+ * every call through with the load error, and the commit gate refuses. (A config that imports and
123
+ * then will not load — `load.ok === false` — is the same fact and gets the same two answers.)
83
124
  */
84
125
  export type Regime = {
85
126
  readonly kind: "none";
@@ -110,7 +151,7 @@ export declare function loadRegime(root: string): Promise<Regime>;
110
151
  *
111
152
  * The shape is deliberately flat rather than a hook function per event: the events differ in what
112
153
  * they CARRY (toEvent's job) and in how their answer is rendered (toResult's job), and the middle —
113
- * load, classify, run, log — is identical for all five. The old engine had five files here, and the
154
+ * load, classify, run, log — is identical for all of them. The old engine had five files here, and the
114
155
  * off switch, the session marker and the fault handling were each written out four or five times
115
156
  * with small differences nobody had chosen.
116
157
  */
@@ -126,10 +167,10 @@ export declare function runHook(hook: HookEvent, payload: HookPayload, root: str
126
167
  * WHO IT IS comes from the marker the PreToolUse rail left — session AND agent — so a commit's rows
127
168
  * land in the session that caused them and an actor-scoped rule fires at this moment as honestly as
128
169
  * at any other. The classification itself is never re-derived here: there is no transcript and no
129
- * sidecar outside a session, so the STORED verdict is the only truthful answer, and a fresh commit
170
+ * hook message outside a session, so the STORED verdict is the only truthful answer, and a fresh commit
130
171
  * on a stale or absent marker wears nothing rather than wearing a guess.
131
172
  */
132
- export declare function runCommit(root: string, files: readonly string[]): Promise<HookResult>;
173
+ export declare function runCommit(root: string, scope: CommitScope): Promise<HookResult>;
133
174
  /** What came in on stdin: a payload, or which of the two ways reading it failed. */
134
175
  export type PayloadRead = {
135
176
  readonly ok: true;
@@ -157,13 +198,21 @@ export declare function readPayload(): PayloadRead;
157
198
  *
158
199
  * `pre-tool-use` is the rail that GUARDS, so it fails CLOSED — a payload it cannot read is a tool
159
200
  * call it cannot judge, and "I could not look" must never be spelled the same way as "I looked and
160
- * it was fine". The other four annotate, and breaking a session over a hook that only adds a
161
- * breadcrumb would be the cure killing the patient — so they SPEAK on stderr and allow, because
162
- * silence is precisely what let the old swallow go unnoticed.
201
+ * it was fine". The after-call rails JUDGE too — every change a call made reaches the rules there —
202
+ * so a payload they cannot read is a call whose changes nobody judged, and they report it with exit
203
+ * 2, which on those rails reaches the model beside the result and blocks nothing. The rest only add
204
+ * a breadcrumb, and breaking a session over one would be the cure killing the patient, so they SPEAK
205
+ * on stderr and allow. `readFault` next door is where that split is decided.
163
206
  *
164
207
  * Everything is wrapped: a hook that throws is a hook that wedges a session, and an unknown event
165
208
  * is silence rather than a usage message in front of the model.
166
209
  */
167
210
  export declare function hookEntry(event: string, cwd: string): Promise<HookResult>;
168
- /** The git gate, end to end. Paths arrive repo-relative from git; a stray absolute one is folded. */
169
- export declare function commitEntry(files: readonly string[], cwd: string): Promise<HookResult>;
211
+ /**
212
+ * The git gate, end to end — `flow hook commit`, or `flow hook commit --all` for the whole tree.
213
+ *
214
+ * It takes no file list: git is asked. `flow commit <files…>`, the name an older hook still calls,
215
+ * arrives here with `legacy` set and its list is dropped, because git's answer is the only list — a
216
+ * second source of the staged set is two answers that can disagree.
217
+ */
218
+ export declare function commitEntry(args: readonly string[], cwd: string, legacy?: boolean): Promise<HookResult>;