@xfey/tutti 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collaboration-state/index.d.ts +2 -2
- package/dist/collaboration-state/index.js +1 -1
- package/dist/collaboration-state/scratchpad.d.ts +2 -2
- package/dist/collaboration-state/scratchpad.js +94 -7
- package/dist/collaboration-state/storage-types.d.ts +14 -0
- package/dist/collaboration-state/types.d.ts +9 -1
- package/dist/control-plane/task-compile-output.js +7 -3
- package/dist/control-plane/task-compile-start.d.ts +3 -0
- package/dist/control-plane/task-compile-start.js +47 -11
- package/dist/server-shell/cli/cli.js +3 -22
- package/dist/server-shell/cli/machine-local.d.ts +4 -0
- package/dist/server-shell/cli/machine-local.js +15 -1
- package/dist/server-shell/cli/project-resolver.d.ts +8 -0
- package/dist/server-shell/cli/project-resolver.js +67 -5
- package/dist/server-shell/cli/provider-tui.d.ts +12 -0
- package/dist/server-shell/cli/provider-tui.js +15 -20
- package/dist/server-shell/cli/runtime-commands.d.ts +10 -1
- package/dist/server-shell/cli/runtime-commands.js +45 -7
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +14 -1
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +14 -1
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +28 -2
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +14 -1
- package/migrations/0012_scratchpad_receipts.sql +31 -0
- package/migrations/README.md +2 -1
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +14 -1
- package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +2 -1
- package/node_modules/@tutti/shared/dist/schemas/api/work-items.d.ts +24 -1
- package/node_modules/@tutti/shared/dist/schemas/api/work-items.js +15 -1
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +28 -2
- package/package.json +1 -1
- package/web/assets/index-BhNJQ717.js +29 -0
- package/web/assets/{index-CohZfGSh.css → index-mXkNKFjm.css} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-YQvFdpG8.js +0 -29
|
@@ -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 {
|
|
4
|
+
export { createEmptyScratchpadProjection, 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";
|
|
@@ -13,5 +13,5 @@ export { recoverStaleRunningTasksAsFailed } from "./recovery.js";
|
|
|
13
13
|
export { markReadStateScope, readReadStateSummary, recordReadNotificationEvent, } from "./read-state.js";
|
|
14
14
|
export { readTaskDetailProjection } from "./task-details.js";
|
|
15
15
|
export { applyTaskCompileProposal, markTaskRunStarted, readNextRunnableTask, readRecoverableScheduledRun, readTaskProjection, readWorklistProjection, } from "./worklist.js";
|
|
16
|
-
export type { ApplyTaskCompileProposalResult, CloseTaskBoundClarificationRetaskingRequiredInput, CloseTaskBoundClarificationRetaskingRequiredResult, CreateClarificationRoundAgentMessageInput, CreateClarificationRoundMessageInput, CreateMainChatAgentMessageInput, CreateMainChatMessageInput, CreateMainChatSystemMessageInput, CursorPageOptions, MarkReadStateScopeInput, MarkReadStateScopeResult, MarkTaskRunStartedInput, MarkTaskRunStartedResult, MaterializeClarificationSuccessorInput, MaterializeTaskBoundRunSuccessorInput, MaterializeTaskBoundRunSuccessorResult, MessageAuthorInput, NextRunnableTaskResult, OpenNextTaskBoundClarificationRoundInput, OpenNextTaskBoundClarificationRoundResult, OpenNextTaskCompileClarificationRoundInput, OpenNextTaskCompileClarificationRoundResult, OpenTaskCompileClarificationRoundInput, OpenTaskCompileClarificationRoundResult, ReadMainChatMessagesAfterOptions, ReadMessageWindowOptions, ReadReadStateSummaryInput, RecoverStaleRunningTasksResult, RecoverableScheduledRun, RecordReadNotificationEventInput, RecordRecoverySummaryInput, RecordRecoverySummaryResult, RecordRunNeedsHumanResultInput, RecordRunNeedsHumanResultResult, RecordRunResultInput, RecordRunResultResult, RunResultPromotionProjection, ScratchpadSnapshotInput, SealedClarificationRoundWithoutSuccessor, SubmitClarificationRoundInput, TaskCompileProposalInput, TaskCompileProposalModuleInput, TaskCompileProposalTaskInput, } from "./types.js";
|
|
16
|
+
export type { ApplyTaskCompileProposalResult, CloseTaskBoundClarificationRetaskingRequiredInput, CloseTaskBoundClarificationRetaskingRequiredResult, CreateClarificationRoundAgentMessageInput, CreateClarificationRoundMessageInput, CreateMainChatAgentMessageInput, CreateMainChatMessageInput, CreateMainChatSystemMessageInput, CursorPageOptions, MarkReadStateScopeInput, MarkReadStateScopeResult, MarkTaskRunStartedInput, MarkTaskRunStartedResult, MaterializeClarificationSuccessorInput, MaterializeTaskBoundRunSuccessorInput, MaterializeTaskBoundRunSuccessorResult, MessageAuthorInput, NextRunnableTaskResult, OpenNextTaskBoundClarificationRoundInput, OpenNextTaskBoundClarificationRoundResult, OpenNextTaskCompileClarificationRoundInput, OpenNextTaskCompileClarificationRoundResult, OpenTaskCompileClarificationRoundInput, OpenTaskCompileClarificationRoundResult, ReadMainChatMessagesAfterOptions, ReadMessageWindowOptions, ReadReadStateSummaryInput, RecoverStaleRunningTasksResult, RecoverableScheduledRun, RecordReadNotificationEventInput, RecordRecoverySummaryInput, RecordRecoverySummaryResult, RecordRunNeedsHumanResultInput, RecordRunNeedsHumanResultResult, RecordRunResultInput, RecordRunResultResult, RunResultPromotionProjection, ScratchpadSnapshotInput, SubmitScratchpadInput, SubmitScratchpadResult, SealedClarificationRoundWithoutSuccessor, SubmitClarificationRoundInput, TaskCompileProposalInput, TaskCompileProposalModuleInput, TaskCompileProposalTaskInput, } from "./types.js";
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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 {
|
|
4
|
+
export { createEmptyScratchpadProjection, 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,8 +1,8 @@
|
|
|
1
1
|
import type { ScratchpadProjection } from "@tutti/shared/schemas/api";
|
|
2
2
|
import type { SqliteDatabase } from "../store/index.js";
|
|
3
|
-
import type { ScratchpadSnapshotInput } from "./types.js";
|
|
3
|
+
import type { ScratchpadSnapshotInput, SubmitScratchpadInput } from "./types.js";
|
|
4
4
|
export declare function createEmptyScratchpadProjection(): ScratchpadProjection;
|
|
5
5
|
export declare function upsertScratchpadProjection(db: SqliteDatabase, input: ScratchpadSnapshotInput): ScratchpadProjection;
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function submitScratchpadProjection(db: SqliteDatabase, input: SubmitScratchpadInput): ScratchpadProjection;
|
|
7
7
|
export declare function readScratchpadProjection(db: SqliteDatabase): ScratchpadProjection;
|
|
8
8
|
//# sourceMappingURL=scratchpad.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { nowIso, parseJson, stringifyJson } from "./serialization.js";
|
|
2
|
+
const SCRATCHPAD_RECEIPT_LIMIT = 100;
|
|
2
3
|
export function createEmptyScratchpadProjection() {
|
|
3
4
|
return {
|
|
4
5
|
id: "current",
|
|
@@ -8,8 +9,37 @@ export function createEmptyScratchpadProjection() {
|
|
|
8
9
|
current_consensus: [],
|
|
9
10
|
open_questions: [],
|
|
10
11
|
task_changes: [],
|
|
12
|
+
receipts: [],
|
|
11
13
|
};
|
|
12
14
|
}
|
|
15
|
+
function readScratchpadReceipts(db) {
|
|
16
|
+
const rows = db
|
|
17
|
+
.prepare(`
|
|
18
|
+
SELECT
|
|
19
|
+
workflow_ref,
|
|
20
|
+
activity_ref,
|
|
21
|
+
topic,
|
|
22
|
+
background_summary,
|
|
23
|
+
current_consensus_json,
|
|
24
|
+
open_questions_json,
|
|
25
|
+
task_changes_json,
|
|
26
|
+
submitted_at
|
|
27
|
+
FROM scratchpad_receipts
|
|
28
|
+
ORDER BY submitted_at DESC, workflow_ref DESC
|
|
29
|
+
LIMIT ${SCRATCHPAD_RECEIPT_LIMIT}
|
|
30
|
+
`)
|
|
31
|
+
.all();
|
|
32
|
+
return rows.map((row) => ({
|
|
33
|
+
workflow_ref: row.workflow_ref,
|
|
34
|
+
activity_ref: row.activity_ref,
|
|
35
|
+
topic: row.topic,
|
|
36
|
+
background_summary: row.background_summary,
|
|
37
|
+
current_consensus: parseJson(row.current_consensus_json, []),
|
|
38
|
+
open_questions: parseJson(row.open_questions_json, []),
|
|
39
|
+
task_changes: parseJson(row.task_changes_json, []),
|
|
40
|
+
submitted_at: row.submitted_at,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
13
43
|
export function upsertScratchpadProjection(db, input) {
|
|
14
44
|
const updatedAt = nowIso(input.now);
|
|
15
45
|
db.prepare(`
|
|
@@ -34,51 +64,108 @@ export function upsertScratchpadProjection(db, input) {
|
|
|
34
64
|
?
|
|
35
65
|
)
|
|
36
66
|
ON CONFLICT(id) DO UPDATE SET
|
|
67
|
+
state = 'ready',
|
|
37
68
|
topic = excluded.topic,
|
|
38
69
|
background_summary = excluded.background_summary,
|
|
39
70
|
current_consensus_json = excluded.current_consensus_json,
|
|
40
71
|
open_questions_json = excluded.open_questions_json,
|
|
41
72
|
task_changes_json = excluded.task_changes_json,
|
|
42
73
|
updated_by_activity_ref = excluded.updated_by_activity_ref,
|
|
43
|
-
updated_at = excluded.updated_at
|
|
74
|
+
updated_at = excluded.updated_at,
|
|
75
|
+
submitted_by_activity_ref = NULL,
|
|
76
|
+
submitted_by_workflow_ref = NULL,
|
|
77
|
+
submitted_at = NULL
|
|
44
78
|
`).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);
|
|
45
79
|
return readScratchpadProjection(db);
|
|
46
80
|
}
|
|
47
|
-
export function
|
|
48
|
-
|
|
49
|
-
|
|
81
|
+
export function submitScratchpadProjection(db, input) {
|
|
82
|
+
const submittedAt = nowIso(input.now);
|
|
83
|
+
const scratchpad = readScratchpadProjection(db);
|
|
84
|
+
if (scratchpad.state === "empty") {
|
|
85
|
+
return scratchpad;
|
|
86
|
+
}
|
|
87
|
+
db.prepare(`
|
|
88
|
+
INSERT INTO scratchpad_receipts (
|
|
89
|
+
workflow_ref,
|
|
90
|
+
activity_ref,
|
|
91
|
+
topic,
|
|
92
|
+
background_summary,
|
|
93
|
+
current_consensus_json,
|
|
94
|
+
open_questions_json,
|
|
95
|
+
task_changes_json,
|
|
96
|
+
submitted_at
|
|
97
|
+
)
|
|
98
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
99
|
+
ON CONFLICT(workflow_ref) DO UPDATE SET
|
|
100
|
+
activity_ref = excluded.activity_ref,
|
|
101
|
+
topic = excluded.topic,
|
|
102
|
+
background_summary = excluded.background_summary,
|
|
103
|
+
current_consensus_json = excluded.current_consensus_json,
|
|
104
|
+
open_questions_json = excluded.open_questions_json,
|
|
105
|
+
task_changes_json = excluded.task_changes_json,
|
|
106
|
+
submitted_at = excluded.submitted_at
|
|
107
|
+
`).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);
|
|
108
|
+
db.prepare(`
|
|
109
|
+
UPDATE scratchpad
|
|
110
|
+
SET
|
|
111
|
+
state = 'submitted',
|
|
112
|
+
submitted_by_activity_ref = ?,
|
|
113
|
+
submitted_by_workflow_ref = ?,
|
|
114
|
+
submitted_at = ?,
|
|
115
|
+
updated_at = ?
|
|
116
|
+
WHERE id = 'current'
|
|
117
|
+
`).run(input.activity_ref, input.workflow_ref, submittedAt, submittedAt);
|
|
118
|
+
return readScratchpadProjection(db);
|
|
50
119
|
}
|
|
51
120
|
export function readScratchpadProjection(db) {
|
|
121
|
+
const receipts = readScratchpadReceipts(db);
|
|
52
122
|
const row = db
|
|
53
123
|
.prepare(`
|
|
54
124
|
SELECT
|
|
125
|
+
state,
|
|
55
126
|
topic,
|
|
56
127
|
background_summary,
|
|
57
128
|
current_consensus_json,
|
|
58
129
|
open_questions_json,
|
|
59
130
|
task_changes_json,
|
|
60
131
|
updated_by_activity_ref,
|
|
61
|
-
updated_at
|
|
132
|
+
updated_at,
|
|
133
|
+
submitted_by_activity_ref,
|
|
134
|
+
submitted_by_workflow_ref,
|
|
135
|
+
submitted_at
|
|
62
136
|
FROM scratchpad
|
|
63
137
|
WHERE id = 'current'
|
|
64
138
|
`)
|
|
65
139
|
.get();
|
|
66
140
|
if (row === undefined) {
|
|
67
|
-
return
|
|
141
|
+
return {
|
|
142
|
+
...createEmptyScratchpadProjection(),
|
|
143
|
+
receipts,
|
|
144
|
+
};
|
|
68
145
|
}
|
|
69
146
|
const scratchpad = {
|
|
70
147
|
id: "current",
|
|
71
|
-
state:
|
|
148
|
+
state: row.state,
|
|
72
149
|
topic: row.topic,
|
|
73
150
|
background_summary: row.background_summary,
|
|
74
151
|
current_consensus: parseJson(row.current_consensus_json, []),
|
|
75
152
|
open_questions: parseJson(row.open_questions_json, []),
|
|
76
153
|
task_changes: parseJson(row.task_changes_json, []),
|
|
77
154
|
updated_at: row.updated_at,
|
|
155
|
+
receipts,
|
|
78
156
|
};
|
|
79
157
|
if (row.updated_by_activity_ref !== null) {
|
|
80
158
|
scratchpad.updated_by_activity_ref = row.updated_by_activity_ref;
|
|
81
159
|
}
|
|
160
|
+
if (row.submitted_by_activity_ref !== null) {
|
|
161
|
+
scratchpad.submitted_by_activity_ref = row.submitted_by_activity_ref;
|
|
162
|
+
}
|
|
163
|
+
if (row.submitted_by_workflow_ref !== null) {
|
|
164
|
+
scratchpad.submitted_by_workflow_ref = row.submitted_by_workflow_ref;
|
|
165
|
+
}
|
|
166
|
+
if (row.submitted_at !== null) {
|
|
167
|
+
scratchpad.submitted_at = row.submitted_at;
|
|
168
|
+
}
|
|
82
169
|
return scratchpad;
|
|
83
170
|
}
|
|
84
171
|
//# sourceMappingURL=scratchpad.js.map
|
|
@@ -13,6 +13,7 @@ export type MessageRow = {
|
|
|
13
13
|
created_at: string;
|
|
14
14
|
};
|
|
15
15
|
export type ScratchpadRow = {
|
|
16
|
+
state: "ready" | "submitted";
|
|
16
17
|
topic: string;
|
|
17
18
|
background_summary: string;
|
|
18
19
|
current_consensus_json: string;
|
|
@@ -20,6 +21,19 @@ export type ScratchpadRow = {
|
|
|
20
21
|
task_changes_json: string;
|
|
21
22
|
updated_by_activity_ref: string | null;
|
|
22
23
|
updated_at: string;
|
|
24
|
+
submitted_by_activity_ref: string | null;
|
|
25
|
+
submitted_by_workflow_ref: string | null;
|
|
26
|
+
submitted_at: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type ScratchpadReceiptRow = {
|
|
29
|
+
workflow_ref: string;
|
|
30
|
+
activity_ref: string;
|
|
31
|
+
topic: string;
|
|
32
|
+
background_summary: string;
|
|
33
|
+
current_consensus_json: string;
|
|
34
|
+
open_questions_json: string;
|
|
35
|
+
task_changes_json: string;
|
|
36
|
+
submitted_at: string;
|
|
23
37
|
};
|
|
24
38
|
export type ScratchpadSourceStateRow = {
|
|
25
39
|
main_chat_cursor_created_at: string | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RunLineage } from "@tutti/shared/domain";
|
|
2
2
|
import type { AccountAvatarProjection } from "@tutti/shared/domain";
|
|
3
3
|
import type { ActivityRef, ClarificationRoundRef, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
4
|
-
import type { ClarificationRequestPayload, ClarificationRoundProjection, ClarificationSuccessorRef, ClarificationThreadProjection, MessageProjection, ReadStateScope, ReadStateSummaryProjection, RecoverySummaryProjection, RunResultProjection, TaskContractProjection, TaskDetailProjection, TaskDetailResultProjection, TaskProjection, WorklistProjection } from "@tutti/shared/schemas/api";
|
|
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";
|
|
7
7
|
ref?: string;
|
|
@@ -56,6 +56,14 @@ export type ScratchpadSnapshotInput = {
|
|
|
56
56
|
updated_by_activity_ref?: ActivityRef;
|
|
57
57
|
now?: () => Date;
|
|
58
58
|
};
|
|
59
|
+
export type SubmitScratchpadInput = {
|
|
60
|
+
workflow_ref: WorkflowInvocationRef;
|
|
61
|
+
activity_ref: ActivityRef;
|
|
62
|
+
now?: () => Date;
|
|
63
|
+
};
|
|
64
|
+
export type SubmitScratchpadResult = {
|
|
65
|
+
scratchpad: ScratchpadProjection;
|
|
66
|
+
};
|
|
59
67
|
export type TaskCompileProposalInput = {
|
|
60
68
|
workflow_ref: WorkflowInvocationRef;
|
|
61
69
|
proposal: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyTaskCompileProposal,
|
|
1
|
+
import { applyTaskCompileProposal, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, readWorklistProjection, submitScratchpadProjection, } from "../collaboration-state/index.js";
|
|
2
2
|
import { clarificationInvalidates, taskCompileInvalidates, } from "./invalidations.js";
|
|
3
3
|
import { normalizeTaskCompileProposal } from "./task-proposal.js";
|
|
4
4
|
const EMPTY_INITIAL_WORKLIST_CLARIFICATION = {
|
|
@@ -86,7 +86,11 @@ export function applyTaskCompileProcedureOutput(input) {
|
|
|
86
86
|
if (applied.changed_task_ids.length > 0) {
|
|
87
87
|
input.onTasksAdded?.();
|
|
88
88
|
}
|
|
89
|
-
const
|
|
89
|
+
const submittedScratchpad = submitScratchpadProjection(input.store.db, {
|
|
90
|
+
workflow_ref: input.workflowRef,
|
|
91
|
+
activity_ref: input.activityRef,
|
|
92
|
+
now: input.now,
|
|
93
|
+
});
|
|
90
94
|
input.events.publish({
|
|
91
95
|
event_type: "worklist.changed",
|
|
92
96
|
payload: {
|
|
@@ -101,7 +105,7 @@ export function applyTaskCompileProcedureOutput(input) {
|
|
|
101
105
|
input.events.publish({
|
|
102
106
|
event_type: "scratchpad.updated",
|
|
103
107
|
payload: {
|
|
104
|
-
scratchpad:
|
|
108
|
+
scratchpad: submittedScratchpad,
|
|
105
109
|
activity_ref: input.activityRef,
|
|
106
110
|
},
|
|
107
111
|
invalidates: taskCompileInvalidates(),
|
|
@@ -51,7 +51,7 @@ export function startControlPlaneTaskCompile(options) {
|
|
|
51
51
|
sourceBatch,
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
-
if (scratchpad
|
|
54
|
+
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
55
55
|
return { disposition: { kind: "scratchpad_empty" } };
|
|
56
56
|
}
|
|
57
57
|
if (shouldInitializeProjectContext) {
|
|
@@ -66,6 +66,10 @@ export function startControlPlaneTaskCompile(options) {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
function startControlPlaneTaskCompileActivity(options) {
|
|
69
|
+
const scratchpad = readScratchpadProjection(options.store.db);
|
|
70
|
+
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
71
|
+
return { disposition: { kind: "scratchpad_empty" } };
|
|
72
|
+
}
|
|
69
73
|
const workflowRef = createWorkflowInvocationRef();
|
|
70
74
|
const start = options.engine.startProcedure({
|
|
71
75
|
workflow_ref: workflowRef,
|
|
@@ -120,13 +124,18 @@ function startScratchpadRefreshBeforeTaskCompileActivity(options) {
|
|
|
120
124
|
now: options.now,
|
|
121
125
|
onTransition: (state) => {
|
|
122
126
|
options.publishProcedureTransition(state);
|
|
123
|
-
if (state.activity.status
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
if (state.transition_kind !== "terminal" || state.activity.status !== "finished") {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const scratchpad = readScratchpadProjection(options.store.db);
|
|
131
|
+
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (shouldInitializeControlPlaneProjectContext(options)) {
|
|
135
|
+
void startProjectContextBootstrapActivity(options);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
void startControlPlaneTaskCompileActivity(options);
|
|
130
139
|
}
|
|
131
140
|
},
|
|
132
141
|
onError: ({ context, error }) => logProcedureExecutionError({
|
|
@@ -186,9 +195,17 @@ function startProjectContextBootstrapActivity(options) {
|
|
|
186
195
|
now: options.now,
|
|
187
196
|
onTransition: (state) => {
|
|
188
197
|
options.publishProcedureTransition(state);
|
|
189
|
-
if (state.activity.status
|
|
190
|
-
|
|
198
|
+
if (state.transition_kind !== "terminal" || state.activity.status !== "finished") {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (shouldInitializeControlPlaneProjectContext(options)) {
|
|
202
|
+
return;
|
|
191
203
|
}
|
|
204
|
+
const scratchpad = readScratchpadProjection(options.store.db);
|
|
205
|
+
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
void startControlPlaneTaskCompileActivity(options);
|
|
192
209
|
},
|
|
193
210
|
onError: ({ context, error }) => logProcedureExecutionError({
|
|
194
211
|
logger: options.logger,
|
|
@@ -261,9 +278,16 @@ function startProjectContextBootstrapActivity(options) {
|
|
|
261
278
|
};
|
|
262
279
|
}
|
|
263
280
|
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
|
+
}
|
|
264
288
|
const output = await options.runner.runTaskCompile({
|
|
265
289
|
workflow_ref: options.workflowRef,
|
|
266
|
-
scratchpad
|
|
290
|
+
scratchpad,
|
|
267
291
|
worklist: readWorklistProjection(options.store.db),
|
|
268
292
|
}, {
|
|
269
293
|
workflow_ref: options.workflowRef,
|
|
@@ -282,4 +306,16 @@ export async function runControlPlaneTaskCompileProcedure(options) {
|
|
|
282
306
|
onTasksAdded: options.onTasksAdded,
|
|
283
307
|
});
|
|
284
308
|
}
|
|
309
|
+
function scratchpadHasSubmittableContent(scratchpad) {
|
|
310
|
+
if (scratchpad.state !== "ready") {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
return [
|
|
314
|
+
scratchpad.topic,
|
|
315
|
+
scratchpad.background_summary,
|
|
316
|
+
...scratchpad.current_consensus,
|
|
317
|
+
...scratchpad.open_questions,
|
|
318
|
+
...scratchpad.task_changes,
|
|
319
|
+
].some((item) => item.trim().length > 0);
|
|
320
|
+
}
|
|
285
321
|
//# sourceMappingURL=task-compile-start.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { formatCliError
|
|
2
|
+
import { formatCliError } from "./errors.js";
|
|
3
3
|
import { parseCliArgs } from "./args.js";
|
|
4
4
|
import { runBackgroundLaunchCommand, runForegroundLaunchCommand, runInternalHostRunCommand, } from "./launch-command.js";
|
|
5
5
|
import { resolveExistingProjectContext } from "./project-resolver.js";
|
|
6
6
|
import { runProviderSetupTui } from "./provider-tui.js";
|
|
7
|
-
import { runInviteCommand, runLogsCommand, runProviderStatusCommand, runPsManageCommand, runPsCommand, runStopCommand, } from "./runtime-commands.js";
|
|
7
|
+
import { runDoctorCommand, runInviteCommand, runLogsCommand, runProviderStatusCommand, runPsManageCommand, runPsCommand, runStopCommand, } from "./runtime-commands.js";
|
|
8
8
|
import { readCliVersion } from "./version.js";
|
|
9
9
|
const HELP_TEXT = `Usage:
|
|
10
10
|
tutti launch [target] [--yes] [--foreground]
|
|
@@ -108,25 +108,6 @@ async function runProviderSetupCommand(target) {
|
|
|
108
108
|
].join("\n"));
|
|
109
109
|
process.stdout.write("\n");
|
|
110
110
|
}
|
|
111
|
-
function runDoctorCommand(target) {
|
|
112
|
-
const checks = [];
|
|
113
|
-
checks.push(`Node: ${process.version}`);
|
|
114
|
-
checks.push(`Tutti: ${readCliVersion()}`);
|
|
115
|
-
try {
|
|
116
|
-
const project = resolveExistingProjectContext({
|
|
117
|
-
...(target === undefined ? {} : { target }),
|
|
118
|
-
});
|
|
119
|
-
checks.push(`Project: ${project.display_name}`);
|
|
120
|
-
checks.push(`Project ID: ${project.project_id}`);
|
|
121
|
-
checks.push(`Provider: ${project.provider_config.status}`);
|
|
122
|
-
checks.push(`Host: ${project.runtime_endpoint === null ? "not running" : project.runtime_endpoint.base_url}`);
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
checks.push("Project: unavailable");
|
|
126
|
-
checks.push(`Project detail: ${formatCliErrorReason(error)}`);
|
|
127
|
-
}
|
|
128
|
-
process.stdout.write(`${checks.join("\n")}\n`);
|
|
129
|
-
}
|
|
130
111
|
try {
|
|
131
112
|
const command = parseCliArgs(process.argv.slice(2));
|
|
132
113
|
switch (command.kind) {
|
|
@@ -171,7 +152,7 @@ try {
|
|
|
171
152
|
process.stdout.write(`${runProviderStatusCommand(command.target)}\n`);
|
|
172
153
|
break;
|
|
173
154
|
case "doctor":
|
|
174
|
-
runDoctorCommand(command.target);
|
|
155
|
+
process.stdout.write(`${runDoctorCommand(command.target)}\n`);
|
|
175
156
|
break;
|
|
176
157
|
}
|
|
177
158
|
}
|
|
@@ -61,6 +61,10 @@ export declare function deleteMachineRuntimeEndpoint(options: {
|
|
|
61
61
|
projectId: ProjectId;
|
|
62
62
|
expectedToken?: string;
|
|
63
63
|
}): boolean;
|
|
64
|
+
export declare function deleteMachineProjectLocalState(options: {
|
|
65
|
+
tuttiHome: string;
|
|
66
|
+
projectId: ProjectId;
|
|
67
|
+
}): boolean;
|
|
64
68
|
export declare function readHostRegistrationSecret(tuttiHome: string, projectId: ProjectId): HostRegistrationSecretFile;
|
|
65
69
|
export declare function updateMachineProjectRelayBinding(options: {
|
|
66
70
|
tuttiHome: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { ID_PREFIXES, isPrefixedId } from "@tutti/shared/ids";
|
|
5
5
|
import { LaunchError } from "./errors.js";
|
|
@@ -150,6 +150,20 @@ export function deleteMachineRuntimeEndpoint(options) {
|
|
|
150
150
|
unlinkSync(endpointPath);
|
|
151
151
|
return true;
|
|
152
152
|
}
|
|
153
|
+
export function deleteMachineProjectLocalState(options) {
|
|
154
|
+
let deleted = false;
|
|
155
|
+
const localStoreRoot = getProjectLocalStoreRoot(options.tuttiHome, options.projectId);
|
|
156
|
+
if (existsSync(localStoreRoot)) {
|
|
157
|
+
rmSync(localStoreRoot, { recursive: true, force: true });
|
|
158
|
+
deleted = true;
|
|
159
|
+
}
|
|
160
|
+
const secretPath = getHostRegistrationSecretPath(options.tuttiHome, options.projectId);
|
|
161
|
+
if (existsSync(secretPath)) {
|
|
162
|
+
unlinkSync(secretPath);
|
|
163
|
+
deleted = true;
|
|
164
|
+
}
|
|
165
|
+
return deleted;
|
|
166
|
+
}
|
|
153
167
|
export function readHostRegistrationSecret(tuttiHome, projectId) {
|
|
154
168
|
const readResult = readJsonFile(getHostRegistrationSecretPath(tuttiHome, projectId));
|
|
155
169
|
if (readResult.kind === "missing") {
|
|
@@ -11,6 +11,9 @@ export type ExistingProjectContext = {
|
|
|
11
11
|
provider_config: OpenAiProviderConfigProjection;
|
|
12
12
|
provider_base_url?: string;
|
|
13
13
|
};
|
|
14
|
+
export type ManagedProjectContext = ExistingProjectContext & {
|
|
15
|
+
workspace_exists: boolean;
|
|
16
|
+
};
|
|
14
17
|
export declare function resolveLaunchWorkspacePath(options: {
|
|
15
18
|
target?: string;
|
|
16
19
|
cwd?: string;
|
|
@@ -22,4 +25,9 @@ export declare function resolveExistingProjectContext(options: {
|
|
|
22
25
|
cwd?: string;
|
|
23
26
|
env?: NodeJS.ProcessEnv;
|
|
24
27
|
}): ExistingProjectContext;
|
|
28
|
+
export declare function resolveManagedProjectContext(options: {
|
|
29
|
+
target?: string;
|
|
30
|
+
cwd?: string;
|
|
31
|
+
env?: NodeJS.ProcessEnv;
|
|
32
|
+
}): ManagedProjectContext;
|
|
25
33
|
//# sourceMappingURL=project-resolver.d.ts.map
|
|
@@ -70,28 +70,50 @@ function resolveSingleTargetMatch(target, matches) {
|
|
|
70
70
|
throw new LaunchError("project_target_not_found", `Project target was not found: ${target}`, "Run `tutti ps` to list known projects, or pass a project workspace path.");
|
|
71
71
|
}
|
|
72
72
|
function resolveProjectTargetWorkspaceRoot(options) {
|
|
73
|
+
return resolveProjectTargetEntry(options).workspace_root;
|
|
74
|
+
}
|
|
75
|
+
function resolveProjectTargetEntry(options) {
|
|
73
76
|
const target = options.target.trim();
|
|
74
77
|
if (target === "") {
|
|
75
|
-
return resolve(options.cwd, ".");
|
|
78
|
+
return readProjectTargetEntryFromWorkspace(resolve(options.cwd, "."));
|
|
76
79
|
}
|
|
77
80
|
const pathCandidate = resolve(options.cwd, target);
|
|
78
81
|
if (existsSync(pathCandidate)) {
|
|
79
|
-
return pathCandidate;
|
|
82
|
+
return readProjectTargetEntryFromWorkspace(pathCandidate);
|
|
80
83
|
}
|
|
81
84
|
const entries = listProjectTargetEntries(options.tuttiHome);
|
|
85
|
+
const pathMatches = entries.filter((entry) => resolve(entry.workspace_root) === pathCandidate);
|
|
86
|
+
if (pathMatches.length > 0) {
|
|
87
|
+
return resolveSingleTargetMatch(target, pathMatches);
|
|
88
|
+
}
|
|
82
89
|
const exactId = entries.filter((entry) => entry.project_id === target);
|
|
83
90
|
if (exactId.length > 0) {
|
|
84
|
-
return resolveSingleTargetMatch(target, exactId)
|
|
91
|
+
return resolveSingleTargetMatch(target, exactId);
|
|
85
92
|
}
|
|
86
93
|
if (target.startsWith(ID_PREFIXES.project)) {
|
|
87
94
|
const idPrefix = entries.filter((entry) => entry.project_id.startsWith(target));
|
|
88
95
|
if (idPrefix.length > 0) {
|
|
89
|
-
return resolveSingleTargetMatch(target, idPrefix)
|
|
96
|
+
return resolveSingleTargetMatch(target, idPrefix);
|
|
90
97
|
}
|
|
91
98
|
}
|
|
92
99
|
const normalizedTarget = normalizeTargetName(target);
|
|
93
100
|
const nameMatches = entries.filter((entry) => entry.aliases.some((alias) => normalizeTargetName(alias) === normalizedTarget));
|
|
94
|
-
return resolveSingleTargetMatch(target, nameMatches)
|
|
101
|
+
return resolveSingleTargetMatch(target, nameMatches);
|
|
102
|
+
}
|
|
103
|
+
function readProjectTargetEntryFromWorkspace(workspaceRoot) {
|
|
104
|
+
assertSafeProjectRoot(workspaceRoot);
|
|
105
|
+
const identity = readProjectIdentity(workspaceRoot);
|
|
106
|
+
if (identity.kind !== "present") {
|
|
107
|
+
throw new LaunchError("project_identity_conflict", "Current directory is not a Tutti project", "Run `tutti launch` from a project root first.");
|
|
108
|
+
}
|
|
109
|
+
const workspaceName = basename(workspaceRoot) || identity.project_id;
|
|
110
|
+
const displayName = readProjectDisplayName(workspaceRoot) ?? workspaceName;
|
|
111
|
+
return {
|
|
112
|
+
project_id: identity.project_id,
|
|
113
|
+
workspace_root: workspaceRoot,
|
|
114
|
+
display_name: displayName,
|
|
115
|
+
aliases: Array.from(new Set([displayName, workspaceName].filter((alias) => alias.trim() !== ""))),
|
|
116
|
+
};
|
|
95
117
|
}
|
|
96
118
|
export function resolveLaunchWorkspacePath(options) {
|
|
97
119
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -154,4 +176,44 @@ export function resolveExistingProjectContext(options) {
|
|
|
154
176
|
: {}),
|
|
155
177
|
};
|
|
156
178
|
}
|
|
179
|
+
export function resolveManagedProjectContext(options) {
|
|
180
|
+
const cwd = options.cwd ?? process.cwd();
|
|
181
|
+
const env = options.env ?? process.env;
|
|
182
|
+
const tuttiHome = resolveTuttiHome(env.TUTTI_HOME, cwd);
|
|
183
|
+
if (options.target === undefined || existsSync(resolve(cwd, options.target))) {
|
|
184
|
+
const existing = resolveExistingProjectContext({
|
|
185
|
+
...(options.target === undefined ? {} : { target: options.target }),
|
|
186
|
+
cwd,
|
|
187
|
+
env,
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
...existing,
|
|
191
|
+
workspace_exists: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
const entry = resolveProjectTargetEntry({
|
|
195
|
+
target: options.target,
|
|
196
|
+
cwd,
|
|
197
|
+
tuttiHome,
|
|
198
|
+
});
|
|
199
|
+
const binding = readBinding(tuttiHome, entry.project_id);
|
|
200
|
+
const runtimeEndpoint = readRuntimeEndpoint(tuttiHome, entry.project_id);
|
|
201
|
+
const projectConfig = readProjectOpenAiProviderConfig(tuttiHome, entry.project_id);
|
|
202
|
+
return {
|
|
203
|
+
workspace_root: entry.workspace_root,
|
|
204
|
+
workspace_exists: existsSync(entry.workspace_root),
|
|
205
|
+
tutti_home: tuttiHome,
|
|
206
|
+
project_id: entry.project_id,
|
|
207
|
+
display_name: entry.display_name,
|
|
208
|
+
binding,
|
|
209
|
+
runtime_endpoint: runtimeEndpoint,
|
|
210
|
+
provider_config: readOpenAiProviderConfigProjection({
|
|
211
|
+
tuttiHome,
|
|
212
|
+
projectId: entry.project_id,
|
|
213
|
+
}),
|
|
214
|
+
...(projectConfig.kind === "ok" && projectConfig.config.api_base_url !== undefined
|
|
215
|
+
? { provider_base_url: projectConfig.config.api_base_url }
|
|
216
|
+
: {}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
157
219
|
//# sourceMappingURL=project-resolver.js.map
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type ConfigureProjectOpenAiProviderResult } from "../../providers/openai/index.js";
|
|
2
2
|
import type { ProjectId } from "@tutti/shared/ids";
|
|
3
|
+
type ProviderSetupStep = "base-url" | "api-key";
|
|
4
|
+
type ProviderFormState = {
|
|
5
|
+
step: ProviderSetupStep;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
error: string | undefined;
|
|
9
|
+
};
|
|
3
10
|
type ProviderSetupLogEvent = {
|
|
4
11
|
ts: string;
|
|
5
12
|
level: "error";
|
|
@@ -17,6 +24,11 @@ export type ProviderSetupResult = {
|
|
|
17
24
|
default_model: string;
|
|
18
25
|
validated_at: string;
|
|
19
26
|
};
|
|
27
|
+
export declare function renderProviderForm(options: {
|
|
28
|
+
state: ProviderFormState;
|
|
29
|
+
footer?: string;
|
|
30
|
+
tty?: boolean;
|
|
31
|
+
}): string;
|
|
20
32
|
export declare function providerValidationFailureMessage(result: ConfigureProjectOpenAiProviderResult): string;
|
|
21
33
|
export declare function writeProviderSetupValidationLog(options: {
|
|
22
34
|
tuttiHome: string;
|