@mengruo/dsh-vision-toolkit 0.1.3 → 0.1.4

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.
Files changed (80) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +4 -0
  3. package/README.zh.md +4 -0
  4. package/docs/requirements-traceability/README.i18n.yaml +2 -2
  5. package/docs/requirements-traceability/README.md +1 -1
  6. package/docs/requirements-traceability/README.zh.md +1 -1
  7. package/lib/artifact-access.js +20 -2
  8. package/lib/artifact-access.js.map +1 -1
  9. package/lib/client.js +22 -7
  10. package/lib/client.js.map +1 -1
  11. package/lib/config.js +34 -0
  12. package/lib/config.js.map +1 -1
  13. package/lib/errors.js +25 -2
  14. package/lib/errors.js.map +1 -1
  15. package/lib/evidence-cache.js +2 -1
  16. package/lib/evidence-cache.js.map +1 -1
  17. package/lib/exposure.js +14 -1
  18. package/lib/exposure.js.map +1 -1
  19. package/lib/image-input-variants.js +22 -12
  20. package/lib/image-input-variants.js.map +1 -1
  21. package/lib/index.js +53 -6
  22. package/lib/index.js.map +1 -1
  23. package/lib/paste-images.js +67 -19
  24. package/lib/paste-images.js.map +1 -1
  25. package/lib/paths.js +214 -28
  26. package/lib/paths.js.map +1 -1
  27. package/lib/runtime-manager.js +76 -10
  28. package/lib/runtime-manager.js.map +1 -1
  29. package/lib/runtime.js +80 -12
  30. package/lib/runtime.js.map +1 -1
  31. package/lib/storage-history.js +154 -0
  32. package/lib/storage-history.js.map +1 -0
  33. package/lib/types/artifact-access.d.ts.map +1 -1
  34. package/lib/types/client/index.d.ts +6 -1
  35. package/lib/types/client/index.d.ts.map +1 -1
  36. package/lib/types/client/paste-images.d.ts +2 -0
  37. package/lib/types/client/paste-images.d.ts.map +1 -1
  38. package/lib/types/config.d.ts +22 -0
  39. package/lib/types/config.d.ts.map +1 -1
  40. package/lib/types/errors.d.ts +18 -2
  41. package/lib/types/errors.d.ts.map +1 -1
  42. package/lib/types/evidence-cache.d.ts +1 -1
  43. package/lib/types/evidence-cache.d.ts.map +1 -1
  44. package/lib/types/exposure.d.ts.map +1 -1
  45. package/lib/types/image-input-variants.d.ts +5 -3
  46. package/lib/types/image-input-variants.d.ts.map +1 -1
  47. package/lib/types/index.d.ts.map +1 -1
  48. package/lib/types/paste-images.d.ts +12 -4
  49. package/lib/types/paste-images.d.ts.map +1 -1
  50. package/lib/types/paths.d.ts +31 -5
  51. package/lib/types/paths.d.ts.map +1 -1
  52. package/lib/types/runtime-manager.d.ts +28 -4
  53. package/lib/types/runtime-manager.d.ts.map +1 -1
  54. package/lib/types/runtime.d.ts +19 -1
  55. package/lib/types/runtime.d.ts.map +1 -1
  56. package/lib/types/storage-history.d.ts +63 -0
  57. package/lib/types/storage-history.d.ts.map +1 -0
  58. package/lib/types/upstream.d.ts.map +1 -1
  59. package/lib/types/web.d.ts.map +1 -1
  60. package/lib/upstream.js +31 -8
  61. package/lib/upstream.js.map +1 -1
  62. package/lib/web.js +9 -3
  63. package/lib/web.js.map +1 -1
  64. package/package.json +1 -1
  65. package/src/artifact-access.ts +22 -2
  66. package/src/client/index.tsx +18 -3
  67. package/src/client/paste-images.tsx +14 -4
  68. package/src/config.ts +61 -0
  69. package/src/errors.ts +25 -2
  70. package/src/evidence-cache.ts +2 -1
  71. package/src/exposure.ts +16 -2
  72. package/src/image-input-variants.ts +21 -6
  73. package/src/index.ts +65 -6
  74. package/src/paste-images.ts +81 -19
  75. package/src/paths.ts +249 -28
  76. package/src/runtime-manager.ts +93 -10
  77. package/src/runtime.ts +79 -11
  78. package/src/storage-history.ts +172 -0
  79. package/src/upstream.ts +32 -7
  80. package/src/web.ts +9 -2
package/lib/index.js CHANGED
@@ -10,11 +10,12 @@
10
10
  * @module @mengruo/dsh-vision-toolkit
11
11
  */
12
12
  import { ArtifactAccessController, prepareArtifactAccessKey } from "./artifact-access.js";
13
- import { Config, VISION_TOOLKIT_SETTINGS_NAMESPACE, resolveConfig, } from "./config.js";
13
+ import { Config, VISION_TOOLKIT_SETTINGS_NAMESPACE, prepareWatchedSettingsGeneration, resolveConfig, } from "./config.js";
14
14
  import { VisionToolExposure } from "./exposure.js";
15
15
  import { createPasteTakeoverResolver, installImageInputVariants } from "./image-input-variants.js";
16
16
  import { VisionToolkitRuntimeManager } from "./runtime-manager.js";
17
17
  import { VISION_SKILLS_SKILL } from "./skill.js";
18
+ import { StorageHistoryStore } from "./storage-history.js";
18
19
  import { createVisionTools } from "./tools.js";
19
20
  import { PLUGIN_VERSION } from "./version.js";
20
21
  import { installVisionToolkitWeb, VisionToolkitWebBackend } from "./web.js";
@@ -37,7 +38,33 @@ export async function apply(ctx, config = {}) {
37
38
  const artifacts = new ArtifactAccessController(await prepareArtifactAccessKey());
38
39
  const lifecycle = new AbortController();
39
40
  const disposers = [];
41
+ const storageHistory = new StorageHistoryStore(ctx);
42
+ disposers.push(() => { storageHistory.dispose(); });
43
+ let storageHistoryWarningReported = false;
40
44
  let operationalDisposers;
45
+ const persistStorageHistory = async (candidate, required) => {
46
+ try {
47
+ const persisted = await storageHistory.persist(candidate);
48
+ if (persisted)
49
+ return;
50
+ const error = new Error('configured storage history requires @deepseek-ai/dsh-storage-domain when Settings cannot persist it');
51
+ if (required)
52
+ throw error;
53
+ if (!storageHistoryWarningReported) {
54
+ storageHistoryWarningReported = true;
55
+ ctx.logger.warn('dsh-vision-toolkit: %s', error.message);
56
+ }
57
+ }
58
+ catch (error) {
59
+ if (required)
60
+ throw error;
61
+ if (!storageHistoryWarningReported) {
62
+ storageHistoryWarningReported = true;
63
+ const message = error instanceof Error ? error.message : String(error);
64
+ ctx.logger.warn('dsh-vision-toolkit: configured storage history was not persisted. %s', message);
65
+ }
66
+ }
67
+ };
41
68
  const ensureOperational = () => {
42
69
  if (!manager.ready || operationalDisposers !== undefined)
43
70
  return;
@@ -61,27 +88,47 @@ export async function apply(ctx, config = {}) {
61
88
  throw error;
62
89
  }
63
90
  };
91
+ const initialConfig = await storageHistory.restore(settings.get());
64
92
  try {
65
- await manager.initialize(settings.get());
93
+ await manager.initialize(initialConfig, candidate => persistStorageHistory(candidate.config, false));
66
94
  ensureOperational();
67
95
  }
68
96
  catch (error) {
97
+ const resolvedInitial = resolveConfig(initialConfig);
98
+ if (resolvedInitial.storageDir === undefined
99
+ || manager.validatedStorageDirectory() === resolvedInitial.storageDir) {
100
+ await persistStorageHistory(initialConfig, false);
101
+ }
69
102
  const message = error instanceof Error ? error.message : String(error);
70
103
  ctx.logger.error('dsh-vision-toolkit %s: runtime not ready; the vision-skills skill, activation bootstrap, and Agent-scoped visual tools are NOT registered. Settings remain available for repair. %s', PLUGIN_VERSION, message);
71
104
  }
72
105
  const backend = new VisionToolkitWebBackend(ctx, manager, artifacts, ensureOperational);
106
+ const currentConfig = () => manager.ready
107
+ ? manager.currentConfig()
108
+ : resolveConfig(settings.get());
73
109
  const pastedImages = new PastedImageBackend(ctx, {
74
110
  maxUploadBytes: () => MAX_PASTE_IMAGE_BYTES,
111
+ storageGeneration: () => manager.storageGeneration(),
75
112
  });
76
113
  // Image-input variants register asynchronously once eligible routes exist;
77
114
  // the runtime getter stays lazy so variants appear even when the runtime
78
115
  // becomes ready after the first sweep.
79
- const variants = installImageInputVariants(ctx, () => resolveConfig(settings.get()), () => manager.ready ? manager.current() : undefined);
80
- installVisionToolkitWeb(ctx, backend, artifacts, pastedImages, createPasteTakeoverResolver(ctx, () => resolveConfig(settings.get())), () => ({ hidden: resolveConfig(settings.get()).imageInputVariants.hidden }));
116
+ const variants = installImageInputVariants(ctx, currentConfig, () => manager.ready ? manager.current() : undefined, () => manager.validatedStorageDirectory());
117
+ installVisionToolkitWeb(ctx, backend, artifacts, pastedImages, createPasteTakeoverResolver(ctx, currentConfig), () => ({ hidden: currentConfig().imageInputVariants.hidden }));
81
118
  disposers.push(variants.dispose);
82
- disposers.push(settings.watch(async (next) => {
119
+ disposers.push(settings.watch(async (next, previous) => {
83
120
  try {
84
- await manager.reconfigure(next);
121
+ const prepared = await prepareWatchedSettingsGeneration(next, previous, ctx.settings.writable, storageHistory => settings.update({ storageHistory }));
122
+ if (prepared.persistenceError !== undefined) {
123
+ const message = prepared.persistenceError instanceof Error
124
+ ? prepared.persistenceError.message
125
+ : String(prepared.persistenceError);
126
+ ctx.logger.warn('dsh-vision-toolkit: activating Settings without persisting internal storage history. %s', message);
127
+ }
128
+ if (prepared.config === undefined)
129
+ return;
130
+ const candidate = await storageHistory.restore(prepared.config);
131
+ await manager.reconfigure(candidate, generation => persistStorageHistory(generation.config, prepared.requiresDurableStorageHistory === true));
85
132
  ensureOperational();
86
133
  variants.reconcile();
87
134
  }
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
- /** Workspace-local storage for images pasted into the DSH Web composer. */
1
+ /** Plugin-managed storage for images pasted into the DSH Web composer. */
2
2
  import { createHash, randomUUID } from 'node:crypto';
3
- import { lstat, mkdir, open, realpath, rename, rm } from 'node:fs/promises';
3
+ import { constants as fsConstants } from 'node:fs';
4
+ import { copyFile, lstat, mkdir, open, realpath, rename, rm } from 'node:fs/promises';
4
5
  import { basename, extname, isAbsolute, join, relative, resolve, sep } from 'node:path';
6
+ import { resolveWorkspaceStorage } from "./paths.js";
5
7
  import { sameOriginPost } from "./web-request.js";
6
8
  /** Exact route used by the browser paste integration. */
7
9
  export const PASTE_IMAGES_ROUTE = '/_dsh/vision-toolkit/paste-images';
@@ -12,6 +14,7 @@ export const PASTE_IMAGES_ROUTE = '/_dsh/vision-toolkit/paste-images';
12
14
  */
13
15
  export const PASTE_POLICY_ROUTE = '/_dsh/vision-toolkit/paste-policy';
14
16
  const MAX_NAME_BYTES = 180;
17
+ const MAX_STORAGE_GENERATION_RETRIES = 4;
15
18
  /**
16
19
  * Hard per-image upload ceiling for pastes. Files between the configured
17
20
  * `maxImageBytes` (default 4 MiB) and this ceiling are stored as-is and
@@ -95,7 +98,7 @@ export function safePastedImageName(raw, mediaType) {
95
98
  export function ensurePathInside(root, target) {
96
99
  const rel = relative(root, target);
97
100
  if (rel !== '' && (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel))) {
98
- throw new Error(`resolved pasted-image path escapes its workspace root: ${target}`);
101
+ throw new Error(`resolved pasted-image path escapes its managed root: ${target}`);
99
102
  }
100
103
  }
101
104
  async function ensureManagedDirectory(workspace, path) {
@@ -108,7 +111,7 @@ async function ensureManagedDirectory(workspace, path) {
108
111
  }
109
112
  const entry = await lstat(path);
110
113
  if (entry.isSymbolicLink()) {
111
- throw new Error(`resolved pasted-image path escapes its workspace root: symbolic link ${path}`);
114
+ throw new Error(`resolved pasted-image path escapes its managed root: symbolic link ${path}`);
112
115
  }
113
116
  if (!entry.isDirectory())
114
117
  throw new Error(`pasted-image path is not a directory: ${path}`);
@@ -118,29 +121,29 @@ async function ensureManagedDirectory(workspace, path) {
118
121
  }
119
122
  /**
120
123
  * Resolve the managed per-session image directory used by both browser pastes
121
- * and native attachment bridging. Keeping both flows under the same workspace
122
- * root makes the resulting absolute path valid for the model's visual tools.
124
+ * and native attachment bridging. A configured shared storage root receives a
125
+ * stable workspace-specific child, keeping projects isolated without writing
126
+ * plugin files into the project directory.
123
127
  */
124
- export async function sessionPasteRoot(ctx, sessionId) {
128
+ export async function sessionPasteRoot(ctx, sessionId, storageDir) {
125
129
  const session = ctx.sessions.get(sessionId);
126
130
  if (session === undefined)
127
131
  throw new Error(`live Session not found: ${sessionId}`);
128
132
  const cwd = session.header.cwd;
129
133
  if (cwd === undefined || !isAbsolute(cwd))
130
134
  throw new Error(`Session has no absolute workspace: ${sessionId}`);
131
- const visibleWorkspace = resolve(cwd);
132
- const workspace = await realpath(visibleWorkspace);
133
- const pluginRoot = join(visibleWorkspace, '.dsh-vision-toolkit');
134
- await ensureManagedDirectory(workspace, pluginRoot);
135
+ const storage = await resolveWorkspaceStorage(resolve(cwd), storageDir);
136
+ const pluginRoot = storage.root;
135
137
  const temporaryRoot = join(pluginRoot, 'tmp');
136
- await ensureManagedDirectory(workspace, temporaryRoot);
138
+ await ensureManagedDirectory(pluginRoot, temporaryRoot);
137
139
  const requestedRoot = join(temporaryRoot, 'pasted-images');
138
- const root = await ensureManagedDirectory(workspace, requestedRoot);
140
+ const root = await ensureManagedDirectory(temporaryRoot, requestedRoot);
141
+ const visibleRoot = join(storage.visibleRoot, 'tmp', 'pasted-images');
139
142
  const sessionKey = createHash('sha256').update(sessionId).digest('hex').slice(0, 20);
140
143
  const requestedSessionRoot = join(requestedRoot, sessionKey);
141
144
  const sessionRoot = await ensureManagedDirectory(root, requestedSessionRoot);
142
145
  ensurePathInside(root, sessionRoot);
143
- return { writeRoot: sessionRoot, visibleRoot: requestedSessionRoot };
146
+ return { writeRoot: sessionRoot, visibleRoot: join(visibleRoot, sessionKey) };
144
147
  }
145
148
  async function writeImage(req, directory, filename, expectedBytes, maxBytes) {
146
149
  if (expectedBytes > maxBytes)
@@ -174,6 +177,24 @@ async function writeImage(req, directory, filename, expectedBytes, maxBytes) {
174
177
  throw error;
175
178
  }
176
179
  }
180
+ async function copyImage(source, directory, filename) {
181
+ const id = randomUUID();
182
+ const finalPath = join(directory, `${id}-${filename}`);
183
+ const stagingPath = join(directory, `.${id}.partial`);
184
+ ensurePathInside(directory, finalPath);
185
+ ensurePathInside(directory, stagingPath);
186
+ try {
187
+ await copyFile(source, stagingPath, fsConstants.COPYFILE_EXCL);
188
+ await rename(stagingPath, finalPath);
189
+ return finalPath;
190
+ }
191
+ catch (error) {
192
+ await rm(stagingPath, { force: true }).catch(() => { });
193
+ throw error;
194
+ }
195
+ }
196
+ class PasteStorageChangedError extends Error {
197
+ }
177
198
  /** Same-origin, live-Session-bound image upload endpoint. */
178
199
  export class PastedImageBackend {
179
200
  ctx;
@@ -182,6 +203,16 @@ export class PastedImageBackend {
182
203
  this.ctx = ctx;
183
204
  this.runtime = runtime;
184
205
  }
206
+ storageGeneration() {
207
+ const current = this.runtime.storageGeneration?.();
208
+ if (current !== undefined)
209
+ return current;
210
+ const storageDir = this.runtime.storageDirectory?.();
211
+ return {
212
+ generation: 0,
213
+ ...(storageDir === undefined ? {} : { storageDir }),
214
+ };
215
+ }
185
216
  async handle(req, res) {
186
217
  if (req.method !== 'POST') {
187
218
  res.setHeader('Allow', 'POST');
@@ -192,6 +223,7 @@ export class PastedImageBackend {
192
223
  requestError(res, 403, 'origin-rejected', 'The request must originate from this DSH Web application');
193
224
  return;
194
225
  }
226
+ let managedPath;
195
227
  try {
196
228
  const url = new URL(req.url ?? PASTE_IMAGES_ROUTE, 'http://dsh.internal');
197
229
  const sessionId = singleQuery(url, 'sessionId');
@@ -202,13 +234,29 @@ export class PastedImageBackend {
202
234
  if (contentLength !== undefined && Number(contentLength) !== size) {
203
235
  throw new TypeError('Content-Length does not match the declared size');
204
236
  }
205
- const directory = await sessionPasteRoot(this.ctx, sessionId);
206
- const writtenPath = await writeImage(req, directory.writeRoot, filename, size, this.runtime.maxUploadBytes());
207
- const absolutePath = join(directory.visibleRoot, basename(writtenPath));
208
- responseJson(res, 201, { ok: true, value: { absolutePath, filename, bytes: size } });
237
+ let storage = this.storageGeneration();
238
+ let directory = await sessionPasteRoot(this.ctx, sessionId, storage.storageDir);
239
+ managedPath = await writeImage(req, directory.writeRoot, filename, size, this.runtime.maxUploadBytes());
240
+ for (let attempt = 0; attempt < MAX_STORAGE_GENERATION_RETRIES; attempt += 1) {
241
+ const current = this.storageGeneration();
242
+ if (current.generation === storage.generation && current.storageDir === storage.storageDir) {
243
+ const absolutePath = join(directory.visibleRoot, basename(managedPath));
244
+ responseJson(res, 201, { ok: true, value: { absolutePath, filename, bytes: size } });
245
+ return;
246
+ }
247
+ const nextDirectory = await sessionPasteRoot(this.ctx, sessionId, current.storageDir);
248
+ const migratedPath = await copyImage(managedPath, nextDirectory.writeRoot, filename);
249
+ await rm(managedPath, { force: true }).catch(() => { });
250
+ managedPath = migratedPath;
251
+ directory = nextDirectory;
252
+ storage = current;
253
+ }
254
+ throw new PasteStorageChangedError('Vision Toolkit settings changed repeatedly during image copy; retry the paste');
209
255
  }
210
256
  catch (error) {
211
- const status = error instanceof RangeError ? 413 : 400;
257
+ if (managedPath !== undefined)
258
+ await rm(managedPath, { force: true }).catch(() => { });
259
+ const status = error instanceof PasteStorageChangedError ? 409 : error instanceof RangeError ? 413 : 400;
212
260
  this.ctx.logger.warn('dsh-vision-toolkit pasted image rejected: %s', message(error));
213
261
  requestError(res, status, 'paste-image-rejected', message(error));
214
262
  }
@@ -1 +1 @@
1
- {"version":3,"file":"paste-images.js","sourceRoot":"","sources":["../src/paste-images.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paste-images.js","sourceRoot":"","sources":["../src/paste-images.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAErF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAGvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,yDAAyD;AACzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,mCAAmC,CAAA;AAErE;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mCAAmC,CAAA;AAkCrE,MAAM,cAAc,GAAG,GAAG,CAAA;AAC1B,MAAM,8BAA8B,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;AAcrD,SAAS,YAAY,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAsB;IAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAA;IAChE,GAAG,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IACrD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;IAC1C,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAA;IAClD,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,4CAA4C,CAAC,CAAA;IACtF,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACrB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAY,EAAE,OAAe;IACtF,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;AACpE,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAED,SAAS,WAAW,CAAC,GAAQ,EAAE,GAAW;IACxC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACvE,MAAM,IAAI,SAAS,CAAC,GAAG,GAAG,2BAA2B,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,GAAQ;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAA;IAC1G,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,cAAc,CAAC,GAAoB;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACjF,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAA;IAC3G,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,YAAY,CAAC,SAAiB;IACrC,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,YAAY,CAAC,CAAC,OAAO,MAAM,CAAA;QAChC,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAA;QAC/B,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAA;QAC/B,KAAK,YAAY,CAAC,CAAC,OAAO,OAAO,CAAA;QACjC,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAA;QAC/B,KAAK,YAAY,CAAC,CAAC,OAAO,OAAO,CAAA;QACjC,KAAK,YAAY,CAAC,CAAC,OAAO,OAAO,CAAA;QACjC,KAAK,YAAY,CAAC,CAAC,OAAO,OAAO,CAAA;QACjC,KAAK,YAAY,CAAC,CAAC,OAAO,OAAO,CAAA;QACjC,KAAK,eAAe,CAAC,CAAC,OAAO,MAAM,CAAA;QACnC,OAAO,CAAC,CAAC,OAAO,MAAM,CAAA;IACxB,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,SAAiB;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACjE,IAAI,OAAO,GAAG,IAAI;SACf,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAC3C,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE;SACN,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACzB,IAAI,kDAAkD,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;IAC7F,MAAM,QAAQ,GAAG,kBAAkB,YAAY,CAAC,SAAS,CAAC,EAAE,CAAA;IAC5D,MAAM,SAAS,GAAG,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAA;IAC5F,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,cAAc;QAAE,OAAO,SAAS,CAAA;IACpE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;IACzE,IAAI,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/E,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACjE,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,CAAA;AAC9B,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAc;IAC3D,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAClC,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,IAAI,KAAK,CAAC,wDAAwD,MAAM,EAAE,CAAC,CAAA;IACnF,CAAC;AACH,CAAC;AAOD,KAAK,UAAU,sBAAsB,CAAC,SAAiB,EAAE,IAAY;IACnE,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;YAAE,MAAM,KAAK,CAAA;IAC1F,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sEAAsE,IAAI,EAAE,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,EAAE,CAAC,CAAA;IAC1F,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAA;IACtC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IACtC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAY,EACZ,SAAiB,EACjB,UAAmB;IAEnB,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAkB,CAAC,CAAA;IACpD,IAAI,OAAO,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,SAAS,EAAE,CAAC,CAAA;IAClF,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAA;IAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAA;IAE7G,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAA;IACvE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAA;IAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;IAC7C,MAAM,sBAAsB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;IACvD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,CAAA;IAC1D,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IACvE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,eAAe,CAAC,CAAA;IAErE,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACpF,MAAM,oBAAoB,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAA;IAC5E,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;IACnC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAA;AAC/E,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,GAAoB,EACpB,SAAiB,EACjB,QAAgB,EAChB,aAAqB,EACrB,QAAgB;IAEhB,IAAI,aAAa,GAAG,QAAQ;QAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,QAAQ,mBAAmB,CAAC,CAAA;IACpG,MAAM,EAAE,GAAG,UAAU,EAAE,CAAA;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAA;IACtD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAA;IACrD,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IACtC,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IAExC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;IACnD,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACjE,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAA;YACxB,IAAI,QAAQ,GAAG,aAAa,IAAI,QAAQ,GAAG,QAAQ;gBAAE,MAAM,IAAI,UAAU,CAAC,6CAA6C,CAAC,CAAA;YACxH,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QACD,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,aAAa,cAAc,QAAQ,EAAE,CAAC,CAAA;QACrG,CAAC;QACD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QACnB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACpB,MAAM,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACpC,OAAO,SAAS,CAAA;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpC,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACtD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,MAAc,EACd,SAAiB,EACjB,QAAgB;IAEhB,MAAM,EAAE,GAAG,UAAU,EAAE,CAAA;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAA;IACtD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAA;IACrD,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IACtC,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IACxC,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAA;QAC9D,MAAM,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACpC,OAAO,SAAS,CAAA;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACtD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAOD,MAAM,wBAAyB,SAAQ,KAAK;CAAG;AAS/C,6DAA6D;AAC7D,MAAM,OAAO,kBAAkB;IAEV;IACA;IAFnB,YACmB,GAAY,EACZ,OAA0B;QAD1B,QAAG,GAAH,GAAG,CAAS;QACZ,YAAO,GAAP,OAAO,CAAmB;IAC1C,CAAC;IAEI,iBAAiB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAA;QAClD,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAA;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAA;QACpD,OAAO;YACL,UAAU,EAAE,CAAC;YACb,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;SACpD,CAAA;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAoB,EAAE,GAAmB;QACpD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC9B,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAE,UAAU,CAAC,CAAA;YACxD,OAAM;QACR,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,0DAA0D,CAAC,CAAA;YACrG,OAAM;QACR,CAAC;QAED,IAAI,WAA+B,CAAA;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,kBAAkB,EAAE,qBAAqB,CAAC,CAAA;YACzE,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;YAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;YAC9B,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,CAAA;YACzE,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;YACnD,IAAI,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,IAAI,EAAE,CAAC;gBAClE,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAA;YACxE,CAAC;YACD,IAAI,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAA;YACtC,IAAI,SAAS,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;YAC/E,WAAW,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;YACvG,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,8BAA8B,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;gBAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAA;gBACxC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;oBAC3F,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;oBACvE,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;oBACpF,OAAM;gBACR,CAAC;gBACD,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;gBACrF,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;gBACpF,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;gBACtD,WAAW,GAAG,YAAY,CAAA;gBAC1B,SAAS,GAAG,aAAa,CAAA;gBACzB,OAAO,GAAG,OAAO,CAAA;YACnB,CAAC;YACD,MAAM,IAAI,wBAAwB,CAAC,+EAA+E,CAAC,CAAA;QACrH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,WAAW,KAAK,SAAS;gBAAE,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACrF,MAAM,MAAM,GAAG,KAAK,YAAY,wBAAwB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;YACxG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;YACpF,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,sBAAsB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QACnE,CAAC;IACH,CAAC;CACF"}
package/lib/paths.js CHANGED
@@ -5,9 +5,9 @@
5
5
  * link is allowed only when its real target stays inside the fence.
6
6
  * @module dsh-vision-toolkit/paths
7
7
  */
8
- import { randomUUID } from 'node:crypto';
9
- import { cp, link, lstat, mkdir, readdir, realpath, rename, rm, stat } from 'node:fs/promises';
10
- import { extname, isAbsolute, join, relative, resolve, sep, win32 } from 'node:path';
8
+ import { createHash, randomUUID } from 'node:crypto';
9
+ import { cp, link, lstat, mkdir, mkdtemp, readdir, realpath, rename, rm, stat } from 'node:fs/promises';
10
+ import { dirname, extname, isAbsolute, join, relative, resolve, sep, win32 } from 'node:path';
11
11
  import { homedir, tmpdir } from 'node:os';
12
12
  import { VisionToolkitError } from "./errors.js";
13
13
  /** Supported input image extensions (the upstream client's allowlist). */
@@ -45,23 +45,205 @@ export function normalizePlatformTempPath(raw, platform = process.platform, temp
45
45
  return raw;
46
46
  return win32.join(tempDirectory, raw.slice('/tmp/'.length));
47
47
  }
48
+ /** Stable opaque per-user workspace id used below a shared storage root. */
49
+ export function workspaceStorageId(workspace, userIdentity = typeof process.geteuid === 'function'
50
+ ? `uid:${process.geteuid()}`
51
+ : `home:${homedir()}`) {
52
+ return createHash('sha256')
53
+ .update(userIdentity)
54
+ .update('\0')
55
+ .update(workspace)
56
+ .digest('hex')
57
+ .slice(0, 20);
58
+ }
59
+ function currentPosixUid() {
60
+ if (typeof process.geteuid !== 'function') {
61
+ throw new VisionToolkitError('path', 'configured storage directory is not supported on this platform because ownership and permissions cannot be verified');
62
+ }
63
+ return process.geteuid();
64
+ }
65
+ export function assertSecureWorkspaceStorage(info, requested) {
66
+ const currentUid = currentPosixUid();
67
+ if (info.uid !== currentUid || (info.mode & 0o777) !== 0o700) {
68
+ throw new VisionToolkitError('path', `workspace storage directory must be owned by the current user with mode 0700: ${requested}`);
69
+ }
70
+ }
71
+ /** Resolve a shared base and prove every POSIX ancestor is protected from replacement. */
72
+ export async function assertSecureSharedStorageBase(requested) {
73
+ const currentUid = currentPosixUid();
74
+ const requestedPath = resolve(requested);
75
+ const requestedChain = [];
76
+ let requestedCurrent = requestedPath;
77
+ while (true) {
78
+ requestedChain.push(requestedCurrent);
79
+ const parent = dirname(requestedCurrent);
80
+ if (parent === requestedCurrent)
81
+ break;
82
+ requestedCurrent = parent;
83
+ }
84
+ for (const component of requestedChain.reverse()) {
85
+ const info = await lstat(component);
86
+ if (info.isSymbolicLink()) {
87
+ if (info.uid !== 0) {
88
+ throw new VisionToolkitError('path', `configured storage directory contains an untrusted symbolic link: ${component}`);
89
+ }
90
+ continue;
91
+ }
92
+ if (!info.isDirectory()) {
93
+ throw new VisionToolkitError('path', `configured storage path component is not a directory: ${component}`);
94
+ }
95
+ const writableByOthers = (info.mode & 0o022) !== 0;
96
+ const sticky = (info.mode & 0o1000) !== 0;
97
+ if ((info.uid !== currentUid && info.uid !== 0)
98
+ || (writableByOthers && !sticky))
99
+ throw new VisionToolkitError('path', `configured storage directory has an untrusted path component: ${component}`);
100
+ }
101
+ const canonical = await realpath(requestedPath);
102
+ let current = canonical;
103
+ while (true) {
104
+ const info = await lstat(current);
105
+ const writableByOthers = (info.mode & 0o022) !== 0;
106
+ const sticky = (info.mode & 0o1000) !== 0;
107
+ if (info.isSymbolicLink()
108
+ || !info.isDirectory()
109
+ || (info.uid !== currentUid && info.uid !== 0)
110
+ || (writableByOthers && !sticky))
111
+ throw new VisionToolkitError('path', `configured storage directory has an untrusted path component: ${current}`);
112
+ const parent = dirname(current);
113
+ if (parent === current)
114
+ return canonical;
115
+ current = parent;
116
+ }
117
+ }
118
+ function requestedSharedStorageBase(storageDirRaw) {
119
+ currentPosixUid();
120
+ const configured = normalizePlatformTempPath(expandUserHome(storageDirRaw.trim()));
121
+ if (!isAbsolute(configured)) {
122
+ throw new VisionToolkitError('path', `configured storage directory must be an absolute path: ${storageDirRaw}`);
123
+ }
124
+ return resolve(configured);
125
+ }
126
+ async function ensureSharedStorageBase(storageDirRaw) {
127
+ const requestedBase = requestedSharedStorageBase(storageDirRaw);
128
+ try {
129
+ await mkdir(requestedBase, { recursive: true, mode: 0o700 });
130
+ }
131
+ catch (error) {
132
+ throw new VisionToolkitError('path', `configured storage directory is not writable: ${requestedBase}`, { cause: error });
133
+ }
134
+ try {
135
+ return { requestedBase, base: await assertSecureSharedStorageBase(requestedBase) };
136
+ }
137
+ catch (error) {
138
+ throw new VisionToolkitError('path', `configured storage directory is not accessible: ${requestedBase}`, { cause: error });
139
+ }
140
+ }
141
+ /** Validate and write-probe a configured shared root before Settings activation. */
142
+ export async function preflightSharedStorageBase(storageDirRaw) {
143
+ const { base } = await ensureSharedStorageBase(storageDirRaw);
144
+ let probe;
145
+ let failure;
146
+ try {
147
+ probe = await mkdtemp(join(base, '.dsh-vision-toolkit-preflight-'));
148
+ assertSecureWorkspaceStorage(await lstat(probe), probe);
149
+ }
150
+ catch (error) {
151
+ failure = error;
152
+ }
153
+ if (probe !== undefined) {
154
+ try {
155
+ await rm(probe, { recursive: true, force: true });
156
+ }
157
+ catch (error) {
158
+ failure ??= error;
159
+ }
160
+ }
161
+ if (failure !== undefined) {
162
+ throw new VisionToolkitError('path', `configured storage directory failed its write preflight: ${base}`, { cause: failure });
163
+ }
164
+ return base;
165
+ }
166
+ async function managedDirectory(parent, requested, label, secureWorkspaceStorage = false) {
167
+ try {
168
+ await mkdir(requested, { mode: 0o700 });
169
+ }
170
+ catch (error) {
171
+ if (!(error instanceof Error && 'code' in error && error.code === 'EEXIST')) {
172
+ throw new VisionToolkitError('path', `${label} is not writable: ${requested}`, { cause: error });
173
+ }
174
+ }
175
+ let info;
176
+ try {
177
+ info = await lstat(requested);
178
+ }
179
+ catch (error) {
180
+ throw new VisionToolkitError('path', `${label} is not accessible: ${requested}`, { cause: error });
181
+ }
182
+ if (info.isSymbolicLink() || !info.isDirectory()) {
183
+ throw new VisionToolkitError('path', `${label} must be a real directory: ${requested}`);
184
+ }
185
+ if (secureWorkspaceStorage)
186
+ assertSecureWorkspaceStorage(info, requested);
187
+ const canonical = await realpath(requested);
188
+ if (!isWithin(parent, canonical)) {
189
+ throw new VisionToolkitError('path', `${label} escaped its configured root: ${requested}`);
190
+ }
191
+ return canonical;
192
+ }
48
193
  /**
49
- * Build the per-invocation path policy: realpath the workspace, resolve and
50
- * realpath the platform temp directory and allowed directories, and create
51
- * the output directory inside the fence.
52
- * @param workspaceRaw - session workspace (or process cwd fallback).
53
- * @param allowedDirs - configured extra allowed roots.
54
- * @param outputDirRaw - configured output directory (default `.dsh-vision-toolkit/artifacts`).
55
- * @returns the resolved policy.
194
+ * Resolve the plugin-managed root for one workspace. Blank configuration keeps
195
+ * the legacy workspace-local `.dsh-vision-toolkit` directory. A configured
196
+ * shared root receives one stable, automatically generated workspace child.
56
197
  */
57
- export async function createPathPolicy(workspaceRaw, allowedDirs, outputDirRaw) {
198
+ export async function resolveWorkspaceStorage(workspaceRaw, storageDirRaw) {
199
+ const expandedWorkspace = expandUserHome(workspaceRaw);
200
+ const visibleWorkspace = resolve(expandedWorkspace);
58
201
  let workspace;
59
202
  try {
60
- workspace = await realpath(expandUserHome(workspaceRaw));
203
+ workspace = await realpath(visibleWorkspace);
61
204
  }
62
205
  catch (error) {
63
206
  throw new VisionToolkitError('path', `workspace is not accessible: ${workspaceRaw}`, { cause: error });
64
207
  }
208
+ if (storageDirRaw === undefined || storageDirRaw.trim().length === 0) {
209
+ const visibleRoot = join(visibleWorkspace, '.dsh-vision-toolkit');
210
+ const root = await managedDirectory(workspace, visibleRoot, 'plugin storage directory');
211
+ return { workspace, root, visibleRoot };
212
+ }
213
+ const { requestedBase, base } = await ensureSharedStorageBase(storageDirRaw);
214
+ const id = workspaceStorageId(workspace);
215
+ const visibleRoot = join(requestedBase, id);
216
+ const root = await managedDirectory(base, join(base, id), 'workspace storage directory', true);
217
+ return { workspace, root, visibleRoot };
218
+ }
219
+ async function resolveReadableWorkspaceStorageRoot(workspace, storageDirRaw) {
220
+ const requestedBase = requestedSharedStorageBase(storageDirRaw);
221
+ const base = await assertSecureSharedStorageBase(requestedBase);
222
+ const requestedRoot = join(base, workspaceStorageId(workspace));
223
+ const info = await lstat(requestedRoot);
224
+ if (info.isSymbolicLink() || !info.isDirectory()) {
225
+ throw new VisionToolkitError('path', `historical workspace storage must be a real directory: ${requestedRoot}`);
226
+ }
227
+ assertSecureWorkspaceStorage(info, requestedRoot);
228
+ const root = await realpath(requestedRoot);
229
+ if (!isWithin(base, root)) {
230
+ throw new VisionToolkitError('path', `historical workspace storage escaped its configured root: ${requestedRoot}`);
231
+ }
232
+ return root;
233
+ }
234
+ /**
235
+ * Build the per-invocation path policy: resolve workspace storage, realpath the
236
+ * platform temp directory and allowed directories, and create the artifact
237
+ * directory inside the managed root.
238
+ * @param workspaceRaw - session workspace (or process cwd fallback).
239
+ * @param allowedDirs - configured extra allowed roots.
240
+ * @param storageDirRaw - optional shared storage root.
241
+ * @param readableStorageDirs - previously validated shared roots retained for persisted input paths.
242
+ * @returns the resolved policy.
243
+ */
244
+ export async function createPathPolicy(workspaceRaw, allowedDirs, storageDirRaw, readableStorageDirs = []) {
245
+ const storage = await resolveWorkspaceStorage(workspaceRaw, storageDirRaw);
246
+ const { workspace } = storage;
65
247
  let tempDir;
66
248
  const tempDirectoryRaw = platformTempDirectory();
67
249
  try {
@@ -70,7 +252,18 @@ export async function createPathPolicy(workspaceRaw, allowedDirs, outputDirRaw)
70
252
  catch (error) {
71
253
  throw new VisionToolkitError('path', `platform temporary directory is not accessible: ${tempDirectoryRaw}`, { cause: error });
72
254
  }
73
- const roots = [workspace, tempDir];
255
+ const roots = [workspace, tempDir, storage.root];
256
+ for (const raw of readableStorageDirs) {
257
+ if (raw === storageDirRaw)
258
+ continue;
259
+ try {
260
+ roots.push(await resolveReadableWorkspaceStorageRoot(workspace, raw));
261
+ }
262
+ catch {
263
+ // Historical roots are read-only compatibility fences. Missing or newly
264
+ // unsafe roots stay unauthorized without breaking the active runtime.
265
+ }
266
+ }
74
267
  for (const raw of allowedDirs) {
75
268
  const candidate = expandUserHome(raw);
76
269
  const target = isAbsolute(candidate) ? candidate : resolve(workspace, candidate);
@@ -81,21 +274,14 @@ export async function createPathPolicy(workspaceRaw, allowedDirs, outputDirRaw)
81
274
  throw new VisionToolkitError('path', `allowedDirs entry is not accessible: ${raw}`, { cause: error });
82
275
  }
83
276
  }
84
- const outputRaw = outputDirRaw === undefined || outputDirRaw.trim().length === 0
85
- ? join(workspace, '.dsh-vision-toolkit', 'artifacts')
86
- : resolve(workspace, expandUserHome(outputDirRaw));
87
- if (!roots.some(root => isWithin(root, outputRaw))) {
88
- throw new VisionToolkitError('path', 'output directory must stay inside the workspace or an allowedDirs entry');
89
- }
90
- let outputDir;
91
- try {
92
- await mkdir(outputRaw, { recursive: true });
93
- outputDir = await realpath(outputRaw);
94
- }
95
- catch (error) {
96
- throw new VisionToolkitError('path', `output directory is not writable: ${outputRaw}`, { cause: error });
97
- }
98
- return { workspace, tempDir, allowedDirs: [...new Set(roots)], outputDir };
277
+ const outputDir = await managedDirectory(storage.root, join(storage.root, 'artifacts'), 'artifact directory');
278
+ return {
279
+ workspace,
280
+ tempDir,
281
+ allowedDirs: [...new Set(roots)],
282
+ storageRoot: storage.root,
283
+ outputDir,
284
+ };
99
285
  }
100
286
  /**
101
287
  * Validate one input image path and return its fence-checked absolute path