@artenx/dshb 0.1.36 → 0.1.38

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/core/index.js CHANGED
@@ -11,7 +11,7 @@ import { registerWorkspaceInstructionRoutes } from "./workspace-instruction-rout
11
11
  import { WorkspaceBindingsStore } from "./workspace-bindings.js";
12
12
  import { registerWorkspaceInstructionInjector } from "./workspace-instruction-context.js";
13
13
  import { SyncPeerManager } from "./sync/peer-manager.js";
14
- import { i as SyncSessionService } from "../session-sync-DLr_BdvN.js";
14
+ import { i as SyncSessionService } from "../session-sync-BBCm_ou2.js";
15
15
  import { registerSyncInternalRoutes } from "./sync/internal-routes.js";
16
16
  import { SyncSshTransport } from "./sync/ssh-transport.js";
17
17
  import { SyncCoordinator } from "./sync/coordinator.js";
@@ -2,8 +2,8 @@ import { a as SyncPeer } from "../../model-CKTBf-Pl.js";
2
2
  import { n as SyncStateStore } from "../../stores-puyTC075.js";
3
3
  import { n as SyncNodeEntry, s as SyncNodeService } from "../../node-sync-C3Ym-HDu.js";
4
4
  import { SyncPeerManager } from "./peer-manager.js";
5
- import { h as SyncSessionService } from "../../session-sync-DrKShc5c.js";
6
- import { m as SyncSshTransport } from "../../ssh-transport-BxPWfu9X.js";
5
+ import { h as SyncSessionService } from "../../session-sync-Bw0cZ4oa.js";
6
+ import { m as SyncSshTransport } from "../../ssh-transport-COZe0BDr.js";
7
7
  //#region src/core/sync/coordinator.d.ts
8
8
  interface NodeTransferPlan {
9
9
  toLocal: SyncNodeEntry[];
@@ -3,7 +3,7 @@ import { syncRecordKey } from "./model.js";
3
3
  import { SyncNodeManifestError } from "./node-sync.js";
4
4
  import { SyncPeerNotFoundError } from "./peer-manager.js";
5
5
  import { SYNC_SESSION_BUNDLE_OBJECTS_CAPABILITY, SYNC_SESSION_EVENT_TAIL_CAPABILITY, SYNC_SESSION_OBJECT_STREAM_CAPABILITY } from "./protocol.js";
6
- import { c as planSessionTransfers, f as validateSyncSessionBundle, l as sessionEventListDigest, n as SyncSessionError, o as makeSyncSessionBundle, p as validateSyncSessionManifest, u as syncSessionEntryKey } from "../../session-sync-DLr_BdvN.js";
6
+ import { c as planSessionTransfers, f as validateSyncSessionBundle, l as sessionEventListDigest, n as SyncSessionError, o as makeSyncSessionBundle, p as validateSyncSessionManifest, u as syncSessionEntryKey } from "../../session-sync-BBCm_ou2.js";
7
7
  import { SyncHostKeyChallengeError } from "./host-key.js";
8
8
  import { SyncSessionDeltaPrefixError, SyncSshProbeError } from "./ssh-transport.js";
9
9
  import { createHash } from "node:crypto";
@@ -1,6 +1,6 @@
1
1
  import { n as SyncStateStore } from "../../stores-puyTC075.js";
2
2
  import { s as SyncNodeService } from "../../node-sync-C3Ym-HDu.js";
3
- import { h as SyncSessionService } from "../../session-sync-DrKShc5c.js";
3
+ import { h as SyncSessionService } from "../../session-sync-Bw0cZ4oa.js";
4
4
  import { Context } from "@deepseek-ai/cordis";
5
5
  //#region src/core/sync/internal-routes.d.ts
6
6
  declare function registerSyncInternalRoutes(ctx: Context, state: SyncStateStore, nodeSync?: SyncNodeService, sessionSync?: SyncSessionService): void;
@@ -1,7 +1,7 @@
1
1
  import { isLoopbackRequest } from "../../auth/loopback.js";
2
2
  import { SyncNodeManifestError } from "./node-sync.js";
3
3
  import { SYNC_SESSION_BUNDLE_OBJECTS_CAPABILITY, SYNC_SESSION_EVENT_TAIL_CAPABILITY, SYNC_SESSION_MANIFEST_CAPABILITY, SYNC_SESSION_OBJECT_STREAM_CAPABILITY } from "./protocol.js";
4
- import { d as validateObjectPayload, n as SyncSessionError } from "../../session-sync-DLr_BdvN.js";
4
+ import { d as validateObjectPayload, n as SyncSessionError } from "../../session-sync-BBCm_ou2.js";
5
5
  //#region src/core/sync/internal-routes.ts
6
6
  const MAX_APPLY_BODY_BYTES = 134217728;
7
7
  function sendJson(res, status, body) {
@@ -1,6 +1,6 @@
1
1
  import { n as SyncStateStore } from "../../stores-puyTC075.js";
2
2
  import { s as SyncNodeService } from "../../node-sync-C3Ym-HDu.js";
3
- import { h as SyncSessionService } from "../../session-sync-DrKShc5c.js";
3
+ import { h as SyncSessionService } from "../../session-sync-Bw0cZ4oa.js";
4
4
  //#region src/core/sync/offline-archive.d.ts
5
5
  declare const MAX_OFFLINE_ARCHIVE_BYTES: number;
6
6
  declare class SyncOfflineArchiveError extends Error {
@@ -1,4 +1,4 @@
1
- import { f as validateSyncSessionBundle, n as SyncSessionError } from "../../session-sync-DLr_BdvN.js";
1
+ import { f as validateSyncSessionBundle, n as SyncSessionError } from "../../session-sync-BBCm_ou2.js";
2
2
  import { SyncOfflineArchiveJournalStore } from "./offline-journal.js";
3
3
  import { homedir } from "node:os";
4
4
  import { appendFileSync, chmodSync, closeSync, createReadStream, createWriteStream, mkdirSync, mkdtempSync, openSync, readSync, readdirSync, rmSync, statSync, statfsSync, writeFileSync } from "node:fs";
@@ -1,4 +1,4 @@
1
- import { n as SyncSessionError } from "../../session-sync-DLr_BdvN.js";
1
+ import { n as SyncSessionError } from "../../session-sync-BBCm_ou2.js";
2
2
  import { SyncOfflineArchiveError } from "./offline-archive.js";
3
3
  import { createReadStream } from "node:fs";
4
4
  import { randomBytes } from "node:crypto";
@@ -1,5 +1,5 @@
1
1
  import { SyncPeerManager } from "./peer-manager.js";
2
- import { m as SyncSshTransport } from "../../ssh-transport-BxPWfu9X.js";
2
+ import { m as SyncSshTransport } from "../../ssh-transport-COZe0BDr.js";
3
3
  import { SyncCoordinator } from "./coordinator.js";
4
4
  import { Context } from "@deepseek-ai/cordis";
5
5
  //#region src/core/sync/routes.d.ts
@@ -1,4 +1,4 @@
1
- import { h as SyncSessionService } from "../../session-sync-DrKShc5c.js";
1
+ import { h as SyncSessionService } from "../../session-sync-Bw0cZ4oa.js";
2
2
  import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/core/sync/session-routes.d.ts
4
4
  declare function registerSyncSessionRoutes(ctx: Context, sessions: SyncSessionService): void;
@@ -1,4 +1,4 @@
1
- import { n as SyncSessionError } from "../../session-sync-DLr_BdvN.js";
1
+ import { n as SyncSessionError } from "../../session-sync-BBCm_ou2.js";
2
2
  //#region src/core/sync/session-routes.ts
3
3
  function sendJson(res, status, body) {
4
4
  res.writeHead(status, {
@@ -1,2 +1,2 @@
1
- import { C as sessionEventListDigest, D as validateSyncSessionManifest, E as validateSyncSessionBundle, S as planSessionTransfers, T as validateObjectPayload, _ as SyncSessionWorkspace, a as SyncSessionBundle, b as makeSyncSessionBundle, c as SyncSessionEventDelta, d as SyncSessionManifest, f as SyncSessionManifestEntry, g as SyncSessionTransferPlan, h as SyncSessionService, i as SyncSessionApplyResult, l as SyncSessionEventPrefix, m as SyncSessionObjectInbox, n as SyncObjectInboxWriter, o as SyncSessionEntry, p as SyncSessionObject, r as SyncSessionApplyOptions, s as SyncSessionError, t as ExportObjectCache, u as SyncSessionInstructionSnapshot, v as WorkspaceRegistryLike, w as syncSessionEntryKey, x as makeSyncSessionManifest, y as estimateJsonBytes } from "../../session-sync-DrKShc5c.js";
1
+ import { C as sessionEventListDigest, D as validateSyncSessionManifest, E as validateSyncSessionBundle, S as planSessionTransfers, T as validateObjectPayload, _ as SyncSessionWorkspace, a as SyncSessionBundle, b as makeSyncSessionBundle, c as SyncSessionEventDelta, d as SyncSessionManifest, f as SyncSessionManifestEntry, g as SyncSessionTransferPlan, h as SyncSessionService, i as SyncSessionApplyResult, l as SyncSessionEventPrefix, m as SyncSessionObjectInbox, n as SyncObjectInboxWriter, o as SyncSessionEntry, p as SyncSessionObject, r as SyncSessionApplyOptions, s as SyncSessionError, t as ExportObjectCache, u as SyncSessionInstructionSnapshot, v as WorkspaceRegistryLike, w as syncSessionEntryKey, x as makeSyncSessionManifest, y as estimateJsonBytes } from "../../session-sync-Bw0cZ4oa.js";
2
2
  export { ExportObjectCache, SyncObjectInboxWriter, SyncSessionApplyOptions, SyncSessionApplyResult, SyncSessionBundle, SyncSessionEntry, SyncSessionError, SyncSessionEventDelta, SyncSessionEventPrefix, SyncSessionInstructionSnapshot, SyncSessionManifest, SyncSessionManifestEntry, SyncSessionObject, SyncSessionObjectInbox, SyncSessionService, SyncSessionTransferPlan, SyncSessionWorkspace, WorkspaceRegistryLike, estimateJsonBytes, makeSyncSessionBundle, makeSyncSessionManifest, planSessionTransfers, sessionEventListDigest, syncSessionEntryKey, validateObjectPayload, validateSyncSessionBundle, validateSyncSessionManifest };
@@ -1,2 +1,2 @@
1
- import { a as estimateJsonBytes, c as planSessionTransfers, d as validateObjectPayload, f as validateSyncSessionBundle, i as SyncSessionService, l as sessionEventListDigest, n as SyncSessionError, o as makeSyncSessionBundle, p as validateSyncSessionManifest, r as SyncSessionObjectInbox, s as makeSyncSessionManifest, t as ExportObjectCache, u as syncSessionEntryKey } from "../../session-sync-DLr_BdvN.js";
1
+ import { a as estimateJsonBytes, c as planSessionTransfers, d as validateObjectPayload, f as validateSyncSessionBundle, i as SyncSessionService, l as sessionEventListDigest, n as SyncSessionError, o as makeSyncSessionBundle, p as validateSyncSessionManifest, r as SyncSessionObjectInbox, s as makeSyncSessionManifest, t as ExportObjectCache, u as syncSessionEntryKey } from "../../session-sync-BBCm_ou2.js";
2
2
  export { ExportObjectCache, SyncSessionError, SyncSessionObjectInbox, SyncSessionService, estimateJsonBytes, makeSyncSessionBundle, makeSyncSessionManifest, planSessionTransfers, sessionEventListDigest, syncSessionEntryKey, validateObjectPayload, validateSyncSessionBundle, validateSyncSessionManifest };
@@ -1,2 +1,2 @@
1
- import { _ as parseRemoteProbeOutput, a as SyncRemoteProbe, c as SyncRemoteProbeProfile, d as SyncSshErrorCategory, f as SyncSshProbeError, g as buildSyncSshConnectConfig, h as buildRemoteProbeScript, i as SyncRemoteNodeManifest, l as SyncRemoteProbeResult, m as SyncSshTransport, n as REMOTE_PROBE_END_MARKER, o as SyncRemoteProbeDraft, p as SyncSshSession, r as SyncRemoteHandshake, s as SyncRemoteProbeHandshake, t as REMOTE_PROBE_BEGIN_MARKER, u as SyncSessionDeltaPrefixError } from "../../ssh-transport-BxPWfu9X.js";
1
+ import { _ as parseRemoteProbeOutput, a as SyncRemoteProbe, c as SyncRemoteProbeProfile, d as SyncSshErrorCategory, f as SyncSshProbeError, g as buildSyncSshConnectConfig, h as buildRemoteProbeScript, i as SyncRemoteNodeManifest, l as SyncRemoteProbeResult, m as SyncSshTransport, n as REMOTE_PROBE_END_MARKER, o as SyncRemoteProbeDraft, p as SyncSshSession, r as SyncRemoteHandshake, s as SyncRemoteProbeHandshake, t as REMOTE_PROBE_BEGIN_MARKER, u as SyncSessionDeltaPrefixError } from "../../ssh-transport-COZe0BDr.js";
2
2
  export { REMOTE_PROBE_BEGIN_MARKER, REMOTE_PROBE_END_MARKER, SyncRemoteHandshake, SyncRemoteNodeManifest, SyncRemoteProbe, SyncRemoteProbeDraft, SyncRemoteProbeHandshake, SyncRemoteProbeProfile, SyncRemoteProbeResult, SyncSessionDeltaPrefixError, SyncSshErrorCategory, SyncSshProbeError, SyncSshSession, SyncSshTransport, buildRemoteProbeScript, buildSyncSshConnectConfig, parseRemoteProbeOutput };
@@ -1,5 +1,5 @@
1
1
  import { h as createUserMessage } from "../index-VF8bcBeX.js";
2
- import { a as SessionInstructionSnapshotStore, i as SessionInstructionSnapshot, s as WorkspaceInstructionStore } from "../workspace-instructions-DirYYiku.js";
2
+ import { a as SessionInstructionSnapshotStore, i as SessionInstructionSnapshot, s as WorkspaceInstructionStore } from "../workspace-instructions-C_ViytzA.js";
3
3
  import { Context } from "@deepseek-ai/cordis";
4
4
  //#region src/core/workspace-instruction-context.d.ts
5
5
  interface InstructionSnapshotResult {
@@ -1,4 +1,4 @@
1
- import { s as WorkspaceInstructionStore } from "../workspace-instructions-DirYYiku.js";
1
+ import { s as WorkspaceInstructionStore } from "../workspace-instructions-C_ViytzA.js";
2
2
  import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/core/workspace-instruction-routes.d.ts
4
4
  declare function registerWorkspaceInstructionRoutes(ctx: Context, store: WorkspaceInstructionStore): void;
@@ -1,2 +1,2 @@
1
- import { a as SessionInstructionSnapshotStore, c as sharedSessionInstructionSnapshotStore, i as SessionInstructionSnapshot, l as sharedWorkspaceInstructionStore, n as InstructionConflictError, o as WorkspaceInstructionRecord, r as InstructionSizeError, s as WorkspaceInstructionStore, t as INSTRUCTION_MAX_BYTES } from "../workspace-instructions-DirYYiku.js";
1
+ import { a as SessionInstructionSnapshotStore, c as sharedSessionInstructionSnapshotStore, i as SessionInstructionSnapshot, l as sharedWorkspaceInstructionStore, n as InstructionConflictError, o as WorkspaceInstructionRecord, r as InstructionSizeError, s as WorkspaceInstructionStore, t as INSTRUCTION_MAX_BYTES } from "../workspace-instructions-C_ViytzA.js";
2
2
  export { INSTRUCTION_MAX_BYTES, InstructionConflictError, InstructionSizeError, SessionInstructionSnapshot, SessionInstructionSnapshotStore, WorkspaceInstructionRecord, WorkspaceInstructionStore, sharedSessionInstructionSnapshotStore, sharedWorkspaceInstructionStore };
@@ -34,8 +34,12 @@ function computeDigest(text) {
34
34
  var WorkspaceInstructionStore = class {
35
35
  data = { records: {} };
36
36
  loaded = false;
37
+ home;
38
+ constructor(home) {
39
+ this.home = home;
40
+ }
37
41
  file() {
38
- return join(dshHome(), "dshb", "workspace-instructions.json");
42
+ return join(this.home ?? dshHome(), "dshb", "workspace-instructions.json");
39
43
  }
40
44
  load() {
41
45
  if (this.loaded) return;
@@ -92,6 +96,29 @@ var WorkspaceInstructionStore = class {
92
96
  delete this.data.records[workspaceId];
93
97
  this.save();
94
98
  }
99
+ /**
100
+ * 同步导入采纳:以对端快照的修订恢复工作区指令。
101
+ * 本地缺失或本地修订更低(对端编辑过)时采纳;本地同版或更新时保留本地。
102
+ * revision 直接采用对端计数,使两端的指令修订序列保持同一根。
103
+ */
104
+ restoreWorkspace(input) {
105
+ this.load();
106
+ if (utf8Bytes(input.text) > 32768) throw new InstructionSizeError(utf8Bytes(input.text));
107
+ const existing = this.data.records[input.workspaceId];
108
+ if (existing && existing.revision >= input.revision) return { ...existing };
109
+ const now = (/* @__PURE__ */ new Date()).toISOString();
110
+ const record = {
111
+ workspaceId: input.workspaceId,
112
+ text: input.text,
113
+ revision: input.revision,
114
+ digest: computeDigest(input.text),
115
+ createdAt: existing?.createdAt ?? input.capturedAt ?? now,
116
+ updatedAt: now
117
+ };
118
+ this.data.records[input.workspaceId] = record;
119
+ this.save();
120
+ return { ...record };
121
+ }
95
122
  removeByWorkspace(workspaceId) {
96
123
  this.load();
97
124
  if (!this.data.records[workspaceId]) return;
@@ -181,6 +208,11 @@ var SessionInstructionSnapshotStore = class {
181
208
  this.save();
182
209
  return { ...snapshot };
183
210
  }
211
+ /**
212
+ * 同步导入采纳:以对端快照的修订恢复工作区指令。
213
+ * 本地缺失或本地修订更低(对端编辑过)时采纳;本地同版或更新时保留本地。
214
+ * revision 直接采用对端计数,使两端的指令修订序列保持同一根。
215
+ */
184
216
  remove(sessionId) {
185
217
  this.load();
186
218
  if (!this.data.records[sessionId]) return;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-instructions.js","names":[],"sources":["../../src/core/workspace-instructions.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport const INSTRUCTION_MAX_BYTES = 32768\n\nexport interface WorkspaceInstructionRecord {\n workspaceId: string\n text: string\n revision: number\n digest: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface SessionInstructionSnapshot {\n sessionId: string\n workspaceId?: string\n workspaceRevision?: number\n digest?: string\n text: string\n capturedAt: string\n inheritedFromSessionId?: string\n}\n\nexport class InstructionConflictError extends Error {\n readonly expected: number\n readonly actual: number\n constructor(expected: number, actual: number) {\n super(`revision conflict: expected ${expected}, current ${actual}`)\n this.name = 'InstructionConflictError'\n this.expected = expected\n this.actual = actual\n }\n}\n\nexport class InstructionSizeError extends Error {\n readonly bytes: number\n constructor(bytes: number) {\n super(`instruction exceeds ${INSTRUCTION_MAX_BYTES} bytes (got ${bytes})`)\n this.name = 'InstructionSizeError'\n this.bytes = bytes\n }\n}\n\nfunction dshHome(): string {\n return process.env.DSH_HOME ?? join(homedir(), '.dsh')\n}\n\nfunction utf8Bytes(text: string): number {\n return Buffer.byteLength(text, 'utf8')\n}\n\nfunction computeDigest(text: string): string {\n return createHash('sha256').update(text, 'utf8').digest('hex')\n}\n\ninterface WorkspaceStoreData {\n records: Record<string, WorkspaceInstructionRecord>\n}\n\ninterface SnapshotStoreData {\n records: Record<string, SessionInstructionSnapshot>\n}\n\nexport class WorkspaceInstructionStore {\n private data: WorkspaceStoreData = { records: {} }\n private loaded = false\n\n private file(): string {\n return join(dshHome(), 'dshb', 'workspace-instructions.json')\n }\n\n private load(): void {\n if (this.loaded) return\n this.loaded = true\n try {\n const raw = readFileSync(this.file(), 'utf8')\n this.data = JSON.parse(raw) as WorkspaceStoreData\n if (!this.data.records || typeof this.data.records !== 'object') {\n this.data = { records: {} }\n }\n } catch {\n this.data = { records: {} }\n }\n }\n\n private save(): void {\n this.load()\n const file = this.file()\n mkdirSync(join(file, '..'), { recursive: true, mode: 0o700 })\n const tmp = `${file}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(this.data, null, 2), { mode: 0o600 })\n renameSync(tmp, file)\n chmodSync(file, 0o600)\n }\n\n get(workspaceId: string): WorkspaceInstructionRecord | undefined {\n this.load()\n const r = this.data.records[workspaceId]\n return r ? { ...r } : undefined\n }\n\n update(input: {\n workspaceId: string\n text: string\n expectedRevision: number\n }): WorkspaceInstructionRecord {\n this.load()\n const bytes = utf8Bytes(input.text)\n if (bytes > INSTRUCTION_MAX_BYTES) throw new InstructionSizeError(bytes)\n const existing = this.data.records[input.workspaceId]\n if (existing && existing.revision !== input.expectedRevision) {\n throw new InstructionConflictError(input.expectedRevision, existing.revision)\n }\n const now = new Date().toISOString()\n const record: WorkspaceInstructionRecord = {\n workspaceId: input.workspaceId,\n text: input.text,\n revision: (existing?.revision ?? 0) + 1,\n digest: computeDigest(input.text),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n }\n this.data.records[input.workspaceId] = record\n this.save()\n return { ...record }\n }\n\n clear(workspaceId: string, expectedRevision: number): void {\n this.load()\n const existing = this.data.records[workspaceId]\n if (existing && existing.revision !== expectedRevision) {\n throw new InstructionConflictError(expectedRevision, existing.revision)\n }\n if (!existing) return\n delete this.data.records[workspaceId]\n this.save()\n }\n\n removeByWorkspace(workspaceId: string): void {\n this.load()\n if (!this.data.records[workspaceId]) return\n delete this.data.records[workspaceId]\n this.save()\n }\n}\n\nexport class SessionInstructionSnapshotStore {\n private data: SnapshotStoreData = { records: {} }\n private loaded = false\n\n private file(): string {\n return join(dshHome(), 'dshb', 'session-instruction-snapshots.json')\n }\n\n private load(): void {\n if (this.loaded) return\n this.loaded = true\n try {\n const raw = readFileSync(this.file(), 'utf8')\n this.data = JSON.parse(raw) as SnapshotStoreData\n if (!this.data.records || typeof this.data.records !== 'object') {\n this.data = { records: {} }\n }\n } catch {\n this.data = { records: {} }\n }\n }\n\n private save(): void {\n this.load()\n const file = this.file()\n mkdirSync(join(file, '..'), { recursive: true, mode: 0o700 })\n const tmp = `${file}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(this.data, null, 2), { mode: 0o600 })\n renameSync(tmp, file)\n chmodSync(file, 0o600)\n }\n\n get(sessionId: string): SessionInstructionSnapshot | undefined {\n this.load()\n const r = this.data.records[sessionId]\n return r ? { ...r } : undefined\n }\n\n createIfAbsent(\n sessionId: string,\n source:\n | { kind: 'workspace'; record: WorkspaceInstructionRecord; workspaceId: string }\n | { kind: 'empty'; workspaceId?: string }\n | { kind: 'inherit'; parentSnapshot: SessionInstructionSnapshot },\n ): SessionInstructionSnapshot {\n this.load()\n const existing = this.data.records[sessionId]\n if (existing) return { ...existing }\n let snapshot: SessionInstructionSnapshot\n const now = new Date().toISOString()\n if (source.kind === 'workspace') {\n snapshot = {\n sessionId,\n workspaceId: source.workspaceId,\n workspaceRevision: source.record.revision,\n digest: source.record.digest,\n text: source.record.text,\n capturedAt: now,\n }\n } else if (source.kind === 'inherit') {\n const parent = source.parentSnapshot\n snapshot = {\n sessionId,\n workspaceId: parent.workspaceId,\n workspaceRevision: parent.workspaceRevision,\n digest: parent.digest,\n text: parent.text,\n capturedAt: now,\n inheritedFromSessionId: parent.sessionId,\n }\n } else {\n snapshot = {\n sessionId,\n workspaceId: source.workspaceId,\n text: '',\n capturedAt: now,\n }\n }\n this.data.records[sessionId] = snapshot\n this.save()\n return { ...snapshot }\n }\n\n restore(snapshot: SessionInstructionSnapshot): SessionInstructionSnapshot {\n this.load()\n if (utf8Bytes(snapshot.text) > INSTRUCTION_MAX_BYTES) throw new InstructionSizeError(utf8Bytes(snapshot.text))\n if (snapshot.digest !== undefined && snapshot.digest !== computeDigest(snapshot.text)) {\n throw new Error('session instruction snapshot digest mismatch')\n }\n const existing = this.data.records[snapshot.sessionId]\n if (existing) {\n if (JSON.stringify(existing) !== JSON.stringify(snapshot)) throw new Error('session instruction snapshot already differs')\n return { ...existing }\n }\n this.data.records[snapshot.sessionId] = { ...snapshot }\n this.save()\n return { ...snapshot }\n }\n\n remove(sessionId: string): void {\n this.load()\n if (!this.data.records[sessionId]) return\n delete this.data.records[sessionId]\n this.save()\n }\n}\n\nlet sharedWorkspaceStore: WorkspaceInstructionStore | null = null\nlet sharedSnapshotStore: SessionInstructionSnapshotStore | null = null\n\nexport function sharedWorkspaceInstructionStore(): WorkspaceInstructionStore {\n if (!sharedWorkspaceStore) sharedWorkspaceStore = new WorkspaceInstructionStore()\n return sharedWorkspaceStore\n}\n\nexport function sharedSessionInstructionSnapshotStore(): SessionInstructionSnapshotStore {\n if (!sharedSnapshotStore) sharedSnapshotStore = new SessionInstructionSnapshotStore()\n return sharedSnapshotStore\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workspace-instructions.js","names":[],"sources":["../../src/core/workspace-instructions.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport const INSTRUCTION_MAX_BYTES = 32768\n\nexport interface WorkspaceInstructionRecord {\n workspaceId: string\n text: string\n revision: number\n digest: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface SessionInstructionSnapshot {\n sessionId: string\n workspaceId?: string\n workspaceRevision?: number\n digest?: string\n text: string\n capturedAt: string\n inheritedFromSessionId?: string\n}\n\nexport class InstructionConflictError extends Error {\n readonly expected: number\n readonly actual: number\n constructor(expected: number, actual: number) {\n super(`revision conflict: expected ${expected}, current ${actual}`)\n this.name = 'InstructionConflictError'\n this.expected = expected\n this.actual = actual\n }\n}\n\nexport class InstructionSizeError extends Error {\n readonly bytes: number\n constructor(bytes: number) {\n super(`instruction exceeds ${INSTRUCTION_MAX_BYTES} bytes (got ${bytes})`)\n this.name = 'InstructionSizeError'\n this.bytes = bytes\n }\n}\n\nfunction dshHome(): string {\n return process.env.DSH_HOME ?? join(homedir(), '.dsh')\n}\n\nfunction utf8Bytes(text: string): number {\n return Buffer.byteLength(text, 'utf8')\n}\n\nfunction computeDigest(text: string): string {\n return createHash('sha256').update(text, 'utf8').digest('hex')\n}\n\ninterface WorkspaceStoreData {\n records: Record<string, WorkspaceInstructionRecord>\n}\n\ninterface SnapshotStoreData {\n records: Record<string, SessionInstructionSnapshot>\n}\n\nexport class WorkspaceInstructionStore {\n private data: WorkspaceStoreData = { records: {} }\n private loaded = false\n private readonly home: string | undefined\n\n constructor(home?: string) {\n this.home = home\n }\n\n private file(): string {\n return join(this.home ?? dshHome(), 'dshb', 'workspace-instructions.json')\n }\n\n private load(): void {\n if (this.loaded) return\n this.loaded = true\n try {\n const raw = readFileSync(this.file(), 'utf8')\n this.data = JSON.parse(raw) as WorkspaceStoreData\n if (!this.data.records || typeof this.data.records !== 'object') {\n this.data = { records: {} }\n }\n } catch {\n this.data = { records: {} }\n }\n }\n\n private save(): void {\n this.load()\n const file = this.file()\n mkdirSync(join(file, '..'), { recursive: true, mode: 0o700 })\n const tmp = `${file}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(this.data, null, 2), { mode: 0o600 })\n renameSync(tmp, file)\n chmodSync(file, 0o600)\n }\n\n get(workspaceId: string): WorkspaceInstructionRecord | undefined {\n this.load()\n const r = this.data.records[workspaceId]\n return r ? { ...r } : undefined\n }\n\n update(input: {\n workspaceId: string\n text: string\n expectedRevision: number\n }): WorkspaceInstructionRecord {\n this.load()\n const bytes = utf8Bytes(input.text)\n if (bytes > INSTRUCTION_MAX_BYTES) throw new InstructionSizeError(bytes)\n const existing = this.data.records[input.workspaceId]\n if (existing && existing.revision !== input.expectedRevision) {\n throw new InstructionConflictError(input.expectedRevision, existing.revision)\n }\n const now = new Date().toISOString()\n const record: WorkspaceInstructionRecord = {\n workspaceId: input.workspaceId,\n text: input.text,\n revision: (existing?.revision ?? 0) + 1,\n digest: computeDigest(input.text),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n }\n this.data.records[input.workspaceId] = record\n this.save()\n return { ...record }\n }\n\n clear(workspaceId: string, expectedRevision: number): void {\n this.load()\n const existing = this.data.records[workspaceId]\n if (existing && existing.revision !== expectedRevision) {\n throw new InstructionConflictError(expectedRevision, existing.revision)\n }\n if (!existing) return\n delete this.data.records[workspaceId]\n this.save()\n }\n\n /**\n * 同步导入采纳:以对端快照的修订恢复工作区指令。\n * 本地缺失或本地修订更低(对端编辑过)时采纳;本地同版或更新时保留本地。\n * revision 直接采用对端计数,使两端的指令修订序列保持同一根。\n */\n restoreWorkspace(input: { workspaceId: string; text: string; revision: number; capturedAt?: string }): WorkspaceInstructionRecord | undefined {\n this.load()\n if (utf8Bytes(input.text) > INSTRUCTION_MAX_BYTES) throw new InstructionSizeError(utf8Bytes(input.text))\n const existing = this.data.records[input.workspaceId]\n if (existing && existing.revision >= input.revision) return { ...existing }\n const now = new Date().toISOString()\n const record: WorkspaceInstructionRecord = {\n workspaceId: input.workspaceId,\n text: input.text,\n revision: input.revision,\n digest: computeDigest(input.text),\n createdAt: existing?.createdAt ?? (input.capturedAt ?? now),\n updatedAt: now,\n }\n this.data.records[input.workspaceId] = record\n this.save()\n return { ...record }\n }\n\n removeByWorkspace(workspaceId: string): void {\n this.load()\n if (!this.data.records[workspaceId]) return\n delete this.data.records[workspaceId]\n this.save()\n }\n}\n\nexport class SessionInstructionSnapshotStore {\n private data: SnapshotStoreData = { records: {} }\n private loaded = false\n\n private file(): string {\n return join(dshHome(), 'dshb', 'session-instruction-snapshots.json')\n }\n\n private load(): void {\n if (this.loaded) return\n this.loaded = true\n try {\n const raw = readFileSync(this.file(), 'utf8')\n this.data = JSON.parse(raw) as SnapshotStoreData\n if (!this.data.records || typeof this.data.records !== 'object') {\n this.data = { records: {} }\n }\n } catch {\n this.data = { records: {} }\n }\n }\n\n private save(): void {\n this.load()\n const file = this.file()\n mkdirSync(join(file, '..'), { recursive: true, mode: 0o700 })\n const tmp = `${file}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(this.data, null, 2), { mode: 0o600 })\n renameSync(tmp, file)\n chmodSync(file, 0o600)\n }\n\n get(sessionId: string): SessionInstructionSnapshot | undefined {\n this.load()\n const r = this.data.records[sessionId]\n return r ? { ...r } : undefined\n }\n\n createIfAbsent(\n sessionId: string,\n source:\n | { kind: 'workspace'; record: WorkspaceInstructionRecord; workspaceId: string }\n | { kind: 'empty'; workspaceId?: string }\n | { kind: 'inherit'; parentSnapshot: SessionInstructionSnapshot },\n ): SessionInstructionSnapshot {\n this.load()\n const existing = this.data.records[sessionId]\n if (existing) return { ...existing }\n let snapshot: SessionInstructionSnapshot\n const now = new Date().toISOString()\n if (source.kind === 'workspace') {\n snapshot = {\n sessionId,\n workspaceId: source.workspaceId,\n workspaceRevision: source.record.revision,\n digest: source.record.digest,\n text: source.record.text,\n capturedAt: now,\n }\n } else if (source.kind === 'inherit') {\n const parent = source.parentSnapshot\n snapshot = {\n sessionId,\n workspaceId: parent.workspaceId,\n workspaceRevision: parent.workspaceRevision,\n digest: parent.digest,\n text: parent.text,\n capturedAt: now,\n inheritedFromSessionId: parent.sessionId,\n }\n } else {\n snapshot = {\n sessionId,\n workspaceId: source.workspaceId,\n text: '',\n capturedAt: now,\n }\n }\n this.data.records[sessionId] = snapshot\n this.save()\n return { ...snapshot }\n }\n\n restore(snapshot: SessionInstructionSnapshot): SessionInstructionSnapshot {\n this.load()\n if (utf8Bytes(snapshot.text) > INSTRUCTION_MAX_BYTES) throw new InstructionSizeError(utf8Bytes(snapshot.text))\n if (snapshot.digest !== undefined && snapshot.digest !== computeDigest(snapshot.text)) {\n throw new Error('session instruction snapshot digest mismatch')\n }\n const existing = this.data.records[snapshot.sessionId]\n if (existing) {\n if (JSON.stringify(existing) !== JSON.stringify(snapshot)) throw new Error('session instruction snapshot already differs')\n return { ...existing }\n }\n this.data.records[snapshot.sessionId] = { ...snapshot }\n this.save()\n return { ...snapshot }\n }\n\n /**\n * 同步导入采纳:以对端快照的修订恢复工作区指令。\n * 本地缺失或本地修订更低(对端编辑过)时采纳;本地同版或更新时保留本地。\n * revision 直接采用对端计数,使两端的指令修订序列保持同一根。\n */\n remove(sessionId: string): void {\n this.load()\n if (!this.data.records[sessionId]) return\n delete this.data.records[sessionId]\n this.save()\n }\n}\n\nlet sharedWorkspaceStore: WorkspaceInstructionStore | null = null\nlet sharedSnapshotStore: SessionInstructionSnapshotStore | null = null\n\nexport function sharedWorkspaceInstructionStore(): WorkspaceInstructionStore {\n if (!sharedWorkspaceStore) sharedWorkspaceStore = new WorkspaceInstructionStore()\n return sharedWorkspaceStore\n}\n\nexport function sharedSessionInstructionSnapshotStore(): SessionInstructionSnapshotStore {\n if (!sharedSnapshotStore) sharedSnapshotStore = new SessionInstructionSnapshotStore()\n return sharedSnapshotStore\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { compareSyncRevision } from "./core/sync/revision.js";
2
2
  import { isNonNegativeSafeInteger, isRecord as isRecord$1, syncRecordKey, syncWorkspaceKey } from "./core/sync/model.js";
3
- import "./core/workspace-instructions.js";
3
+ import { InstructionSizeError, sharedWorkspaceInstructionStore } from "./core/workspace-instructions.js";
4
4
  import { i as deepFreeze, r as brandString } from "./lib-gdtU_WKT.js";
5
5
  import { MAX_SESSION_OBJECT_INLINE_BYTES, MAX_SESSION_OBJECT_STREAM_BYTES, MAX_SYNC_TRANSFER_BYTES } from "./core/sync/protocol.js";
6
6
  import { SyncSessionJournalStore } from "./core/sync/session-journal.js";
@@ -1042,11 +1042,11 @@ function sessionEventDigest(header, inheritedEventCount, events, workspace, inst
1042
1042
  hash.update(`,"instructionSnapshot":${instructionSnapshot ? canonicalJson({
1043
1043
  text: instructionSnapshot.text,
1044
1044
  capturedAt: instructionSnapshot.capturedAt,
1045
- workspaceOrigin: instructionSnapshot.workspaceOrigin,
1046
- workspaceRemotePath: instructionSnapshot.workspaceRemotePath,
1047
- workspaceRevision: instructionSnapshot.workspaceRevision,
1048
- digest: instructionSnapshot.digest,
1049
- inheritedFromOrigin: instructionSnapshot.inheritedFromOrigin
1045
+ ...instructionSnapshot.workspaceOrigin === void 0 ? {} : { workspaceOrigin: instructionSnapshot.workspaceOrigin },
1046
+ ...instructionSnapshot.workspaceRemotePath === void 0 ? {} : { workspaceRemotePath: instructionSnapshot.workspaceRemotePath },
1047
+ ...instructionSnapshot.workspaceRevision === void 0 ? {} : { workspaceRevision: instructionSnapshot.workspaceRevision },
1048
+ ...instructionSnapshot.digest === void 0 ? {} : { digest: instructionSnapshot.digest },
1049
+ ...instructionSnapshot.inheritedFromOrigin === void 0 ? {} : { inheritedFromOrigin: instructionSnapshot.inheritedFromOrigin }
1050
1050
  }) : "undefined"}`);
1051
1051
  hash.update(`,"parentOrigin":${parentOrigin ? canonicalJson(parentOrigin) : "undefined"}`);
1052
1052
  hash.update(`,"workspace":${canonicalJson({
@@ -1079,7 +1079,6 @@ function sessionStateDigest(workspace, workspacePosition, archived, pinned) {
1079
1079
  revision: workspace.revision,
1080
1080
  contentDigest: workspace.contentDigest
1081
1081
  },
1082
- workspacePosition,
1083
1082
  archived,
1084
1083
  pinned
1085
1084
  }));
@@ -1746,7 +1745,9 @@ var SyncSessionService = class SyncSessionService {
1746
1745
  manifestPayloadCacheBytes = 0;
1747
1746
  /** 带外对象收件箱:对象流 RPC 的落盘暂存区,apply 水合后删除。 */
1748
1747
  objectInbox;
1749
- constructor(state, nodes, registry, bindings, getWorkspaces, getPersistence, getAttachments, getSpills, instructions, journal = new SyncSessionJournalStore(), now = Date.now, home) {
1748
+ /** 工作区级指令存储:导入采纳写入,驱动该工作区新会话的指令注入。 */
1749
+ workspaceInstructions;
1750
+ constructor(state, nodes, registry, bindings, getWorkspaces, getPersistence, getAttachments, getSpills, instructions, journal = new SyncSessionJournalStore(), now = Date.now, home, workspaceInstructions) {
1750
1751
  this.state = state;
1751
1752
  this.nodes = nodes;
1752
1753
  this.registry = registry;
@@ -1760,6 +1761,7 @@ var SyncSessionService = class SyncSessionService {
1760
1761
  this.now = now;
1761
1762
  this.exportCacheStore = new SyncSessionExportCacheStore(home);
1762
1763
  this.objectInbox = new SyncSessionObjectInbox(home);
1764
+ this.workspaceInstructions = workspaceInstructions ?? sharedWorkspaceInstructionStore();
1763
1765
  for (const [key, entry] of this.exportCacheStore.entries()) if (!this.exportCache.has(key)) this.exportCache.set(key, entry);
1764
1766
  }
1765
1767
  exportBundle() {
@@ -2630,7 +2632,20 @@ var SyncSessionService = class SyncSessionService {
2630
2632
  async applyPrepared(prepared) {
2631
2633
  const sessionId = prepared.localSessionId;
2632
2634
  const existed = await this.writeSession(prepared);
2633
- if (prepared.instructionSnapshot) this.instructions.restore(prepared.instructionSnapshot);
2635
+ if (prepared.instructionSnapshot) {
2636
+ this.instructions.restore(prepared.instructionSnapshot);
2637
+ const snapshot = prepared.instructionSnapshot;
2638
+ if (snapshot.workspaceId && snapshot.workspaceRevision !== void 0) try {
2639
+ this.workspaceInstructions.restoreWorkspace({
2640
+ workspaceId: snapshot.workspaceId,
2641
+ text: snapshot.text,
2642
+ revision: snapshot.workspaceRevision,
2643
+ capturedAt: snapshot.capturedAt
2644
+ });
2645
+ } catch (error) {
2646
+ if (!(error instanceof InstructionSizeError)) throw error;
2647
+ }
2648
+ }
2634
2649
  const registry = this.getWorkspaces();
2635
2650
  const workspace = registry?.get(prepared.workspaceId);
2636
2651
  if (!registry || !workspace || normalize(workspace.path) !== normalize(prepared.workspacePath)) throw new SyncSessionError("workspace-unmapped", "导入 session 的目标工作区不可用");
@@ -2985,7 +3000,7 @@ var SyncSessionService = class SyncSessionService {
2985
3000
  let contentDigest = digest;
2986
3001
  let outputBranchId = archive?.branchId;
2987
3002
  if (archive) {
2988
- if (archive.contentDigest !== digest || archive.stateDigest !== stateDigest || archive.workspacePosition !== workspacePosition) {
3003
+ if (archive.contentDigest !== digest || archive.stateDigest !== stateDigest) {
2989
3004
  const nextRevision = this.state.nextRevision(this.now());
2990
3005
  revision = nextRevision;
2991
3006
  const branchId = archive.contentDigest !== digest ? branchIdFor({
@@ -3398,4 +3413,4 @@ var SyncSessionService = class SyncSessionService {
3398
3413
  //#endregion
3399
3414
  export { estimateJsonBytes as a, planSessionTransfers as c, validateObjectPayload as d, validateSyncSessionBundle as f, SyncSessionService as i, sessionEventListDigest as l, SyncSessionError as n, makeSyncSessionBundle as o, validateSyncSessionManifest as p, SyncSessionObjectInbox as r, makeSyncSessionManifest as s, ExportObjectCache as t, syncSessionEntryKey as u };
3400
3415
 
3401
- //# sourceMappingURL=session-sync-DLr_BdvN.js.map
3416
+ //# sourceMappingURL=session-sync-BBCm_ou2.js.map