@xfey/tutti 0.1.20 → 0.1.22

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.
Files changed (42) hide show
  1. package/dist/collaboration-state/index.d.ts +1 -1
  2. package/dist/collaboration-state/index.js +1 -1
  3. package/dist/collaboration-state/messages.js +50 -1
  4. package/dist/collaboration-state/scratchpad.d.ts +2 -0
  5. package/dist/collaboration-state/scratchpad.js +63 -0
  6. package/dist/collaboration-state/storage-types.d.ts +5 -0
  7. package/dist/collaboration-state/types.d.ts +8 -1
  8. package/dist/control-plane/event-publishers.js +2 -2
  9. package/dist/control-plane/invalidations.d.ts +2 -1
  10. package/dist/control-plane/invalidations.js +25 -0
  11. package/dist/control-plane/scratchpad-refresh-start.d.ts +2 -0
  12. package/dist/control-plane/scratchpad-refresh-start.js +10 -0
  13. package/dist/control-plane/scratchpad-refresh.d.ts +2 -0
  14. package/dist/control-plane/scratchpad-refresh.js +1 -0
  15. package/dist/project-timeline/index.d.ts +17 -3
  16. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +1 -0
  17. package/dist/server-shell/http/routes/project-api/openapi-timeline-routes.d.ts +94 -5
  18. package/dist/server-shell/http/routes/project-api/openapi.d.ts +95 -5
  19. package/dist/server-shell/http/routes/project-api/payload-validation.d.ts +6 -2
  20. package/dist/server-shell/http/routes/project-api/payload-validation.js +3 -0
  21. package/dist/server-shell/http/routes/project-api/project-timeline-projection.js +694 -502
  22. package/migrations/0013_scratchpad_receipt_sources.sql +24 -0
  23. package/migrations/README.md +3 -2
  24. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
  25. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
  26. package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +1 -0
  27. package/node_modules/@tutti/shared/dist/schemas/api/messages.js +1 -0
  28. package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.d.ts +313 -12
  29. package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.js +131 -14
  30. package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +5 -1
  31. package/package.json +1 -1
  32. package/prompts/procedures/README.md +1 -1
  33. package/prompts/procedures/task-compile.md +9 -2
  34. package/prompts/runs/README.md +2 -2
  35. package/prompts/runs/task-continuation.md +11 -4
  36. package/prompts/runs/task-retry.md +11 -4
  37. package/prompts/runs/task-run.md +11 -4
  38. package/web/assets/index-BfFYfzeO.js +29 -0
  39. package/web/assets/index-De6mK5Q2.css +1 -0
  40. package/web/index.html +2 -2
  41. package/web/assets/index-BtneECwp.js +0 -29
  42. package/web/assets/index-CM9mbbeW.css +0 -1
@@ -1,7 +1,7 @@
1
1
  export { CollaborationStateCursorError } from "./serialization.js";
2
2
  export { createIdleExecutionStatusProjection } from "./execution-status.js";
3
3
  export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesAfter, readMainChatMessagesAfterCursor, readMainChatMessagesBeforeCursor, } from "./messages.js";
4
- export { createEmptyScratchpadProjection, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
4
+ export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
5
5
  export { advanceScratchpadTaskCompileSourceCursor, markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
6
6
  export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, readSubmittedTaskCompileClarificationRounds, readSubmittedTaskCompileClarificationRoundsAfterCursor, } from "./clarification-records.js";
7
7
  export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
@@ -1,7 +1,7 @@
1
1
  export { CollaborationStateCursorError } from "./serialization.js";
2
2
  export { createIdleExecutionStatusProjection } from "./execution-status.js";
3
3
  export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesAfter, readMainChatMessagesAfterCursor, readMainChatMessagesBeforeCursor, } from "./messages.js";
4
- export { createEmptyScratchpadProjection, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
4
+ export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
5
5
  export { advanceScratchpadTaskCompileSourceCursor, markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
6
6
  export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, readSubmittedTaskCompileClarificationRounds, readSubmittedTaskCompileClarificationRoundsAfterCursor, } from "./clarification-records.js";
7
7
  export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
@@ -245,10 +245,59 @@ export function readMainChatMessageWindow(db, options = {}) {
245
245
  if (before !== null && after !== null) {
246
246
  throw new Error("before and after cursors cannot be used together");
247
247
  }
248
+ if (options.around !== undefined && (before !== null || after !== null)) {
249
+ throw new Error("around cannot be used with before or after cursors");
250
+ }
248
251
  let rows;
249
252
  let hasOlder = false;
250
253
  let hasNewer = false;
251
- if (before !== null) {
254
+ if (options.around !== undefined) {
255
+ const target = db
256
+ .prepare(`
257
+ SELECT *
258
+ FROM messages
259
+ WHERE scope_kind = 'main_chat'
260
+ AND id = ?
261
+ `)
262
+ .get(options.around);
263
+ if (target === undefined) {
264
+ rows = [];
265
+ }
266
+ else {
267
+ const beforeLimit = Math.floor((limit - 1) / 2);
268
+ const afterLimit = Math.max(0, limit - beforeLimit - 1);
269
+ const olderRows = db
270
+ .prepare(`
271
+ SELECT *
272
+ FROM messages
273
+ WHERE scope_kind = 'main_chat'
274
+ AND (
275
+ created_at < ?
276
+ OR (created_at = ? AND id < ?)
277
+ )
278
+ ORDER BY created_at DESC, id DESC
279
+ LIMIT ?
280
+ `)
281
+ .all(target.created_at, target.created_at, target.id, beforeLimit + 1);
282
+ const newerRows = db
283
+ .prepare(`
284
+ SELECT *
285
+ FROM messages
286
+ WHERE scope_kind = 'main_chat'
287
+ AND (
288
+ created_at > ?
289
+ OR (created_at = ? AND id > ?)
290
+ )
291
+ ORDER BY created_at ASC, id ASC
292
+ LIMIT ?
293
+ `)
294
+ .all(target.created_at, target.created_at, target.id, afterLimit + 1);
295
+ hasOlder = olderRows.length > beforeLimit;
296
+ hasNewer = newerRows.length > afterLimit;
297
+ rows = [...olderRows.slice(0, beforeLimit).reverse(), target, ...newerRows.slice(0, afterLimit)];
298
+ }
299
+ }
300
+ else if (before !== null) {
252
301
  rows = db
253
302
  .prepare(`
254
303
  SELECT *
@@ -1,8 +1,10 @@
1
1
  import type { ScratchpadProjection } from "@tutti/shared/schemas/api";
2
2
  import type { SqliteDatabase } from "../store/index.js";
3
+ import type { ScratchpadSourceRefRow } from "./storage-types.js";
3
4
  import type { ScratchpadSnapshotInput, SubmitScratchpadInput } from "./types.js";
4
5
  export declare function createEmptyScratchpadProjection(): ScratchpadProjection;
5
6
  export declare function upsertScratchpadProjection(db: SqliteDatabase, input: ScratchpadSnapshotInput): ScratchpadProjection;
6
7
  export declare function submitScratchpadProjection(db: SqliteDatabase, input: SubmitScratchpadInput): ScratchpadProjection;
7
8
  export declare function readScratchpadProjection(db: SqliteDatabase): ScratchpadProjection;
9
+ export declare function readScratchpadReceiptSourceRefs(db: SqliteDatabase, workflowRef: string): ScratchpadSourceRefRow[];
8
10
  //# sourceMappingURL=scratchpad.d.ts.map
@@ -1,5 +1,56 @@
1
1
  import { nowIso, parseJson, stringifyJson } from "./serialization.js";
2
2
  const SCRATCHPAD_RECEIPT_LIMIT = 100;
3
+ function normalizeSourceRefs(sourceRefs = []) {
4
+ const byMessageId = new Map();
5
+ for (const sourceRef of sourceRefs) {
6
+ if (sourceRef.message_id.trim() === "" || sourceRef.created_at.trim() === "") {
7
+ continue;
8
+ }
9
+ byMessageId.set(sourceRef.message_id, sourceRef);
10
+ }
11
+ return [...byMessageId.values()].sort((left, right) => {
12
+ const timeOrder = left.created_at.localeCompare(right.created_at);
13
+ return timeOrder === 0 ? left.message_id.localeCompare(right.message_id) : timeOrder;
14
+ });
15
+ }
16
+ function replaceCurrentScratchpadSourceRefs(db, sourceRefs) {
17
+ db.prepare("DELETE FROM scratchpad_source_refs WHERE scratchpad_id = 'current'").run();
18
+ const normalized = normalizeSourceRefs(sourceRefs);
19
+ if (normalized.length === 0) {
20
+ return;
21
+ }
22
+ const insert = db.prepare(`
23
+ INSERT INTO scratchpad_source_refs (
24
+ scratchpad_id,
25
+ message_id,
26
+ source_scope,
27
+ created_at
28
+ )
29
+ VALUES ('current', ?, ?, ?)
30
+ `);
31
+ for (const sourceRef of normalized) {
32
+ insert.run(sourceRef.message_id, sourceRef.source_scope, sourceRef.created_at);
33
+ }
34
+ }
35
+ function copyCurrentScratchpadSourcesToReceipt(db, workflowRef) {
36
+ db.prepare("DELETE FROM scratchpad_receipt_sources WHERE workflow_ref = ?").run(workflowRef);
37
+ db.prepare(`
38
+ INSERT INTO scratchpad_receipt_sources (
39
+ workflow_ref,
40
+ message_id,
41
+ source_scope,
42
+ created_at
43
+ )
44
+ SELECT
45
+ ?,
46
+ message_id,
47
+ source_scope,
48
+ created_at
49
+ FROM scratchpad_source_refs
50
+ WHERE scratchpad_id = 'current'
51
+ ORDER BY created_at ASC, message_id ASC
52
+ `).run(workflowRef);
53
+ }
3
54
  export function createEmptyScratchpadProjection() {
4
55
  return {
5
56
  id: "current",
@@ -76,6 +127,7 @@ export function upsertScratchpadProjection(db, input) {
76
127
  submitted_by_workflow_ref = NULL,
77
128
  submitted_at = NULL
78
129
  `).run(input.topic, input.background_summary, stringifyJson(input.current_consensus), stringifyJson(input.open_questions), stringifyJson(input.task_changes), input.updated_by_activity_ref ?? null, updatedAt);
130
+ replaceCurrentScratchpadSourceRefs(db, input.source_refs);
79
131
  return readScratchpadProjection(db);
80
132
  }
81
133
  export function submitScratchpadProjection(db, input) {
@@ -105,6 +157,7 @@ export function submitScratchpadProjection(db, input) {
105
157
  task_changes_json = excluded.task_changes_json,
106
158
  submitted_at = excluded.submitted_at
107
159
  `).run(input.workflow_ref, input.activity_ref, scratchpad.topic, scratchpad.background_summary, stringifyJson(scratchpad.current_consensus), stringifyJson(scratchpad.open_questions), stringifyJson(scratchpad.task_changes), submittedAt);
160
+ copyCurrentScratchpadSourcesToReceipt(db, input.workflow_ref);
108
161
  db.prepare(`
109
162
  UPDATE scratchpad
110
163
  SET
@@ -168,4 +221,14 @@ export function readScratchpadProjection(db) {
168
221
  }
169
222
  return scratchpad;
170
223
  }
224
+ export function readScratchpadReceiptSourceRefs(db, workflowRef) {
225
+ return db
226
+ .prepare(`
227
+ SELECT message_id, source_scope, created_at
228
+ FROM scratchpad_receipt_sources
229
+ WHERE workflow_ref = ?
230
+ ORDER BY created_at ASC, message_id ASC
231
+ `)
232
+ .all(workflowRef);
233
+ }
171
234
  //# sourceMappingURL=scratchpad.js.map
@@ -35,6 +35,11 @@ export type ScratchpadReceiptRow = {
35
35
  task_changes_json: string;
36
36
  submitted_at: string;
37
37
  };
38
+ export type ScratchpadSourceRefRow = {
39
+ message_id: MessageId;
40
+ source_scope: "main_chat" | "clarification_round";
41
+ created_at: string;
42
+ };
38
43
  export type ScratchpadSourceStateRow = {
39
44
  main_chat_cursor_created_at: string | null;
40
45
  main_chat_cursor_message_id: string | null;
@@ -1,6 +1,6 @@
1
1
  import type { RunLineage } from "@tutti/shared/domain";
2
2
  import type { AccountAvatarProjection } from "@tutti/shared/domain";
3
- import type { ActivityRef, ClarificationRoundRef, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
3
+ import type { ActivityRef, ClarificationRoundRef, MessageId, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
4
4
  import type { ClarificationRequestPayload, ClarificationRoundProjection, ClarificationSuccessorRef, ClarificationThreadProjection, MessageProjection, ReadStateScope, ReadStateSummaryProjection, RecoverySummaryProjection, RunResultProjection, ScratchpadProjection, TaskContractProjection, TaskDetailProjection, TaskDetailResultProjection, TaskProjection, WorklistProjection } from "@tutti/shared/schemas/api";
5
5
  export type MessageAuthorInput = {
6
6
  kind: "human" | "system" | "agent";
@@ -53,9 +53,15 @@ export type ScratchpadSnapshotInput = {
53
53
  current_consensus: string[];
54
54
  open_questions: string[];
55
55
  task_changes: string[];
56
+ source_refs?: ScratchpadSourceRefInput[];
56
57
  updated_by_activity_ref?: ActivityRef;
57
58
  now?: () => Date;
58
59
  };
60
+ export type ScratchpadSourceRefInput = {
61
+ message_id: MessageId;
62
+ source_scope: "main_chat" | "clarification_round";
63
+ created_at: string;
64
+ };
59
65
  export type SubmitScratchpadInput = {
60
66
  workflow_ref: WorkflowInvocationRef;
61
67
  activity_ref: ActivityRef;
@@ -286,6 +292,7 @@ export type ReadMessageWindowOptions = {
286
292
  anchor?: "latest" | "start";
287
293
  before?: string;
288
294
  after?: string;
295
+ around?: string;
289
296
  };
290
297
  export type ReadMainChatMessagesAfterOptions = {
291
298
  after_created_at: string;
@@ -1,6 +1,6 @@
1
1
  import { createEventRef, } from "@tutti/shared/ids";
2
2
  import { createMainChatSystemMessage, } from "../collaboration-state/index.js";
3
- import { EXECUTION_STATUS_INVALIDATES, clarificationInvalidates, procedureFailureInvalidates, taskRunInvalidates, } from "./invalidations.js";
3
+ import { EXECUTION_STATUS_INVALIDATES, clarificationInvalidates, procedureFailureInvalidates, taskRunResultInvalidates, taskRunInvalidates, } from "./invalidations.js";
4
4
  import { defaultProcedureFailureSystemMessage } from "./formatters.js";
5
5
  function activityEventKind(activity, transitionKind) {
6
6
  if (transitionKind === "progress") {
@@ -37,7 +37,7 @@ export function publishTaskRunStarted(events, task, activityRef) {
37
37
  }
38
38
  export function publishRunResultRecorded(events, recorded) {
39
39
  const taskId = recorded.task.id;
40
- const invalidates = taskRunInvalidates(taskId);
40
+ const invalidates = taskRunResultInvalidates(taskId, recorded.task_detail.detail.result);
41
41
  if ("card_message" in recorded) {
42
42
  const threadId = recorded.thread.id;
43
43
  const roundId = recorded.round.id;
@@ -1,5 +1,5 @@
1
1
  import type { ClarificationRoundRef, TaskId } from "@tutti/shared/ids";
2
- import type { QueryInvalidationHint } from "@tutti/shared/schemas/api";
2
+ import type { QueryInvalidationHint, TaskDetailResultProjection } from "@tutti/shared/schemas/api";
3
3
  export declare const EXECUTION_STATUS_INVALIDATES: QueryInvalidationHint[];
4
4
  export declare const STARTUP_RECOVERY_INVALIDATES: QueryInvalidationHint[];
5
5
  export declare function mainChatInvalidates(): QueryInvalidationHint[];
@@ -8,5 +8,6 @@ export declare function taskCompileInvalidates(): QueryInvalidationHint[];
8
8
  export declare function projectContextBootstrapInvalidates(): QueryInvalidationHint[];
9
9
  export declare function clarificationInvalidates(roundId: ClarificationRoundRef, threadId?: string): QueryInvalidationHint[];
10
10
  export declare function taskRunInvalidates(taskId: TaskId): QueryInvalidationHint[];
11
+ export declare function taskRunResultInvalidates(taskId: TaskId, result: TaskDetailResultProjection | undefined): QueryInvalidationHint[];
11
12
  export declare function procedureFailureInvalidates(): QueryInvalidationHint[];
12
13
  //# sourceMappingURL=invalidations.d.ts.map
@@ -1,3 +1,4 @@
1
+ const REFERENCE_DIRECTORY_PATH = "docs/reference";
1
2
  export const EXECUTION_STATUS_INVALIDATES = [
2
3
  { kind: "execution_status" },
3
4
  { kind: "bootstrap" },
@@ -57,6 +58,30 @@ export function taskRunInvalidates(taskId) {
57
58
  { kind: "bootstrap" },
58
59
  ];
59
60
  }
61
+ function pathTouchesReferenceFiles(path) {
62
+ return path === REFERENCE_DIRECTORY_PATH || path.startsWith(`${REFERENCE_DIRECTORY_PATH}/`);
63
+ }
64
+ function hasArtifactRelevantPromotedChange(paths) {
65
+ // The active artifact root can only be resolved from committed repo state.
66
+ // At this event-publishing layer, conservatively refresh Artifacts for any
67
+ // promoted repo change.
68
+ return paths.length > 0;
69
+ }
70
+ export function taskRunResultInvalidates(taskId, result) {
71
+ const invalidates = taskRunInvalidates(taskId);
72
+ if (result?.promotion?.status !== "promoted" ||
73
+ result.changed_paths === undefined ||
74
+ result.changed_paths.length === 0) {
75
+ return invalidates;
76
+ }
77
+ if (result.changed_paths.some(pathTouchesReferenceFiles)) {
78
+ invalidates.push({ kind: "viewer", path: REFERENCE_DIRECTORY_PATH });
79
+ }
80
+ if (hasArtifactRelevantPromotedChange(result.changed_paths)) {
81
+ invalidates.push({ kind: "artifacts" });
82
+ }
83
+ return invalidates;
84
+ }
60
85
  export function procedureFailureInvalidates() {
61
86
  return [
62
87
  { kind: "messages", scope: "main_chat" },
@@ -1,6 +1,7 @@
1
1
  import { createWorkflowInvocationRef, type ActivityRef } from "@tutti/shared/ids";
2
2
  import type { RefreshScratchpadDisposition, RefreshScratchpadResult, ProcedureLane } from "@tutti/shared/schemas/api";
3
3
  import type { ScratchpadSourceCursorUpdate } from "../collaboration-state/scratchpad-source-state.js";
4
+ import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
4
5
  import type { ProcedureEngine, ProcedureEngineState } from "../procedure-engine/index.js";
5
6
  import type { HostProjectStore } from "../store/index.js";
6
7
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
@@ -12,6 +13,7 @@ type ScratchpadProjectContext = {
12
13
  export type ScratchpadSourceBatch = {
13
14
  workflow_input: Parameters<ProcedureWorkflowRunner["runScratchpadRefresh"]>[0];
14
15
  cursor_update: ScratchpadSourceCursorUpdate;
16
+ source_refs: ScratchpadSourceRefInput[];
15
17
  source_message_count: number;
16
18
  };
17
19
  export declare function readControlPlaneScratchpadSourceBatch(store: HostProjectStore, options?: {
@@ -96,6 +96,10 @@ export function readControlPlaneScratchpadSourceBatch(store, options = {}) {
96
96
  ...newMainChatSourceMessages,
97
97
  ...clarificationSourceMessages,
98
98
  ]);
99
+ const sourceRefMessages = sortScratchpadSourceMessages([
100
+ ...(isInitialMainChatRefresh ? recentMessages : []),
101
+ ...sourceMessages,
102
+ ]);
99
103
  const latestMainChatSource = mainChatSourceMessages.at(-1);
100
104
  const latestClarificationRound = clarificationRounds.at(-1);
101
105
  const cursorUpdate = {};
@@ -124,6 +128,11 @@ export function readControlPlaneScratchpadSourceBatch(store, options = {}) {
124
128
  new_messages: compactScratchpadSourceMessages(sourceMessages),
125
129
  },
126
130
  cursor_update: cursorUpdate,
131
+ source_refs: sourceRefMessages.map((message) => ({
132
+ message_id: message.id,
133
+ source_scope: message.scope.kind,
134
+ created_at: message.created_at,
135
+ })),
127
136
  source_message_count: sourceMessages.length + (isInitialMainChatRefresh ? recentMessages.length : 0),
128
137
  };
129
138
  }
@@ -153,6 +162,7 @@ export async function runControlPlaneScratchpadRefreshProcedure(options) {
153
162
  workflowRef: options.workflowRef,
154
163
  activityRef: options.activityRef,
155
164
  cursorUpdate: options.sourceBatch.cursor_update,
165
+ sourceRefs: options.sourceBatch.source_refs,
156
166
  now: options.now,
157
167
  });
158
168
  }
@@ -1,5 +1,6 @@
1
1
  import type { ActivityRef, WorkflowInvocationRef } from "@tutti/shared/ids";
2
2
  import type { ScratchpadSourceCursorUpdate } from "../collaboration-state/scratchpad-source-state.js";
3
+ import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
3
4
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
4
5
  import type { HostProjectStore } from "../store/index.js";
5
6
  import type { ScratchpadRefreshWorkflowOutput } from "./workflows/index.js";
@@ -10,6 +11,7 @@ export declare function applyScratchpadRefreshOutput(input: {
10
11
  workflowRef: WorkflowInvocationRef;
11
12
  activityRef: ActivityRef;
12
13
  cursorUpdate: ScratchpadSourceCursorUpdate;
14
+ sourceRefs: ScratchpadSourceRefInput[];
13
15
  now: () => Date;
14
16
  }): {
15
17
  kind: "needs_human";
@@ -31,6 +31,7 @@ export function applyScratchpadRefreshOutput(input) {
31
31
  current_consensus: input.output.scratchpad_snapshot.current_consensus,
32
32
  open_questions: input.output.scratchpad_snapshot.open_questions,
33
33
  task_changes: input.output.scratchpad_snapshot.task_changes,
34
+ source_refs: input.sourceRefs,
34
35
  updated_by_activity_ref: input.activityRef,
35
36
  now: input.now,
36
37
  });
@@ -1,10 +1,24 @@
1
1
  import { type ActivityRef, type EventRef, type TaskId, type WorkflowInvocationRef } from "@tutti/shared/ids";
2
- import type { ProjectTimelineItem } from "@tutti/shared/schemas/api";
3
2
  import type { SqliteDatabase } from "../store/index.js";
4
3
  export type ProjectTimelineEventKind = "context_sync" | "reference_summary" | "promotion_reconcile";
4
+ export type ProjectTimelineEventStatus = "completed" | "failed";
5
+ export type ProjectTimelineEventItem = {
6
+ id: string;
7
+ kind: "procedure" | "promotion";
8
+ occurred_at: string;
9
+ title: string;
10
+ status: ProjectTimelineEventStatus;
11
+ summary?: string;
12
+ activity_ref?: ActivityRef;
13
+ workflow_ref?: WorkflowInvocationRef;
14
+ task_id?: TaskId;
15
+ commit_oid?: string;
16
+ commit_short_oid?: string;
17
+ meta?: string[];
18
+ };
5
19
  export type ProjectTimelineEventInput = {
6
20
  event_kind: ProjectTimelineEventKind;
7
- status: NonNullable<ProjectTimelineItem["status"]>;
21
+ status: ProjectTimelineEventStatus;
8
22
  summary?: string;
9
23
  activity_ref?: ActivityRef;
10
24
  workflow_ref?: WorkflowInvocationRef;
@@ -16,5 +30,5 @@ export type ProjectTimelineEventInput = {
16
30
  export declare function recordProjectTimelineEvent(db: SqliteDatabase, input: ProjectTimelineEventInput): EventRef;
17
31
  export declare function readProjectTimelineEventItems(db: SqliteDatabase, options?: {
18
32
  limit?: number;
19
- }): ProjectTimelineItem[];
33
+ }): ProjectTimelineEventItem[];
20
34
  //# sourceMappingURL=index.d.ts.map
@@ -8,6 +8,7 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
8
8
  anchor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"latest">, import("@sinclair/typebox").TLiteral<"start">]>>;
9
9
  before: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
10
  after: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
11
+ around: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
11
12
  }>;
12
13
  responses: {
13
14
  200: {
@@ -67,7 +67,7 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
67
67
  }>;
68
68
  items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
69
69
  id: import("@sinclair/typebox").TString;
70
- kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"run">, import("@sinclair/typebox").TLiteral<"procedure">, import("@sinclair/typebox").TLiteral<"commit">, import("@sinclair/typebox").TLiteral<"usage">, import("@sinclair/typebox").TLiteral<"clarification">, import("@sinclair/typebox").TLiteral<"checks">, import("@sinclair/typebox").TLiteral<"promotion">, import("@sinclair/typebox").TLiteral<"recovery">]>;
70
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"task_accepted">, import("@sinclair/typebox").TLiteral<"task_update">, import("@sinclair/typebox").TLiteral<"checkpoint">]>;
71
71
  occurred_at: import("@sinclair/typebox").TString;
72
72
  title: import("@sinclair/typebox").TString;
73
73
  summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -75,9 +75,10 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
75
75
  task_title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
76
76
  activity_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
77
77
  workflow_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
78
- commit_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
79
- commit_short_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
80
- status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"running">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"needs_human">, import("@sinclair/typebox").TLiteral<"skipped">]>>;
78
+ run_result_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
79
+ message_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
80
+ status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"needs_human">]>>;
81
+ update_state: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"needs_input">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"failed">]>>;
81
82
  token_usage: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
82
83
  input_tokens: import("@sinclair/typebox").TInteger;
83
84
  cached_input_tokens: import("@sinclair/typebox").TInteger;
@@ -106,7 +107,95 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
106
107
  total_tokens: import("@sinclair/typebox").TInteger;
107
108
  event_count: import("@sinclair/typebox").TInteger;
108
109
  }>>>;
109
- meta: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
110
+ trace_card: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
111
+ tone: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"neutral">, import("@sinclair/typebox").TLiteral<"success">, import("@sinclair/typebox").TLiteral<"warning">, import("@sinclair/typebox").TLiteral<"error">]>;
112
+ summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
113
+ origin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
114
+ title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
115
+ summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
116
+ snippets: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
117
+ message_id: import("@sinclair/typebox").TString;
118
+ author: import("@sinclair/typebox").TString;
119
+ body: import("@sinclair/typebox").TString;
120
+ created_at: import("@sinclair/typebox").TString;
121
+ }>>>;
122
+ source_count: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
123
+ unavailable_reason: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
124
+ }>>;
125
+ decisions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
126
+ title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
127
+ summary: import("@sinclair/typebox").TString;
128
+ source: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"scratchpad">, import("@sinclair/typebox").TLiteral<"clarification">, import("@sinclair/typebox").TLiteral<"contract">]>>;
129
+ }>>>;
130
+ clarification: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
131
+ title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
132
+ summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
133
+ request: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
134
+ status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"resolved">]>>;
135
+ answer_count: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
136
+ answers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
137
+ message_id: import("@sinclair/typebox").TString;
138
+ author: import("@sinclair/typebox").TString;
139
+ body: import("@sinclair/typebox").TString;
140
+ created_at: import("@sinclair/typebox").TString;
141
+ }>>>;
142
+ }>>;
143
+ contract: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
144
+ goal: import("@sinclair/typebox").TString;
145
+ scope: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
146
+ truncated: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
147
+ }>>;
148
+ result: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
149
+ summary: import("@sinclair/typebox").TString;
150
+ error_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
151
+ }>>;
152
+ changes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
153
+ items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
154
+ status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"added">, import("@sinclair/typebox").TLiteral<"modified">, import("@sinclair/typebox").TLiteral<"deleted">, import("@sinclair/typebox").TLiteral<"renamed">, import("@sinclair/typebox").TLiteral<"unknown">]>;
155
+ path: import("@sinclair/typebox").TString;
156
+ previous_path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
157
+ }>>;
158
+ total_count: import("@sinclair/typebox").TInteger;
159
+ truncated: import("@sinclair/typebox").TBoolean;
160
+ }>>;
161
+ verification: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
162
+ checks: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"passed">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"skipped">]>;
163
+ skip_reason_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
164
+ skip_reason_summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
165
+ }>>;
166
+ promotion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
167
+ status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"promoted">, import("@sinclair/typebox").TLiteral<"not_promoted">, import("@sinclair/typebox").TLiteral<"not_attempted">]>;
168
+ commit_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
169
+ commit_short_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
170
+ summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
171
+ reason_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
172
+ }>>;
173
+ checkpoint: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
174
+ counters: import("@sinclair/typebox").TObject<{
175
+ completed: import("@sinclair/typebox").TInteger;
176
+ failed: import("@sinclair/typebox").TInteger;
177
+ remaining: import("@sinclair/typebox").TInteger;
178
+ }>;
179
+ items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
180
+ task_id: import("@sinclair/typebox").TString;
181
+ title: import("@sinclair/typebox").TString;
182
+ status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"done">, import("@sinclair/typebox").TLiteral<"failed">]>;
183
+ summary: import("@sinclair/typebox").TString;
184
+ }>>;
185
+ generated_files: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
186
+ path: import("@sinclair/typebox").TString;
187
+ name: import("@sinclair/typebox").TString;
188
+ }>>>;
189
+ truncated: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
190
+ }>>;
191
+ links: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
192
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"worklist_task">, import("@sinclair/typebox").TLiteral<"chat_message">, import("@sinclair/typebox").TLiteral<"reference_file">, import("@sinclair/typebox").TLiteral<"repo_path">]>;
193
+ label: import("@sinclair/typebox").TString;
194
+ task_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
195
+ message_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
196
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
197
+ }>>;
198
+ }>>;
110
199
  }>>;
111
200
  }>;
112
201
  };