@gr8ful/spf 0.14.0 → 0.16.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.
- package/README.md +51 -9
- package/assets/skill/references/config.md +12 -5
- package/assets/skill/references/observability.md +57 -12
- package/assets/templates/ts-opencode.spf.config.yaml +54 -0
- package/dist/chains/index.js +1 -1
- package/dist/chains/simple_sdlc.d.ts +2 -2
- package/dist/chains/simple_sdlc.js +13 -13
- package/dist/chains/steps.d.ts +2 -2
- package/dist/chains/steps.js +35 -19
- package/dist/cli/commands/abort.d.ts +1 -1
- package/dist/cli/commands/abort.js +30 -3
- package/dist/cli/commands/doctor.js +121 -8
- package/dist/cli/commands/estimate.js +3 -3
- package/dist/cli/commands/events.js +4 -4
- package/dist/cli/commands/fanout.js +93 -21
- package/dist/cli/commands/loop.js +31 -32
- package/dist/cli/commands/migrate.js +8 -1
- package/dist/cli/commands/phases.js +2 -2
- package/dist/cli/commands/sessions.js +2 -2
- package/dist/cli/commands/trace.d.ts +28 -8
- package/dist/cli/commands/trace.js +28 -15
- package/dist/cli/commands/ui.js +15 -5
- package/dist/cli/commands/watch.js +91 -30
- package/dist/cli/index.js +3 -1
- package/dist/cli/interview.d.ts +1 -0
- package/dist/cli/interview.js +95 -5
- package/dist/core/agent_opencode.d.ts +247 -0
- package/dist/core/agent_opencode.js +590 -0
- package/dist/core/agents.d.ts +12 -12
- package/dist/core/agents.js +113 -46
- package/dist/core/console.d.ts +12 -12
- package/dist/core/console.js +25 -25
- package/dist/core/data_types.d.ts +356 -15
- package/dist/core/data_types.js +180 -7
- package/dist/core/fanout.d.ts +1 -1
- package/dist/core/fanout.js +1 -1
- package/dist/core/gates.js +14 -1
- package/dist/core/issues/github_provider.d.ts +66 -2
- package/dist/core/issues/github_provider.js +161 -2
- package/dist/core/issues/jira_provider.d.ts +50 -9
- package/dist/core/issues/jira_provider.js +62 -2
- package/dist/core/paths.d.ts +41 -4
- package/dist/core/paths.js +32 -3
- package/dist/core/quality.d.ts +7 -7
- package/dist/core/quality.js +16 -10
- package/dist/core/refine.js +2 -2
- package/dist/core/runner.d.ts +9 -3
- package/dist/core/runner.js +39 -27
- package/dist/core/session.d.ts +2 -2
- package/dist/core/session.js +39 -18
- package/dist/core/sqlite.d.ts +14 -7
- package/dist/core/sqlite.js +14 -7
- package/dist/core/trace_db.d.ts +118 -0
- package/dist/core/trace_db.js +278 -0
- package/dist/core/tracer.d.ts +64 -34
- package/dist/core/tracer.js +141 -69
- package/dist/core/watch.d.ts +4 -4
- package/dist/core/watch.js +2 -2
- package/dist/ui/server/app.js +10 -10
- package/dist/ui/server/db.d.ts +89 -21
- package/dist/ui/server/db.js +235 -99
- package/dist/ui/server/serve.d.ts +5 -1
- package/dist/ui/server/serve.js +4 -5
- package/package.json +1 -1
- package/web/assets/index-CQ3k1Y1-.css +1 -0
- package/web/assets/index-CU8tom6S.js +21 -0
- package/web/assets/overpass-latin-400-normal-BpeLJ0bs.woff2 +0 -0
- package/web/assets/overpass-latin-600-normal-25RhTNCi.woff2 +0 -0
- package/web/assets/overpass-latin-700-normal-CQX2QTgM.woff2 +0 -0
- package/web/assets/overpass-mono-latin-400-normal-VINZG6Js.woff2 +0 -0
- package/web/assets/overpass-mono-latin-700-normal-D6nRBrbd.woff2 +0 -0
- package/web/index.html +33 -2
- package/web/logo.svg +4 -4
- package/web/assets/index-C7nF068F.css +0 -1
- package/web/assets/index-mzSArcnQ.js +0 -11
- package/web/assets/play-latin-400-normal-GKW-4YV7.woff2 +0 -0
- package/web/assets/play-latin-700-normal-DyPlLDbb.woff2 +0 -0
package/dist/ui/server/db.d.ts
CHANGED
|
@@ -1,21 +1,75 @@
|
|
|
1
|
+
import type { NormalizedObservabilityDb } from "../../core/data_types.ts";
|
|
2
|
+
import type { DataPaths } from "../../core/paths.ts";
|
|
1
3
|
import type { AgentSession, Envelope, EventsPage, GateResult, Phase, Session, SessionDetail, SessionSummary, SessionUsage } from "../shared/types.ts";
|
|
2
4
|
export declare class SfDb {
|
|
3
|
-
|
|
5
|
+
/** Absolute local sqlite path — `null` for a `kind:"d1"` config. */
|
|
6
|
+
readonly path: string | null;
|
|
7
|
+
/** Human label for API/console display: the sqlite path, or `d1:<database_id>`. */
|
|
8
|
+
readonly label: string;
|
|
4
9
|
/**
|
|
5
10
|
* Where the ADW session dirs live: `{data_dir}/sessions/{adw_id}/{agent}/`.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
11
|
+
* Passed in explicitly (from `paths.resolveDataPaths(...).sessions_dir`)
|
|
12
|
+
* rather than derived from the db path — session JSONL/envelope artifact
|
|
13
|
+
* files always live on the local filesystem regardless of where the
|
|
14
|
+
* queryable trace mirror (`db` below) lives; see `paths.ts`'s `DataPaths`.
|
|
9
15
|
*/
|
|
10
16
|
readonly sessionsDir: string;
|
|
17
|
+
/** `"n/a (d1)"` for a remote backend — journal mode is a local-file concept. */
|
|
11
18
|
readonly journalMode: string;
|
|
12
19
|
private readonly db;
|
|
13
|
-
|
|
20
|
+
private readonly dbConfig;
|
|
21
|
+
/** D1-only; carried from `open()`'s `options.fetchImpl` so a lazily-opened writer (`setArchived`) uses the same injected fetch a test gave the reader. */
|
|
22
|
+
private readonly fetchImpl;
|
|
23
|
+
/** Opened on first archive and kept; `null` until then. */
|
|
14
24
|
private writer;
|
|
15
25
|
/** Cache for optionalColumn(), keyed "table.column". Only ever false → true. */
|
|
16
26
|
private readonly columnCache;
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
private constructor();
|
|
28
|
+
/**
|
|
29
|
+
* Open a trace db for reading. `dbConfig` accepts either a bare local
|
|
30
|
+
* sqlite path (sugar for `{kind:"sqlite",path}` — `--db <path>`/`SF_DB`
|
|
31
|
+
* CLI overrides, and every test's shorthand) or a normalized
|
|
32
|
+
* `observability.db` descriptor (`paths.resolveDataPaths(...).db`).
|
|
33
|
+
*
|
|
34
|
+
* `sessionsDir` should be `paths.resolveDataPaths(...).sessions_dir`
|
|
35
|
+
* whenever the caller has a `DataPaths` in hand; omitted, it falls back to
|
|
36
|
+
* the historical "sibling of the sqlite file" derivation — only valid for
|
|
37
|
+
* the LOCAL backend (a bare-path caller has no other sessions dir to
|
|
38
|
+
* offer), so it is required when `dbConfig` names a `kind:"d1"` config.
|
|
39
|
+
*
|
|
40
|
+
* `options.fetchImpl` is D1-only and exists purely so tests can drive this
|
|
41
|
+
* end-to-end against a mocked D1 HTTP response shape — every real caller
|
|
42
|
+
* omits it and gets the global `fetch`, same as `createTraceDb` itself.
|
|
43
|
+
*/
|
|
44
|
+
static open(dbConfig: NormalizedObservabilityDb | string, sessionsDir?: string, options?: {
|
|
45
|
+
fetchImpl?: typeof fetch;
|
|
46
|
+
}): Promise<SfDb>;
|
|
47
|
+
/**
|
|
48
|
+
* Cheap "is there anything to read yet" check — the async equivalent of
|
|
49
|
+
* the `existsSync(dataPaths.db_path)` fast path every sqlite-only caller
|
|
50
|
+
* used before D1 existed, extended to cover the d1 case those callers
|
|
51
|
+
* never accounted for.
|
|
52
|
+
*
|
|
53
|
+
* `open()` deliberately THROWS a friendly, actionable error on a
|
|
54
|
+
* never-written db (see above) — the right behavior for `spf ui`, where
|
|
55
|
+
* "nothing here yet" is a misconfiguration to surface loudly. Callers that
|
|
56
|
+
* instead want to treat a never-written db as "empty, skip this check" —
|
|
57
|
+
* `spf fanout`'s collision preflight and lazy metrics reader, `spf loop`'s
|
|
58
|
+
* per-iteration readback, `spf estimate`'s cold-start path, `spf watch`'s
|
|
59
|
+
* salt-collision short-circuit — use this instead, so they behave
|
|
60
|
+
* identically whether the backend is local sqlite or a fresh D1 database
|
|
61
|
+
* that has never been written to.
|
|
62
|
+
*
|
|
63
|
+
* For a `kind:"sqlite"` db: `existsSync(dataPaths.db_path)`, unchanged.
|
|
64
|
+
* For a `kind:"d1"` db: the same `sqlite_master` probe `open()`'s
|
|
65
|
+
* friendly-error path already runs, but returning `false` instead of
|
|
66
|
+
* throwing when the `sessions` table isn't there yet. Any OTHER failure
|
|
67
|
+
* (network, auth, a malformed database_id) still throws — only "nothing
|
|
68
|
+
* written yet" collapses to `false`.
|
|
69
|
+
*/
|
|
70
|
+
static exists(dataPaths: Pick<DataPaths, "db" | "db_path">, options?: {
|
|
71
|
+
fetchImpl?: typeof fetch;
|
|
72
|
+
}): Promise<boolean>;
|
|
19
73
|
/**
|
|
20
74
|
* A SELECT fragment for a column the tracer adds by migration.
|
|
21
75
|
*
|
|
@@ -32,7 +86,21 @@ export declare class SfDb {
|
|
|
32
86
|
*/
|
|
33
87
|
private hasColumn;
|
|
34
88
|
private optionalColumn;
|
|
35
|
-
|
|
89
|
+
/**
|
|
90
|
+
* D1 caps bound parameters at 100 per statement; local sqlite allows tens
|
|
91
|
+
* of thousands. Any query that binds a whole id list into an `IN (...)`
|
|
92
|
+
* clause must go through this instead of a single unbounded bind, or it
|
|
93
|
+
* throws past ~100 ids on the D1 backend. Chunking is harmless on the
|
|
94
|
+
* local backend too (just slightly less efficient), so this is used
|
|
95
|
+
* unconditionally rather than special-cased per backend.
|
|
96
|
+
*
|
|
97
|
+
* Each id belongs to exactly one chunk, so per-id ordering from `fn`'s own
|
|
98
|
+
* ORDER BY is preserved — only the relative order of rows belonging to
|
|
99
|
+
* *different* chunks can interleave, which none of this class's callers
|
|
100
|
+
* depend on (they always regroup by id afterward).
|
|
101
|
+
*/
|
|
102
|
+
private chunked;
|
|
103
|
+
close(): Promise<void>;
|
|
36
104
|
/**
|
|
37
105
|
* Archive or restore a session — the only write in this process.
|
|
38
106
|
*
|
|
@@ -40,12 +108,12 @@ export declare class SfDb {
|
|
|
40
108
|
* click should wait its turn rather than fail. Returns false when the id
|
|
41
109
|
* does not exist, so the route can 404 instead of silently succeeding.
|
|
42
110
|
*/
|
|
43
|
-
setArchived(adwId: string, archived: boolean): boolean
|
|
111
|
+
setArchived(adwId: string, archived: boolean): Promise<boolean>;
|
|
44
112
|
/** Sessions, most recent first, each with its phase statuses for the progress dots. */
|
|
45
|
-
sessions(limit?: number): SessionSummary[]
|
|
46
|
-
session(adwId: string): Session | null
|
|
47
|
-
phases(adwId: string): Phase[]
|
|
48
|
-
agentSessions(adwId: string): AgentSession[]
|
|
113
|
+
sessions(limit?: number): Promise<SessionSummary[]>;
|
|
114
|
+
session(adwId: string): Promise<Session | null>;
|
|
115
|
+
phases(adwId: string): Promise<Phase[]>;
|
|
116
|
+
agentSessions(adwId: string): Promise<AgentSession[]>;
|
|
49
117
|
/**
|
|
50
118
|
* Agents per session, for a set of ids at once: the agent_sessions rows plus
|
|
51
119
|
* anything that has started but not finished.
|
|
@@ -57,7 +125,7 @@ export declare class SfDb {
|
|
|
57
125
|
*/
|
|
58
126
|
private agentsFor;
|
|
59
127
|
/** Session + phases + agents in one shot — L2 needs all three to draw lanes. */
|
|
60
|
-
sessionDetail(adwId: string): SessionDetail | null
|
|
128
|
+
sessionDetail(adwId: string): Promise<SessionDetail | null>;
|
|
61
129
|
/**
|
|
62
130
|
* Raw tokens read and written, beside the billed headline.
|
|
63
131
|
*
|
|
@@ -70,15 +138,15 @@ export declare class SfDb {
|
|
|
70
138
|
* material generated. The gap between them and the headline is cached
|
|
71
139
|
* re-reads, which is usually most of it.
|
|
72
140
|
*/
|
|
73
|
-
usage(adwId: string): SessionUsage
|
|
141
|
+
usage(adwId: string): Promise<SessionUsage>;
|
|
74
142
|
/**
|
|
75
143
|
* The polling query. Rowid cursor, insertion order, bounded page — the same
|
|
76
144
|
* mechanism serves the live tail and lazy-paged history.
|
|
77
145
|
*/
|
|
78
|
-
events(adwId: string, after?: number, limit?: number): EventsPage
|
|
79
|
-
envelopes(adwId: string): Envelope[]
|
|
80
|
-
gates(adwId: string): GateResult[]
|
|
81
|
-
sessionCount(): number
|
|
146
|
+
events(adwId: string, after?: number, limit?: number): Promise<EventsPage>;
|
|
147
|
+
envelopes(adwId: string): Promise<Envelope[]>;
|
|
148
|
+
gates(adwId: string): Promise<GateResult[]>;
|
|
149
|
+
sessionCount(): Promise<number>;
|
|
82
150
|
/**
|
|
83
151
|
* `spf estimate`'s one read: every session that ran EXACTLY `chainName`
|
|
84
152
|
* (never a joined one — see below), each with its per-phase token totals,
|
|
@@ -100,10 +168,10 @@ export declare class SfDb {
|
|
|
100
168
|
* first (`spf estimate`'s own sample-selection order), which is a decision
|
|
101
169
|
* `estimate.ts` makes, not this method.
|
|
102
170
|
*/
|
|
103
|
-
chainPhaseHistory(chainName: string): {
|
|
171
|
+
chainPhaseHistory(chainName: string): Promise<{
|
|
104
172
|
sessions: ChainHistorySession[];
|
|
105
173
|
joinedExcluded: number;
|
|
106
|
-
}
|
|
174
|
+
}>;
|
|
107
175
|
}
|
|
108
176
|
/** One EXACT-match session's history, as `chainPhaseHistory` returns it — `spf estimate`'s raw material. */
|
|
109
177
|
export interface ChainHistorySession {
|