@xfey/tutti 0.1.60 → 0.1.62

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 (90) hide show
  1. package/README.md +2 -2
  2. package/dist/collaboration-state/clarification-records.d.ts +0 -9
  3. package/dist/collaboration-state/clarification-records.js +0 -57
  4. package/dist/collaboration-state/index.d.ts +6 -5
  5. package/dist/collaboration-state/index.js +5 -4
  6. package/dist/collaboration-state/messages.d.ts +4 -6
  7. package/dist/collaboration-state/messages.js +22 -29
  8. package/dist/collaboration-state/scratchpad-source-state.d.ts +4 -12
  9. package/dist/collaboration-state/scratchpad-source-state.js +24 -58
  10. package/dist/collaboration-state/scratchpad.d.ts +1 -2
  11. package/dist/collaboration-state/scratchpad.js +0 -59
  12. package/dist/collaboration-state/storage-types.d.ts +25 -5
  13. package/dist/collaboration-state/task-compile-context.d.ts +40 -0
  14. package/dist/collaboration-state/task-compile-context.js +273 -0
  15. package/dist/collaboration-state/types.d.ts +39 -9
  16. package/dist/control-plane/clarification-commands.d.ts +0 -1
  17. package/dist/control-plane/clarification-commands.js +0 -1
  18. package/dist/control-plane/index.js +16 -3
  19. package/dist/control-plane/project-context-bootstrap.d.ts +4 -4
  20. package/dist/control-plane/project-context-bootstrap.js +7 -12
  21. package/dist/control-plane/scratchpad-auto-refresh.js +12 -1
  22. package/dist/control-plane/scratchpad-refresh-start.js +77 -94
  23. package/dist/control-plane/scratchpad-refresh.js +3 -1
  24. package/dist/control-plane/scratchpad-source-messages.d.ts +15 -7
  25. package/dist/control-plane/scratchpad-source-messages.js +53 -69
  26. package/dist/control-plane/task-compile-clarification-context.d.ts +9 -0
  27. package/dist/control-plane/task-compile-clarification-context.js +70 -0
  28. package/dist/control-plane/task-compile-continuation.js +28 -56
  29. package/dist/control-plane/task-compile-output.js +50 -14
  30. package/dist/control-plane/task-compile-start.js +119 -55
  31. package/dist/control-plane/workflows/openai.d.ts +2 -1
  32. package/dist/control-plane/workflows/openai.js +13 -27
  33. package/dist/control-plane/workflows/types.d.ts +27 -17
  34. package/dist/server-shell/cli/args.d.ts +4 -0
  35. package/dist/server-shell/cli/args.js +11 -0
  36. package/dist/server-shell/cli/cli.js +35 -11
  37. package/dist/server-shell/cli/host-server-runtime.d.ts +2 -0
  38. package/dist/server-shell/cli/host-server-runtime.js +12 -5
  39. package/dist/server-shell/cli/local-control-client.d.ts +5 -1
  40. package/dist/server-shell/cli/local-control-client.js +19 -0
  41. package/dist/server-shell/desktop-integration/manager.d.ts +2 -0
  42. package/dist/server-shell/desktop-integration/manager.js +19 -31
  43. package/dist/server-shell/http/routes/local-control.d.ts +2 -0
  44. package/dist/server-shell/http/routes/local-control.js +24 -0
  45. package/dist/server-shell/local-console/invocation-context.js +10 -1
  46. package/dist/server-shell/local-console/operation-coordinator.d.ts +16 -0
  47. package/dist/server-shell/local-console/operation-coordinator.js +50 -0
  48. package/dist/server-shell/local-console/package-update-completion.d.ts +25 -0
  49. package/dist/server-shell/local-console/package-update-completion.js +91 -0
  50. package/dist/server-shell/local-console/package-update-hosts.d.ts +17 -0
  51. package/dist/server-shell/local-console/package-update-hosts.js +92 -0
  52. package/dist/server-shell/local-console/package-update-lock.d.ts +46 -0
  53. package/dist/server-shell/local-console/package-update-lock.js +223 -0
  54. package/dist/server-shell/local-console/package-update-log.d.ts +20 -0
  55. package/dist/server-shell/local-console/package-update-log.js +75 -0
  56. package/dist/server-shell/local-console/package-update-process.d.ts +22 -0
  57. package/dist/server-shell/local-console/package-update-process.js +252 -0
  58. package/dist/server-shell/local-console/package-update-record.d.ts +53 -0
  59. package/dist/server-shell/local-console/package-update-record.js +180 -0
  60. package/dist/server-shell/local-console/package-update-recovery.d.ts +34 -0
  61. package/dist/server-shell/local-console/package-update-recovery.js +140 -0
  62. package/dist/server-shell/local-console/package-update-service.d.ts +72 -0
  63. package/dist/server-shell/local-console/package-update-service.js +400 -0
  64. package/dist/server-shell/local-console/package-update-worker.d.ts +55 -0
  65. package/dist/server-shell/local-console/package-update-worker.js +297 -0
  66. package/dist/server-shell/local-console/project-service.d.ts +2 -0
  67. package/dist/server-shell/local-console/project-service.js +16 -12
  68. package/dist/server-shell/local-console/server.d.ts +9 -0
  69. package/dist/server-shell/local-console/server.js +92 -4
  70. package/dist/server-shell/package-installation/command.d.ts +36 -0
  71. package/dist/server-shell/package-installation/command.js +162 -0
  72. package/dist/server-shell/package-installation/discovery.d.ts +51 -0
  73. package/dist/server-shell/package-installation/discovery.js +137 -0
  74. package/dist/server-shell/package-installation/index.d.ts +5 -0
  75. package/dist/server-shell/package-installation/index.js +5 -0
  76. package/dist/server-shell/package-installation/installation.d.ts +34 -0
  77. package/dist/server-shell/package-installation/installation.js +123 -0
  78. package/dist/server-shell/package-installation/semver.d.ts +9 -0
  79. package/dist/server-shell/package-installation/semver.js +84 -0
  80. package/migrations/0014_scratchpad_task_compile_context.sql +147 -0
  81. package/migrations/README.md +2 -1
  82. package/package.json +1 -1
  83. package/prompts/procedures/README.md +3 -3
  84. package/prompts/procedures/scratchpad-refresh.md +17 -9
  85. package/prompts/procedures/task-compile.md +6 -3
  86. package/prompts/prompt-flow-map.md +21 -14
  87. package/web/assets/{homepage-motion-scene-CY7o4hnR.js → homepage-motion-scene-CRmrkkEH.js} +1 -1
  88. package/web/assets/{index-B08r3x8o.js → index-C9JrplHV.js} +14 -14
  89. package/web/assets/{index-DpabiRgp.css → index-IZKcmU_g.css} +1 -1
  90. package/web/index.html +2 -2
@@ -1,4 +1,5 @@
1
- import { applyTaskCompileProposal, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, readWorklistProjection, submitScratchpadProjection, } from "../collaboration-state/index.js";
1
+ import { applyTaskCompileProposal, completeTaskCompileContext, materializeClarificationSuccessor, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, readClarificationRoundProjection, readWorklistProjection, } from "../collaboration-state/index.js";
2
+ import { withHostStoreTransaction } from "../store/index.js";
2
3
  import { clarificationInvalidates, taskCompileInvalidates, } from "./invalidations.js";
3
4
  import { normalizeTaskCompileProposal } from "./task-proposal.js";
4
5
  const EMPTY_INITIAL_WORKLIST_CLARIFICATION = {
@@ -72,25 +73,45 @@ export function applyTaskCompileProcedureOutput(input) {
72
73
  }
73
74
  const currentWorklist = readWorklistProjection(input.store.db);
74
75
  const proposal = normalizeTaskCompileProposal(input.output.proposal);
75
- if (proposal.tasks.length === 0 && countWorklistTasks(currentWorklist) === 0) {
76
+ if (input.continueFromRoundId === undefined &&
77
+ proposal.tasks.length === 0 &&
78
+ countWorklistTasks(currentWorklist) === 0) {
76
79
  return openTaskCompileNeedsHuman({
77
80
  ...input,
78
81
  requestPayload: EMPTY_INITIAL_WORKLIST_CLARIFICATION,
79
82
  });
80
83
  }
81
- const applied = applyTaskCompileProposal(input.store.db, {
82
- workflow_ref: input.workflowRef,
83
- proposal,
84
- now: input.now,
84
+ const continuationRound = input.continueFromRoundId === undefined
85
+ ? null
86
+ : readClarificationRoundProjection(input.store.db, input.continueFromRoundId);
87
+ const committed = withHostStoreTransaction(input.store.db, (tx) => {
88
+ const applied = applyTaskCompileProposal(tx, {
89
+ workflow_ref: input.workflowRef,
90
+ proposal,
91
+ now: input.now,
92
+ });
93
+ const scratchpad = completeTaskCompileContext(tx, {
94
+ workflow_ref: input.workflowRef,
95
+ activity_ref: input.activityRef,
96
+ now: input.now,
97
+ });
98
+ if (input.continueFromRoundId !== undefined) {
99
+ materializeClarificationSuccessor(tx, {
100
+ round_id: input.continueFromRoundId,
101
+ successor_ref: {
102
+ kind: "proposal_applied",
103
+ workflow_ref: input.workflowRef,
104
+ },
105
+ close_thread: true,
106
+ now: input.now,
107
+ });
108
+ }
109
+ return { applied, scratchpad };
85
110
  });
111
+ const { applied } = committed;
86
112
  if (applied.changed_task_ids.length > 0) {
87
113
  input.onTasksAdded?.();
88
114
  }
89
- const submittedScratchpad = submitScratchpadProjection(input.store.db, {
90
- workflow_ref: input.workflowRef,
91
- activity_ref: input.activityRef,
92
- now: input.now,
93
- });
94
115
  input.events.publish({
95
116
  event_type: "worklist.changed",
96
117
  payload: {
@@ -105,21 +126,36 @@ export function applyTaskCompileProcedureOutput(input) {
105
126
  input.events.publish({
106
127
  event_type: "scratchpad.updated",
107
128
  payload: {
108
- scratchpad: submittedScratchpad,
129
+ scratchpad: committed.scratchpad,
109
130
  activity_ref: input.activityRef,
110
131
  },
111
132
  invalidates: taskCompileInvalidates(),
112
133
  });
134
+ if (input.continueFromRoundId !== undefined && continuationRound !== null) {
135
+ input.events.publish({
136
+ event_type: "clarification.changed",
137
+ payload: {
138
+ reason: "successor_materialized",
139
+ thread_id: continuationRound.thread_id,
140
+ round_id: input.continueFromRoundId,
141
+ successor_ref: {
142
+ kind: "proposal_applied",
143
+ workflow_ref: input.workflowRef,
144
+ },
145
+ },
146
+ invalidates: clarificationInvalidates(input.continueFromRoundId, continuationRound.thread_id),
147
+ });
148
+ }
113
149
  if (input.continueFromRoundId !== undefined) {
114
150
  return {
115
151
  kind: "completed",
116
- summary: "Worklist compiled.",
152
+ summary: proposal.tasks.length === 0 ? "No new task created." : "Worklist compiled.",
117
153
  result_anchor: { kind: "workflow", workflow_ref: input.workflowRef },
118
154
  };
119
155
  }
120
156
  return {
121
157
  kind: "completed",
122
- summary: "Worklist compiled.",
158
+ summary: proposal.tasks.length === 0 ? "No new task created." : "Worklist compiled.",
123
159
  result_anchor: { kind: "workflow", workflow_ref: input.workflowRef },
124
160
  };
125
161
  }
@@ -1,5 +1,5 @@
1
1
  import { createWorkflowInvocationRef, } from "@tutti/shared/ids";
2
- import { readScratchpadProjection, readWorklistProjection } from "../collaboration-state/index.js";
2
+ import { captureTaskCompileContext, readActiveTaskCompileContext, readScratchpadProjection, readWorklistProjection, rollbackTaskCompileContext, } from "../collaboration-state/index.js";
3
3
  import { initializeProjectDocs, readProjectDocsInitializationStatus, } from "../workspace-ops/index.js";
4
4
  import { logProcedureExecutionError } from "./procedure-logging.js";
5
5
  import { projectBriefShouldRefreshForUpdatedPaths, refreshProjectBriefProjection, } from "./project-brief-refresh.js";
@@ -7,6 +7,15 @@ import { applyProjectDocsInitializationResult, buildProjectDocsInitializationCon
7
7
  import { readActiveScratchpadRefreshActivityRef, readControlPlaneScratchpadSourceBatch, runControlPlaneScratchpadRefreshProcedure, } from "./scratchpad-refresh-start.js";
8
8
  import { applyTaskCompileProcedureOutput } from "./task-compile-output.js";
9
9
  export function startControlPlaneTaskCompile(options) {
10
+ const activeContext = readActiveTaskCompileContext(options.store.db);
11
+ if (activeContext !== null) {
12
+ return {
13
+ disposition: {
14
+ kind: "already_running",
15
+ activity_ref: activeContext.captured_by_activity_ref,
16
+ },
17
+ };
18
+ }
10
19
  const scratchpad = readScratchpadProjection(options.store.db);
11
20
  if (options.payload.expected_scratchpad_updated_at !== undefined &&
12
21
  options.payload.expected_scratchpad_updated_at !== scratchpad.updated_at) {
@@ -31,6 +40,7 @@ export function startControlPlaneTaskCompile(options) {
31
40
  },
32
41
  };
33
42
  }
43
+ const taskCompileWorkflowRef = createWorkflowInvocationRef();
34
44
  const sourceBatch = readControlPlaneScratchpadSourceBatch(options.store);
35
45
  if (sourceBatch.source_message_count > 0) {
36
46
  const activeScratchpadRefresh = readActiveScratchpadRefreshActivityRef({
@@ -49,6 +59,7 @@ export function startControlPlaneTaskCompile(options) {
49
59
  ...options,
50
60
  runner: runnerResolution.runner,
51
61
  sourceBatch,
62
+ taskCompileWorkflowRef,
52
63
  });
53
64
  }
54
65
  if (!scratchpadHasSubmittableContent(scratchpad)) {
@@ -58,19 +69,23 @@ export function startControlPlaneTaskCompile(options) {
58
69
  return startProjectContextBootstrapActivity({
59
70
  ...options,
60
71
  runner: runnerResolution.runner,
72
+ taskCompileWorkflowRef,
61
73
  });
62
74
  }
63
75
  return startControlPlaneTaskCompileActivity({
64
76
  ...options,
65
77
  runner: runnerResolution.runner,
78
+ taskCompileWorkflowRef,
66
79
  });
67
80
  }
68
81
  function startControlPlaneTaskCompileActivity(options) {
82
+ const activeContext = readActiveTaskCompileContext(options.store.db, options.taskCompileWorkflowRef);
69
83
  const scratchpad = readScratchpadProjection(options.store.db);
70
- if (!scratchpadHasSubmittableContent(scratchpad)) {
84
+ if (activeContext === null &&
85
+ !scratchpadHasSubmittableContent(scratchpad)) {
71
86
  return { disposition: { kind: "scratchpad_empty" } };
72
87
  }
73
- const workflowRef = createWorkflowInvocationRef();
88
+ const workflowRef = options.taskCompileWorkflowRef;
74
89
  const start = options.engine.startProcedure({
75
90
  workflow_ref: workflowRef,
76
91
  workflow_kind: "task_compile",
@@ -201,8 +216,7 @@ function startProjectContextBootstrapActivity(options) {
201
216
  if (shouldInitializeControlPlaneProjectContext(options)) {
202
217
  return;
203
218
  }
204
- const scratchpad = readScratchpadProjection(options.store.db);
205
- if (!scratchpadHasSubmittableContent(scratchpad)) {
219
+ if (readActiveTaskCompileContext(options.store.db, options.taskCompileWorkflowRef) === null) {
206
220
  return;
207
221
  }
208
222
  void startControlPlaneTaskCompileActivity(options);
@@ -221,44 +235,59 @@ function startProjectContextBootstrapActivity(options) {
221
235
  summary: "Project context is unavailable.",
222
236
  };
223
237
  }
224
- const initializationContext = buildProjectDocsInitializationContext(readScratchpadProjection(options.store.db));
225
- const modelDocuments = await tryProjectContextBootstrapDocuments({
226
- runner: options.runner,
227
- projectContext: options.projectContext,
228
- scratchpad: readScratchpadProjection(options.store.db),
229
- projectName: options.projectContext.projectName,
230
- workflowRef,
238
+ const taskCompileContext = readOrCaptureTaskCompileContext({
239
+ store: options.store,
240
+ workflowRef: options.taskCompileWorkflowRef,
231
241
  activityRef: context.activity_ref,
232
- logger: options.logger,
233
- reportProgress: context.reportProgress,
234
- now: options.now,
235
- });
236
- const initialized = initializeProjectDocs({
237
- workspaceRoot: options.projectContext.workspaceRoot,
238
- projectName: options.projectContext.projectName,
239
- context: initializationContext,
240
- ...(modelDocuments === undefined ? {} : { documents: modelDocuments }),
241
242
  now: options.now,
242
243
  });
243
- if (projectBriefShouldRefreshForUpdatedPaths(initialized.created_paths)) {
244
- await refreshProjectBriefProjection({
245
- store: options.store,
246
- projectContext: options.projectContext,
247
- reason: "project_context_bootstrap",
244
+ try {
245
+ const initializationContext = buildProjectDocsInitializationContext(taskCompileContext.scratchpad_snapshot);
246
+ const modelDocuments = await tryProjectContextBootstrapDocuments({
248
247
  runner: options.runner,
248
+ projectContext: options.projectContext,
249
+ scratchpad: taskCompileContext.scratchpad_snapshot,
250
+ projectName: options.projectContext.projectName,
249
251
  workflowRef,
250
252
  activityRef: context.activity_ref,
251
253
  logger: options.logger,
254
+ reportProgress: context.reportProgress,
255
+ now: options.now,
256
+ });
257
+ const initialized = initializeProjectDocs({
258
+ workspaceRoot: options.projectContext.workspaceRoot,
259
+ projectName: options.projectContext.projectName,
260
+ context: initializationContext,
261
+ ...(modelDocuments === undefined ? {} : { documents: modelDocuments }),
262
+ now: options.now,
263
+ });
264
+ if (projectBriefShouldRefreshForUpdatedPaths(initialized.created_paths)) {
265
+ await refreshProjectBriefProjection({
266
+ store: options.store,
267
+ projectContext: options.projectContext,
268
+ reason: "project_context_bootstrap",
269
+ runner: options.runner,
270
+ workflowRef,
271
+ activityRef: context.activity_ref,
272
+ logger: options.logger,
273
+ now: options.now,
274
+ });
275
+ }
276
+ return applyProjectDocsInitializationResult({
277
+ events: options.events,
278
+ logger: options.logger,
279
+ result: initialized,
280
+ workflowRef,
281
+ activityRef: context.activity_ref,
282
+ });
283
+ }
284
+ catch (error) {
285
+ rollbackTaskCompileContext(options.store.db, {
286
+ workflow_ref: options.taskCompileWorkflowRef,
252
287
  now: options.now,
253
288
  });
289
+ throw error;
254
290
  }
255
- return applyProjectDocsInitializationResult({
256
- events: options.events,
257
- logger: options.logger,
258
- result: initialized,
259
- workflowRef,
260
- activityRef: context.activity_ref,
261
- });
262
291
  },
263
292
  });
264
293
  if (start.kind === "already_running") {
@@ -278,33 +307,59 @@ function startProjectContextBootstrapActivity(options) {
278
307
  };
279
308
  }
280
309
  export async function runControlPlaneTaskCompileProcedure(options) {
281
- const scratchpad = readScratchpadProjection(options.store.db);
282
- if (!scratchpadHasSubmittableContent(scratchpad)) {
283
- return {
284
- kind: "failed",
285
- summary: "Scratchpad is empty. Discuss more before running.",
286
- };
287
- }
288
- const output = await options.runner.runTaskCompile({
289
- workflow_ref: options.workflowRef,
290
- scratchpad,
291
- worklist: readWorklistProjection(options.store.db),
292
- }, {
293
- workflow_ref: options.workflowRef,
294
- activity_ref: options.activityRef,
295
- ...(options.reportProgress === undefined
296
- ? {}
297
- : { reportProgress: options.reportProgress }),
298
- });
299
- return applyTaskCompileProcedureOutput({
310
+ const context = readOrCaptureTaskCompileContext({
300
311
  store: options.store,
301
- events: options.events,
302
- output,
303
312
  workflowRef: options.workflowRef,
304
313
  activityRef: options.activityRef,
305
314
  now: options.now,
306
- onTasksAdded: options.onTasksAdded,
307
315
  });
316
+ if (!scratchpadSnapshotHasSubmittableContent(context.scratchpad_snapshot)) {
317
+ rollbackTaskCompileContext(options.store.db, {
318
+ workflow_ref: options.workflowRef,
319
+ now: options.now,
320
+ });
321
+ return {
322
+ kind: "failed",
323
+ summary: "Scratchpad is empty. Discuss more before running.",
324
+ };
325
+ }
326
+ try {
327
+ const output = await options.runner.runTaskCompile({
328
+ workflow_ref: options.workflowRef,
329
+ scratchpad: context.scratchpad_snapshot,
330
+ worklist: readWorklistProjection(options.store.db),
331
+ }, {
332
+ workflow_ref: options.workflowRef,
333
+ activity_ref: options.activityRef,
334
+ ...(options.reportProgress === undefined
335
+ ? {}
336
+ : { reportProgress: options.reportProgress }),
337
+ });
338
+ return applyTaskCompileProcedureOutput({
339
+ store: options.store,
340
+ events: options.events,
341
+ output,
342
+ workflowRef: options.workflowRef,
343
+ activityRef: options.activityRef,
344
+ now: options.now,
345
+ onTasksAdded: options.onTasksAdded,
346
+ });
347
+ }
348
+ catch (error) {
349
+ rollbackTaskCompileContext(options.store.db, {
350
+ workflow_ref: options.workflowRef,
351
+ now: options.now,
352
+ });
353
+ throw error;
354
+ }
355
+ }
356
+ function readOrCaptureTaskCompileContext(input) {
357
+ return (readActiveTaskCompileContext(input.store.db, input.workflowRef) ??
358
+ captureTaskCompileContext(input.store.db, {
359
+ workflow_ref: input.workflowRef,
360
+ captured_by_activity_ref: input.activityRef,
361
+ now: input.now,
362
+ }));
308
363
  }
309
364
  function scratchpadHasSubmittableContent(scratchpad) {
310
365
  if (scratchpad.state !== "ready") {
@@ -318,4 +373,13 @@ function scratchpadHasSubmittableContent(scratchpad) {
318
373
  ...scratchpad.task_changes,
319
374
  ].some((item) => item.trim().length > 0);
320
375
  }
376
+ function scratchpadSnapshotHasSubmittableContent(scratchpad) {
377
+ return [
378
+ scratchpad.topic,
379
+ scratchpad.background_summary,
380
+ ...scratchpad.current_consensus,
381
+ ...scratchpad.open_questions,
382
+ ...scratchpad.task_changes,
383
+ ].some((item) => item.trim().length > 0);
384
+ }
321
385
  //# sourceMappingURL=task-compile-start.js.map
@@ -2,7 +2,7 @@ import type { ProjectId } from "@tutti/shared/ids";
2
2
  import type { ProviderUsageRecorder } from "../../provider-usage/index.js";
3
3
  import { type OpenAiStructuredOutputClient } from "../../providers/openai/sdk-procedure-runner.js";
4
4
  import { type OpenAiProviderConfig } from "../../providers/openai/provider-config.js";
5
- import type { ProcedureWorkflowRunner, ProcedureWorkflowRunnerResolution } from "./types.js";
5
+ import type { ProcedureWorkflowRunner, ProcedureWorkflowRunnerResolution, TaskCompilePromptInput, TaskCompileWorkflowInput } from "./types.js";
6
6
  import type { CodexAppServerAgentContextRuntime } from "../../providers/openai/app-server/skills.js";
7
7
  export type OpenAiProcedureWorkflowRunnerOptions = {
8
8
  config: OpenAiProviderConfig;
@@ -30,6 +30,7 @@ export type ProjectOpenAiProcedureWorkflowRunnerOptions = {
30
30
  agentContext?: CodexAppServerAgentContextRuntime;
31
31
  recordUsage?: ProviderUsageRecorder;
32
32
  };
33
+ export declare function buildTaskCompilePromptInput(input: TaskCompileWorkflowInput): TaskCompilePromptInput;
33
34
  export declare function createOpenAiProcedureWorkflowRunner(options: OpenAiProcedureWorkflowRunnerOptions): ProcedureWorkflowRunner;
34
35
  export declare function resolveProjectOpenAiProcedureWorkflowRunner(options: ProjectOpenAiProcedureWorkflowRunnerOptions): ProcedureWorkflowRunnerResolution;
35
36
  //# sourceMappingURL=openai.d.ts.map
@@ -137,7 +137,7 @@ function followUpCheckWorkflowOutput(output) {
137
137
  summary: output.result.requires_retasking.summary,
138
138
  };
139
139
  }
140
- function taskCompilePromptInput(input) {
140
+ export function buildTaskCompilePromptInput(input) {
141
141
  const promptInput = {
142
142
  scratchpad: {
143
143
  topic: input.scratchpad.topic,
@@ -160,34 +160,20 @@ function taskCompilePromptInput(input) {
160
160
  })),
161
161
  },
162
162
  };
163
- if (input.clarification !== undefined) {
164
- const request = {
165
- ...(input.clarification.request_payload.title === undefined
166
- ? {}
167
- : { title: input.clarification.request_payload.title }),
168
- summary: input.clarification.request_payload.summary,
169
- request: input.clarification.request_payload.request,
170
- };
171
- promptInput.clarification = {
172
- request,
173
- answer_messages: input.clarification.messages
174
- .filter((message) => message.message_kind === "user_text" || message.message_kind === "agent_text")
175
- .map(taskCompileClarificationMessage),
176
- };
163
+ if (input.clarification_rounds !== undefined) {
164
+ promptInput.clarification_rounds = input.clarification_rounds.map((round) => ({
165
+ request: {
166
+ ...(round.request_payload.title === undefined
167
+ ? {}
168
+ : { title: round.request_payload.title }),
169
+ summary: round.request_payload.summary,
170
+ request: round.request_payload.request,
171
+ },
172
+ answer_messages: round.answer_messages,
173
+ }));
177
174
  }
178
175
  return promptInput;
179
176
  }
180
- function taskCompileClarificationMessage(message) {
181
- const role = message.author.kind === "agent" ? "tutti" : "human";
182
- const authorDisplayName = message.author.display_name?.trim();
183
- return {
184
- role,
185
- ...(role === "human" && authorDisplayName !== undefined && authorDisplayName !== ""
186
- ? { author_display_name: authorDisplayName }
187
- : {}),
188
- text: message.body.trim(),
189
- };
190
- }
191
177
  function taskCompileWorkflowOutput(output) {
192
178
  if ("clarification_request_payload" in output.result) {
193
179
  return {
@@ -280,7 +266,7 @@ export function createOpenAiProcedureWorkflowRunner(options) {
280
266
  templateKey: "procedures.task_compile",
281
267
  ...(options.promptsRoot === undefined ? {} : { promptsRoot: options.promptsRoot }),
282
268
  variables: {
283
- workflow_input_json: taskCompilePromptInput(input),
269
+ workflow_input_json: buildTaskCompilePromptInput(input),
284
270
  },
285
271
  });
286
272
  const result = await runCodexAppServerReadOnlyProcedure({
@@ -1,4 +1,4 @@
1
- import type { ExecutionRuntimeSnapshot, MessageProjection, RunResultProjection, ScratchpadProjection, TaskDetailProjection, WorklistProjection } from "@tutti/shared/schemas/api";
1
+ import type { ExecutionRuntimeSnapshot, MessageProjection, RunResultProjection, TaskDetailProjection, WorklistProjection } from "@tutti/shared/schemas/api";
2
2
  import type { ClarificationRequestPayload, TaskContractProjection } from "@tutti/shared/schemas/api";
3
3
  import type { ProjectDocKey } from "@tutti/shared/schemas/api";
4
4
  import type { ActivityRef, ClarificationRoundRef, ClarificationThreadRef, MessageId, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
@@ -6,21 +6,31 @@ import type { RunLineage } from "@tutti/shared/domain";
6
6
  import type { ProjectBriefSnapshot, ProjectBriefSourceDocument } from "../../project-brief/index.js";
7
7
  export type ScratchpadRefreshWorkflowInput = {
8
8
  project_brief?: ProjectBriefSnapshot;
9
- previous: {
10
- topic?: string;
11
- background?: string;
12
- consensus?: string[];
13
- questions?: string[];
14
- changes?: string[];
15
- };
16
- recent_messages: ScratchpadRefreshSourceMessageInput[];
17
- new_messages: ScratchpadRefreshSourceMessageInput[];
9
+ worklist: ScratchpadRefreshWorklistInput;
10
+ active_task_compile?: ScratchpadWorkflowSnapshot;
11
+ messages: ScratchpadRefreshSourceMessageInput[];
12
+ };
13
+ export type ScratchpadWorkflowSnapshot = {
14
+ topic: string;
15
+ background_summary: string;
16
+ current_consensus: string[];
17
+ open_questions: string[];
18
+ task_changes: string[];
19
+ };
20
+ export type ScratchpadRefreshWorklistInput = {
21
+ modules: Array<{
22
+ name: string;
23
+ tasks: Array<{
24
+ title: string;
25
+ summary?: string;
26
+ status: WorklistProjection["modules"][number]["tasks"][number]["status"];
27
+ }>;
28
+ }>;
18
29
  };
19
30
  export type ScratchpadRefreshSourceMessageInput = {
20
31
  role: "human" | "tutti";
21
32
  author_display_name?: string;
22
33
  text: string;
23
- ref?: string;
24
34
  };
25
35
  export type ScratchpadRefreshWorkflowContext = {
26
36
  workflow_ref: WorkflowInvocationRef;
@@ -68,12 +78,12 @@ export type TaskCompileProposalTask = {
68
78
  };
69
79
  export type TaskCompileWorkflowInput = {
70
80
  workflow_ref: WorkflowInvocationRef;
71
- scratchpad: ScratchpadProjection;
81
+ scratchpad: ScratchpadWorkflowSnapshot;
72
82
  worklist: WorklistProjection;
73
- clarification?: {
83
+ clarification_rounds?: Array<{
74
84
  request_payload: ClarificationRequestPayload;
75
- messages: MessageProjection[];
76
- };
85
+ answer_messages: TaskCompilePromptClarificationMessage[];
86
+ }>;
77
87
  };
78
88
  export type TaskCompileWorkflowOutput = {
79
89
  decision: "ready";
@@ -103,14 +113,14 @@ export type TaskCompilePromptInput = {
103
113
  }>;
104
114
  }>;
105
115
  };
106
- clarification?: {
116
+ clarification_rounds?: Array<{
107
117
  request: {
108
118
  title?: string;
109
119
  summary: string;
110
120
  request: string;
111
121
  };
112
122
  answer_messages: TaskCompilePromptClarificationMessage[];
113
- };
123
+ }>;
114
124
  };
115
125
  export type TaskCompilePromptClarificationMessage = {
116
126
  role: "human" | "tutti";
@@ -28,6 +28,10 @@ export type CliCommand = {
28
28
  } | {
29
29
  kind: "internal-desktop-open";
30
30
  url?: string;
31
+ } | {
32
+ kind: "internal-package-update-worker";
33
+ } | {
34
+ kind: "internal-package-update-complete";
31
35
  } | {
32
36
  kind: "ps";
33
37
  manage: boolean;
@@ -138,6 +138,17 @@ export function parseCliArgs(argv, cwd = process.cwd()) {
138
138
  }
139
139
  if (command === "internal") {
140
140
  const internalCommand = args.shift();
141
+ if (internalCommand === "package-update-worker" ||
142
+ internalCommand === "package-update-complete") {
143
+ if (args.length > 0) {
144
+ throw new LaunchError("git_bootstrap_failed", `Internal ${internalCommand} does not accept options`, "Internal commands are managed by Tutti.");
145
+ }
146
+ return {
147
+ kind: internalCommand === "package-update-worker"
148
+ ? "internal-package-update-worker"
149
+ : "internal-package-update-complete",
150
+ };
151
+ }
141
152
  if (internalCommand === "console-run") {
142
153
  if (args.length > 0) {
143
154
  throw new LaunchError("git_bootstrap_failed", "Internal console-run does not accept options", "Internal commands are managed by Tutti.");
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { dirname, resolve } from "node:path";
3
+ import { resolveTuttiHome } from "../../providers/openai/index.js";
3
4
  import { formatCliError, formatCliErrorReason, LaunchError } from "./errors.js";
4
5
  import { parseCliArgs, shouldEnsureDesktopIntegrationAutomatically } from "./args.js";
5
6
  import { confirmTextFromTty, runBackgroundLaunchCommand, runForegroundLaunchCommand, runInternalHostRunCommand, } from "./launch-command.js";
@@ -9,6 +10,8 @@ import { runArchiveCommand, runDoctorCommand, runForgetCommand, runInviteCommand
9
10
  import { readCliVersion } from "./version.js";
10
11
  import { ensureDesktopIntegrationAutomatically, parseTuttiDesktopUrl, runDesktopIntegrationCommand, TUTTI_DESKTOP_PROJECTS_URL, TuttiDesktopProtocolError, } from "../desktop-integration/index.js";
11
12
  import { ensureLocalConsole, openLocalConsoleBrowser, readLocalConsoleServiceStatus, restartLocalConsoleService, runLocalConsoleProcess, stopLocalConsoleService, } from "../local-console/index.js";
13
+ import { runPackageUpdateCompletionProtocol, runPackageUpdateWorkerProtocol, } from "../local-console/package-update-process.js";
14
+ import { recoverPackageUpdateForConsoleStartup } from "../local-console/package-update-recovery.js";
12
15
  const HELP_TEXT = `Usage:
13
16
  tutti
14
17
  tutti launch [target] [--yes] [--foreground]
@@ -209,13 +212,30 @@ function ensureDesktopIntegrationForConsole() {
209
212
  process.stderr.write("Tutti could not update its desktop entry. Run `tutti desktop` for details.\n");
210
213
  }
211
214
  }
215
+ async function ensureUserLocalConsole(options) {
216
+ const env = process.env;
217
+ const entrypointArgument = process.argv[1];
218
+ if (entrypointArgument !== undefined && entrypointArgument.trim() !== "") {
219
+ const recovery = await recoverPackageUpdateForConsoleStartup({
220
+ tuttiHome: resolveTuttiHome(env.TUTTI_HOME, options.cwd),
221
+ cliEntrypoint: resolve(entrypointArgument),
222
+ cwd: options.cwd,
223
+ env,
224
+ source: options.source,
225
+ });
226
+ if (recovery.status === "completed") {
227
+ return recovery.url;
228
+ }
229
+ }
230
+ return (await ensureLocalConsole({ cwd: options.cwd, env, source: options.source })).url;
231
+ }
212
232
  async function runLocalConsoleCommand() {
213
- const console = await ensureLocalConsole();
214
- if (openLocalConsoleBrowser(console.url)) {
215
- process.stdout.write(`Tutti is ready at ${console.endpoint.base_url}/console\n`);
233
+ const url = await ensureUserLocalConsole({ cwd: process.cwd(), source: "terminal" });
234
+ if (openLocalConsoleBrowser(url)) {
235
+ process.stdout.write(`Tutti is ready at ${new URL(url).origin}/console\n`);
216
236
  return;
217
237
  }
218
- process.stdout.write(["Open Tutti in a browser:", console.url, ""].join("\n"));
238
+ process.stdout.write(["Open Tutti in a browser:", url, ""].join("\n"));
219
239
  }
220
240
  function desktopResultMessage(result) {
221
241
  if (result.status === "installed") {
@@ -239,9 +259,9 @@ function runDesktopCommand(action) {
239
259
  return desktopResultMessage(runDesktopIntegrationCommand(action));
240
260
  }
241
261
  async function runDesktopOpenCommand(value) {
242
- const url = value ?? TUTTI_DESKTOP_PROJECTS_URL;
262
+ const desktopUrl = value ?? TUTTI_DESKTOP_PROJECTS_URL;
243
263
  try {
244
- parseTuttiDesktopUrl(url);
264
+ parseTuttiDesktopUrl(desktopUrl);
245
265
  }
246
266
  catch (error) {
247
267
  if (error instanceof TuttiDesktopProtocolError) {
@@ -250,11 +270,9 @@ async function runDesktopOpenCommand(value) {
250
270
  throw error;
251
271
  }
252
272
  const cliEntrypoint = process.argv[1];
253
- const console = await ensureLocalConsole({
254
- source: "desktop",
255
- ...(cliEntrypoint === undefined ? {} : { cwd: dirname(resolve(cliEntrypoint)) }),
256
- });
257
- if (!openLocalConsoleBrowser(console.url)) {
273
+ const cwd = cliEntrypoint === undefined ? process.cwd() : dirname(resolve(cliEntrypoint));
274
+ const url = await ensureUserLocalConsole({ source: "desktop", cwd });
275
+ if (!openLocalConsoleBrowser(url)) {
258
276
  throw new LaunchError("desktop_open_failed", "The Local Console started, but no desktop browser opener is available.", "Run `tutti` from a terminal to print a one-time browser URL.");
259
277
  }
260
278
  }
@@ -378,6 +396,12 @@ try {
378
396
  case "internal-desktop-open":
379
397
  await runDesktopOpenCommand(command.url);
380
398
  break;
399
+ case "internal-package-update-worker":
400
+ await runPackageUpdateWorkerProtocol();
401
+ break;
402
+ case "internal-package-update-complete":
403
+ await runPackageUpdateCompletionProtocol();
404
+ break;
381
405
  case "ps":
382
406
  if (command.manage) {
383
407
  await runPsManageCommand({ all: command.all });
@@ -1,4 +1,5 @@
1
1
  import type { FastifyInstance } from "fastify";
2
+ import type { ExecutionStatusProjection } from "@tutti/shared/schemas/api";
2
3
  import { type HostProjectStore } from "../../store/index.js";
3
4
  import type { createHostServer } from "../http/create-server.js";
4
5
  import type { HostLocalLaunchStatus } from "../http/routes/local-control.js";
@@ -8,6 +9,7 @@ import type { HostRelayConnectionManager } from "./host-relay-connection-manager
8
9
  import type { LaunchPreparationResult } from "./launch.js";
9
10
  import { type MachineRuntimeEndpointRecord } from "./machine-local.js";
10
11
  export declare const HOST_SERVER_VERSION: string;
12
+ export declare function packageUpdateReadinessFromExecutionStatus(execution: Pick<ExecutionStatusProjection, "status" | "active_activity" | "active_activities" | "blocked_by">): "ready" | "busy";
11
13
  export type HostServerFactory = typeof createHostServer;
12
14
  export type HostServerHandle = {
13
15
  app: FastifyInstance;