@openchambery/web 1.19.1 → 1.19.2-beta.1
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/assets/{AssistantView-H6shoxl5.js → AssistantView-DGqRio2e.js} +1 -1
- package/dist/assets/{ChatContainer-Daa5W1sk.js → ChatContainer-CM43Pxln.js} +6 -6
- package/dist/assets/ContextPanel-Bp3ZKAJE.js +288 -0
- package/dist/assets/{DiagramView-BfyN-k_0.js → DiagramView-BH5YxFAL.js} +1 -1
- package/dist/assets/{MarkdownRendererImpl-DNhuoybt.js → MarkdownRendererImpl-Cmm9i5Vj.js} +1 -1
- package/dist/assets/{MobileDetailNavigation-B21nwHVB.js → MobileDetailNavigation-nITHp7W3.js} +1 -1
- package/dist/assets/{MobileShareBridge-CVuIIOkq.js → MobileShareBridge-C_QaKaB6.js} +1 -1
- package/dist/assets/MobileSurface-CjpCviv6.js +2 -0
- package/dist/assets/{MultiRunWindow-BHa95dXi.js → MultiRunWindow-B1ALyR36.js} +1 -1
- package/dist/assets/{SettingsView-TLcvwH03.js → SettingsView-BW8d_8pw.js} +1 -1
- package/dist/assets/{SettingsWindow-BUIQkiO2.js → SettingsWindow-7SmQV5GW.js} +1 -1
- package/dist/assets/{TerminalView-BIk-diLF.js → TerminalView-C7EFF7ZS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-ClZXQ2ee.js → ToolOutputDialog-Cba_60bU.js} +1 -1
- package/dist/assets/appThemeRegistry-Co5dwWx_.js +2 -0
- package/dist/assets/{gitApi-G6u4mIJa.js → gitApi-DaTTo7St.js} +1 -1
- package/dist/assets/{insertionBoundaries-lo4zrlFI.js → insertionBoundaries-BoIHXczc.js} +1 -1
- package/dist/assets/{main-8r9WN9j6.js → main-IyYkGXkX.js} +2 -2
- package/dist/assets/{main-tsB0yCVi.js → main-WVLfE2Df.js} +5 -5
- package/dist/assets/{miniChat-B4rTOWDV.js → miniChat-CAAQzm9R.js} +2 -2
- package/dist/assets/{mobile-Dd71U7If.js → mobile-BiCmfs5Y.js} +2 -2
- package/dist/assets/{multirun-DYvDqrOC.js → multirun-DPXG-TWE.js} +1 -1
- package/dist/assets/{projectMeta-B6E8Feg8.js → projectMeta-B0YA9FxC.js} +1 -1
- package/dist/assets/{radio-DswLr47h.js → radio-CUea8K8R.js} +1 -1
- package/dist/assets/{renderElectronMiniChatApp-Dz39AM3_.js → renderElectronMiniChatApp-CGA16ZyN.js} +2 -2
- package/dist/assets/{renderMobileApp-DHc-J2Fc.js → renderMobileApp-D9fgFt6E.js} +4 -4
- package/dist/assets/{runtimeConfig-Cf_G38k8.js → runtimeConfig-BJ3S27Ah.js} +1 -1
- package/dist/assets/runtimeEndpointReset-C9pWVmjf.js +4 -0
- package/dist/assets/{shikiHighlight-BzV876r7.js → shikiHighlight-_cgskSv2.js} +1 -1
- package/dist/assets/{useAppFontEffects-Cgp7KwNF.js → useAppFontEffects-B_a7MLYy.js} +5 -5
- package/dist/assets/{useDesktopWindowControlsLayout-DPffJ02b.js → useDesktopWindowControlsLayout-D-74BaI3.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-DSrxWL-k.js → useEffectiveDirectory-DWwrRiBF.js} +1 -1
- package/dist/assets/{useMobileNavigationStore-B-eF_OVT.js → useMobileNavigationStore-7LBI6idi.js} +1 -1
- package/dist/assets/{useSessionAutoCleanup-0GyoJ4_9.js → useSessionAutoCleanup-Buvg8rem.js} +1 -1
- package/dist/assets/{useWorkerHighlightedLines-CcNKZE-g.js → useWorkerHighlightedLines-BdlVg3Sj.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/mini-chat.html +2 -2
- package/dist/mobile.html +2 -2
- package/package.json +1 -1
- package/server/index.js +4 -0
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +25 -2
- package/server/lib/scheduled-tasks/runtime.js +234 -3
- package/server/lib/scheduled-tasks/runtime.test.js +221 -0
- package/dist/assets/ContextPanel-BTUao9L2.js +0 -288
- package/dist/assets/MobileSurface-BJ9fqB5L.js +0 -2
- package/dist/assets/appThemeRegistry-CyE8QPIG.js +0 -2
- package/dist/assets/runtimeEndpointReset-51jb_Bfy.js +0 -4
|
@@ -993,4 +993,225 @@ describe('scheduled-tasks run history and session lifecycle', () => {
|
|
|
993
993
|
|
|
994
994
|
vi.unstubAllGlobals();
|
|
995
995
|
});
|
|
996
|
+
|
|
997
|
+
it('persists lastSessionId when an error run still created a session', async () => {
|
|
998
|
+
const history = createHistoryStore();
|
|
999
|
+
createSuccessfulClient({ settlement: 'assistant-error' });
|
|
1000
|
+
const fetchMock = vi.fn(async (url) => {
|
|
1001
|
+
if (String(url).includes('prompt_async')) {
|
|
1002
|
+
return { ok: true, text: async () => '' };
|
|
1003
|
+
}
|
|
1004
|
+
throw new Error(`unexpected fetch ${url}`);
|
|
1005
|
+
});
|
|
1006
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
1007
|
+
|
|
1008
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
1009
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
1010
|
+
}));
|
|
1011
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
1012
|
+
runHistoryStore: history,
|
|
1013
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1014
|
+
});
|
|
1015
|
+
await runtime.syncProject('project-1');
|
|
1016
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
1017
|
+
|
|
1018
|
+
expect(result.ok).toBe(false);
|
|
1019
|
+
expect(result.status).toBe('error');
|
|
1020
|
+
const finalPatch = updateScheduledTaskState.mock.calls.at(-1)[2];
|
|
1021
|
+
expect(finalPatch.lastStatus).toBe('error');
|
|
1022
|
+
expect(finalPatch.lastSessionId).toBe('ses_1');
|
|
1023
|
+
|
|
1024
|
+
vi.unstubAllGlobals();
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
it('omits lastSessionId from the final patch when the failed run has no session', async () => {
|
|
1028
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
1029
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
1030
|
+
}));
|
|
1031
|
+
const runtime = createRuntime(updateScheduledTaskState);
|
|
1032
|
+
await runtime.syncProject('project-1');
|
|
1033
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
1034
|
+
|
|
1035
|
+
expect(result.ok).toBe(false);
|
|
1036
|
+
expect(result.status).toBe('error');
|
|
1037
|
+
const finalPatch = updateScheduledTaskState.mock.calls.at(-1)[2];
|
|
1038
|
+
expect(finalPatch.lastStatus).toBe('error');
|
|
1039
|
+
expect(Object.hasOwn(finalPatch, 'lastSessionId')).toBe(false);
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
it('corrects lastStatus error → success on idle after a continuation, without rewriting history', async () => {
|
|
1043
|
+
const history = createHistoryStore();
|
|
1044
|
+
const client = createSuccessfulClient({ settlement: 'assistant-error' });
|
|
1045
|
+
const fetchMock = vi.fn(async (url) => {
|
|
1046
|
+
if (String(url).includes('prompt_async')) {
|
|
1047
|
+
return { ok: true, text: async () => '' };
|
|
1048
|
+
}
|
|
1049
|
+
throw new Error(`unexpected fetch ${url}`);
|
|
1050
|
+
});
|
|
1051
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
1052
|
+
|
|
1053
|
+
const emitTaskRunEvent = vi.fn();
|
|
1054
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
1055
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
1056
|
+
}));
|
|
1057
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
1058
|
+
runHistoryStore: history,
|
|
1059
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1060
|
+
emitTaskRunEvent,
|
|
1061
|
+
});
|
|
1062
|
+
await runtime.syncProject('project-1');
|
|
1063
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
1064
|
+
expect(result.status).toBe('error');
|
|
1065
|
+
expect(history.finishRun).toHaveBeenCalledTimes(1);
|
|
1066
|
+
|
|
1067
|
+
client.messages.mockImplementation(async () => ({
|
|
1068
|
+
data: [{
|
|
1069
|
+
info: {
|
|
1070
|
+
id: 'msg_ok',
|
|
1071
|
+
role: 'assistant',
|
|
1072
|
+
time: { completed: Date.now() },
|
|
1073
|
+
},
|
|
1074
|
+
}],
|
|
1075
|
+
}));
|
|
1076
|
+
|
|
1077
|
+
await runtime.observeSessionEvent({
|
|
1078
|
+
payload: {
|
|
1079
|
+
type: 'session.idle',
|
|
1080
|
+
properties: { sessionID: 'ses_1' },
|
|
1081
|
+
},
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
expect(history.finishRun).toHaveBeenCalledTimes(1);
|
|
1085
|
+
const correctionPatch = updateScheduledTaskState.mock.calls.at(-1)[2];
|
|
1086
|
+
expect(correctionPatch).toEqual(expect.objectContaining({
|
|
1087
|
+
lastStatus: 'success',
|
|
1088
|
+
lastError: undefined,
|
|
1089
|
+
lastSessionId: 'ses_1',
|
|
1090
|
+
}));
|
|
1091
|
+
expect(Object.hasOwn(correctionPatch, 'lastRunAt')).toBe(false);
|
|
1092
|
+
expect(Object.hasOwn(correctionPatch, 'lastDurationMs')).toBe(false);
|
|
1093
|
+
expect(Object.hasOwn(correctionPatch, 'nextRunAt')).toBe(false);
|
|
1094
|
+
expect(emitTaskRunEvent).toHaveBeenCalledWith(expect.objectContaining({
|
|
1095
|
+
projectID: 'project-1',
|
|
1096
|
+
taskID: 'task-1',
|
|
1097
|
+
status: 'success',
|
|
1098
|
+
sessionID: 'ses_1',
|
|
1099
|
+
}));
|
|
1100
|
+
|
|
1101
|
+
vi.unstubAllGlobals();
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
it('does not correct lastStatus while the task is still running', async () => {
|
|
1105
|
+
vi.useFakeTimers();
|
|
1106
|
+
const history = createHistoryStore();
|
|
1107
|
+
const erroredTask = {
|
|
1108
|
+
...scheduledTask,
|
|
1109
|
+
state: {
|
|
1110
|
+
...scheduledTask.state,
|
|
1111
|
+
lastStatus: 'error',
|
|
1112
|
+
lastSessionId: 'ses_1',
|
|
1113
|
+
lastError: 'ProviderError',
|
|
1114
|
+
},
|
|
1115
|
+
};
|
|
1116
|
+
createSuccessfulClient({ settlement: 'busy-then-success' });
|
|
1117
|
+
const fetchMock = vi.fn(async (url) => {
|
|
1118
|
+
if (String(url).includes('prompt_async')) {
|
|
1119
|
+
return { ok: true, text: async () => '' };
|
|
1120
|
+
}
|
|
1121
|
+
throw new Error(`unexpected fetch ${url}`);
|
|
1122
|
+
});
|
|
1123
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
1124
|
+
|
|
1125
|
+
const emitTaskRunEvent = vi.fn();
|
|
1126
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
1127
|
+
task: { ...erroredTask, state: { ...erroredTask.state, ...state } },
|
|
1128
|
+
}));
|
|
1129
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
1130
|
+
projectConfigRuntime: {
|
|
1131
|
+
listScheduledTasks: vi.fn(async () => [erroredTask]),
|
|
1132
|
+
updateScheduledTaskState,
|
|
1133
|
+
upsertScheduledTask: vi.fn(),
|
|
1134
|
+
},
|
|
1135
|
+
runHistoryStore: history,
|
|
1136
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1137
|
+
emitTaskRunEvent,
|
|
1138
|
+
});
|
|
1139
|
+
await runtime.syncProject('project-1');
|
|
1140
|
+
|
|
1141
|
+
const runPromise = runtime.runNow('project-1', 'task-1');
|
|
1142
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
1143
|
+
expect(history.finishRun).not.toHaveBeenCalled();
|
|
1144
|
+
|
|
1145
|
+
const successEmitsBefore = emitTaskRunEvent.mock.calls.filter((call) => call[0].status === 'success').length;
|
|
1146
|
+
await runtime.observeSessionEvent({
|
|
1147
|
+
payload: {
|
|
1148
|
+
type: 'session.idle',
|
|
1149
|
+
properties: { sessionID: 'ses_1' },
|
|
1150
|
+
},
|
|
1151
|
+
});
|
|
1152
|
+
expect(history.finishRun).not.toHaveBeenCalled();
|
|
1153
|
+
expect(updateScheduledTaskState.mock.calls.map((call) => call[2].lastStatus)).not.toContain('success');
|
|
1154
|
+
expect(emitTaskRunEvent.mock.calls.filter((call) => call[0].status === 'success')).toHaveLength(successEmitsBefore);
|
|
1155
|
+
|
|
1156
|
+
await vi.advanceTimersByTimeAsync(1_000);
|
|
1157
|
+
const result = await runPromise;
|
|
1158
|
+
expect(result.ok).toBe(true);
|
|
1159
|
+
|
|
1160
|
+
vi.unstubAllGlobals();
|
|
1161
|
+
vi.useRealTimers();
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
it('does not correct lastStatus when it is already success', async () => {
|
|
1165
|
+
const history = createHistoryStore();
|
|
1166
|
+
const client = createSuccessfulClient();
|
|
1167
|
+
const fetchMock = vi.fn(async (url) => {
|
|
1168
|
+
if (String(url).includes('prompt_async')) {
|
|
1169
|
+
return { ok: true, text: async () => '' };
|
|
1170
|
+
}
|
|
1171
|
+
throw new Error(`unexpected fetch ${url}`);
|
|
1172
|
+
});
|
|
1173
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
1174
|
+
|
|
1175
|
+
const emitTaskRunEvent = vi.fn();
|
|
1176
|
+
const updateScheduledTaskState = vi.fn(async (_projectID, _taskID, state) => ({
|
|
1177
|
+
task: { ...scheduledTask, state: { ...scheduledTask.state, ...state } },
|
|
1178
|
+
}));
|
|
1179
|
+
const runtime = createRuntime(updateScheduledTaskState, {
|
|
1180
|
+
runHistoryStore: history,
|
|
1181
|
+
waitForOpenCodeReady: vi.fn(async () => {}),
|
|
1182
|
+
emitTaskRunEvent,
|
|
1183
|
+
});
|
|
1184
|
+
await runtime.syncProject('project-1');
|
|
1185
|
+
const result = await runtime.runNow('project-1', 'task-1');
|
|
1186
|
+
expect(result.ok).toBe(true);
|
|
1187
|
+
expect(history.finishRun).toHaveBeenCalledTimes(1);
|
|
1188
|
+
const stateWritesAfterRun = updateScheduledTaskState.mock.calls.length;
|
|
1189
|
+
const successEmitsAfterRun = emitTaskRunEvent.mock.calls.filter((call) => call[0].status === 'success').length;
|
|
1190
|
+
|
|
1191
|
+
client.messages.mockImplementation(async () => ({
|
|
1192
|
+
data: [{
|
|
1193
|
+
info: {
|
|
1194
|
+
id: 'msg_ok',
|
|
1195
|
+
role: 'assistant',
|
|
1196
|
+
time: { completed: Date.now() },
|
|
1197
|
+
},
|
|
1198
|
+
}],
|
|
1199
|
+
}));
|
|
1200
|
+
|
|
1201
|
+
await runtime.observeSessionEvent({
|
|
1202
|
+
payload: {
|
|
1203
|
+
type: 'session.status',
|
|
1204
|
+
properties: {
|
|
1205
|
+
sessionID: 'ses_1',
|
|
1206
|
+
status: { type: 'idle' },
|
|
1207
|
+
},
|
|
1208
|
+
},
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
expect(history.finishRun).toHaveBeenCalledTimes(1);
|
|
1212
|
+
expect(updateScheduledTaskState).toHaveBeenCalledTimes(stateWritesAfterRun);
|
|
1213
|
+
expect(emitTaskRunEvent.mock.calls.filter((call) => call[0].status === 'success')).toHaveLength(successEmitsAfterRun);
|
|
1214
|
+
|
|
1215
|
+
vi.unstubAllGlobals();
|
|
1216
|
+
});
|
|
996
1217
|
});
|