@knpkv/herdr-work 0.2.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.
@@ -0,0 +1,64 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { WorkProjectionError } from "./errors.js";
3
+ import { WorkGoalCheckpoint, workHistoryMaxEvents, WorkSnapshots } from "./model.js";
4
+ const windowOffset = {
5
+ now: 0,
6
+ day: 24 * 60 * 60 * 1_000,
7
+ week: 7 * 24 * 60 * 60 * 1_000,
8
+ month: 30 * 24 * 60 * 60 * 1_000
9
+ };
10
+ const projectionError = (reason, detail, cause) => new WorkProjectionError({ cause, detail, reason });
11
+ const validateHistory = Effect.fn("HerdrWork.validateHistory")(function* (input) {
12
+ const events = yield* Schema.decodeUnknownEffect(Schema.Array(WorkGoalCheckpoint).check(Schema.isMaxLength(workHistoryMaxEvents)))(input).pipe(Effect.mapError((cause) => projectionError("malformed", "work checkpoint history is malformed", cause)));
13
+ const eventIds = new Set();
14
+ const goalTimes = new Set();
15
+ const createdAt = new Map();
16
+ for (const event of events) {
17
+ if (eventIds.has(event.eventId)) {
18
+ return yield* projectionError("duplicate_event", `work event ${event.eventId} occurs more than once`, event);
19
+ }
20
+ eventIds.add(event.eventId);
21
+ const timeKey = `${event.goal.id}\u0000${event.occurredAt}`;
22
+ if (goalTimes.has(timeKey)) {
23
+ return yield* projectionError("ambiguous_checkpoint", `goal ${event.goal.id} has more than one checkpoint at ${event.occurredAt}`, event);
24
+ }
25
+ goalTimes.add(timeKey);
26
+ const firstCreatedAt = createdAt.get(event.goal.id);
27
+ if (firstCreatedAt !== undefined && firstCreatedAt !== event.goal.createdAt) {
28
+ return yield* projectionError("inconsistent_history", `goal ${event.goal.id} changed its creation timestamp`, event);
29
+ }
30
+ createdAt.set(event.goal.id, event.goal.createdAt);
31
+ }
32
+ for (const [goalId, timestamp] of createdAt) {
33
+ if (!events.some((event) => event.goal.id === goalId && event.occurredAt === timestamp)) {
34
+ return yield* projectionError("inconsistent_history", `goal ${goalId} has no checkpoint at its creation timestamp`, { goalId, timestamp });
35
+ }
36
+ }
37
+ return events;
38
+ });
39
+ const snapshotAt = (events, observedAt, window) => {
40
+ const asOf = Math.max(0, observedAt - windowOffset[window]);
41
+ const latest = new Map();
42
+ for (const event of events.toSorted((left, right) => left.occurredAt - right.occurredAt)) {
43
+ if (event.occurredAt <= asOf)
44
+ latest.set(event.goal.id, event.goal);
45
+ }
46
+ return {
47
+ window,
48
+ observedAt,
49
+ asOf,
50
+ goals: [...latest.values()].toSorted((left, right) => right.updatedAt - left.updatedAt || left.title.localeCompare(right.title))
51
+ };
52
+ };
53
+ export const projectWorkSnapshots = Effect.fn("HerdrWork.projectSnapshots")(function* (input, observedAt) {
54
+ const timestamp = yield* Schema.decodeUnknownEffect(WorkSnapshots.fields.observedAt)(observedAt).pipe(Effect.mapError((cause) => projectionError("malformed", "work observation timestamp is malformed", cause)));
55
+ const events = yield* validateHistory(input);
56
+ return yield* Schema.decodeUnknownEffect(WorkSnapshots)({
57
+ observedAt: timestamp,
58
+ now: snapshotAt(events, timestamp, "now"),
59
+ day: snapshotAt(events, timestamp, "day"),
60
+ week: snapshotAt(events, timestamp, "week"),
61
+ month: snapshotAt(events, timestamp, "month")
62
+ }).pipe(Effect.mapError((cause) => projectionError("malformed", "work snapshots could not be encoded", cause)));
63
+ });
64
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { Effect } from "effect";
2
+ import type { WorkCheckpointConflictError, WorkProjectionError, WorkStoreError } from "./errors.js";
3
+ import type { WorkGoalCheckpoint, WorkSnapshots } from "./model.js";
4
+ import type { WorkStoreService } from "./store.js";
5
+ export interface WorkService {
6
+ readonly record: (event: WorkGoalCheckpoint) => Effect.Effect<WorkGoalCheckpoint, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError>;
7
+ readonly snapshots: (observedAt?: number) => Effect.Effect<WorkSnapshots, WorkStoreError | WorkProjectionError>;
8
+ }
9
+ export declare const makeWorkService: (store: WorkStoreService) => Effect.Effect<{
10
+ record: (event: WorkGoalCheckpoint) => Effect.Effect<WorkGoalCheckpoint, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError, never>;
11
+ snapshots: (observedAt?: number | undefined) => Effect.Effect<{
12
+ readonly observedAt: number;
13
+ readonly now: {
14
+ readonly window: "day" | "month" | "now" | "week";
15
+ readonly observedAt: number;
16
+ readonly asOf: number;
17
+ readonly goals: readonly {
18
+ readonly id: string;
19
+ readonly title: string;
20
+ readonly summary: string;
21
+ readonly detail: string;
22
+ readonly state: "blocked" | "completed" | "deployed" | "planned" | "review" | "working";
23
+ readonly owner: {
24
+ readonly id: string;
25
+ readonly name: string;
26
+ };
27
+ readonly repository: {
28
+ readonly repository: string;
29
+ readonly branch: string;
30
+ };
31
+ readonly spend: {
32
+ readonly currency: string;
33
+ readonly minorUnits: number;
34
+ } | null;
35
+ readonly delivery: "deployed" | "local" | "merged" | "pull_request" | "review";
36
+ readonly blocker: {
37
+ readonly summary: string;
38
+ readonly since: number;
39
+ } | null;
40
+ readonly connectTarget: {
41
+ readonly host: string;
42
+ readonly agentId: string;
43
+ readonly url: string;
44
+ } | null;
45
+ readonly createdAt: number;
46
+ readonly updatedAt: number;
47
+ }[];
48
+ };
49
+ readonly day: {
50
+ readonly window: "day" | "month" | "now" | "week";
51
+ readonly observedAt: number;
52
+ readonly asOf: number;
53
+ readonly goals: readonly {
54
+ readonly id: string;
55
+ readonly title: string;
56
+ readonly summary: string;
57
+ readonly detail: string;
58
+ readonly state: "blocked" | "completed" | "deployed" | "planned" | "review" | "working";
59
+ readonly owner: {
60
+ readonly id: string;
61
+ readonly name: string;
62
+ };
63
+ readonly repository: {
64
+ readonly repository: string;
65
+ readonly branch: string;
66
+ };
67
+ readonly spend: {
68
+ readonly currency: string;
69
+ readonly minorUnits: number;
70
+ } | null;
71
+ readonly delivery: "deployed" | "local" | "merged" | "pull_request" | "review";
72
+ readonly blocker: {
73
+ readonly summary: string;
74
+ readonly since: number;
75
+ } | null;
76
+ readonly connectTarget: {
77
+ readonly host: string;
78
+ readonly agentId: string;
79
+ readonly url: string;
80
+ } | null;
81
+ readonly createdAt: number;
82
+ readonly updatedAt: number;
83
+ }[];
84
+ };
85
+ readonly week: {
86
+ readonly window: "day" | "month" | "now" | "week";
87
+ readonly observedAt: number;
88
+ readonly asOf: number;
89
+ readonly goals: readonly {
90
+ readonly id: string;
91
+ readonly title: string;
92
+ readonly summary: string;
93
+ readonly detail: string;
94
+ readonly state: "blocked" | "completed" | "deployed" | "planned" | "review" | "working";
95
+ readonly owner: {
96
+ readonly id: string;
97
+ readonly name: string;
98
+ };
99
+ readonly repository: {
100
+ readonly repository: string;
101
+ readonly branch: string;
102
+ };
103
+ readonly spend: {
104
+ readonly currency: string;
105
+ readonly minorUnits: number;
106
+ } | null;
107
+ readonly delivery: "deployed" | "local" | "merged" | "pull_request" | "review";
108
+ readonly blocker: {
109
+ readonly summary: string;
110
+ readonly since: number;
111
+ } | null;
112
+ readonly connectTarget: {
113
+ readonly host: string;
114
+ readonly agentId: string;
115
+ readonly url: string;
116
+ } | null;
117
+ readonly createdAt: number;
118
+ readonly updatedAt: number;
119
+ }[];
120
+ };
121
+ readonly month: {
122
+ readonly window: "day" | "month" | "now" | "week";
123
+ readonly observedAt: number;
124
+ readonly asOf: number;
125
+ readonly goals: readonly {
126
+ readonly id: string;
127
+ readonly title: string;
128
+ readonly summary: string;
129
+ readonly detail: string;
130
+ readonly state: "blocked" | "completed" | "deployed" | "planned" | "review" | "working";
131
+ readonly owner: {
132
+ readonly id: string;
133
+ readonly name: string;
134
+ };
135
+ readonly repository: {
136
+ readonly repository: string;
137
+ readonly branch: string;
138
+ };
139
+ readonly spend: {
140
+ readonly currency: string;
141
+ readonly minorUnits: number;
142
+ } | null;
143
+ readonly delivery: "deployed" | "local" | "merged" | "pull_request" | "review";
144
+ readonly blocker: {
145
+ readonly summary: string;
146
+ readonly since: number;
147
+ } | null;
148
+ readonly connectTarget: {
149
+ readonly host: string;
150
+ readonly agentId: string;
151
+ readonly url: string;
152
+ } | null;
153
+ readonly createdAt: number;
154
+ readonly updatedAt: number;
155
+ }[];
156
+ };
157
+ }, WorkProjectionError | WorkStoreError, never>;
158
+ }, never, never>;
159
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACnG,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,kBAAkB,KACtB,MAAM,CAAC,MAAM,CAChB,kBAAkB,EAClB,2BAA2B,GAAG,mBAAmB,GAAG,cAAc,CACnE,CAAA;IACD,QAAQ,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,GAAG,mBAAmB,CAAC,CAAA;CAChH;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAO1B,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { Clock, Effect } from "effect";
2
+ import { projectWorkSnapshots } from "./projection.js";
3
+ export const makeWorkService = Effect.fn("HerdrWork.makeService")(function* (store) {
4
+ const record = Effect.fn("HerdrWork.record")((event) => store.append(event));
5
+ const snapshots = Effect.fn("HerdrWork.snapshots")(function* (observedAt) {
6
+ const timestamp = observedAt ?? (yield* Clock.currentTimeMillis);
7
+ return yield* store.list().pipe(Effect.flatMap((events) => projectWorkSnapshots(events, timestamp)));
8
+ });
9
+ return { record, snapshots };
10
+ });
11
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAatD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAC,KAAuB;IACjG,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAyB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IAChG,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAC,UAAmB;QAC9E,MAAM,SAAS,GAAG,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAChE,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACtG,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAwB,CAAA;AACpD,CAAC,CAAC,CAAA"}
@@ -0,0 +1,53 @@
1
+ import { Effect, FileSystem, Path } from "effect";
2
+ import { WorkCheckpointConflictError, WorkProjectionError, WorkStoreError } from "./errors.js";
3
+ import { WorkGoalCheckpoint, type WorkGoalCheckpoint as WorkGoalCheckpointType } from "./model.js";
4
+ export interface WorkStoreService {
5
+ readonly append: (event: WorkGoalCheckpointType) => Effect.Effect<WorkGoalCheckpointType, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError>;
6
+ readonly list: () => Effect.Effect<ReadonlyArray<WorkGoalCheckpointType>, WorkStoreError>;
7
+ }
8
+ export declare class WorkStore implements WorkStoreService {
9
+ #private;
10
+ readonly path: string;
11
+ private constructor();
12
+ static readonly open: (path: string) => Effect.Effect<WorkStore, WorkStoreError, FileSystem.FileSystem | Path.Path>;
13
+ readonly append: (this: WorkStore, event: WorkGoalCheckpoint) => Effect.Effect<WorkGoalCheckpoint, WorkCheckpointConflictError | WorkProjectionError | WorkStoreError, never>;
14
+ readonly list: (this: WorkStore) => Effect.Effect<{
15
+ readonly version: "herdr.work.event.v1";
16
+ readonly eventId: string;
17
+ readonly occurredAt: number;
18
+ readonly goal: {
19
+ readonly id: string;
20
+ readonly title: string;
21
+ readonly summary: string;
22
+ readonly detail: string;
23
+ readonly state: "blocked" | "completed" | "deployed" | "planned" | "review" | "working";
24
+ readonly owner: {
25
+ readonly id: string;
26
+ readonly name: string;
27
+ };
28
+ readonly repository: {
29
+ readonly repository: string;
30
+ readonly branch: string;
31
+ };
32
+ readonly spend: {
33
+ readonly currency: string;
34
+ readonly minorUnits: number;
35
+ } | null;
36
+ readonly delivery: "deployed" | "local" | "merged" | "pull_request" | "review";
37
+ readonly blocker: {
38
+ readonly summary: string;
39
+ readonly since: number;
40
+ } | null;
41
+ readonly connectTarget: {
42
+ readonly host: string;
43
+ readonly agentId: string;
44
+ readonly url: string;
45
+ } | null;
46
+ readonly createdAt: number;
47
+ readonly updatedAt: number;
48
+ };
49
+ }[], WorkStoreError, never>;
50
+ private secureFiles;
51
+ close(): void;
52
+ }
53
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAU,MAAM,QAAQ,CAAA;AAEzD,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC9F,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,IAAI,sBAAsB,EAGlD,MAAM,YAAY,CAAA;AAyDnB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,sBAAsB,KAC1B,MAAM,CAAC,MAAM,CAChB,sBAAsB,EACtB,2BAA2B,GAAG,mBAAmB,GAAG,cAAc,CACnE,CAAA;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,sBAAsB,CAAC,EAAE,cAAc,CAAC,CAAA;CAC1F;AAED,qBAAa,SAAU,YAAW,gBAAgB;;IAGhD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,OAAO,eAmBN;IAED,MAAM,CAAC,QAAQ,CAAC,IAAI,gGAgBlB;IAEF,QAAQ,CAAC,MAAM,+JA4Hb;IAEF,QAAQ,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCASX;IAEF,OAAO,CAAC,WAAW;IAiBnB,KAAK,IAAI,IAAI,CAEZ;CACF"}
package/dist/store.js ADDED
@@ -0,0 +1,187 @@
1
+ import { fleetResponseBodyMaxBytes } from "@knpkv/herdr-fleet";
2
+ import { Effect, FileSystem, Path, Schema } from "effect";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { WorkCheckpointConflictError, WorkProjectionError, WorkStoreError } from "./errors.js";
5
+ import { WorkGoalCheckpoint, workHistoryMaxEvents, workSnapshotMaxGoals } from "./model.js";
6
+ const StoredEventRow = Schema.Struct({ record: Schema.String });
7
+ const StoredEventRows = Schema.Array(StoredEventRow);
8
+ const CountRow = Schema.Struct({ count: Schema.Number });
9
+ const storeError = (operation) => (cause) => new WorkStoreError({ cause, operation });
10
+ const utf8 = new TextEncoder();
11
+ const encodedBytes = (value) => utf8.encode(JSON.stringify(value)).byteLength;
12
+ const maximumTimestamp = 8_640_000_000_000_000;
13
+ const workSnapshotEnvelopeMaxBytes = encodedBytes({
14
+ observedAt: maximumTimestamp,
15
+ now: { window: "now", observedAt: maximumTimestamp, asOf: maximumTimestamp, goals: [] },
16
+ day: { window: "day", observedAt: maximumTimestamp, asOf: maximumTimestamp, goals: [] },
17
+ week: { window: "week", observedAt: maximumTimestamp, asOf: maximumTimestamp, goals: [] },
18
+ month: { window: "month", observedAt: maximumTimestamp, asOf: maximumTimestamp, goals: [] }
19
+ });
20
+ const maximumSnapshotBytes = (history, candidate) => {
21
+ const maximumGoalBytes = new Map();
22
+ for (const { goal } of [...history, candidate]) {
23
+ const bytes = encodedBytes(goal);
24
+ maximumGoalBytes.set(goal.id, Math.max(maximumGoalBytes.get(goal.id) ?? 0, bytes));
25
+ }
26
+ const encodedGoals = [...maximumGoalBytes.values()].reduce((total, bytes) => total + bytes, 0);
27
+ const separators = Math.max(0, maximumGoalBytes.size - 1);
28
+ return workSnapshotEnvelopeMaxBytes + 4 * (encodedGoals + separators);
29
+ };
30
+ const decodeRow = (row) => Schema.decodeUnknownEffect(StoredEventRow)(row).pipe(Effect.mapError(storeError("decode.row")), Effect.flatMap(({ record }) => Effect.try({
31
+ try: () => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)),
32
+ catch: storeError("decode.event")
33
+ })));
34
+ const encodeEvent = (event) => JSON.stringify(Schema.encodeSync(WorkGoalCheckpoint)(event));
35
+ export class WorkStore {
36
+ #database;
37
+ #fileSystem;
38
+ path;
39
+ constructor(path, fileSystem) {
40
+ this.path = path;
41
+ this.#fileSystem = fileSystem;
42
+ this.#database = new DatabaseSync(path);
43
+ try {
44
+ this.#database.exec(`
45
+ PRAGMA journal_mode = WAL;
46
+ CREATE TABLE IF NOT EXISTS work_goal_events (
47
+ event_id TEXT PRIMARY KEY,
48
+ goal_id TEXT NOT NULL,
49
+ occurred_at INTEGER NOT NULL,
50
+ record TEXT NOT NULL,
51
+ UNIQUE (goal_id, occurred_at)
52
+ );
53
+ `);
54
+ }
55
+ catch (error) {
56
+ this.#database.close();
57
+ throw error;
58
+ }
59
+ }
60
+ static open = Effect.fn("WorkStore.open")(function* (path) {
61
+ const fileSystem = yield* FileSystem.FileSystem;
62
+ const paths = yield* Path.Path;
63
+ const directory = paths.dirname(path);
64
+ yield* fileSystem.makeDirectory(directory, { recursive: true, mode: 0o700 }).pipe(Effect.mapError(storeError("open.directory")));
65
+ yield* fileSystem.chmod(directory, 0o700).pipe(Effect.mapError(storeError("open.secureDirectory")));
66
+ const store = yield* Effect.try({
67
+ try: () => new WorkStore(path, fileSystem),
68
+ catch: storeError("open.database")
69
+ });
70
+ yield* store.secureFiles();
71
+ return store;
72
+ });
73
+ append = Effect.fn("WorkStore.append")(function* (event) {
74
+ const decoded = yield* Schema.decodeUnknownEffect(WorkGoalCheckpoint)(event).pipe(Effect.mapError(storeError("append.decode")));
75
+ const inserted = yield* Effect.try({
76
+ try: () => {
77
+ let transaction = false;
78
+ try {
79
+ this.#database.exec("BEGIN IMMEDIATE");
80
+ transaction = true;
81
+ const reject = (error) => {
82
+ this.#database.exec("ROLLBACK");
83
+ transaction = false;
84
+ return { _tag: "rejected", error };
85
+ };
86
+ const existingRows = this.#database.prepare(`SELECT record FROM work_goal_events
87
+ WHERE event_id = ? OR (goal_id = ? AND occurred_at = ?)`).all(decoded.eventId, decoded.goal.id, decoded.occurredAt);
88
+ if (existingRows.length > 0) {
89
+ const encoded = encodeEvent(decoded);
90
+ const existingEvents = Schema.decodeUnknownSync(StoredEventRows)(existingRows).map(({ record }) => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)));
91
+ const existingEvent = existingEvents[0];
92
+ if (existingEvents.length === 1 && existingEvent !== undefined && encodeEvent(existingEvent) === encoded) {
93
+ this.#database.exec("ROLLBACK");
94
+ transaction = false;
95
+ return { _tag: "replayed", event: existingEvent };
96
+ }
97
+ return reject(new WorkCheckpointConflictError({
98
+ eventId: decoded.eventId,
99
+ goalId: decoded.goal.id,
100
+ occurredAt: decoded.occurredAt
101
+ }));
102
+ }
103
+ const eventCount = Schema.decodeUnknownSync(CountRow)(this.#database.prepare("SELECT COUNT(*) AS count FROM work_goal_events").get()).count;
104
+ if (eventCount >= workHistoryMaxEvents) {
105
+ return reject(new WorkProjectionError({
106
+ cause: decoded,
107
+ detail: `work history cannot exceed ${workHistoryMaxEvents} checkpoints`,
108
+ reason: "capacity_exceeded"
109
+ }));
110
+ }
111
+ const history = Schema.decodeUnknownSync(StoredEventRows)(this.#database.prepare("SELECT record FROM work_goal_events").all()).map(({ record }) => Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(record)));
112
+ if (maximumSnapshotBytes(history, decoded) > fleetResponseBodyMaxBytes) {
113
+ return reject(new WorkProjectionError({
114
+ cause: decoded,
115
+ detail: `work snapshots cannot exceed ${fleetResponseBodyMaxBytes} encoded bytes`,
116
+ reason: "capacity_exceeded"
117
+ }));
118
+ }
119
+ const firstGoalRow = this.#database.prepare("SELECT record FROM work_goal_events WHERE goal_id = ? ORDER BY occurred_at ASC, event_id ASC LIMIT 1").get(decoded.goal.id);
120
+ if (firstGoalRow === undefined) {
121
+ if (decoded.occurredAt !== decoded.goal.createdAt) {
122
+ return reject(new WorkProjectionError({
123
+ cause: decoded,
124
+ detail: `goal ${decoded.goal.id} must begin at its creation timestamp`,
125
+ reason: "inconsistent_history"
126
+ }));
127
+ }
128
+ const goalCount = Schema.decodeUnknownSync(CountRow)(this.#database.prepare("SELECT COUNT(DISTINCT goal_id) AS count FROM work_goal_events").get()).count;
129
+ if (goalCount >= workSnapshotMaxGoals) {
130
+ return reject(new WorkProjectionError({
131
+ cause: decoded,
132
+ detail: `work snapshots cannot exceed ${workSnapshotMaxGoals} goals`,
133
+ reason: "capacity_exceeded"
134
+ }));
135
+ }
136
+ }
137
+ else {
138
+ const firstGoal = Schema.decodeUnknownSync(WorkGoalCheckpoint)(JSON.parse(Schema.decodeUnknownSync(StoredEventRow)(firstGoalRow).record));
139
+ if (firstGoal.goal.createdAt !== decoded.goal.createdAt) {
140
+ return reject(new WorkProjectionError({
141
+ cause: decoded,
142
+ detail: `goal ${decoded.goal.id} changed its creation timestamp`,
143
+ reason: "inconsistent_history"
144
+ }));
145
+ }
146
+ }
147
+ const result = this.#database.prepare("INSERT INTO work_goal_events (event_id, goal_id, occurred_at, record) VALUES (?, ?, ?, ?)").run(decoded.eventId, decoded.goal.id, decoded.occurredAt, encodeEvent(decoded));
148
+ this.#database.exec("COMMIT");
149
+ transaction = false;
150
+ return { _tag: "inserted", changes: result.changes };
151
+ }
152
+ catch (error) {
153
+ if (transaction)
154
+ this.#database.exec("ROLLBACK");
155
+ throw error;
156
+ }
157
+ },
158
+ catch: storeError("append.insert")
159
+ });
160
+ if (inserted._tag === "rejected")
161
+ return yield* inserted.error;
162
+ if (inserted._tag === "replayed")
163
+ return inserted.event;
164
+ if (inserted.changes !== 1 && inserted.changes !== 1n) {
165
+ return yield* storeError("append.insert.count")(inserted.changes);
166
+ }
167
+ yield* this.secureFiles();
168
+ return decoded;
169
+ });
170
+ list = Effect.fn("WorkStore.list")(function* () {
171
+ const rows = yield* Effect.try({
172
+ try: () => this.#database.prepare("SELECT record FROM work_goal_events ORDER BY occurred_at ASC, event_id ASC").all(),
173
+ catch: storeError("list")
174
+ });
175
+ return yield* Effect.forEach(rows, decodeRow);
176
+ });
177
+ secureFiles() {
178
+ const files = [this.path, `${this.path}-wal`, `${this.path}-shm`];
179
+ return Effect.forEach(files, (path) => this.#fileSystem.exists(path).pipe(Effect.mapError(storeError("secure.exists")), Effect.flatMap((exists) => exists
180
+ ? this.#fileSystem.chmod(path, 0o600).pipe(Effect.mapError(storeError("secure.chmod")))
181
+ : Effect.void)), { discard: true });
182
+ }
183
+ close() {
184
+ this.#database.close();
185
+ }
186
+ }
187
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { type ReactElement } from "react";
2
+ import type { WorkSnapshots } from "./model.js";
3
+ export declare const WorkBoard: ({ snapshots }: {
4
+ readonly snapshots: WorkSnapshots;
5
+ }) => ReactElement;
6
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,KAAK,EAAyC,aAAa,EAAsB,MAAM,YAAY,CAAA;AAqE1G,eAAO,MAAM,SAAS,kBAAmB;IAAE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAE,KAAG,YA4KhF,CAAA"}
package/dist/view.js ADDED
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Divider, StateLabel, Surface, Text } from "@knpkv/rly/primitives";
3
+ import { StageRail } from "@knpkv/rly/patterns";
4
+ import { useState } from "react";
5
+ const windows = ["now", "day", "week", "month"];
6
+ const stageOrder = ["local", "review", "pull_request", "merged", "deployed"];
7
+ const windowLabel = {
8
+ now: "Now",
9
+ day: "24 hours ago",
10
+ week: "7 days ago",
11
+ month: "30 days ago"
12
+ };
13
+ const statePresentation = {
14
+ planned: { label: "Planned", tone: "neutral" },
15
+ working: { label: "Working", tone: "progress" },
16
+ blocked: { label: "Blocked", tone: "critical" },
17
+ review: { label: "In review", tone: "caution" },
18
+ deployed: { label: "Deployed", tone: "positive" },
19
+ completed: { label: "Completed", tone: "positive" }
20
+ };
21
+ const deliveryLabel = {
22
+ local: "Local",
23
+ review: "Review",
24
+ pull_request: "Pull request",
25
+ merged: "Merged",
26
+ deployed: "Deployed"
27
+ };
28
+ const formatTimestamp = (timestamp) => new Intl.DateTimeFormat("en-GB", {
29
+ dateStyle: "medium",
30
+ timeStyle: "short"
31
+ }).format(timestamp);
32
+ const formatSpend = (goal) => goal.spend === null
33
+ ? "Not recorded"
34
+ : new Intl.NumberFormat("en", {
35
+ style: "currency",
36
+ currency: goal.spend.currency
37
+ }).format(goal.spend.minorUnits / 100);
38
+ const stagesFor = (goal) => {
39
+ const current = stageOrder.indexOf(goal.delivery);
40
+ return stageOrder.map((stage, index) => {
41
+ const presentation = {
42
+ id: `${goal.id}-${stage}`,
43
+ name: deliveryLabel[stage],
44
+ state: index < current ? "Complete" : index === current ? deliveryLabel[stage] : "Not started",
45
+ tone: index < current ? "positive" : index === current ? statePresentation[goal.state].tone : "neutral"
46
+ };
47
+ return index === current ? { ...presentation, reason: goal.detail } : presentation;
48
+ });
49
+ };
50
+ const SummaryCell = ({ label, value }) => (_jsxs(Surface, { className: "work-summary-cell", padding: "compact", tone: "secondary", children: [_jsx(Text, { tone: "secondary", variant: "meta", children: label }), _jsx(Text, { as: "span", variant: "card-title", children: value })] }));
51
+ const snapshotFor = (snapshots, window) => snapshots[window];
52
+ export const WorkBoard = ({ snapshots }) => {
53
+ const [window, setWindow] = useState("now");
54
+ const snapshot = snapshotFor(snapshots, window);
55
+ const [selectedId, setSelectedId] = useState(snapshot.goals[0]?.id ?? null);
56
+ const selected = snapshot.goals.find(({ id }) => id === selectedId) ?? null;
57
+ const counts = {
58
+ blocked: snapshot.goals.filter(({ state }) => state === "blocked").length,
59
+ deployed: snapshot.goals.filter(({ state }) => state === "deployed").length,
60
+ review: snapshot.goals.filter(({ state }) => state === "review").length,
61
+ working: snapshot.goals.filter(({ state }) => state === "working").length
62
+ };
63
+ return (_jsxs("section", { className: "work-page", "aria-labelledby": "work-board-title", children: [_jsxs("header", { className: "work-page-intro", children: [_jsxs("div", { children: [_jsx(Text, { as: "h1", id: "work-board-title", variant: "page-title", children: "Fleet departure board" }), _jsx(Text, { tone: "secondary", variant: "body-large", children: "Exceptions first. Delivery evidence and exact agent context stay one click away." })] }), _jsxs("div", { className: "work-snapshot-stamp", children: [_jsx(Text, { tone: "secondary", variant: "meta", children: "Durable snapshot" }), _jsx(Text, { variant: "code", children: formatTimestamp(snapshot.asOf) })] })] }), _jsxs(Surface, { className: "work-time-travel", padding: "compact", tone: "secondary", children: [_jsxs("div", { className: "work-time-heading", children: [_jsxs("div", { children: [_jsx(Text, { as: "h2", variant: "card-title", children: "Time travel" }), _jsx(Text, { tone: "secondary", variant: "meta", children: "Checkpoint events only. Missing history stays absent." })] }), _jsx(StateLabel, { label: window === "now" ? "Live" : "Historical", tone: window === "now" ? "positive" : "neutral" })] }), _jsx("div", { "aria-label": "Choose work snapshot", className: "work-time-controls", role: "group", children: windows.map((option) => (_jsx(Button, { "aria-pressed": window === option, onClick: () => setWindow(option), variant: window === option ? "primary" : "secondary", children: windowLabel[option] }, option))) })] }), _jsxs("div", { className: "work-summary-grid", "aria-label": "Work summary", children: [_jsx(SummaryCell, { label: "Goals", value: String(snapshot.goals.length) }), _jsx(SummaryCell, { label: "Working", value: String(counts.working) }), _jsx(SummaryCell, { label: "Blocked", value: String(counts.blocked) }), _jsx(SummaryCell, { label: "In review", value: String(counts.review) }), _jsx(SummaryCell, { label: "Deployed", value: String(counts.deployed) })] }), snapshot.goals.length === 0 ? (_jsxs(Surface, { padding: "spacious", tone: "secondary", children: [_jsx(Text, { as: "h2", variant: "card-title", children: "No goals at this checkpoint" }), _jsx(Text, { tone: "secondary", children: "Record a WorkGoalCheckpoint to add durable work state." })] })) : (_jsxs("div", { className: "work-board-layout", children: [_jsxs(Surface, { className: "work-departure-board", padding: "none", tone: "secondary", children: [_jsxs("div", { className: "work-board-head", "aria-hidden": "true", children: [_jsx("span", { children: "Status" }), _jsx("span", { children: "Work" }), _jsx("span", { children: "Owner" }), _jsx("span", { children: "Repository" }), _jsx("span", { children: "Delivery" }), _jsx("span", { children: "Spend" })] }), snapshot.goals.map((goal) => (_jsxs("button", { "aria-pressed": selected?.id === goal.id, className: "work-board-row", onClick: () => setSelectedId(goal.id), type: "button", children: [_jsx(StateLabel, { label: statePresentation[goal.state].label, size: "compact", tone: statePresentation[goal.state].tone }), _jsxs("span", { className: "work-board-copy", children: [_jsx(Text, { as: "strong", variant: "label", children: goal.title }), _jsx(Text, { tone: "secondary", variant: "meta", children: goal.summary })] }), _jsx(Text, { "data-label": "Owner", children: goal.owner.name }), _jsxs("span", { className: "work-board-copy", "data-label": "Repository", children: [_jsx(Text, { variant: "code", children: goal.repository.repository }), _jsx(Text, { tone: "secondary", variant: "meta", children: goal.repository.branch })] }), _jsx(Text, { "data-label": "Delivery", children: deliveryLabel[goal.delivery] }), _jsx(Text, { "data-label": "Spend", variant: "code", children: formatSpend(goal) })] }, goal.id)))] }), selected === null ? null : (_jsxs(Surface, { as: "aside", className: "work-inspector", padding: "spacious", children: [_jsx(StateLabel, { label: statePresentation[selected.state].label, tone: statePresentation[selected.state].tone }), _jsx(Text, { as: "h2", variant: "section-title", children: selected.title }), _jsx(Text, { tone: "secondary", children: selected.detail }), selected.blocker === null ? null : (_jsxs(Surface, { padding: "compact", tone: "secondary", children: [_jsxs(Text, { variant: "meta", tone: "secondary", children: ["Blocked since ", formatTimestamp(selected.blocker.since)] }), _jsx(Text, { children: selected.blocker.summary })] })), _jsx(Divider, {}), _jsxs("dl", { className: "work-facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Owner" }), _jsx("dd", { children: selected.owner.name })] }), _jsxs("div", { children: [_jsx("dt", { children: "Repository" }), _jsx("dd", { children: selected.repository.repository })] }), _jsxs("div", { children: [_jsx("dt", { children: "Branch" }), _jsx("dd", { children: selected.repository.branch })] }), _jsxs("div", { children: [_jsx("dt", { children: "Spend" }), _jsx("dd", { children: formatSpend(selected) })] })] }), selected.connectTarget === null ? (_jsx(Text, { tone: "secondary", children: "No worker has started for this goal." })) : (_jsx("a", { className: "work-connect-link", href: selected.connectTarget.url, children: "Open exact agent in Connect \u2192" }))] }))] })), selected === null ? null : (_jsx(Surface, { className: "work-delivery-evidence", padding: "spacious", children: _jsx(StageRail, { heading: `Delivery path · ${selected.title}`, stages: stagesFor(selected) }) }))] }));
64
+ };
65
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"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"}