@sumicom/quicksave 0.8.6 → 0.8.7
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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/ai/asyncQueue.d.ts.map +1 -1
- package/dist/ai/asyncQueue.js +2 -0
- package/dist/ai/asyncQueue.js.map +1 -1
- package/dist/ai/attachmentStaging.d.ts +71 -0
- package/dist/ai/attachmentStaging.d.ts.map +1 -0
- package/dist/ai/attachmentStaging.js +243 -0
- package/dist/ai/attachmentStaging.js.map +1 -0
- package/dist/ai/attachmentStore.d.ts +40 -0
- package/dist/ai/attachmentStore.d.ts.map +1 -0
- package/dist/ai/attachmentStore.js +173 -0
- package/dist/ai/attachmentStore.js.map +1 -0
- package/dist/ai/cardBuilder.d.ts +3 -2
- package/dist/ai/cardBuilder.d.ts.map +1 -1
- package/dist/ai/cardBuilder.js +156 -5
- package/dist/ai/cardBuilder.js.map +1 -1
- package/dist/ai/claudeCliProvider.d.ts +7 -2
- package/dist/ai/claudeCliProvider.d.ts.map +1 -1
- package/dist/ai/claudeCliProvider.js +29 -11
- package/dist/ai/claudeCliProvider.js.map +1 -1
- package/dist/ai/claudeCodeProvider.d.ts.map +1 -1
- package/dist/ai/claudeCodeProvider.js +2 -0
- package/dist/ai/claudeCodeProvider.js.map +1 -1
- package/dist/ai/claudeSdkProvider.d.ts +2 -1
- package/dist/ai/claudeSdkProvider.d.ts.map +1 -1
- package/dist/ai/claudeSdkProvider.js +76 -12
- package/dist/ai/claudeSdkProvider.js.map +1 -1
- package/dist/ai/codexAppServer/approvalMapping.d.ts.map +1 -1
- package/dist/ai/codexAppServer/approvalMapping.js.map +1 -1
- package/dist/ai/codexAppServer/cardAdapter.d.ts.map +1 -1
- package/dist/ai/codexAppServer/cardAdapter.js.map +1 -1
- package/dist/ai/codexAppServer/index.d.ts.map +1 -1
- package/dist/ai/codexAppServer/index.js +2 -0
- package/dist/ai/codexAppServer/index.js.map +1 -1
- package/dist/ai/codexAppServer/overrideStore.d.ts.map +1 -1
- package/dist/ai/codexAppServer/overrideStore.js.map +1 -1
- package/dist/ai/codexAppServer/permissionMapping.d.ts.map +1 -1
- package/dist/ai/codexAppServer/permissionMapping.js.map +1 -1
- package/dist/ai/codexAppServer/processManager.d.ts.map +1 -1
- package/dist/ai/codexAppServer/processManager.js +2 -0
- package/dist/ai/codexAppServer/processManager.js.map +1 -1
- package/dist/ai/codexAppServer/provider.d.ts.map +1 -1
- package/dist/ai/codexAppServer/provider.js.map +1 -1
- package/dist/ai/codexAppServer/rpcClient.d.ts.map +1 -1
- package/dist/ai/codexAppServer/rpcClient.js.map +1 -1
- package/dist/ai/codexAppServer/schema/index.d.ts.map +1 -1
- package/dist/ai/codexAppServer/schema/index.js +2 -0
- package/dist/ai/codexAppServer/schema/index.js.map +1 -1
- package/dist/ai/codexAppServer/stdioTransport.d.ts.map +1 -1
- package/dist/ai/codexAppServer/stdioTransport.js.map +1 -1
- package/dist/ai/codexAppServer/tokenAccounting.d.ts.map +1 -1
- package/dist/ai/codexAppServer/tokenAccounting.js.map +1 -1
- package/dist/ai/codexAppServer/version.d.ts.map +1 -1
- package/dist/ai/codexAppServer/version.js +2 -0
- package/dist/ai/codexAppServer/version.js.map +1 -1
- package/dist/ai/codexLogin.d.ts.map +1 -1
- package/dist/ai/codexLogin.js +2 -0
- package/dist/ai/codexLogin.js.map +1 -1
- package/dist/ai/codexMcpProvider.d.ts.map +1 -1
- package/dist/ai/codexMcpProvider.js +2 -0
- package/dist/ai/codexMcpProvider.js.map +1 -1
- package/dist/ai/commitSummary.d.ts.map +1 -1
- package/dist/ai/commitSummary.js +2 -0
- package/dist/ai/commitSummary.js.map +1 -1
- package/dist/ai/commitSummaryCli.d.ts.map +1 -1
- package/dist/ai/commitSummaryCli.js +2 -0
- package/dist/ai/commitSummaryCli.js.map +1 -1
- package/dist/ai/commitSummaryStore.d.ts.map +1 -1
- package/dist/ai/commitSummaryStore.js +2 -0
- package/dist/ai/commitSummaryStore.js.map +1 -1
- package/dist/ai/contentBlocks.d.ts +9 -0
- package/dist/ai/contentBlocks.d.ts.map +1 -0
- package/dist/ai/contentBlocks.js +86 -0
- package/dist/ai/contentBlocks.js.map +1 -0
- package/dist/ai/debugLogger.d.ts.map +1 -1
- package/dist/ai/debugLogger.js +2 -0
- package/dist/ai/debugLogger.js.map +1 -1
- package/dist/ai/enrichEntry.d.ts.map +1 -1
- package/dist/ai/enrichEntry.js.map +1 -1
- package/dist/ai/pdfMeta.d.ts +8 -0
- package/dist/ai/pdfMeta.d.ts.map +1 -0
- package/dist/ai/pdfMeta.js +51 -0
- package/dist/ai/pdfMeta.js.map +1 -0
- package/dist/ai/provider.d.ts +14 -6
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js.map +1 -1
- package/dist/ai/sandboxMcp.d.ts.map +1 -1
- package/dist/ai/sandboxMcp.js +2 -0
- package/dist/ai/sandboxMcp.js.map +1 -1
- package/dist/ai/sandboxMcpStdio.d.ts.map +1 -1
- package/dist/ai/sandboxMcpStdio.js +2 -0
- package/dist/ai/sandboxMcpStdio.js.map +1 -1
- package/dist/ai/sessionManager.d.ts +12 -2
- package/dist/ai/sessionManager.d.ts.map +1 -1
- package/dist/ai/sessionManager.js +39 -5
- package/dist/ai/sessionManager.js.map +1 -1
- package/dist/ai/sessionRegistry.d.ts.map +1 -1
- package/dist/ai/sessionRegistry.js +2 -0
- package/dist/ai/sessionRegistry.js.map +1 -1
- package/dist/ai/sessionStore.d.ts.map +1 -1
- package/dist/ai/sessionStore.js +2 -0
- package/dist/ai/sessionStore.js.map +1 -1
- package/dist/ai/systemPrompt.d.ts.map +1 -1
- package/dist/ai/systemPrompt.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/connection/connection.d.ts.map +1 -1
- package/dist/connection/connection.js +2 -0
- package/dist/connection/connection.js.map +1 -1
- package/dist/connection/e2eHarness.d.ts.map +1 -1
- package/dist/connection/e2eHarness.js +2 -0
- package/dist/connection/e2eHarness.js.map +1 -1
- package/dist/connection/fakeRelay.d.ts.map +1 -1
- package/dist/connection/fakeRelay.js +2 -0
- package/dist/connection/fakeRelay.js.map +1 -1
- package/dist/connection/pubsub.d.ts.map +1 -1
- package/dist/connection/pubsub.js +2 -0
- package/dist/connection/pubsub.js.map +1 -1
- package/dist/connection/relay.d.ts.map +1 -1
- package/dist/connection/relay.js +2 -0
- package/dist/connection/relay.js.map +1 -1
- package/dist/files/fileBrowser.d.ts.map +1 -1
- package/dist/files/fileBrowser.js +2 -0
- package/dist/files/fileBrowser.js.map +1 -1
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +2 -0
- package/dist/git/operations.js.map +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts +1 -1
- package/dist/handlers/legacyBusAdapter.d.ts.map +1 -1
- package/dist/handlers/legacyBusAdapter.js +13 -1
- package/dist/handlers/legacyBusAdapter.js.map +1 -1
- package/dist/handlers/messageHandler.d.ts +23 -0
- package/dist/handlers/messageHandler.d.ts.map +1 -1
- package/dist/handlers/messageHandler.js +223 -7
- package/dist/handlers/messageHandler.js.map +1 -1
- package/dist/index.js +42 -2
- package/dist/index.js.map +1 -1
- package/dist/messageBus/busServerTransport.d.ts.map +1 -1
- package/dist/messageBus/busServerTransport.js +2 -0
- package/dist/messageBus/busServerTransport.js.map +1 -1
- package/dist/service/debugHttpServer.d.ts.map +1 -1
- package/dist/service/debugHttpServer.js +2 -0
- package/dist/service/debugHttpServer.js.map +1 -1
- package/dist/service/ensureDaemon.d.ts.map +1 -1
- package/dist/service/ensureDaemon.js +27 -2
- package/dist/service/ensureDaemon.js.map +1 -1
- package/dist/service/index.d.ts.map +1 -1
- package/dist/service/index.js +2 -0
- package/dist/service/index.js.map +1 -1
- package/dist/service/ipcClient.d.ts.map +1 -1
- package/dist/service/ipcClient.js +3 -1
- package/dist/service/ipcClient.js.map +1 -1
- package/dist/service/ipcServer.d.ts.map +1 -1
- package/dist/service/ipcServer.js +2 -0
- package/dist/service/ipcServer.js.map +1 -1
- package/dist/service/pushClient.d.ts.map +1 -1
- package/dist/service/pushClient.js +2 -0
- package/dist/service/pushClient.js.map +1 -1
- package/dist/service/run.d.ts.map +1 -1
- package/dist/service/run.js +14 -1
- package/dist/service/run.js.map +1 -1
- package/dist/service/singleton.d.ts +1 -0
- package/dist/service/singleton.d.ts.map +1 -1
- package/dist/service/singleton.js +5 -0
- package/dist/service/singleton.js.map +1 -1
- package/dist/service/stateStore.d.ts.map +1 -1
- package/dist/service/stateStore.js +2 -0
- package/dist/service/stateStore.js.map +1 -1
- package/dist/service/systemdUnit.d.ts +149 -0
- package/dist/service/systemdUnit.d.ts.map +1 -0
- package/dist/service/systemdUnit.js +322 -0
- package/dist/service/systemdUnit.js.map +1 -0
- package/dist/service/types.d.ts +6 -0
- package/dist/service/types.d.ts.map +1 -1
- package/dist/service/types.js +3 -1
- package/dist/service/types.js.map +1 -1
- package/dist/storage/eventStore.d.ts.map +1 -1
- package/dist/storage/eventStore.js +2 -0
- package/dist/storage/eventStore.js.map +1 -1
- package/dist/terminal/terminalManager.d.ts.map +1 -1
- package/dist/terminal/terminalManager.js +2 -0
- package/dist/terminal/terminalManager.js.map +1 -1
- package/dist/tombstoneCheck.d.ts.map +1 -1
- package/dist/tombstoneCheck.js +2 -0
- package/dist/tombstoneCheck.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 King Young Technology
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
1
3
|
import { createMessage, } from '@sumicom/quicksave-shared';
|
|
2
4
|
/**
|
|
3
5
|
* Verbs from the legacy `MessageHandler` switch that are exposed as bus
|
|
@@ -11,7 +13,7 @@ import { createMessage, } from '@sumicom/quicksave-shared';
|
|
|
11
13
|
* touching:
|
|
12
14
|
* 1. `messageHandler.ts` switch (the handler itself)
|
|
13
15
|
* 2. This array (the bus exposure)
|
|
14
|
-
* 3. The relevant docs (`docs/references/quicksave-architecture.md`)
|
|
16
|
+
* 3. The relevant docs (`docs/references/quicksave-architecture.en.md`)
|
|
15
17
|
*/
|
|
16
18
|
export const LEGACY_BUS_VERBS = [
|
|
17
19
|
'ping',
|
|
@@ -52,6 +54,10 @@ export const LEGACY_BUS_VERBS = [
|
|
|
52
54
|
'agent:check-update',
|
|
53
55
|
'agent:update',
|
|
54
56
|
'agent:restart',
|
|
57
|
+
// systemd user-unit (Linux only — agent returns available:false elsewhere)
|
|
58
|
+
'systemd:status',
|
|
59
|
+
'systemd:install',
|
|
60
|
+
'systemd:uninstall',
|
|
55
61
|
// codex
|
|
56
62
|
'codex:list-models',
|
|
57
63
|
'codex:login-start',
|
|
@@ -73,6 +79,7 @@ export const LEGACY_BUS_VERBS = [
|
|
|
73
79
|
'session:update-history',
|
|
74
80
|
'session:delete-history',
|
|
75
81
|
'session:list-archived',
|
|
82
|
+
'session:mark-read',
|
|
76
83
|
// project
|
|
77
84
|
'project:list-summaries',
|
|
78
85
|
'project:list-repos',
|
|
@@ -88,6 +95,10 @@ export const LEGACY_BUS_VERBS = [
|
|
|
88
95
|
// files
|
|
89
96
|
'files:list',
|
|
90
97
|
'files:read',
|
|
98
|
+
// attachments
|
|
99
|
+
'attachment:upload',
|
|
100
|
+
'attachment:cancel',
|
|
101
|
+
'attachment:fetch',
|
|
91
102
|
];
|
|
92
103
|
/**
|
|
93
104
|
* Bridge legacy `MessageHandler` request/response verbs onto a
|
|
@@ -105,6 +116,7 @@ export const LEGACY_BUS_VERBS = [
|
|
|
105
116
|
* callers can `String#startsWith` to detect specific codes.
|
|
106
117
|
*/
|
|
107
118
|
export function wireLegacyBusVerbs(bus, handler, verbs = LEGACY_BUS_VERBS) {
|
|
119
|
+
console.log(`[legacy-bus] wiring ${verbs.length} verbs; attachment* present: ${verbs.filter(v => v.startsWith('attachment:')).join(',') || 'NONE'}`);
|
|
108
120
|
for (const verb of verbs) {
|
|
109
121
|
bus.onCommand(verb, async (rawPayload, { peer }) => {
|
|
110
122
|
let repoPath;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacyBusAdapter.js","sourceRoot":"","sources":["../../src/handlers/legacyBusAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAEd,MAAM,2BAA2B,CAAC;AAInC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAkB;IAC7C,MAAM;IACN,MAAM;IACN,YAAY;IACZ,UAAU;IACV,WAAW;IACX,aAAa;IACb,iBAAiB;IACjB,mBAAmB;IACnB,YAAY;IACZ,SAAS;IACT,cAAc;IACd,cAAc;IACd,aAAa;IACb,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,gBAAgB;IAChB,mBAAmB;IACnB,oBAAoB;IACpB,qBAAqB;IACrB,KAAK;IACL,4BAA4B;IAC5B,yBAAyB;IACzB,gBAAgB;IAChB,uBAAuB;IACvB,QAAQ;IACR,kBAAkB;IAClB,mBAAmB;IACnB,wBAAwB;IACxB,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;IAClB,yBAAyB;IACzB,uBAAuB;IACvB,0BAA0B;IAC1B,oBAAoB;IACpB,cAAc;IACd,eAAe;IACf,QAAQ;IACR,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;IACpB,oBAAoB;IACpB,SAAS;IACT,cAAc;IACd,eAAe;IACf,eAAe;IACf,cAAc;IACd,iBAAiB;IACjB,4BAA4B;IAC5B,wBAAwB;IACxB,+BAA+B;IAC/B,kBAAkB;IAClB,UAAU;IACV,oBAAoB;IACpB,yBAAyB;IACzB,wBAAwB;IACxB,wBAAwB;IACxB,uBAAuB;IACvB,UAAU;IACV,wBAAwB;IACxB,oBAAoB;IACpB,gBAAgB;IAChB,OAAO;IACP,yBAAyB;IACzB,WAAW;IACX,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,QAAQ;IACR,YAAY;IACZ,YAAY;
|
|
1
|
+
{"version":3,"file":"legacyBusAdapter.js","sourceRoot":"","sources":["../../src/handlers/legacyBusAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { Message, License, Repository, SessionRegistryEntry, AgentId, CodexModel
|
|
|
2
2
|
import type { PushClient } from '../service/pushClient.js';
|
|
3
3
|
import { CommitSummaryStateStore } from '../ai/commitSummaryStore.js';
|
|
4
4
|
import { SessionManager } from '../ai/sessionManager.js';
|
|
5
|
+
import { AttachmentStaging } from '../ai/attachmentStaging.js';
|
|
5
6
|
import { CodexLoginManager } from '../ai/codexLogin.js';
|
|
6
7
|
export declare class MessageHandler {
|
|
7
8
|
private repos;
|
|
@@ -17,6 +18,8 @@ export declare class MessageHandler {
|
|
|
17
18
|
* `state-updated` event to `connection.broadcast` (see service/run.ts). */
|
|
18
19
|
private commitSummaryStore;
|
|
19
20
|
private claudeService;
|
|
21
|
+
private attachmentStaging;
|
|
22
|
+
private attachmentGcTimer;
|
|
20
23
|
private pushClient;
|
|
21
24
|
private latestVersionCache;
|
|
22
25
|
private versionCheckInFlight;
|
|
@@ -172,6 +175,9 @@ export declare class MessageHandler {
|
|
|
172
175
|
private handleAgentCheckUpdate;
|
|
173
176
|
private handleAgentUpdate;
|
|
174
177
|
private handleAgentRestart;
|
|
178
|
+
private handleSystemdStatus;
|
|
179
|
+
private handleSystemdInstall;
|
|
180
|
+
private handleSystemdUninstall;
|
|
175
181
|
private handleCodexListModels;
|
|
176
182
|
/**
|
|
177
183
|
* Kick off the Codex device-auth OAuth flow on the daemon. Returns the
|
|
@@ -208,6 +214,18 @@ export declare class MessageHandler {
|
|
|
208
214
|
private handleUpdateHistory;
|
|
209
215
|
private handleDeleteHistory;
|
|
210
216
|
private handleListArchived;
|
|
217
|
+
/**
|
|
218
|
+
* Stamp `lastReadAt` on a registry entry and broadcast the update so every
|
|
219
|
+
* connected PWA client converges on the same read state. The "unread" mark
|
|
220
|
+
* lives server-side under the user's group identity (see
|
|
221
|
+
* `docs/guidelines/sync-security.en.md`) — there's no per-device scoping,
|
|
222
|
+
* so reading on the phone clears the badge on the desktop too.
|
|
223
|
+
*
|
|
224
|
+
* Idempotent: late-arriving / out-of-order viewedAt values that are older
|
|
225
|
+
* than the persisted timestamp are dropped (max-wins) so a slow tab can't
|
|
226
|
+
* undo a fresh read from a faster one.
|
|
227
|
+
*/
|
|
228
|
+
private handleMarkRead;
|
|
211
229
|
private handleListProjectSummaries;
|
|
212
230
|
private handleListProjectRepos;
|
|
213
231
|
/**
|
|
@@ -236,6 +254,11 @@ export declare class MessageHandler {
|
|
|
236
254
|
private handleTerminalRename;
|
|
237
255
|
private handleFilesList;
|
|
238
256
|
private handleFilesRead;
|
|
257
|
+
/** Exposed so other agent paths (sessionManager) can resolve staged ids. */
|
|
258
|
+
getAttachmentStaging(): AttachmentStaging;
|
|
259
|
+
private handleAttachmentUpload;
|
|
260
|
+
private handleAttachmentCancel;
|
|
261
|
+
private handleAttachmentFetch;
|
|
239
262
|
private createErrorResponse;
|
|
240
263
|
}
|
|
241
264
|
//# sourceMappingURL=messageHandler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/messageHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"messageHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/messageHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 King Young Technology
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
1
3
|
import { createMessage, } from '@sumicom/quicksave-shared';
|
|
4
|
+
import { getSystemdStatus, installUserUnit, uninstallUserUnit, systemctlAvailable, } from '../service/systemdUnit.js';
|
|
2
5
|
import { GitOperations } from '../git/operations.js';
|
|
3
6
|
import { getAnthropicApiKey, setAnthropicApiKey, hasAnthropicApiKey, addManagedRepo, removeManagedRepo, addManagedCodingPath, removeManagedCodingPath } from '../config.js';
|
|
4
7
|
import { CommitSummaryService } from '../ai/commitSummary.js';
|
|
@@ -6,6 +9,8 @@ import { CommitSummaryCliService, CommitSummaryCliError } from '../ai/commitSumm
|
|
|
6
9
|
import { CommitSummaryStateStore } from '../ai/commitSummaryStore.js';
|
|
7
10
|
import { SessionManager } from '../ai/sessionManager.js';
|
|
8
11
|
import { ClaudeCodeProvider } from '../ai/claudeCodeProvider.js';
|
|
12
|
+
import { AttachmentStaging } from '../ai/attachmentStaging.js';
|
|
13
|
+
import { loadAttachment, removeSessionAttachments } from '../ai/attachmentStore.js';
|
|
9
14
|
import { CodexAppServerProvider } from '../ai/codexAppServer/index.js';
|
|
10
15
|
import { CodexLoginManager } from '../ai/codexLogin.js';
|
|
11
16
|
import { getTerminalManager } from '../terminal/terminalManager.js';
|
|
@@ -16,7 +21,7 @@ import { getEventStore } from '../storage/eventStore.js';
|
|
|
16
21
|
import { readdir, stat, readFile } from 'fs/promises';
|
|
17
22
|
import { existsSync } from 'fs';
|
|
18
23
|
import { join, dirname, basename } from 'path';
|
|
19
|
-
import { homedir } from 'os';
|
|
24
|
+
import { homedir, platform as osPlatform } from 'os';
|
|
20
25
|
import { spawnAppServer } from '../ai/codexAppServer/index.js';
|
|
21
26
|
const VERSION_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000; // 12 hours
|
|
22
27
|
// model/list reflects the current authenticated account's available models.
|
|
@@ -24,6 +29,14 @@ const VERSION_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000; // 12 hours
|
|
|
24
29
|
// every PWA reload; short enough that plan upgrades / model rollouts surface
|
|
25
30
|
// within the same session day. Force-refreshes still bypass the TTL.
|
|
26
31
|
const CODEX_MODELS_TTL_MS = 30 * 60 * 1000;
|
|
32
|
+
/** Coerce `os.platform()` into the narrow union the PWA expects. Anything
|
|
33
|
+
* outside the three first-class platforms gets `'other'` so the field is
|
|
34
|
+
* always present and the PWA doesn't have to handle `undefined`. */
|
|
35
|
+
function normalizePlatform(p) {
|
|
36
|
+
if (p === 'linux' || p === 'darwin' || p === 'win32')
|
|
37
|
+
return p;
|
|
38
|
+
return 'other';
|
|
39
|
+
}
|
|
27
40
|
/** Shallow equality on a model list. Used to suppress no-op
|
|
28
41
|
* `/codex/models` broadcasts after a TTL refresh that returned the
|
|
29
42
|
* same list. */
|
|
@@ -74,7 +87,7 @@ function projectAppServerModel(m) {
|
|
|
74
87
|
}
|
|
75
88
|
export class MessageHandler {
|
|
76
89
|
repos;
|
|
77
|
-
agentVersion = '0.8.
|
|
90
|
+
agentVersion = '0.8.7';
|
|
78
91
|
defaultRepoPath;
|
|
79
92
|
clientRepos = new Map(); // peerAddress -> repoPath
|
|
80
93
|
repoLocks = new Map(); // repoPath -> peerAddress holding lock
|
|
@@ -86,6 +99,8 @@ export class MessageHandler {
|
|
|
86
99
|
* `state-updated` event to `connection.broadcast` (see service/run.ts). */
|
|
87
100
|
commitSummaryStore = new CommitSummaryStateStore();
|
|
88
101
|
claudeService;
|
|
102
|
+
attachmentStaging = new AttachmentStaging();
|
|
103
|
+
attachmentGcTimer = null;
|
|
89
104
|
pushClient = null;
|
|
90
105
|
latestVersionCache = null;
|
|
91
106
|
versionCheckInFlight = null;
|
|
@@ -117,6 +132,10 @@ export class MessageHandler {
|
|
|
117
132
|
this.codingPaths.set(p, { path: p, name: basename(p) });
|
|
118
133
|
}
|
|
119
134
|
}
|
|
135
|
+
this.attachmentGcTimer = setInterval(() => this.attachmentStaging.gc(), 60_000);
|
|
136
|
+
if (typeof this.attachmentGcTimer.unref === 'function') {
|
|
137
|
+
this.attachmentGcTimer.unref();
|
|
138
|
+
}
|
|
120
139
|
}
|
|
121
140
|
/**
|
|
122
141
|
* Check npm registry for latest version. Deduped: returns cached value
|
|
@@ -359,10 +378,17 @@ export class MessageHandler {
|
|
|
359
378
|
this.repoLocks.delete(repoPath);
|
|
360
379
|
}
|
|
361
380
|
}
|
|
381
|
+
// Drop any in-flight uploads from this peer; on reconnect the PWA will
|
|
382
|
+
// re-stage them via the upload manager's resume path.
|
|
383
|
+
this.attachmentStaging.removePeer(peerAddress);
|
|
362
384
|
// Pending user input requests are NOT auto-approved on disconnect.
|
|
363
385
|
// They persist until the user reconnects and explicitly responds.
|
|
364
386
|
}
|
|
365
387
|
cleanup() {
|
|
388
|
+
if (this.attachmentGcTimer) {
|
|
389
|
+
clearInterval(this.attachmentGcTimer);
|
|
390
|
+
this.attachmentGcTimer = null;
|
|
391
|
+
}
|
|
366
392
|
this.claudeService.cleanup();
|
|
367
393
|
}
|
|
368
394
|
getActiveSessionCount() {
|
|
@@ -397,7 +423,8 @@ export class MessageHandler {
|
|
|
397
423
|
async handleMessage(message, peerAddress = 'default') {
|
|
398
424
|
const isVerbose = message.type.startsWith('claude:') ||
|
|
399
425
|
message.type.startsWith('agent:add') ||
|
|
400
|
-
message.type.startsWith('project:')
|
|
426
|
+
message.type.startsWith('project:') ||
|
|
427
|
+
message.type.startsWith('attachment:');
|
|
401
428
|
if (isVerbose) {
|
|
402
429
|
console.log(`[msg] ${message.type} from ${peerAddress.slice(0, 12)}`);
|
|
403
430
|
}
|
|
@@ -498,6 +525,12 @@ export class MessageHandler {
|
|
|
498
525
|
return this.handleAgentUpdate(message);
|
|
499
526
|
case 'agent:restart':
|
|
500
527
|
return this.handleAgentRestart(message);
|
|
528
|
+
case 'systemd:status':
|
|
529
|
+
return this.handleSystemdStatus(message);
|
|
530
|
+
case 'systemd:install':
|
|
531
|
+
return this.handleSystemdInstall(message);
|
|
532
|
+
case 'systemd:uninstall':
|
|
533
|
+
return this.handleSystemdUninstall(message);
|
|
501
534
|
case 'codex:list-models':
|
|
502
535
|
return this.handleCodexListModels(message);
|
|
503
536
|
case 'codex:login-start':
|
|
@@ -535,6 +568,8 @@ export class MessageHandler {
|
|
|
535
568
|
return this.handleDeleteHistory(message);
|
|
536
569
|
case 'session:list-archived':
|
|
537
570
|
return this.handleListArchived(message);
|
|
571
|
+
case 'session:mark-read':
|
|
572
|
+
return this.handleMarkRead(message);
|
|
538
573
|
case 'project:list-summaries':
|
|
539
574
|
return this.handleListProjectSummaries(message);
|
|
540
575
|
case 'project:list-repos':
|
|
@@ -557,6 +592,12 @@ export class MessageHandler {
|
|
|
557
592
|
return this.handleFilesList(message);
|
|
558
593
|
case 'files:read':
|
|
559
594
|
return this.handleFilesRead(message);
|
|
595
|
+
case 'attachment:upload':
|
|
596
|
+
return this.handleAttachmentUpload(message, peerAddress);
|
|
597
|
+
case 'attachment:cancel':
|
|
598
|
+
return this.handleAttachmentCancel(message, peerAddress);
|
|
599
|
+
case 'attachment:fetch':
|
|
600
|
+
return this.handleAttachmentFetch(message);
|
|
560
601
|
default:
|
|
561
602
|
return this.createErrorResponse(message.id, 'UNKNOWN_MESSAGE_TYPE', `Unknown message type: ${message.type}`);
|
|
562
603
|
}
|
|
@@ -575,6 +616,7 @@ export class MessageHandler {
|
|
|
575
616
|
latestVersion: this.latestVersionCache?.version,
|
|
576
617
|
devBuild: !this.productionBuild || undefined,
|
|
577
618
|
codexModels: this.codexModelsCache?.models,
|
|
619
|
+
platform: normalizePlatform(osPlatform()),
|
|
578
620
|
});
|
|
579
621
|
response.id = message.id;
|
|
580
622
|
return response;
|
|
@@ -1506,6 +1548,77 @@ export class MessageHandler {
|
|
|
1506
1548
|
return response;
|
|
1507
1549
|
}
|
|
1508
1550
|
}
|
|
1551
|
+
// ==========================================================================
|
|
1552
|
+
// systemd user-unit (Linux auto-start at login)
|
|
1553
|
+
//
|
|
1554
|
+
// The PWA toggles install/uninstall from the per-machine settings page.
|
|
1555
|
+
// These handlers are no-ops on non-Linux hosts (the status payload's
|
|
1556
|
+
// `available: false` field is the gate the PWA uses to hide the section,
|
|
1557
|
+
// so non-Linux still gets a well-formed response instead of an error).
|
|
1558
|
+
// ==========================================================================
|
|
1559
|
+
handleSystemdStatus(message) {
|
|
1560
|
+
const status = getSystemdStatus();
|
|
1561
|
+
const response = createMessage('systemd:status:response', status);
|
|
1562
|
+
response.id = message.id;
|
|
1563
|
+
return response;
|
|
1564
|
+
}
|
|
1565
|
+
handleSystemdInstall(message) {
|
|
1566
|
+
if (!systemctlAvailable()) {
|
|
1567
|
+
const response = createMessage('systemd:install:response', {
|
|
1568
|
+
success: false,
|
|
1569
|
+
error: 'systemctl --user is not available on this host',
|
|
1570
|
+
status: getSystemdStatus(),
|
|
1571
|
+
});
|
|
1572
|
+
response.id = message.id;
|
|
1573
|
+
return response;
|
|
1574
|
+
}
|
|
1575
|
+
const result = installUserUnit();
|
|
1576
|
+
const response = createMessage('systemd:install:response', result);
|
|
1577
|
+
response.id = message.id;
|
|
1578
|
+
return response;
|
|
1579
|
+
}
|
|
1580
|
+
handleSystemdUninstall(message) {
|
|
1581
|
+
// Uninstalling can stop the systemd-managed daemon as a side effect — if
|
|
1582
|
+
// the running process IS that daemon, `disable --now` would kill our IPC
|
|
1583
|
+
// server before the response reaches the PWA. So we compute the response
|
|
1584
|
+
// up front (which captures the pre-uninstall status) but defer the
|
|
1585
|
+
// actual mutation until next tick, giving the bus transport a chance to
|
|
1586
|
+
// flush. The next CLI invocation will hit `ensureDaemon`, which falls
|
|
1587
|
+
// back to detached spawn now that the unit is gone.
|
|
1588
|
+
if (!systemctlAvailable()) {
|
|
1589
|
+
const response = createMessage('systemd:uninstall:response', {
|
|
1590
|
+
success: false,
|
|
1591
|
+
error: 'systemctl --user is not available on this host',
|
|
1592
|
+
status: getSystemdStatus(),
|
|
1593
|
+
});
|
|
1594
|
+
response.id = message.id;
|
|
1595
|
+
return response;
|
|
1596
|
+
}
|
|
1597
|
+
setImmediate(() => {
|
|
1598
|
+
try {
|
|
1599
|
+
uninstallUserUnit();
|
|
1600
|
+
}
|
|
1601
|
+
catch (err) {
|
|
1602
|
+
console.error('[systemd] deferred uninstall failed:', err);
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
// Optimistic response: report the post-uninstall shape (unitInstalled,
|
|
1606
|
+
// unitEnabled, isActive all expected to flip false). We can't actually
|
|
1607
|
+
// observe the post state because we haven't run the disable yet.
|
|
1608
|
+
const optimistic = getSystemdStatus();
|
|
1609
|
+
const response = createMessage('systemd:uninstall:response', {
|
|
1610
|
+
success: true,
|
|
1611
|
+
status: {
|
|
1612
|
+
...optimistic,
|
|
1613
|
+
unitInstalled: false,
|
|
1614
|
+
unitEnabled: false,
|
|
1615
|
+
isActive: false,
|
|
1616
|
+
currentExecStart: undefined,
|
|
1617
|
+
},
|
|
1618
|
+
});
|
|
1619
|
+
response.id = message.id;
|
|
1620
|
+
return response;
|
|
1621
|
+
}
|
|
1509
1622
|
async handleCodexListModels(message) {
|
|
1510
1623
|
try {
|
|
1511
1624
|
const [models, auth] = await Promise.all([
|
|
@@ -1558,7 +1671,7 @@ export class MessageHandler {
|
|
|
1558
1671
|
// Claude Code SDK Handlers
|
|
1559
1672
|
// ============================================================================
|
|
1560
1673
|
async handleClaudeStart(message, peerAddress) {
|
|
1561
|
-
const { prompt, cwd: payloadCwd, agent, allowedTools, systemPrompt, model, permissionMode, sandboxed, reasoningEffort, contextWindow } = message.payload;
|
|
1674
|
+
const { prompt, cwd: payloadCwd, agent, allowedTools, systemPrompt, model, permissionMode, sandboxed, reasoningEffort, contextWindow, attachmentIds } = message.payload;
|
|
1562
1675
|
const legacyProvider = message.payload.provider;
|
|
1563
1676
|
const cwd = payloadCwd || this.getClientRepoPath(peerAddress);
|
|
1564
1677
|
const resolvedAgent = agent ?? (legacyProvider === 'codex-mcp' ? 'codex' : legacyProvider ? 'claude-code' : undefined);
|
|
@@ -1568,7 +1681,20 @@ export class MessageHandler {
|
|
|
1568
1681
|
// turn/start with `BadRequest`. Pass-through for non-codex agents and
|
|
1569
1682
|
// when the cache hasn't loaded yet.
|
|
1570
1683
|
const validatedModel = this.validateCodexModel(model, resolvedAgent ?? 'claude-code');
|
|
1571
|
-
console.log(`[agent:start] agent=${resolvedAgent ?? 'default'} model=${validatedModel ?? 'default'}${validatedModel !== model ? ` (coerced from ${model})` : ''} cwd=${cwd} prompt=${prompt.slice(0, 80)}${sandboxed ? ' [sandboxed]' : ''}`);
|
|
1684
|
+
console.log(`[agent:start] agent=${resolvedAgent ?? 'default'} model=${validatedModel ?? 'default'}${validatedModel !== model ? ` (coerced from ${model})` : ''} cwd=${cwd} prompt=${prompt.slice(0, 80)}${sandboxed ? ' [sandboxed]' : ''}${attachmentIds && attachmentIds.length > 0 ? ` [+${attachmentIds.length} attachments]` : ''}`);
|
|
1685
|
+
let attachments;
|
|
1686
|
+
if (attachmentIds && attachmentIds.length > 0) {
|
|
1687
|
+
try {
|
|
1688
|
+
attachments = this.attachmentStaging.consume(peerAddress, attachmentIds);
|
|
1689
|
+
}
|
|
1690
|
+
catch (error) {
|
|
1691
|
+
const code = error.code ?? 'attachment_error';
|
|
1692
|
+
const text = error instanceof Error ? error.message : 'attachment resolve failed';
|
|
1693
|
+
const response = createMessage('claude:start:response', { success: false, error: `${code}: ${text}` });
|
|
1694
|
+
response.id = message.id;
|
|
1695
|
+
return response;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1572
1698
|
try {
|
|
1573
1699
|
const sessionId = await this.claudeService.startSession({
|
|
1574
1700
|
prompt,
|
|
@@ -1581,6 +1707,7 @@ export class MessageHandler {
|
|
|
1581
1707
|
sandboxed,
|
|
1582
1708
|
reasoningEffort,
|
|
1583
1709
|
contextWindow,
|
|
1710
|
+
attachments,
|
|
1584
1711
|
});
|
|
1585
1712
|
console.log(`[agent:start] session created: ${sessionId} agent=${resolvedAgent ?? 'default'}`);
|
|
1586
1713
|
// Register in session history
|
|
@@ -1622,18 +1749,32 @@ export class MessageHandler {
|
|
|
1622
1749
|
}
|
|
1623
1750
|
}
|
|
1624
1751
|
async handleClaudeResume(message, peerAddress) {
|
|
1625
|
-
const { sessionId: requestedId, prompt, cwd: payloadCwd, agent } = message.payload;
|
|
1752
|
+
const { sessionId: requestedId, prompt, cwd: payloadCwd, agent, attachmentIds } = message.payload;
|
|
1626
1753
|
const legacyProvider = message.payload.provider;
|
|
1627
1754
|
const cwd = payloadCwd || this.getClientRepoPath(peerAddress);
|
|
1628
1755
|
const resolvedAgent = agent ?? (legacyProvider === 'codex-mcp' ? 'codex' : legacyProvider ? 'claude-code' : undefined);
|
|
1629
1756
|
const activeCfg = this.claudeService.getSessionConfig(requestedId);
|
|
1630
|
-
console.log(`[agent:resume] session=${requestedId} agent=${resolvedAgent ?? 'stored'} model=${activeCfg.model ?? 'default'} cwd=${cwd} prompt=${prompt.slice(0, 80)}`);
|
|
1757
|
+
console.log(`[agent:resume] session=${requestedId} agent=${resolvedAgent ?? 'stored'} model=${activeCfg.model ?? 'default'} cwd=${cwd} prompt=${prompt.slice(0, 80)}${attachmentIds && attachmentIds.length > 0 ? ` [+${attachmentIds.length} attachments]` : ''}`);
|
|
1758
|
+
let attachments;
|
|
1759
|
+
if (attachmentIds && attachmentIds.length > 0) {
|
|
1760
|
+
try {
|
|
1761
|
+
attachments = this.attachmentStaging.consume(peerAddress, attachmentIds);
|
|
1762
|
+
}
|
|
1763
|
+
catch (error) {
|
|
1764
|
+
const code = error.code ?? 'attachment_error';
|
|
1765
|
+
const text = error instanceof Error ? error.message : 'attachment resolve failed';
|
|
1766
|
+
const response = createMessage('claude:resume:response', { success: false, error: `${code}: ${text}` });
|
|
1767
|
+
response.id = message.id;
|
|
1768
|
+
return response;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1631
1771
|
try {
|
|
1632
1772
|
const actualSessionId = await this.claudeService.resumeSession({
|
|
1633
1773
|
sessionId: requestedId,
|
|
1634
1774
|
prompt,
|
|
1635
1775
|
cwd,
|
|
1636
1776
|
agent: resolvedAgent,
|
|
1777
|
+
attachments,
|
|
1637
1778
|
});
|
|
1638
1779
|
console.log(`[agent:resume] session resumed: ${actualSessionId}`);
|
|
1639
1780
|
getEventStore().record({
|
|
@@ -1708,6 +1849,11 @@ export class MessageHandler {
|
|
|
1708
1849
|
}
|
|
1709
1850
|
}
|
|
1710
1851
|
const closed = this.claudeService.closeSession(sessionId);
|
|
1852
|
+
// Drop persisted attachment bytes for this session — fire-and-forget;
|
|
1853
|
+
// a stuck rm shouldn't block the response.
|
|
1854
|
+
removeSessionAttachments(sessionId).catch((err) => {
|
|
1855
|
+
console.error(`[agent:end-task] removeSessionAttachments failed session=${sessionId}:`, err);
|
|
1856
|
+
});
|
|
1711
1857
|
const success = closed || archived;
|
|
1712
1858
|
console.log(`[agent:end-task] session=${sessionId} closed=${closed} archived=${archived} cwd=${cwd ?? 'unknown'}`);
|
|
1713
1859
|
const response = createMessage('claude:end-task:response', { success, error: success ? undefined : 'Session not found' });
|
|
@@ -1842,6 +1988,42 @@ export class MessageHandler {
|
|
|
1842
1988
|
response.id = message.id;
|
|
1843
1989
|
return response;
|
|
1844
1990
|
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Stamp `lastReadAt` on a registry entry and broadcast the update so every
|
|
1993
|
+
* connected PWA client converges on the same read state. The "unread" mark
|
|
1994
|
+
* lives server-side under the user's group identity (see
|
|
1995
|
+
* `docs/guidelines/sync-security.en.md`) — there's no per-device scoping,
|
|
1996
|
+
* so reading on the phone clears the badge on the desktop too.
|
|
1997
|
+
*
|
|
1998
|
+
* Idempotent: late-arriving / out-of-order viewedAt values that are older
|
|
1999
|
+
* than the persisted timestamp are dropped (max-wins) so a slow tab can't
|
|
2000
|
+
* undo a fresh read from a faster one.
|
|
2001
|
+
*/
|
|
2002
|
+
handleMarkRead(message) {
|
|
2003
|
+
const { sessionId, cwd, viewedAt } = message.payload;
|
|
2004
|
+
const stamp = typeof viewedAt === 'number' ? viewedAt : Date.now();
|
|
2005
|
+
const existing = getSessionRegistry().getEntry(cwd, sessionId);
|
|
2006
|
+
if (!existing) {
|
|
2007
|
+
const failed = createMessage('session:mark-read:response', { success: false, error: 'Entry not found' });
|
|
2008
|
+
failed.id = message.id;
|
|
2009
|
+
return failed;
|
|
2010
|
+
}
|
|
2011
|
+
const nextLastReadAt = Math.max(existing.lastReadAt ?? 0, stamp);
|
|
2012
|
+
let entry = existing;
|
|
2013
|
+
if (nextLastReadAt !== existing.lastReadAt) {
|
|
2014
|
+
const updated = getSessionRegistry().updateEntry(cwd, sessionId, { lastReadAt: nextLastReadAt });
|
|
2015
|
+
if (updated)
|
|
2016
|
+
entry = updated;
|
|
2017
|
+
// Broadcast on /sessions/history so other PWA clients see the new
|
|
2018
|
+
// read state immediately. /sessions/active is also re-emitted via
|
|
2019
|
+
// sessionManager so the live-stats path stays consistent.
|
|
2020
|
+
this.onHistoryUpdated?.(cwd, entry, 'upsert');
|
|
2021
|
+
this.claudeService.emitSessionUpdate(sessionId);
|
|
2022
|
+
}
|
|
2023
|
+
const response = createMessage('session:mark-read:response', { success: true, lastReadAt: entry.lastReadAt });
|
|
2024
|
+
response.id = message.id;
|
|
2025
|
+
return response;
|
|
2026
|
+
}
|
|
1845
2027
|
handleListProjectSummaries(message) {
|
|
1846
2028
|
const allEntries = getSessionRegistry().getEntriesForProject();
|
|
1847
2029
|
// Group by cwd
|
|
@@ -2162,6 +2344,40 @@ export class MessageHandler {
|
|
|
2162
2344
|
response.id = message.id;
|
|
2163
2345
|
return response;
|
|
2164
2346
|
}
|
|
2347
|
+
// ── Attachment staging handlers ──────────────────────────────────────────
|
|
2348
|
+
/** Exposed so other agent paths (sessionManager) can resolve staged ids. */
|
|
2349
|
+
getAttachmentStaging() {
|
|
2350
|
+
return this.attachmentStaging;
|
|
2351
|
+
}
|
|
2352
|
+
handleAttachmentUpload(message, peerAddress) {
|
|
2353
|
+
try {
|
|
2354
|
+
const result = this.attachmentStaging.acceptChunk(peerAddress, message.payload);
|
|
2355
|
+
const response = createMessage('attachment:upload:response', result);
|
|
2356
|
+
response.id = message.id;
|
|
2357
|
+
return response;
|
|
2358
|
+
}
|
|
2359
|
+
catch (error) {
|
|
2360
|
+
const code = error.code ?? 'attachment_error';
|
|
2361
|
+
const text = error instanceof Error ? error.message : 'attachment upload failed';
|
|
2362
|
+
return this.createErrorResponse(message.id, code, text);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
handleAttachmentCancel(message, peerAddress) {
|
|
2366
|
+
const removed = this.attachmentStaging.cancel(peerAddress, message.payload.attachmentId);
|
|
2367
|
+
const response = createMessage('attachment:cancel:response', { removed });
|
|
2368
|
+
response.id = message.id;
|
|
2369
|
+
return response;
|
|
2370
|
+
}
|
|
2371
|
+
async handleAttachmentFetch(message) {
|
|
2372
|
+
const { sessionId, attachmentId } = message.payload;
|
|
2373
|
+
const attachment = await loadAttachment(sessionId, attachmentId);
|
|
2374
|
+
if (!attachment) {
|
|
2375
|
+
return this.createErrorResponse(message.id, 'attachment_not_found', `attachment ${attachmentId} not on disk for session ${sessionId}`);
|
|
2376
|
+
}
|
|
2377
|
+
const response = createMessage('attachment:fetch:response', { attachment });
|
|
2378
|
+
response.id = message.id;
|
|
2379
|
+
return response;
|
|
2380
|
+
}
|
|
2165
2381
|
createErrorResponse(id, code, message) {
|
|
2166
2382
|
const response = createMessage('error', { code, message });
|
|
2167
2383
|
response.id = id;
|