@chatcode/chatcode-cli 3.0.4-rc.1 → 3.0.4-rc.2
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/lib/{command-errors-BkCHTQHj.js → command-errors-CScdshCl.js} +12 -12
- package/lib/{command-trees-5HFyC5sI.js → command-trees-Dc17MYfV.js} +2 -2
- package/lib/{component-identity-De91VHwW.js → component-identity-DFJD_d-P.js} +3 -3
- package/lib/{dist-CsDWUvQ4.js → dist-w_sIm4VD.js} +231 -231
- package/lib/{extension-events-CdYCRP0o.js → extension-events-qXmhzmHo.js} +26 -26
- package/lib/{frames-DOX-Jgk8.js → frames-B89znn_0.js} +4 -4
- package/lib/{host-access-Bk4xps5E.js → host-access-B0CRAwsX.js} +1 -1
- package/lib/{keymap-CJ1kvLR2.js → keymap-CIoVICBI.js} +2 -2
- package/lib/{plugin-XR7ncbnW.js → plugin-BKQsL2xn.js} +1638 -1363
- package/lib/{scenes-CAmWncZD.js → scenes-BRf-zMpF.js} +3 -3
- package/lib/{settings-sections-CakcvBv9.js → settings-sections-4gMhveN_.js} +3 -3
- package/lib/{statusBarSettings-BPPS_Usm.js → statusBarSettings-CnmdSHkO.js} +3 -3
- package/lib/{supports-color-DyChQwlI.js → supports-color-CcW-FGjr.js} +2 -2
- package/lib/{themes-OjcUpZzw.js → themes-Ce97Zsri.js} +12 -12
- package/lib/tui-compat-command-trees.js +1 -1
- package/lib/tui-compat-extensions.js +3 -3
- package/lib/tui-compat-plugin-host.js +5 -5
- package/lib/tui-compat-scenes.js +1 -1
- package/lib/tui-compat-settings-sections.js +1 -1
- package/lib/tui-compat-working-activity.js +4 -4
- package/lib/tui-compat-workspaces.js +1 -1
- package/lib/tui-compat.js +5 -5
- package/lib/{workspaces-XY7UdfXp.js → workspaces-1xrm-e3V.js} +2 -2
- package/package.json +29 -28
- package/runtime/manifest.json +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js +118 -22
- package/runtime/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts +20 -3
- package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js +113 -39
- package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts +3 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js +1 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/index.js +173 -34
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/typert.host.js +48 -28
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/typert.remote-client.js +24 -19
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/agent.d.ts +9 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/agent.js +36 -6
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/archived-session-gate.js +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/catalog.js +4 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/service.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/commands.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/commands.js +24 -8
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/index.d.ts +4 -3
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/index.js +31 -14
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/list.d.ts +6 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/list.js +89 -4
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/remote-events.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/types.d.ts +18 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/client.js +30 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/index.js +83 -2
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.host.js +104 -11
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.remote-client.d.ts +5 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.remote-client.js +78 -11
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/model.d.ts +14 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/model.js +17 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/service.d.ts +15 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/service.js +12 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/commands.d.ts +13 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/commands.js +44 -2
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/index.d.ts +13 -1
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/index.js +22 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/types.d.ts +17 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/client.js +931 -7
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/index.js +57 -19
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/client/index.d.ts +5 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/config.d.ts +12 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/events.d.ts +4 -4
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/index.d.ts +3 -8
- package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/package.json +6 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-commands/lib/client.js +10 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/client/present-open.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/client.js +8 -4
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-account/lib/client.js +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-general/lib/client.js +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar/lib/client.js +3 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/client.js +1917 -206
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/ArchivedSessions.d.ts +13 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/contract/slots.d.ts +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/locales.d.ts +40 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/recent.d.ts +11 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/rows/RecentList.d.ts +15 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/rows/Rows.d.ts +6 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/session-actions/DeleteSession.d.ts +24 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/stores.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/tree.d.ts +15 -13
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/package.json +3 -1
- package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/index.js +16 -0
- package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js +7 -3
- package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js +6 -2
- package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js +20 -0
- package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts +5 -0
- package/runtime/node_modules/@deepseek-ai/dsh-cordis-client-runner/lib/client.js +5 -2
- package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/index.js +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/typert.host.js +5 -5
- package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/typert.remote-client.js +5 -5
- package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/types/index.js +5 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts +21 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js +12 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts +15 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js +95 -2
- package/runtime/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/types/index.d.ts +3 -1
- package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js +25 -1
- package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts +1 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-session-query/lib/index.js +13 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-query/lib/types/observation.d.ts +5 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-query-sqlite/lib/index.js +26 -0
- package/runtime/node_modules/@deepseek-ai/dsh-session-query-sqlite/package.json +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js +5 -1
- package/runtime/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-subagent/lib/types/control.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/index.js +106 -56
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/config.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/index.d.ts +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/services/tianti/config.d.ts +4 -2
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/tools.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-tianti/package.json +2 -0
- package/runtime/node_modules/@deepseek-ai/dsh-tool-cordis/lib/types/api-catalog.js +103 -12
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/index.js +215 -4
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js +6 -1
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts +31 -0
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js +219 -2
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js +4 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** Model-facing Tianti queries and review proposals; human commands execute writes. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import { TiantiRuntime } from './runtime.ts';
|
|
4
|
-
/** Install
|
|
4
|
+
/** Install model tools for one enabled Tianti activation; its owner unregisters them on off.
|
|
5
5
|
* @param ctx Harness tool registry.
|
|
6
6
|
* @param runtime Plugin-owned endpoint and switch state.
|
|
7
|
-
* @param signal
|
|
7
|
+
* @param signal Cancellation for this activation, aborted on off or plugin disposal.
|
|
8
8
|
* @param track Track active work until plugin disposal settles.
|
|
9
9
|
* @returns Registration disposers, removed before active work is drained.
|
|
10
10
|
*/
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"@deepseek-ai/dsh-home-paths": "workspace:*"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"@deepseek-ai/dsh-agent-loop": "workspace:*",
|
|
39
|
+
"@deepseek-ai/dsh-session-projection": "workspace:*",
|
|
38
40
|
"@deepseek-ai/dsh-bash-local": "workspace:*",
|
|
39
41
|
"@deepseek-ai/dsh-subprocess-local": "workspace:*",
|
|
40
42
|
"@deepseek-ai/cordis": "workspace:~",
|
|
@@ -20,20 +20,32 @@ export const SERVICE_API = [
|
|
|
20
20
|
methods: [
|
|
21
21
|
{
|
|
22
22
|
signature: 'currentSelection(): ModelSelection',
|
|
23
|
-
description: 'Read the current default model selection.',
|
|
23
|
+
description: 'Read the current default model selection. A first launch without a valid preference adopts the first complete Config default when it arrives; that process-local choice then stays cached.',
|
|
24
24
|
parameters: [],
|
|
25
25
|
returns: 'a detached provider, model, and optional reasoning selection.',
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
signature: 'usesSharedPreference(): boolean',
|
|
29
|
+
description: 'Whether this product uses a process-local selection initialized from Home at startup.',
|
|
30
|
+
parameters: [],
|
|
31
|
+
returns: 'true for the integrated ChatCode CLI and Web profiles.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
signature: 'async resolveSelection(): Promise<ModelSelection>',
|
|
35
|
+
description: 'Resolve the cached route against the live catalog without reading or writing preferences. A first launch without a valid preference may adopt an advertised fallback until its first available default is resolved. Saved or initialized choices never switch implicitly. Catalog errors preserve the candidate for retry.',
|
|
36
|
+
parameters: [],
|
|
37
|
+
returns: 'the exact available selection, an unverified candidate, or an empty provider/model pair.',
|
|
38
|
+
},
|
|
27
39
|
{
|
|
28
40
|
signature: 'sharedDisplayName(): { provider: string; model: string; name: string } | undefined',
|
|
29
|
-
description: 'Read
|
|
41
|
+
description: 'Read this process\'s cached display name without observing another process\'s saves.',
|
|
30
42
|
parameters: [],
|
|
31
43
|
returns: 'The saved provider/model/name tuple, or undefined for missing or invalid name metadata.',
|
|
32
44
|
},
|
|
33
45
|
{
|
|
34
|
-
signature: 'async saveSelection(next: ModelSelection): Promise<void>',
|
|
35
|
-
description: 'Save the complete default model selection to the shared ChatCode Home file, or the owning profile entry in other deployments. Saves commit in submission order; a failed save rejects its caller without blocking later saves. A shared save
|
|
36
|
-
parameters: [{ name: 'next', description: 'resolved selection accepted by an entry point.' }],
|
|
46
|
+
signature: 'async saveSelection(next: ModelSelection, name?: string): Promise<void>',
|
|
47
|
+
description: 'Save the complete default model selection to the shared ChatCode Home file, or the owning profile entry in other deployments. Saves commit in submission order; a failed save rejects its caller without blocking later saves. A shared save uses the caller\'s already resolved catalog name without an additional lookup.',
|
|
48
|
+
parameters: [{ name: 'next', description: 'resolved selection accepted by an entry point.' }, { name: 'name', description: 'optional display name from the entry point\'s catalog.' }],
|
|
37
49
|
returns: 'fulfillment after the preference or optional profile write settles.',
|
|
38
50
|
},
|
|
39
51
|
],
|
|
@@ -1843,20 +1855,20 @@ export const SERVICE_API = [
|
|
|
1843
1855
|
returns: 'authorized bounded Session search results.',
|
|
1844
1856
|
},
|
|
1845
1857
|
{
|
|
1846
|
-
signature: '@Remote(\'create\') create(request: SessionCreateRequest): Promise<SessionCreateValue>',
|
|
1858
|
+
signature: '@Remote(\'create\') async create(request: SessionCreateRequest): Promise<SessionCreateValue>',
|
|
1847
1859
|
description: 'Create or idempotently adopt one ordinary Session.',
|
|
1848
1860
|
parameters: [{ name: 'request', description: 'requested identity, location, and Agent preset.' }],
|
|
1849
1861
|
returns: 'the Session identity and resolved preset when configured.',
|
|
1850
1862
|
},
|
|
1851
1863
|
{
|
|
1852
1864
|
signature: '@Remote(\'selectModel\') selectModel(request: SessionSelectModelRequest): Promise<SessionSelectModelValue>',
|
|
1853
|
-
description: 'Select
|
|
1865
|
+
description: 'Select a model after explicitly resuming the Session and awaiting default persistence.',
|
|
1854
1866
|
parameters: [{ name: 'request', description: 'Session identity and requested model selection.' }],
|
|
1855
|
-
returns: 'the normalized selection
|
|
1867
|
+
returns: 'the normalized selection after the shared save and Session selection succeed.',
|
|
1856
1868
|
},
|
|
1857
1869
|
{
|
|
1858
1870
|
signature: '@Remote async initializeDefaultModel(): Promise<void>',
|
|
1859
|
-
description: '
|
|
1871
|
+
description: 'Initialize legacy account deployments without changing a product process\'s cached selection.',
|
|
1860
1872
|
parameters: [],
|
|
1861
1873
|
returns: 'after saving the first available model or retaining the existing default.',
|
|
1862
1874
|
},
|
|
@@ -1935,7 +1947,7 @@ export const SERVICE_API = [
|
|
|
1935
1947
|
returns: 'one chronological page.',
|
|
1936
1948
|
},
|
|
1937
1949
|
{
|
|
1938
|
-
signature: '@Remote({ mode: \'stream\' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>',
|
|
1950
|
+
signature: '@Remote({ mode: \'stream\' }) async *follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>',
|
|
1939
1951
|
description: 'Follow one Session log from its opening or resume cursor.',
|
|
1940
1952
|
parameters: [{ name: 'request', description: 'durable address and last committed sequence already held by the caller.' }, { name: 'signal', description: 'cancellation owned by the Remote stream carrier.' }],
|
|
1941
1953
|
returns: 'a complete opening snapshot followed by gap-free durable event frames and optional cursorless assistant-stream frames.',
|
|
@@ -2023,6 +2035,13 @@ export const SERVICE_API = [
|
|
|
2023
2035
|
parameters: [{ name: 'options', description: 'optional cancellation.' }],
|
|
2024
2036
|
returns: 'one snapshot per stored session.',
|
|
2025
2037
|
},
|
|
2038
|
+
{
|
|
2039
|
+
signature: 'prepareDeletion(sessionIds: readonly SessionId[]): Promise<SessionDeletion>',
|
|
2040
|
+
description: 'Reserve every target\'s write ownership before any deletion is committed. The caller persists its recovery journal while this reservation is held, calls commit, and always disposes it to release ownership. Backends must retain deletion identities so old generations cannot reappear or be recreated.',
|
|
2041
|
+
parameters: [{ name: 'sessionIds', description: 'complete deletion scope, including owned descendants.' }],
|
|
2042
|
+
returns: 'an exclusive deletion reservation; missing targets are idempotent.',
|
|
2043
|
+
throws: ['when a writer holds any target, or the backend does not support deletion.'],
|
|
2044
|
+
},
|
|
2026
2045
|
],
|
|
2027
2046
|
},
|
|
2028
2047
|
{
|
|
@@ -3526,6 +3545,18 @@ export const SERVICE_API = [
|
|
|
3526
3545
|
parameters: [{ name: 'request', description: 'Session identity to unarchive.' }],
|
|
3527
3546
|
returns: 'the complete resulting archive set.',
|
|
3528
3547
|
},
|
|
3548
|
+
{
|
|
3549
|
+
signature: '@Remote(\'sessionDeletionScope\') sessionDeletionScope(request: WorkspaceSessionDeletionPreviewRequest): Promise<WorkspaceSessionDeletionValue>',
|
|
3550
|
+
description: 'Preview the archived root and owned subagent Sessions covered by deletion.',
|
|
3551
|
+
parameters: [{ name: 'request', description: 'archived root to preview.' }],
|
|
3552
|
+
returns: 'complete deletion scope for confirmation.',
|
|
3553
|
+
},
|
|
3554
|
+
{
|
|
3555
|
+
signature: '@Remote(\'deleteSession\') deleteSession(request: WorkspaceSessionDeletionRequest): Promise<WorkspaceSessionDeletionValue>',
|
|
3556
|
+
description: 'Permanently remove an archived Session and its confirmed owned subagents.',
|
|
3557
|
+
parameters: [{ name: 'request', description: 'archived root and confirmed scope.' }],
|
|
3558
|
+
returns: 'identities permanently removed.',
|
|
3559
|
+
},
|
|
3529
3560
|
{
|
|
3530
3561
|
signature: '@Remote(\'pinSession\') pinSession(request: WorkspacePinSessionRequest): Promise<WorkspacePinValue>',
|
|
3531
3562
|
description: 'Surface one known unarchived Session ahead of unpinned Sessions.',
|
|
@@ -3630,6 +3661,18 @@ export const SERVICE_API = [
|
|
|
3630
3661
|
parameters: [{ name: 'id', description: 'Workspace to move.' }, { name: 'beforeId', description: 'Workspace anchor; omitted appends.' }],
|
|
3631
3662
|
returns: 'the complete committed workspace order.',
|
|
3632
3663
|
},
|
|
3664
|
+
{
|
|
3665
|
+
signature: 'deleteSession(sessionId: SessionId, expectedIds?: readonly SessionId[]): Promise<readonly SessionId[]>',
|
|
3666
|
+
description: 'Permanently delete an archived, inactive root and its owned subagent descendants. Independent forks are preserved. Reserve every writer before recording a recovery marker; a failure after that marker is retried on refresh or restart.',
|
|
3667
|
+
parameters: [{ name: 'sessionId', description: 'archived root identity; repeated deletion is idempotent.' }, { name: 'expectedIds', description: 'identities confirmed by the user; a changed scope refuses deletion.' }],
|
|
3668
|
+
returns: 'deleted root and descendant identities after durable cleanup.',
|
|
3669
|
+
},
|
|
3670
|
+
{
|
|
3671
|
+
signature: 'sessionDeletionScope(sessionId: SessionId): Promise<readonly SessionId[]>',
|
|
3672
|
+
description: 'Preview the root and owned descendants without opening their histories.',
|
|
3673
|
+
parameters: [{ name: 'sessionId', description: 'archived root to preview.' }],
|
|
3674
|
+
returns: 'identities to show in the deletion confirmation.',
|
|
3675
|
+
},
|
|
3633
3676
|
{
|
|
3634
3677
|
signature: 'archiveSession(sessionId: SessionId, options: ArchiveSessionOptions = {}): Promise<void>',
|
|
3635
3678
|
description: 'Archive one session durably. The session must exist (live or in session persistence); its workspace accounting — or lack of one — is irrelevant. Without `stopActivity` the session must also be inactive: the `workspace/session-activity` waterfall is asked once, and any reported activity rejects with WorkspaceActiveSessionError before anything is written. With `stopActivity` the archive is written without an activity check, and the `workspace/session-stop` providers are then asked to stop the session\'s work: the durable archive set is what a provider\'s `agent/pre-step` gate reads, so every wake the stops induce is already blocked. Archiving drops the session\'s pin in the same durable write (pinning and archival are mutually exclusive). An already archived id resolves without writing, asking, or stopping.',
|
|
@@ -3801,6 +3844,14 @@ export const EVENT_API = [
|
|
|
3801
3844
|
description: 'One Agent failed outside a durable turn position.',
|
|
3802
3845
|
parameters: [{ name: 'sessionId', description: 'Agent and Session identity.' }, { name: 'message', description: 'user-safe failure chain.' }],
|
|
3803
3846
|
},
|
|
3847
|
+
{
|
|
3848
|
+
name: 'api-session/model-updated',
|
|
3849
|
+
mode: 'emit',
|
|
3850
|
+
signature: '\'api-session/model-updated\'(): void',
|
|
3851
|
+
summary: 'The Host process committed a user-selected default; browser catalogs must reload from that process.',
|
|
3852
|
+
description: 'The Host process committed a user-selected default; browser catalogs must reload from that process.',
|
|
3853
|
+
parameters: [],
|
|
3854
|
+
},
|
|
3804
3855
|
{
|
|
3805
3856
|
name: 'api-session/removed',
|
|
3806
3857
|
mode: 'emit',
|
|
@@ -4097,6 +4148,30 @@ export const EVENT_API = [
|
|
|
4097
4148
|
description: 'Creation announcement during session publication. A synchronous throw vetoes and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent\'s context.',
|
|
4098
4149
|
parameters: [{ name: 'session', description: 'the session just entered and announced.' }],
|
|
4099
4150
|
},
|
|
4151
|
+
{
|
|
4152
|
+
name: 'session/delete-release',
|
|
4153
|
+
mode: 'parallel',
|
|
4154
|
+
signature: '\'session/delete-release\'(request: { readonly sessionIds: readonly SessionId[] }): Promise<void> | void',
|
|
4155
|
+
summary: 'Ask capability owners to release idle, archived Sessions before writer reservation.',
|
|
4156
|
+
description: 'Ask capability owners to release idle, archived Sessions before writer reservation. Owners release only handles they own; foreign or running Sessions remain protected.',
|
|
4157
|
+
parameters: [{ name: 'request', description: 'confirmed root and owned subagent identities.' }],
|
|
4158
|
+
},
|
|
4159
|
+
{
|
|
4160
|
+
name: 'session/deleted',
|
|
4161
|
+
mode: 'emit',
|
|
4162
|
+
signature: '\'session/deleted\'(sessionIds: readonly SessionId[]): void',
|
|
4163
|
+
summary: 'Permanent deletion observed locally or from shared storage.',
|
|
4164
|
+
description: 'Permanent deletion observed locally or from shared storage.',
|
|
4165
|
+
parameters: [{ name: 'sessionIds', description: 'removed identities, including owned descendants.' }],
|
|
4166
|
+
},
|
|
4167
|
+
{
|
|
4168
|
+
name: 'session/deleting',
|
|
4169
|
+
mode: 'parallel',
|
|
4170
|
+
signature: '\'session/deleting\'(request: { readonly sessionIds: readonly SessionId[] }): Promise<void> | void',
|
|
4171
|
+
summary: 'Permanently remove secondary Session records after stored payload deletion.',
|
|
4172
|
+
description: 'Permanently remove secondary Session records after stored payload deletion. Listeners are idempotent; failures leave the deletion journal pending for recovery.',
|
|
4173
|
+
parameters: [{ name: 'request', description: 'confirmed root and owned subagent identities.' }],
|
|
4174
|
+
},
|
|
4100
4175
|
{
|
|
4101
4176
|
name: 'session/disposed',
|
|
4102
4177
|
mode: 'emit',
|
|
@@ -5714,7 +5789,7 @@ export const TYPE_API = [
|
|
|
5714
5789
|
},
|
|
5715
5790
|
{
|
|
5716
5791
|
name: 'ModelCatalog',
|
|
5717
|
-
declaration: 'export interface ModelCatalog {\n readonly default: ModelSelection;\n readonly savedDisplayName?: {\n readonly provider: string;\n readonly model: string;\n readonly name: string;\n };\n readonly routableProviders: readonly string[];\n readonly groups: readonly ModelProviderGroup[];\n readonly failures: readonly ModelCatalogFailure[];\n}',
|
|
5792
|
+
declaration: 'export interface ModelCatalog {\n readonly default: ModelSelection;\n readonly selectionScope?: \'process\';\n readonly savedDisplayName?: {\n readonly provider: string;\n readonly model: string;\n readonly name: string;\n };\n readonly routableProviders: readonly string[];\n readonly groups: readonly ModelProviderGroup[];\n readonly failures: readonly ModelCatalogFailure[];\n}',
|
|
5718
5793
|
},
|
|
5719
5794
|
{
|
|
5720
5795
|
name: 'ModelCatalogFailure',
|
|
@@ -6066,7 +6141,7 @@ export const TYPE_API = [
|
|
|
6066
6141
|
},
|
|
6067
6142
|
{
|
|
6068
6143
|
name: 'RecordTable',
|
|
6069
|
-
declaration: 'export type RecordTable<K extends string, V> = Pick<KvTable<K, V>, \'read\' | \'put\'>;',
|
|
6144
|
+
declaration: 'export type RecordTable<K extends string, V> = Pick<KvTable<K, V>, \'read\' | \'put\' | \'delete\'>;',
|
|
6070
6145
|
},
|
|
6071
6146
|
{
|
|
6072
6147
|
name: 'RecurringScheduleRecord',
|
|
@@ -6408,6 +6483,10 @@ export const TYPE_API = [
|
|
|
6408
6483
|
name: 'SessionCreateValue',
|
|
6409
6484
|
declaration: 'export interface SessionCreateValue {\n readonly sessionId: SessionId;\n readonly agentPreset?: string;\n}',
|
|
6410
6485
|
},
|
|
6486
|
+
{
|
|
6487
|
+
name: 'SessionDeletion',
|
|
6488
|
+
declaration: 'export interface SessionDeletion extends AsyncDisposable {\n commit(): Promise<void>;\n}',
|
|
6489
|
+
},
|
|
6411
6490
|
{
|
|
6412
6491
|
name: 'SessionEvent',
|
|
6413
6492
|
declaration: 'export type SessionEvent<T extends SessionEventType = SessionEventType> = {\n [K in SessionEventType]: {\n type: K;\n seq: SessionSeq;\n time: number;\n data: SessionEventMap[K];\n ignorable?: true;\n } & (K extends SurfaceEventType ? SurfaceIntent<K> : {\n surfaceOp?: never;\n sourceEventSeqs?: never;\n });\n}[T];',
|
|
@@ -8028,6 +8107,18 @@ export const TYPE_API = [
|
|
|
8028
8107
|
name: 'WorkspaceRenameRequest',
|
|
8029
8108
|
declaration: 'export interface WorkspaceRenameRequest {\n readonly workspaceId: WorkspaceId;\n readonly title: string;\n}',
|
|
8030
8109
|
},
|
|
8110
|
+
{
|
|
8111
|
+
name: 'WorkspaceSessionDeletionPreviewRequest',
|
|
8112
|
+
declaration: 'export interface WorkspaceSessionDeletionPreviewRequest {\n readonly sessionId: SessionId;\n}',
|
|
8113
|
+
},
|
|
8114
|
+
{
|
|
8115
|
+
name: 'WorkspaceSessionDeletionRequest',
|
|
8116
|
+
declaration: 'export interface WorkspaceSessionDeletionRequest extends WorkspaceSessionDeletionPreviewRequest {\n readonly expectedSessionIds: readonly SessionId[];\n}',
|
|
8117
|
+
},
|
|
8118
|
+
{
|
|
8119
|
+
name: 'WorkspaceSessionDeletionValue',
|
|
8120
|
+
declaration: 'export interface WorkspaceSessionDeletionValue {\n readonly sessionIds: readonly SessionId[];\n}',
|
|
8121
|
+
},
|
|
8031
8122
|
{
|
|
8032
8123
|
name: 'WorkspaceUnarchiveSessionRequest',
|
|
8033
8124
|
declaration: 'export interface WorkspaceUnarchiveSessionRequest {\n readonly sessionId: SessionId;\n}',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { mkdir, realpath, stat } from "node:fs/promises";
|
|
3
3
|
import { Service } from "@deepseek-ai/cordis";
|
|
4
|
+
import { SessionAlreadyOwnedError } from "@deepseek-ai/dsh-session-persistence";
|
|
4
5
|
import { posix, win32 } from "node:path";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
@@ -252,7 +253,11 @@ const workspaceDomainState = z.object({
|
|
|
252
253
|
workspaceIds: z.array(workspaceId),
|
|
253
254
|
archivedSessionIds: z.array(sessionId).default([]),
|
|
254
255
|
pinnedSessionIds: z.array(sessionId).default([]),
|
|
255
|
-
pendingMutation: workspacePendingMutation.optional()
|
|
256
|
+
pendingMutation: workspacePendingMutation.optional(),
|
|
257
|
+
/** Payload deletion committed identities; old processes must never restore these Sessions. */
|
|
258
|
+
deletedSessionIds: z.array(sessionId).optional(),
|
|
259
|
+
/** Complete deletion scope retained until payloads and secondary owners finish cleanup. */
|
|
260
|
+
pendingSessionDeletion: z.array(sessionId).optional()
|
|
256
261
|
});
|
|
257
262
|
/**
|
|
258
263
|
* The workspace domain spec: one `workspaces` table keyed by
|
|
@@ -282,6 +287,64 @@ const workspaceDomainSpec = defineDomain({
|
|
|
282
287
|
* domain data form.
|
|
283
288
|
* @module @deepseek-ai/dsh-workspace
|
|
284
289
|
*/
|
|
290
|
+
var __addDisposableResource = function(env, value, async) {
|
|
291
|
+
if (value !== null && value !== void 0) {
|
|
292
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
293
|
+
var dispose, inner;
|
|
294
|
+
if (async) {
|
|
295
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
296
|
+
dispose = value[Symbol.asyncDispose];
|
|
297
|
+
}
|
|
298
|
+
if (dispose === void 0) {
|
|
299
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
300
|
+
dispose = value[Symbol.dispose];
|
|
301
|
+
if (async) inner = dispose;
|
|
302
|
+
}
|
|
303
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
304
|
+
if (inner) dispose = function() {
|
|
305
|
+
try {
|
|
306
|
+
inner.call(this);
|
|
307
|
+
} catch (e) {
|
|
308
|
+
return Promise.reject(e);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
env.stack.push({
|
|
312
|
+
value,
|
|
313
|
+
dispose,
|
|
314
|
+
async
|
|
315
|
+
});
|
|
316
|
+
} else if (async) env.stack.push({ async: true });
|
|
317
|
+
return value;
|
|
318
|
+
};
|
|
319
|
+
var __disposeResources = (function(SuppressedError) {
|
|
320
|
+
return function(env) {
|
|
321
|
+
function fail(e) {
|
|
322
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
323
|
+
env.hasError = true;
|
|
324
|
+
}
|
|
325
|
+
var r, s = 0;
|
|
326
|
+
function next() {
|
|
327
|
+
while (r = env.stack.pop()) try {
|
|
328
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
329
|
+
if (r.dispose) {
|
|
330
|
+
var result = r.dispose.call(r.value);
|
|
331
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
332
|
+
fail(e);
|
|
333
|
+
return next();
|
|
334
|
+
});
|
|
335
|
+
} else s |= 1;
|
|
336
|
+
} catch (e) {
|
|
337
|
+
fail(e);
|
|
338
|
+
}
|
|
339
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
340
|
+
if (env.hasError) throw env.error;
|
|
341
|
+
}
|
|
342
|
+
return next();
|
|
343
|
+
};
|
|
344
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
345
|
+
var e = new Error(message);
|
|
346
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
347
|
+
});
|
|
285
348
|
/**
|
|
286
349
|
* Brand a string as a {@link WorkspaceId}.
|
|
287
350
|
* @param id - Raw workspace id string.
|
|
@@ -338,6 +401,21 @@ var WorkspaceArchivedSessionPinError = class extends Error {
|
|
|
338
401
|
this.name = "WorkspaceArchivedSessionPinError";
|
|
339
402
|
}
|
|
340
403
|
};
|
|
404
|
+
/** Permanent deletion requires an archived root and no active Session ownership. */
|
|
405
|
+
var WorkspaceSessionDeletionError = class extends Error {
|
|
406
|
+
sessionId;
|
|
407
|
+
reason;
|
|
408
|
+
/**
|
|
409
|
+
* @param sessionId - identity whose lifecycle prevents the requested operation.
|
|
410
|
+
* @param reason - stable refusal discriminant shared by the Web and TUI.
|
|
411
|
+
*/
|
|
412
|
+
constructor(sessionId, reason) {
|
|
413
|
+
super(`cannot delete session '${sessionId}': ${reason}`);
|
|
414
|
+
this.sessionId = sessionId;
|
|
415
|
+
this.reason = reason;
|
|
416
|
+
this.name = "WorkspaceSessionDeletionError";
|
|
417
|
+
}
|
|
418
|
+
};
|
|
341
419
|
/** A workspace reorder named a source or anchor absent from the durable registry order. */
|
|
342
420
|
var WorkspaceOrderInvalidError = class extends Error {
|
|
343
421
|
workspaceId;
|
|
@@ -403,6 +481,7 @@ var WorkspaceRegistry = class extends Service {
|
|
|
403
481
|
await domain.refresh();
|
|
404
482
|
this.state = domain.global.get();
|
|
405
483
|
await this.recoverPendingMutation();
|
|
484
|
+
await this.recoverSessionDeletion();
|
|
406
485
|
this.validateStoredState(this.requireState());
|
|
407
486
|
if (!this.requireState().initialized) {
|
|
408
487
|
const headers = await this.listStoredHeaders();
|
|
@@ -550,6 +629,130 @@ var WorkspaceRegistry = class extends Service {
|
|
|
550
629
|
get archivedSessionIds() {
|
|
551
630
|
return this.requireState().archivedSessionIds;
|
|
552
631
|
}
|
|
632
|
+
/** Permanently deleted identities retained for cross-process invalidation and stale-operation refusal. */
|
|
633
|
+
get deletedSessionIds() {
|
|
634
|
+
return this.requireState().deletedSessionIds ?? [];
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Permanently delete an archived, inactive root and its owned subagent descendants.
|
|
638
|
+
* Independent forks are preserved. Reserve every writer before recording a recovery
|
|
639
|
+
* marker; a failure after that marker is retried on refresh or restart.
|
|
640
|
+
* @param sessionId - archived root identity; repeated deletion is idempotent.
|
|
641
|
+
* @param expectedIds - identities confirmed by the user; a changed scope refuses deletion.
|
|
642
|
+
* @returns deleted root and descendant identities after durable cleanup.
|
|
643
|
+
*/
|
|
644
|
+
deleteSession(sessionId, expectedIds) {
|
|
645
|
+
return this.enqueueOperation(async () => {
|
|
646
|
+
const env_1 = {
|
|
647
|
+
stack: [],
|
|
648
|
+
error: void 0,
|
|
649
|
+
hasError: false
|
|
650
|
+
};
|
|
651
|
+
try {
|
|
652
|
+
if (this.deletedSessionIds.includes(sessionId)) return [sessionId];
|
|
653
|
+
if (!this.archivedSessionIds.includes(sessionId)) throw new WorkspaceSessionDeletionError(sessionId, "not-archived");
|
|
654
|
+
const ids = new Set(await this.collectSessionDeletionScope(sessionId));
|
|
655
|
+
if (expectedIds !== void 0 && (expectedIds.length !== ids.size || new Set(expectedIds).size !== ids.size || expectedIds.some((id) => !ids.has(id)))) throw new WorkspaceSessionDeletionError(sessionId, "scope-changed");
|
|
656
|
+
for (const id of ids) {
|
|
657
|
+
const activity = await this.ctx.waterfall("workspace/session-activity", { sessionId: id }, () => Promise.resolve([]));
|
|
658
|
+
if (activity.length > 0) throw new WorkspaceActiveSessionError(id, activity);
|
|
659
|
+
}
|
|
660
|
+
const targets = [...ids];
|
|
661
|
+
await this.ctx.parallel("session/delete-release", { sessionIds: targets });
|
|
662
|
+
for (const id of ids) if (this.ctx.get("sessions")?.get(id) !== void 0) throw new WorkspaceSessionDeletionError(id, "in-use");
|
|
663
|
+
const reservation = __addDisposableResource(env_1, await this.ctx.sessionPersistence.prepareDeletion(targets).catch((error) => {
|
|
664
|
+
if (error instanceof SessionAlreadyOwnedError) throw new WorkspaceSessionDeletionError(sessionId, "in-use");
|
|
665
|
+
throw error;
|
|
666
|
+
}), true);
|
|
667
|
+
await this.setState({
|
|
668
|
+
...this.requireState(),
|
|
669
|
+
pendingSessionDeletion: targets
|
|
670
|
+
});
|
|
671
|
+
await reservation.commit();
|
|
672
|
+
await this.finishSessionDeletion(targets);
|
|
673
|
+
return targets;
|
|
674
|
+
} catch (e_1) {
|
|
675
|
+
env_1.error = e_1;
|
|
676
|
+
env_1.hasError = true;
|
|
677
|
+
} finally {
|
|
678
|
+
const result_1 = __disposeResources(env_1);
|
|
679
|
+
if (result_1) await result_1;
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Preview the root and owned descendants without opening their histories.
|
|
685
|
+
* @param sessionId - archived root to preview.
|
|
686
|
+
* @returns identities to show in the deletion confirmation.
|
|
687
|
+
*/
|
|
688
|
+
sessionDeletionScope(sessionId) {
|
|
689
|
+
return this.enqueueOperation(async () => {
|
|
690
|
+
if (!this.archivedSessionIds.includes(sessionId)) throw new WorkspaceSessionDeletionError(sessionId, "not-archived");
|
|
691
|
+
return this.collectSessionDeletionScope(sessionId);
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
async collectSessionDeletionScope(sessionId) {
|
|
695
|
+
const headers = await this.listStoredHeaders();
|
|
696
|
+
const ids = new Set([sessionId]);
|
|
697
|
+
for (let changed = true; changed;) {
|
|
698
|
+
changed = false;
|
|
699
|
+
for (const header of headers) if (header.origin === "subagent" && header.parentSession !== void 0 && ids.has(header.parentSession) && !ids.has(header.id)) {
|
|
700
|
+
ids.add(header.id);
|
|
701
|
+
changed = true;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return [...ids];
|
|
705
|
+
}
|
|
706
|
+
async recoverSessionDeletion() {
|
|
707
|
+
const env_2 = {
|
|
708
|
+
stack: [],
|
|
709
|
+
error: void 0,
|
|
710
|
+
hasError: false
|
|
711
|
+
};
|
|
712
|
+
try {
|
|
713
|
+
const ids = this.requireState().pendingSessionDeletion;
|
|
714
|
+
if (ids === void 0) return;
|
|
715
|
+
await __addDisposableResource(env_2, await this.ctx.sessionPersistence.prepareDeletion(ids), true).commit();
|
|
716
|
+
await this.finishSessionDeletion(ids);
|
|
717
|
+
} catch (e_2) {
|
|
718
|
+
env_2.error = e_2;
|
|
719
|
+
env_2.hasError = true;
|
|
720
|
+
} finally {
|
|
721
|
+
const result_2 = __disposeResources(env_2);
|
|
722
|
+
if (result_2) await result_2;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
notifyDeleted(ids) {
|
|
726
|
+
try {
|
|
727
|
+
this.ctx.emit("session/deleted", ids);
|
|
728
|
+
} catch (error) {
|
|
729
|
+
this.ctx.logger.warn(`workspace: deletion listener failed: ${String(error)}`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
async finishSessionDeletion(ids) {
|
|
733
|
+
await this.ctx.parallel("session/deleting", { sessionIds: ids });
|
|
734
|
+
const removed = new Set(ids);
|
|
735
|
+
for (const [id, record] of this.requireTable().entries()) if (record.sessionIds.some((member) => removed.has(member))) await this.requireTable().update(id, (current) => ({
|
|
736
|
+
...current,
|
|
737
|
+
sessionIds: current.sessionIds.filter((member) => !removed.has(member)),
|
|
738
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
739
|
+
}));
|
|
740
|
+
const state = this.requireState();
|
|
741
|
+
await this.setState({
|
|
742
|
+
...state,
|
|
743
|
+
archivedSessionIds: state.archivedSessionIds.filter((id) => !removed.has(id)),
|
|
744
|
+
pinnedSessionIds: state.pinnedSessionIds.filter((id) => !removed.has(id)),
|
|
745
|
+
deletedSessionIds: [...new Set([...state.deletedSessionIds ?? [], ...ids])],
|
|
746
|
+
pendingSessionDeletion: void 0
|
|
747
|
+
});
|
|
748
|
+
for (const id of ids) {
|
|
749
|
+
this.headers.delete(id);
|
|
750
|
+
this.sessionPaths.delete(id);
|
|
751
|
+
this.invalidSessionPaths.delete(id);
|
|
752
|
+
}
|
|
753
|
+
this.rebuildEntities();
|
|
754
|
+
this.notifyDeleted(ids);
|
|
755
|
+
}
|
|
553
756
|
/**
|
|
554
757
|
* Archive one session durably. The session must exist (live or in session
|
|
555
758
|
* persistence); its workspace accounting — or lack of one — is irrelevant.
|
|
@@ -596,6 +799,7 @@ var WorkspaceRegistry = class extends Service {
|
|
|
596
799
|
*/
|
|
597
800
|
unarchiveSession(sessionId) {
|
|
598
801
|
return this.enqueueOperation(async () => {
|
|
802
|
+
if (this.deletedSessionIds.includes(sessionId)) throw new WorkspaceSessionDeletionError(sessionId, "deleted");
|
|
599
803
|
const state = this.requireState();
|
|
600
804
|
if (!state.archivedSessionIds.includes(sessionId)) return;
|
|
601
805
|
await this.setState({
|
|
@@ -656,6 +860,7 @@ var WorkspaceRegistry = class extends Service {
|
|
|
656
860
|
* masquerade as an unknown session.
|
|
657
861
|
*/
|
|
658
862
|
async sessionKnown(id) {
|
|
863
|
+
if (this.deletedSessionIds.includes(id)) return false;
|
|
659
864
|
if (this.ctx.get("sessions")?.get(id) !== void 0) return true;
|
|
660
865
|
if (this.headers.has(id)) return true;
|
|
661
866
|
await this.indexHeaders(await this.listStoredHeaders());
|
|
@@ -939,12 +1144,14 @@ var WorkspaceRegistry = class extends Service {
|
|
|
939
1144
|
}
|
|
940
1145
|
/** Every stored session's header, projected from the persistence snapshot listing. */
|
|
941
1146
|
async listStoredHeaders() {
|
|
942
|
-
|
|
1147
|
+
const snapshots = await this.ctx.sessionPersistence.list();
|
|
1148
|
+
const deleted = new Set(this.deletedSessionIds);
|
|
1149
|
+
return snapshots.map((snapshot) => snapshot.header).filter((header) => !deleted.has(header.id));
|
|
943
1150
|
}
|
|
944
1151
|
async indexLiveSessions() {
|
|
945
1152
|
const sessions = this.ctx.get("sessions");
|
|
946
1153
|
if (sessions === void 0) return;
|
|
947
|
-
await this.indexHeaders(sessions.list().map((session) => session.header));
|
|
1154
|
+
await this.indexHeaders(sessions.list().filter((session) => !this.deletedSessionIds.includes(session.id)).map((session) => session.header));
|
|
948
1155
|
}
|
|
949
1156
|
reportFilteredCandidates() {
|
|
950
1157
|
for (const entity of this.entities.values()) {
|
|
@@ -990,6 +1197,7 @@ var WorkspaceRegistry = class extends Service {
|
|
|
990
1197
|
if (domain === void 0) throw new Error("workspace registry is not started yet");
|
|
991
1198
|
return await domain.exclusive(async () => {
|
|
992
1199
|
const before = JSON.stringify([...this.entities.values()].map((entity) => [entity.id, entity.sessionIds]));
|
|
1200
|
+
const previousDeleted = new Set(this.deletedSessionIds);
|
|
993
1201
|
await domain.refresh();
|
|
994
1202
|
const changed = this.snapshotIdentity() !== this.refreshedState;
|
|
995
1203
|
this.state = domain.global.get();
|
|
@@ -1000,6 +1208,9 @@ var WorkspaceRegistry = class extends Service {
|
|
|
1000
1208
|
this.rebuildEntities();
|
|
1001
1209
|
}
|
|
1002
1210
|
await this.recoverPendingMutation();
|
|
1211
|
+
await this.recoverSessionDeletion();
|
|
1212
|
+
const newlyDeleted = this.deletedSessionIds.filter((id) => !previousDeleted.has(id));
|
|
1213
|
+
if (newlyDeleted.length > 0) this.notifyDeleted(newlyDeleted);
|
|
1003
1214
|
this.validateStoredState(this.requireState());
|
|
1004
1215
|
const after = JSON.stringify([...this.entities.values()].map((entity) => [entity.id, entity.sessionIds]));
|
|
1005
1216
|
if (changed || before !== after) try {
|
|
@@ -1022,4 +1233,4 @@ var WorkspaceRegistry = class extends Service {
|
|
|
1022
1233
|
};
|
|
1023
1234
|
const sameSessionIds = (left, right) => left.length === right.length && left.every((id, index) => id === right[index]);
|
|
1024
1235
|
//#endregion
|
|
1025
|
-
export { WorkspaceActiveSessionError, WorkspaceArchivedSessionPinError, WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceRegistry, WorkspaceRegistry as default, WorkspaceUnknownSessionError, realpathNormalize, workspaceDomainSpec, workspaceDomainState, workspaceRecord };
|
|
1236
|
+
export { WorkspaceActiveSessionError, WorkspaceArchivedSessionPinError, WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceRegistry, WorkspaceRegistry as default, WorkspaceSessionDeletionError, WorkspaceUnknownSessionError, realpathNormalize, workspaceDomainSpec, workspaceDomainState, workspaceRecord };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "node:crypto";
|
|
2
2
|
import "node:fs/promises";
|
|
3
3
|
import { Service } from "@deepseek-ai/cordis";
|
|
4
|
+
import "@deepseek-ai/dsh-session-persistence";
|
|
4
5
|
import "node:path";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
@@ -51,7 +52,11 @@ defineDomain({
|
|
|
51
52
|
workspaceIds: z.array(workspaceId),
|
|
52
53
|
archivedSessionIds: z.array(sessionId).default([]),
|
|
53
54
|
pinnedSessionIds: z.array(sessionId).default([]),
|
|
54
|
-
pendingMutation: workspacePendingMutation.optional()
|
|
55
|
+
pendingMutation: workspacePendingMutation.optional(),
|
|
56
|
+
/** Payload deletion committed identities; old processes must never restore these Sessions. */
|
|
57
|
+
deletedSessionIds: z.array(sessionId).optional(),
|
|
58
|
+
/** Complete deletion scope retained until payloads and secondary owners finish cleanup. */
|
|
59
|
+
pendingSessionDeletion: z.array(sessionId).optional()
|
|
55
60
|
}),
|
|
56
61
|
initial: {
|
|
57
62
|
initialized: false,
|
|
@@ -55,6 +55,16 @@ export declare class WorkspaceArchivedSessionPinError extends Error {
|
|
|
55
55
|
*/
|
|
56
56
|
constructor(sessionId: SessionId);
|
|
57
57
|
}
|
|
58
|
+
/** Permanent deletion requires an archived root and no active Session ownership. */
|
|
59
|
+
export declare class WorkspaceSessionDeletionError extends Error {
|
|
60
|
+
readonly sessionId: SessionId;
|
|
61
|
+
readonly reason: 'not-archived' | 'in-use' | 'deleted' | 'scope-changed';
|
|
62
|
+
/**
|
|
63
|
+
* @param sessionId - identity whose lifecycle prevents the requested operation.
|
|
64
|
+
* @param reason - stable refusal discriminant shared by the Web and TUI.
|
|
65
|
+
*/
|
|
66
|
+
constructor(sessionId: SessionId, reason: 'not-archived' | 'in-use' | 'deleted' | 'scope-changed');
|
|
67
|
+
}
|
|
58
68
|
/** A workspace reorder named a source or anchor absent from the durable registry order. */
|
|
59
69
|
export declare class WorkspaceOrderInvalidError extends Error {
|
|
60
70
|
readonly workspaceId: WorkspaceId;
|
|
@@ -202,6 +212,27 @@ export declare class WorkspaceRegistry extends Service {
|
|
|
202
212
|
* @returns the archived session ids in archive order.
|
|
203
213
|
*/
|
|
204
214
|
get archivedSessionIds(): readonly SessionId[];
|
|
215
|
+
/** Permanently deleted identities retained for cross-process invalidation and stale-operation refusal. */
|
|
216
|
+
get deletedSessionIds(): readonly SessionId[];
|
|
217
|
+
/**
|
|
218
|
+
* Permanently delete an archived, inactive root and its owned subagent descendants.
|
|
219
|
+
* Independent forks are preserved. Reserve every writer before recording a recovery
|
|
220
|
+
* marker; a failure after that marker is retried on refresh or restart.
|
|
221
|
+
* @param sessionId - archived root identity; repeated deletion is idempotent.
|
|
222
|
+
* @param expectedIds - identities confirmed by the user; a changed scope refuses deletion.
|
|
223
|
+
* @returns deleted root and descendant identities after durable cleanup.
|
|
224
|
+
*/
|
|
225
|
+
deleteSession(sessionId: SessionId, expectedIds?: readonly SessionId[]): Promise<readonly SessionId[]>;
|
|
226
|
+
/**
|
|
227
|
+
* Preview the root and owned descendants without opening their histories.
|
|
228
|
+
* @param sessionId - archived root to preview.
|
|
229
|
+
* @returns identities to show in the deletion confirmation.
|
|
230
|
+
*/
|
|
231
|
+
sessionDeletionScope(sessionId: SessionId): Promise<readonly SessionId[]>;
|
|
232
|
+
private collectSessionDeletionScope;
|
|
233
|
+
private recoverSessionDeletion;
|
|
234
|
+
private notifyDeleted;
|
|
235
|
+
private finishSessionDeletion;
|
|
205
236
|
/**
|
|
206
237
|
* Archive one session durably. The session must exist (live or in session
|
|
207
238
|
* persistence); its workspace accounting — or lack of one — is irrelevant.
|