@try-works/dsh-tool-mode 0.5.49 → 0.5.51

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.
@@ -47,8 +47,8 @@
47
47
  "modelSizeMB": null,
48
48
  "appleOnly": false,
49
49
  "closedBeta": false,
50
- "verifiedRunnableOnWindows": false,
51
- "windowsSupport": "browser-only",
50
+ "verifiedRunnableOnWindows": true,
51
+ "windowsSupport": "onnxruntime-node",
52
52
  "npmPackage": "@desert-ant-labs/clear",
53
53
  "npmSubpath": "/native",
54
54
  "requiresRuntime": [],
@@ -58,17 +58,20 @@
58
58
  "hfRepo": "https://huggingface.co/desert-ant-labs/clear",
59
59
  "tool": {
60
60
  "name": "enhance_speech",
61
- "description": "Clean up a recording on device: remove noise and room echo and level the loudness to a podcast-ready 48 kHz.",
61
+ "description": "Denoise and dereverb a speech recording on device and return the enhanced 48 kHz mono WAV with honest coverage of the analysed audio.",
62
62
  "params": {
63
- "audio_path": "Absolute path to the input audio or video file.",
64
- "output_path": "Absolute path to write the enhanced audio to."
63
+ "audio_path": "Absolute path to the WAV file. Read from the caller's granted filesystem, never uploaded."
65
64
  },
66
- "returns": "The path of the enhanced audio file."
65
+ "returns": "Base64 48 kHz mono WAV, sample rate, duration and coverage."
67
66
  },
68
67
  "skill": {
69
68
  "name": "desert-ant-clear",
70
69
  "description": "Enhance noisy speech recordings on device with the Desert Ant Clear model.",
71
70
  "whenToUse": "Use when a recording needs denoising, dereverberation or loudness normalization before publication."
71
+ },
72
+ "provider": {
73
+ "extension": "@try-works/extension-clear-recipe",
74
+ "modelId": "clear"
72
75
  }
73
76
  },
74
77
  {
@@ -119,8 +122,8 @@
119
122
  "modelSizeMB": null,
120
123
  "appleOnly": false,
121
124
  "closedBeta": false,
122
- "verifiedRunnableOnWindows": false,
123
- "windowsSupport": "browser-only",
125
+ "verifiedRunnableOnWindows": true,
126
+ "windowsSupport": "onnxruntime-node",
124
127
  "npmPackage": "@desert-ant-labs/ear",
125
128
  "npmSubpath": "/native",
126
129
  "requiresRuntime": [],
@@ -129,17 +132,25 @@
129
132
  "docsUrl": "https://desertant.com/models/ear/",
130
133
  "hfRepo": "https://huggingface.co/desert-ant-labs/ear",
131
134
  "tool": {
132
- "name": "detect_spoken_language",
133
- "description": "Identify which language is being spoken in a recording, before transcription starts, across 102 languages.",
135
+ "name": "identify_language",
136
+ "description": "Identify the spoken language of an audio recording on device: the most likely language, its confidence, a reliability flag and the top candidates.",
134
137
  "params": {
135
- "audio_path": "Absolute path to the audio or video file."
138
+ "audio_path": "Absolute path to the WAV file. Read from the caller's granted filesystem, never uploaded.",
139
+ "windows": {
140
+ "description": "How many 30 second windows to listen to, spread across the recording and ranked by syllabic modulation. Defaults to 3.",
141
+ "type": "integer"
142
+ }
136
143
  },
137
- "returns": "The detected spoken language with a confidence and runner-up candidates."
144
+ "returns": "language, confidence, isReliable, ranked candidates and window timings."
138
145
  },
139
146
  "skill": {
140
147
  "name": "desert-ant-ear",
141
148
  "description": "Identify the spoken language of a recording on device with the Desert Ant Ear model.",
142
149
  "whenToUse": "Use to pick a transcription language or route audio before running speech recognition."
150
+ },
151
+ "provider": {
152
+ "extension": "@try-works/extension-ear-recipe",
153
+ "modelId": "ear"
143
154
  }
144
155
  },
145
156
  {
@@ -154,8 +165,8 @@
154
165
  "modelSizeMB": 10.2,
155
166
  "appleOnly": false,
156
167
  "closedBeta": false,
157
- "verifiedRunnableOnWindows": false,
158
- "windowsSupport": "browser-only",
168
+ "verifiedRunnableOnWindows": true,
169
+ "windowsSupport": "onnxruntime-node",
159
170
  "npmPackage": "@desert-ant-labs/emo",
160
171
  "npmSubpath": "/native",
161
172
  "requiresRuntime": [],
@@ -164,21 +175,25 @@
164
175
  "docsUrl": "https://desertant.com/models/emo/",
165
176
  "hfRepo": "https://huggingface.co/desert-ant-labs/emo",
166
177
  "tool": {
167
- "name": "suggest_emoji",
168
- "description": "Suggest emoji that fit a piece of text, in 22 languages, running entirely on device.",
178
+ "name": "suggest_emojis",
179
+ "description": "Suggest emojis for a piece of text on device: the top labels by probability with their confidences.",
169
180
  "params": {
170
- "text": "The text to suggest emoji for.",
181
+ "text": "The text to suggest emojis for, counted in Unicode code points, 1..1024. Empty or whitespace-only text is refused.",
171
182
  "limit": {
172
- "description": "Maximum number of suggestions to return (default 5).",
183
+ "description": "How many suggestions to return: the top labels by descending probability. Defaults to 5.",
173
184
  "type": "integer"
174
185
  }
175
186
  },
176
- "returns": "Ranked emoji suggestions with confidence scores."
187
+ "returns": "Top emoji labels by probability with confidences."
177
188
  },
178
189
  "skill": {
179
190
  "name": "desert-ant-emo",
180
191
  "description": "Suggest fitting emoji for text with the Desert Ant Emo model.",
181
192
  "whenToUse": "Use when writing release notes, commit summaries or UI copy that should carry emoji."
193
+ },
194
+ "provider": {
195
+ "extension": "@try-works/extension-emo-recipe",
196
+ "modelId": "emo"
182
197
  }
183
198
  },
184
199
  {
@@ -313,8 +328,8 @@
313
328
  "modelSizeMB": 9.2,
314
329
  "appleOnly": false,
315
330
  "closedBeta": false,
316
- "verifiedRunnableOnWindows": false,
317
- "windowsSupport": "browser-only",
331
+ "verifiedRunnableOnWindows": true,
332
+ "windowsSupport": "onnxruntime-node",
318
333
  "npmPackage": "@desert-ant-labs/moderator",
319
334
  "npmSubpath": "/native",
320
335
  "requiresRuntime": [],
@@ -323,20 +338,27 @@
323
338
  "docsUrl": "https://desertant.com/models/moderator/",
324
339
  "hfRepo": "https://huggingface.co/desert-ant-labs/moderator",
325
340
  "tool": {
326
- "name": "detect_nsfw",
327
- "description": "Check images for nudity or sexual content on device before they are uploaded or shown.",
341
+ "name": "classify_nsfw",
342
+ "description": "Check an image for nudity or sexual content on device: per-region scores, an NSFW decision at a threshold, and the policy and quality used.",
328
343
  "params": {
329
- "image_paths": {
330
- "description": "Absolute paths of the images to check.",
331
- "type": "string[]"
332
- }
344
+ "image_path": "Absolute path to the PNG file. Read from the caller's granted filesystem, never uploaded.",
345
+ "quality": "How many crops to score: fast = 1 center crop, balanced = 4 crops, accurate = 8 crops. Defaults to balanced.",
346
+ "threshold": {
347
+ "description": "Decision threshold; isNSFW is true when score >= threshold. Defaults to 0.5.",
348
+ "type": "number"
349
+ },
350
+ "policy": "standard counts all five heads; allowTopless counts all but nipples. Defaults to standard."
333
351
  },
334
- "returns": "A per-image NSFW verdict with score and labels."
352
+ "returns": "isNSFW, score, threshold, policy, quality, per-region scores and crops."
335
353
  },
336
354
  "skill": {
337
355
  "name": "desert-ant-moderator",
338
356
  "description": "Screen images for NSFW content on device with the Desert Ant Moderator model.",
339
357
  "whenToUse": "Use to gate user-supplied images before storing, publishing or sending them anywhere."
358
+ },
359
+ "provider": {
360
+ "extension": "@try-works/extension-moderator-recipe",
361
+ "modelId": "moderator"
340
362
  }
341
363
  },
342
364
  {
@@ -351,8 +373,8 @@
351
373
  "modelSizeMB": null,
352
374
  "appleOnly": false,
353
375
  "closedBeta": false,
354
- "verifiedRunnableOnWindows": false,
355
- "windowsSupport": "browser-only",
376
+ "verifiedRunnableOnWindows": true,
377
+ "windowsSupport": "native-node",
356
378
  "npmPackage": "@desert-ant-labs/redact",
357
379
  "npmSubpath": "/native",
358
380
  "requiresRuntime": [],
@@ -361,25 +383,21 @@
361
383
  "docsUrl": "https://desertant.com/models/redact/",
362
384
  "hfRepo": "https://huggingface.co/desert-ant-labs/redact",
363
385
  "tool": {
364
- "name": "redact_pii",
365
- "description": "Replace personal data (names, emails, phone numbers, addresses, card numbers and more) in text with stable placeholders, on device, before the text reaches any remote service.",
386
+ "name": "redact_text",
387
+ "description": "Detect PII and secrets in text as labelled UTF-16 spans, with honest coverage when the local window cap truncates a long document.",
366
388
  "params": {
367
- "text": "The text to redact.",
368
- "labels": {
369
- "description": "Optional list of entity labels to restrict redaction to, for example [\"EMAIL\", \"PHONE\"].",
370
- "type": "string[]"
371
- },
372
- "minimum_confidence": {
373
- "description": "Optional confidence floor between 0 and 1 (default 0.6).",
374
- "type": "number"
375
- }
389
+ "text": "The text to redact. Long documents are processed up to the local window cap; coverage reports truncation."
376
390
  },
377
- "returns": "The redacted text plus the placeholder map, so originals can be restored after a remote round trip."
391
+ "returns": "Labelled UTF-16 spans and coverage of the analysed text."
378
392
  },
379
393
  "skill": {
380
394
  "name": "desert-ant-redact",
381
395
  "description": "Strip personal data from text on device with the Desert Ant Redact model before sending it to any remote service.",
382
396
  "whenToUse": "Use before sending logs, transcripts, tickets or documents containing names, emails or numbers to a remote model or API."
397
+ },
398
+ "provider": {
399
+ "extension": "@try-works/extension-redact",
400
+ "modelId": "redact"
383
401
  }
384
402
  },
385
403
  {
@@ -430,8 +448,8 @@
430
448
  "modelSizeMB": null,
431
449
  "appleOnly": false,
432
450
  "closedBeta": false,
433
- "verifiedRunnableOnWindows": false,
434
- "windowsSupport": "browser-only",
451
+ "verifiedRunnableOnWindows": true,
452
+ "windowsSupport": "native-node",
435
453
  "npmPackage": "@desert-ant-labs/shapes",
436
454
  "npmSubpath": "/native",
437
455
  "requiresRuntime": [],
@@ -440,18 +458,25 @@
440
458
  "docsUrl": "https://desertant.com/models/shapes/",
441
459
  "hfRepo": "https://huggingface.co/desert-ant-labs/shapes",
442
460
  "tool": {
443
- "name": "recognize_shape",
444
- "description": "Turn a single hand-drawn stroke into a clean shape: rectangle, ellipse, triangle, star or line.",
461
+ "name": "shape_recognize",
462
+ "description": "Recognize a single hand-drawn stroke as one of the Shapes classes and return the ranked candidates with confidences.",
445
463
  "params": {
446
- "points": "The stroke as an array of [x, y] points in drawing order.",
447
- "closed": "Whether the stroke is a closed shape."
464
+ "points": "The stroke in drawing order as an array of [x, y] points (first stroke only).",
465
+ "closed": {
466
+ "description": "Whether the stroke was drawn closed; the fitted-geometry gates use it.",
467
+ "type": "boolean"
468
+ }
448
469
  },
449
- "returns": "The recognized shape with a confidence and runner-up candidates."
470
+ "returns": "The recognized shape, its confidence, the ranked candidates and rejected labels."
450
471
  },
451
472
  "skill": {
452
473
  "name": "desert-ant-shapes",
453
474
  "description": "Recognize hand-drawn strokes as clean shapes with the Desert Ant Shapes model.",
454
475
  "whenToUse": "Use in drawing or diagram tooling to snap an ink stroke to a geometric shape."
476
+ },
477
+ "provider": {
478
+ "extension": "@try-works/extension-shapes-recipe",
479
+ "modelId": "shapes"
455
480
  }
456
481
  },
457
482
  {
@@ -585,10 +610,10 @@
585
610
  "output": "[{ start, end, word }] filler spans to cut",
586
611
  "languages": null,
587
612
  "modelSizeMB": null,
588
- "appleOnly": true,
613
+ "appleOnly": false,
589
614
  "closedBeta": false,
590
- "verifiedRunnableOnWindows": false,
591
- "windowsSupport": "apple-only",
615
+ "verifiedRunnableOnWindows": true,
616
+ "windowsSupport": "onnxruntime-node",
592
617
  "npmPackage": null,
593
618
  "npmSubpath": null,
594
619
  "requiresRuntime": [],
@@ -598,16 +623,20 @@
598
623
  "hfRepo": "https://huggingface.co/desert-ant-labs/uhm",
599
624
  "tool": {
600
625
  "name": "detect_fillers",
601
- "description": "Find every um, uh and hmm in a recording with the exact span to cut.",
626
+ "description": "Find every uh, um, hmm and filler \"and\" in a recording on device and return the millisecond spans to cut, with honest coverage.",
602
627
  "params": {
603
- "audio_path": "Absolute path to the audio or video file."
628
+ "audio_path": "Absolute path to the audio to analyse. Read from the caller's granted filesystem, never uploaded."
604
629
  },
605
- "returns": "Filler spans with start and end times in seconds, ready to cut."
630
+ "returns": "Millisecond filler spans to cut, plus coverage."
606
631
  },
607
632
  "skill": {
608
633
  "name": "desert-ant-uhm",
609
634
  "description": "Detect filler words in speech on device with the Desert Ant Uhm model.",
610
635
  "whenToUse": "Use when editing spoken audio to remove hesitations and tighten a transcript."
636
+ },
637
+ "provider": {
638
+ "extension": "@try-works/extension-uhm-recipe",
639
+ "modelId": "uhm"
611
640
  }
612
641
  },
613
642
  {
package/client/index.js CHANGED
@@ -2233,12 +2233,11 @@ function createToolInsights(createElement, reactLib) {
2233
2233
  "name": "Clear",
2234
2234
  "summary": "On-device speech enhancement: denoise, dereverb and loudness-normalize to 48 kHz.",
2235
2235
  "package": "@desert-ant-labs/clear",
2236
- "extension": null,
2236
+ "extension": "@try-works/extension-clear-recipe",
2237
2237
  "capability": "audio.speech-enhancement",
2238
2238
  "sizeMB": null,
2239
2239
  "license": "source-available",
2240
- "runnable": false,
2241
- "reason": "Clear has no prebuilt native build for win32-x64: @desert-ant-labs/clear/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2240
+ "runnable": true
2242
2241
  },
2243
2242
  {
2244
2243
  "id": "clips",
@@ -2257,24 +2256,22 @@ function createToolInsights(createElement, reactLib) {
2257
2256
  "name": "Ear",
2258
2257
  "summary": "On-device spoken language identification across 102 languages from a short audio stretch.",
2259
2258
  "package": "@desert-ant-labs/ear",
2260
- "extension": null,
2259
+ "extension": "@try-works/extension-ear-recipe",
2261
2260
  "capability": "audio.spoken-language-identification",
2262
2261
  "sizeMB": null,
2263
2262
  "license": "source-available",
2264
- "runnable": false,
2265
- "reason": "Ear has no prebuilt native build for win32-x64: @desert-ant-labs/ear/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2263
+ "runnable": true
2266
2264
  },
2267
2265
  {
2268
2266
  "id": "emo",
2269
2267
  "name": "Emo",
2270
2268
  "summary": "Type a task or message and get the emoji that fit, in 22 languages, on the device.",
2271
2269
  "package": "@desert-ant-labs/emo",
2272
- "extension": null,
2270
+ "extension": "@try-works/extension-emo-recipe",
2273
2271
  "capability": "text.emoji-suggestion",
2274
2272
  "sizeMB": 10.2,
2275
2273
  "license": "source-available",
2276
- "runnable": false,
2277
- "reason": "Emo has no prebuilt native build for win32-x64: @desert-ant-labs/emo/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2274
+ "runnable": true
2278
2275
  },
2279
2276
  {
2280
2277
  "id": "eye",
@@ -2317,24 +2314,22 @@ function createToolInsights(createElement, reactLib) {
2317
2314
  "name": "Moderator",
2318
2315
  "summary": "On-device NSFW detection that flags nudity before upload, trained only on licensed and synthetic data.",
2319
2316
  "package": "@desert-ant-labs/moderator",
2320
- "extension": null,
2317
+ "extension": "@try-works/extension-moderator-recipe",
2321
2318
  "capability": "image.nsfw-detection",
2322
2319
  "sizeMB": 9.2,
2323
2320
  "license": "source-available",
2324
- "runnable": false,
2325
- "reason": "Moderator has no prebuilt native build for win32-x64: @desert-ant-labs/moderator/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2321
+ "runnable": true
2326
2322
  },
2327
2323
  {
2328
2324
  "id": "redact",
2329
2325
  "name": "Redact",
2330
2326
  "summary": "On-device redaction that strips personal data as you type, in 27 languages, with restore support.",
2331
2327
  "package": "@desert-ant-labs/redact",
2332
- "extension": null,
2328
+ "extension": "@try-works/extension-redact",
2333
2329
  "capability": "text.pii-redaction",
2334
2330
  "sizeMB": null,
2335
2331
  "license": "source-available",
2336
- "runnable": false,
2337
- "reason": "Redact has no prebuilt native build for win32-x64: @desert-ant-labs/redact/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2332
+ "runnable": true
2338
2333
  },
2339
2334
  {
2340
2335
  "id": "schemer",
@@ -2353,12 +2348,11 @@ function createToolInsights(createElement, reactLib) {
2353
2348
  "name": "Shapes",
2354
2349
  "summary": "On-device shape recognition that turns one hand-drawn stroke into a rectangle, ellipse, triangle, star or line in under 10ms.",
2355
2350
  "package": "@desert-ant-labs/shapes",
2356
- "extension": null,
2351
+ "extension": "@try-works/extension-shapes-recipe",
2357
2352
  "capability": "stroke.shape-recognition",
2358
2353
  "sizeMB": null,
2359
2354
  "license": "source-available",
2360
- "runnable": false,
2361
- "reason": "Shapes has no prebuilt native build for win32-x64: @desert-ant-labs/shapes/native supports linux-x64, linux-arm64 and darwin-arm64 only."
2355
+ "runnable": true
2362
2356
  },
2363
2357
  {
2364
2358
  "id": "title",
@@ -2400,12 +2394,11 @@ function createToolInsights(createElement, reactLib) {
2400
2394
  "name": "Uhm",
2401
2395
  "summary": "On-device filler detection that marks every um, uh and hmm to within 20ms, an hour of audio in 12s.",
2402
2396
  "package": null,
2403
- "extension": null,
2397
+ "extension": "@try-works/extension-uhm-recipe",
2404
2398
  "capability": "audio.filler-detection",
2405
2399
  "sizeMB": null,
2406
2400
  "license": "source-available",
2407
- "runnable": false,
2408
- "reason": "Uhm is Apple-only (Core ML/MLX through the Swift package); there is no JavaScript SDK, so it cannot run in a Node process. Point `remote.endpoint` at a bridge on an Apple machine to reach it."
2401
+ "runnable": true
2409
2402
  },
2410
2403
  {
2411
2404
  "id": "voz",
@@ -3285,9 +3278,72 @@ function createToolInsights(createElement, reactLib) {
3285
3278
  }
3286
3279
  }
3287
3280
 
3288
- /** Read one extension state snapshot, unwrapping the Remote result. */
3289
- async function describeExtensions(namespace) {
3290
- return normalizeDescribe(unwrapRemoteResult(await namespace.describe()))
3281
+ /** How long a normalized describe() snapshot is reused before a real host read. */
3282
+ const REMOTE_SNAPSHOT_TTL_MS = 5000
3283
+
3284
+ /**
3285
+ * Per-namespace read state: one in-flight promise, the last snapshot and when
3286
+ * it was taken. A WeakMap because the namespace object is the mounted Remote;
3287
+ * entries disappear with it.
3288
+ */
3289
+ const extensionReads = new WeakMap()
3290
+
3291
+ /** The read state for one namespace, created on first use. */
3292
+ function extensionReadState(namespace) {
3293
+ let state = extensionReads.get(namespace)
3294
+ if (state === undefined) {
3295
+ state = { inFlight: null, snapshot: null, at: 0, generation: 0 }
3296
+ extensionReads.set(namespace, state)
3297
+ }
3298
+ return state
3299
+ }
3300
+
3301
+ /**
3302
+ * Read one extension state snapshot, coalesced per namespace.
3303
+ *
3304
+ * The page reads from four places (mount, Recheck, the post-action re-read and
3305
+ * its follow-up); each would otherwise pay the host's describe, which can take
3306
+ * minutes on a large store. Concurrent callers share one in-flight promise, a
3307
+ * caller within REMOTE_SNAPSHOT_TTL_MS of the last answer gets that snapshot,
3308
+ * and a rejection is never cached, so a retry reaches the host again.
3309
+ */
3310
+ function describeExtensions(namespace) {
3311
+ const state = extensionReadState(namespace)
3312
+ if (state.inFlight !== null) return state.inFlight
3313
+ if (state.snapshot !== null && Date.now() - state.at < REMOTE_SNAPSHOT_TTL_MS) {
3314
+ return Promise.resolve(state.snapshot)
3315
+ }
3316
+ const generation = state.generation
3317
+ const read = (async () => {
3318
+ try {
3319
+ const described = normalizeDescribe(unwrapRemoteResult(await namespace.describe()))
3320
+ // Publish only an answer the current state still wants: an invalidation
3321
+ // that arrived while this read was in flight must win over it.
3322
+ if (state.generation === generation) {
3323
+ state.snapshot = described
3324
+ state.at = Date.now()
3325
+ }
3326
+ return described
3327
+ } finally {
3328
+ if (state.inFlight === read) state.inFlight = null
3329
+ }
3330
+ })()
3331
+ state.inFlight = read
3332
+ return read
3333
+ }
3334
+
3335
+ /**
3336
+ * Drop the cached and in-flight read state for a namespace.
3337
+ *
3338
+ * Called after install/enable/disable/prepare and by Recheck ("Try again"):
3339
+ * after an action the page must read the host, not a snapshot from before it.
3340
+ */
3341
+ function invalidateExtensionState(namespace) {
3342
+ const state = extensionReadState(namespace)
3343
+ state.generation += 1
3344
+ state.inFlight = null
3345
+ state.snapshot = null
3346
+ state.at = 0
3291
3347
  }
3292
3348
 
3293
3349
  /**
@@ -3902,6 +3958,7 @@ function createToolInsights(createElement, reactLib) {
3902
3958
  setExtRemote({ kind: 'absent' })
3903
3959
  return
3904
3960
  }
3961
+ invalidateExtensionState(namespace)
3905
3962
  try {
3906
3963
  setExtRemote({ kind: 'ready', namespace, ...(await describeExtensions(namespace)) })
3907
3964
  } catch (error) {
@@ -3959,6 +4016,7 @@ function createToolInsights(createElement, reactLib) {
3959
4016
  unwrapRemoteResult(await namespace.disable(id))
3960
4017
  await dualWriteDisabledExtensions(id, 'disable')
3961
4018
  }
4019
+ invalidateExtensionState(namespace)
3962
4020
  setExtRemote({ kind: 'ready', namespace, ...(await describeExtensions(namespace)) })
3963
4021
  // A store write and the following describe can land in either order
3964
4022
  // under load. One bounded re-read after a successful action settles
@@ -3970,6 +4028,7 @@ function createToolInsights(createElement, reactLib) {
3970
4028
  try {
3971
4029
  const settled = modelToolsRemote(ctx, mounted())
3972
4030
  if (settled !== null) {
4031
+ invalidateExtensionState(settled)
3973
4032
  setExtRemote({ kind: 'ready', namespace: settled, ...(await describeExtensions(settled)) })
3974
4033
  }
3975
4034
  } catch (settleError) {
@@ -3984,6 +4043,7 @@ function createToolInsights(createElement, reactLib) {
3984
4043
  try {
3985
4044
  const namespace = modelToolsRemote(ctx, mounted())
3986
4045
  if (namespace !== null) {
4046
+ invalidateExtensionState(namespace)
3987
4047
  setExtRemote({ kind: 'ready', namespace, ...(await describeExtensions(namespace)) })
3988
4048
  }
3989
4049
  } catch (readError) {
@@ -4202,6 +4262,8 @@ function createToolInsights(createElement, reactLib) {
4202
4262
  unwrapRemoteResult,
4203
4263
  normalizeDescribe,
4204
4264
  describeExtensions,
4265
+ invalidateExtensionState,
4266
+ REMOTE_SNAPSHOT_TTL_MS,
4205
4267
  findExtensionState,
4206
4268
  nextDisabledExtensions,
4207
4269
  extensionRequirements,
@@ -1 +1 @@
1
- {"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"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"}
@@ -1014,12 +1014,22 @@ export class ExtensionsService {
1014
1014
  requirements.push(requirement('platform', false, `the extension supports ${input.facts.platforms.map(platformLabel).join(', ')} but this host is ${process.platform}/${process.arch}`, 'none'));
1015
1015
  }
1016
1016
  // INTEGRITY: the installed bytes must still be the recorded bytes.
1017
+ //
1018
+ // SKIPPED is not FAILED. describeFast() does not digest installed trees (a 4.6 GB
1019
+ // store would stall the page for minutes), so it reports integrity 'unknown' with no
1020
+ // reason. That is absence of evidence, not evidence of tampering: the digest is
1021
+ // verified when the extension activates, and the full describe() still reports it.
1022
+ // Only a real verification verdict — 'changed', or 'unknown' WITH a reason, which is
1023
+ // the digest pass itself failing — may block the row.
1017
1024
  if (!input.installed) {
1018
1025
  requirements.push(requirement('integrity', true, 'the extension is not installed, so there are no installed bytes to verify'));
1019
1026
  }
1020
1027
  else if (input.integrity === 'unchanged') {
1021
1028
  requirements.push(requirement('integrity', true, 'the installed content matches the recorded digest'));
1022
1029
  }
1030
+ else if (input.integrity === 'unknown' && input.integrityReason === null) {
1031
+ requirements.push(requirement('integrity', true, 'integrity verification was skipped for this page read; the installed digest is verified when the extension activates'));
1032
+ }
1023
1033
  else {
1024
1034
  requirements.push(requirement('integrity', false, input.integrityReason ?? `the installed content's integrity is ${input.integrity}`, 'install'));
1025
1035
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.js CHANGED
@@ -818,7 +818,11 @@ export async function apply(ctx, config = {}) {
818
818
  ? config.customToolsDir
819
819
  : join(dirname(resolve(config.stateFile ?? defaultStateFile())), 'custom-tools'));
820
820
  const remoteService = {
821
- describe: signal => extensionsService.describe(signal),
821
+ // The Remote-facing describe is a PAGE read: it must not digest multi-GB installed
822
+ // trees (EXT-33 verification stays available through the full describe() and runs
823
+ // when an extension activates). A skipped digest is reported as integrity 'unknown'
824
+ // and does not block a row.
825
+ describe: signal => extensionsService.describeFast(signal),
822
826
  install: (id, source, signal) => extensionsService.install(id, source, signal),
823
827
  enable: (id, signal) => extensionsService.enable(id, signal),
824
828
  disable: (id, signal) => extensionsService.disable(id, signal),
@@ -1926,12 +1930,6 @@ export async function apply(ctx, config = {}) {
1926
1930
  * lifecycle yet, so their existing capability verdict remains the readiness
1927
1931
  * source.
1928
1932
  */
1929
- const callableReadiness = new Set([
1930
- 'prepared-cold',
1931
- 'loading',
1932
- 'ready',
1933
- 'busy',
1934
- ]);
1935
1933
  const readinessOf = async (item) => {
1936
1934
  if (item.verdict.route !== 'extension')
1937
1935
  return 'ready';
@@ -2003,6 +2001,17 @@ export async function apply(ctx, config = {}) {
2003
2001
  if (entry.contract !== null && contractById.has(entry.contract)) {
2004
2002
  const binding = bindings.get(entry.contract);
2005
2003
  if (binding === undefined) {
2004
+ /**
2005
+ * A provider-bound model whose contract has no host binding is still served
2006
+ * by its extension, which owns the tool name. Record it and report success;
2007
+ * only a model with no owner is the "not the selected provider" case.
2008
+ */
2009
+ if (entry.provider !== undefined && extensionOwnsToolName(entry.tool.name)) {
2010
+ catalogueDeferred.add(entry.id);
2011
+ installed.set(entry.id, { entry, toolName: entry.tool.name, dispose: () => { } });
2012
+ notifyCatalogChange();
2013
+ return true;
2014
+ }
2006
2015
  // The model implements a contract but lost provider selection, or cannot
2007
2016
  // run. Report rather than register a second tool for the same contract.
2008
2017
  ctx.logger.info(`model-tools: ${entry.name} implements ${entry.contract} but is not the selected provider; `
@@ -2045,7 +2054,10 @@ export async function apply(ctx, config = {}) {
2045
2054
  catalogueDeferred.add(entry.id);
2046
2055
  ctx.logger.info(`model-tools: ${entry.name}'s tool ${entry.tool.name} is owned by an installed extension; `
2047
2056
  + 'the catalogue registration is deferred until the extension releases the name');
2048
- return false;
2057
+ // The extension serves the tool already: enabling the catalogue entry is a
2058
+ // success that records the model, never "cannot be installed here".
2059
+ toolName = entry.tool.name;
2060
+ dispose = () => { };
2049
2061
  }
2050
2062
  else {
2051
2063
  const registered = registerContractTool(ctx, binding, host);
@@ -2061,14 +2073,22 @@ export async function apply(ctx, config = {}) {
2061
2073
  });
2062
2074
  }
2063
2075
  }
2064
- else {
2065
- if (verdict.route === 'extension') {
2066
- const readiness = await readinessOf(item);
2067
- if (!callableReadiness.has(readiness)) {
2068
- ctx.logger.info(`model-tools: ${entry.name} is active but its provider reports ${readiness}; skipping ${entry.tool.name}`);
2069
- return false;
2070
- }
2076
+ else if (entry.provider !== undefined) {
2077
+ /**
2078
+ * PROVIDER-BOUND: the extension owns the tool name. When it is active the
2079
+ * catalogue joins that tool instead of registering a second one; when it is
2080
+ * not active there is no tool to join, so the entry is skipped rather than
2081
+ * replaced by a provider-bridge tool the MCP surface cannot export.
2082
+ */
2083
+ if (!extensionOwnsToolName(entry.tool.name)) {
2084
+ ctx.logger.info(`model-tools: ${entry.name}'s provider extension is not active; skipping ${entry.tool.name}`);
2085
+ return false;
2071
2086
  }
2087
+ catalogueDeferred.add(entry.id);
2088
+ toolName = entry.tool.name;
2089
+ dispose = () => { };
2090
+ }
2091
+ else {
2072
2092
  const adapter = createAdapter(entry, { route: verdict.route, ...transportOptions }, undefined, bridge);
2073
2093
  if (adapter === undefined) {
2074
2094
  // Runnable but no adapter yet: report rather than register a dead tool.
@@ -2170,6 +2190,10 @@ export async function apply(ctx, config = {}) {
2170
2190
  if (extensionOwnsToolName(item.entry.tool.name))
2171
2191
  continue;
2172
2192
  catalogueDeferred.delete(modelId);
2193
+ // A deferred model was recorded as served by the extension; drop that record
2194
+ // first or install() short-circuits on it and never registers the catalogue tool.
2195
+ if (installed.has(modelId))
2196
+ uninstall(modelId);
2173
2197
  ctx.logger.info(`model-tools: ${item.entry.name}'s tool ${item.entry.tool.name} is released; restoring the catalogue registration`);
2174
2198
  try {
2175
2199
  await install(item);
@@ -150,6 +150,45 @@ export interface StateReadResult<T> {
150
150
  * @returns the content digest, lowercase hex.
151
151
  */
152
152
  export declare function digestInstalledContent(directory: string): string;
153
+ /** A cheap metadata fingerprint of an installed tree (task-28 cache key). */
154
+ export interface InstallFingerprint {
155
+ /** Content files, excluding the install receipt. */
156
+ readonly fileCount: number;
157
+ /** Sum of the content files' byte sizes. */
158
+ readonly totalSize: number;
159
+ /** Newest modification time, in milliseconds since the epoch. */
160
+ readonly maxMtimeMs: number;
161
+ /**
162
+ * Newest change time (ctime), in milliseconds since the epoch. This is the fingerprint field
163
+ * that catches an in-place rewrite whose author restored the modification time: writing the
164
+ * bytes advances ctime on the supported filesystems.
165
+ */
166
+ readonly maxChangeTimeMs: number;
167
+ }
168
+ /**
169
+ * Digest an installed package with a bounded worker pool (task-28).
170
+ *
171
+ * Byte-identical to {@link digestInstalledContent}: the per-file sha256 values are gathered
172
+ * (in parallel) and then the final sha256 is updated in the same sorted order, with the same
173
+ * relative name, size and separators. A worker failure falls back to bounded async I/O, which
174
+ * produces the same values; the parallelism can only change how fast the digest is computed.
175
+ * @param directory - the installed package directory.
176
+ * @param options - concurrency override (defaults to min(8, cpus - 1)).
177
+ * @returns the content digest, lowercase hex.
178
+ */
179
+ export declare function digestInstalledContentAsync(directory: string, options?: {
180
+ readonly concurrency?: number;
181
+ }): Promise<string>;
182
+ /**
183
+ * The cheap metadata fingerprint verifyUnchangedAsync caches against (task-28).
184
+ *
185
+ * It walks the tree (directory reads and stat calls only, never file contents) and records the
186
+ * content-file count, their total size, the newest modification time and the newest change time.
187
+ * The install receipt is excluded so rewriting it cannot invalidate an otherwise unchanged tree.
188
+ * @param directory - the installed package directory.
189
+ * @returns the fingerprint.
190
+ */
191
+ export declare function installContentFingerprint(directory: string): InstallFingerprint;
153
192
  /**
154
193
  * Whether a process with this pid exists. `process.kill(pid, 0)` is the probe.
155
194
  *
@@ -162,6 +201,7 @@ export declare function digestInstalledContent(directory: string): string;
162
201
  export declare function isProcessAlive(pid: number): boolean;
163
202
  /** The operator-owned extension store. */
164
203
  export declare class ExtensionStore {
204
+ #private;
165
205
  /** Absolute path of the store root. */
166
206
  readonly rootDir: string;
167
207
  constructor(rootDir: string);
@@ -238,6 +278,29 @@ export declare class ExtensionStore {
238
278
  contentDigest?: string;
239
279
  diagnostic?: string;
240
280
  };
281
+ /**
282
+ * Async, cached form of {@link verifyUnchanged} (task-28).
283
+ *
284
+ * Uses the worker-pool digest so a multi-GB installation does not block the event loop for
285
+ * minutes, and reuses the last verified answer while the cheap fingerprint and the record's
286
+ * digest both still match. A stale or forged record is never served from the cache: the
287
+ * cache entry must carry the SAME recorded digest, and any fingerprint change falls back to a
288
+ * full digest. A failed check removes the entry, so a tampered tree is re-digested next time.
289
+ *
290
+ * Residual limitation: a rewrite that preserved byte size, mtime AND ctime would not change
291
+ * the cheap fingerprint, so a warm cache could not see it without re-reading the bytes. That
292
+ * is why the full digest remains the authority on a fresh process and on every fingerprint
293
+ * change; the ctime component makes ordinary "restore the timestamps" tampering detectable.
294
+ * @param record - the recorded installation.
295
+ * @returns whether the content is unchanged, the current digest when computed, and whether
296
+ * the answer came from the cache.
297
+ */
298
+ verifyUnchangedAsync(record: InstalledRecord): Promise<{
299
+ unchanged: boolean;
300
+ contentDigest?: string;
301
+ diagnostic?: string;
302
+ cached: boolean;
303
+ }>;
241
304
  /**
242
305
  * Read one profile's activation state.
243
306
  *
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/install/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAEL,aAAa,EAIb,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAKzD,mDAAmD;AACnD,eAAO,MAAM,SAAS,yBAAyB,CAAA;AAE/C,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,yBAAyB;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,gFAAgF;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,iFAAiF;IACjF,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IACtC,uEAAuE;IACvE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAA;IAC/E,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACnD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE;QACpB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;QACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;QAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KACxC,CAAA;CACF;AAED,yBAAyB;AACzB,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAA;IAC/C;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACrD;AAED,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,WAAW,CAAA;IAC3C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,OAAO,aAAa,CAAA;IAC3C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAA;IAC9C,wEAAwE;IACxE,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACxD,2EAA2E;IAC3E,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAC7D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,sEAAsE;AACtE,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;IACjB,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAID;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuBhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASnD;AA2CD,0CAA0C;AAC1C,qBAAa,cAAc;IACzB,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM;IAI3B,iCAAiC;IACjC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,wCAAwC;IACxC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAczC;;;;;;;;;;OAUG;IACH,gBAAgB,IAAI,MAAM,IAAI;IA6B9B;;;;;;;;;;;;;;OAcG;IACG,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoDtD;;;;;;OAMG;IACH,QAAQ,IAAI,eAAe,CAAC,SAAS,CAAC;IAUtC,iCAAiC;IACjC,aAAa,IAAI,eAAe,CAAC,SAAS,eAAe,EAAE,CAAC;IAK5D;;;;;;;OAOG;IACH,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAsC5C;;;;;;;OAOG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IA2BvC;;;;;;;OAOG;IACH,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAe7G;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,SAAS,cAAc,EAAE,CAAC;IAqD7E;;;;;;;;;;;;;;;;;;;OAmBG;IACH,iBAAiB,CACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,SAAS,cAAc,EAAE,EACrC,cAAc,CAAC,EAAE,SAAS,mBAAmB,EAAE,EAC/C,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACjD,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAClD,IAAI;IAmBP;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC;QACpD,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACzD,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;KAC5D,CAAC;IA8BF,gFAAgF;IAChF,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAI1D;;;;;;;;OAQG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAcrG;;;;;;;;;;OAUG;IACH,cAAc,CACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,QAAQ,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GACjE,IAAI;IA4BP;;;;;;;;OAQG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA+B/D,+CAA+C;IAC/C,iBAAiB,IAAI,MAAM;IAI3B;;;;;;;;OAQG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAY/D;;;;;;;;OAQG;IACH,mBAAmB,CAAC,WAAW,SAAI,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAqDxF;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAyBpF;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,yBAAyB,CAC7B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,SAA8B,GACzC,OAAO,CAAC,eAAe,CAAC;CAuH5B"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/install/store.ts"],"names":[],"mappings":"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"}
@@ -19,7 +19,10 @@
19
19
  */
20
20
  import { createHash, randomUUID } from 'node:crypto';
21
21
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync, } from 'node:fs';
22
+ import { readFile } from 'node:fs/promises';
23
+ import { cpus } from 'node:os';
22
24
  import { dirname, join, relative, resolve, sep } from 'node:path';
25
+ import { Worker } from 'node:worker_threads';
23
26
  import { ManagementError } from "./../errors.js";
24
27
  import { STATE_SCHEMA_VERSION, STATE_VERSION, applyLegacyChoices, parseLegacyModelState, } from "./migration.js";
25
28
  /** Reentrant acquisition depth per resolved store root, process-local. */
@@ -64,6 +67,177 @@ export function digestInstalledContent(directory) {
64
67
  }
65
68
  return hash.digest('hex');
66
69
  }
70
+ /**
71
+ * The worker source. EVAL keeps the pool self-contained in this module (no separate file and
72
+ * no build/config coupling); the worker only reads files and returns per-file digests, so the
73
+ * digest itself is still assembled in ONE deterministic order on the main thread.
74
+ */
75
+ const DIGEST_WORKER_SOURCE = `
76
+ const { parentPort, workerData } = require('node:worker_threads')
77
+ const { readFileSync } = require('node:fs')
78
+ const { createHash } = require('node:crypto')
79
+ const digests = workerData.files.map((file) => {
80
+ const bytes = readFileSync(file)
81
+ return { file, size: bytes.byteLength, digest: createHash('sha256').update(bytes).digest('hex') }
82
+ })
83
+ parentPort.postMessage(digests)
84
+ `;
85
+ /** The default worker-pool size: min(8, cpus - 1), never less than one. */
86
+ const digestConcurrency = () => Math.max(1, Math.min(8, cpus().length - 1));
87
+ /**
88
+ * Walk an installed tree exactly as digestInstalledContent does: sorted-by-name directories,
89
+ * files collected and then sorted by absolute path. The async digest must not change identity,
90
+ * so the file list is produced with the same ordering rule.
91
+ */
92
+ function installedFilesForDigest(directory) {
93
+ const files = [];
94
+ const walk = (current) => {
95
+ for (const entry of readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
96
+ const absolute = join(current, entry.name);
97
+ if (entry.isDirectory())
98
+ walk(absolute);
99
+ else if (entry.isFile())
100
+ files.push(absolute);
101
+ }
102
+ };
103
+ walk(directory);
104
+ return files.sort();
105
+ }
106
+ /** The digest's relative name for a file: forward slashes on every platform. */
107
+ const relativeContentName = (directory, file) => relative(directory, file).split(sep).join('/');
108
+ /** Hash files on the main thread with bounded async I/O (the worker-free fallback). */
109
+ async function digestFilesInline(files, concurrency) {
110
+ const results = new Array(files.length);
111
+ let cursor = 0;
112
+ const run = async () => {
113
+ for (;;) {
114
+ const index = cursor;
115
+ cursor += 1;
116
+ const file = files[index];
117
+ if (file === undefined)
118
+ return;
119
+ const bytes = await readFile(file);
120
+ results[index] = { file, size: bytes.byteLength, digest: createHash('sha256').update(bytes).digest('hex') };
121
+ }
122
+ };
123
+ await Promise.all(Array.from({ length: Math.min(concurrency, files.length) }, () => run()));
124
+ return results;
125
+ }
126
+ /** Hash a chunk of files inside one worker. */
127
+ function digestFilesInWorker(files) {
128
+ return new Promise((resolvePromise, reject) => {
129
+ const worker = new Worker(DIGEST_WORKER_SOURCE, { eval: true, workerData: { files } });
130
+ let settled = false;
131
+ const fail = (error) => {
132
+ if (settled)
133
+ return;
134
+ settled = true;
135
+ void worker.terminate();
136
+ reject(error instanceof Error ? error : new Error(String(error)));
137
+ };
138
+ worker.once('message', (value) => {
139
+ if (settled)
140
+ return;
141
+ settled = true;
142
+ void worker.terminate();
143
+ resolvePromise(value);
144
+ });
145
+ worker.once('error', fail);
146
+ worker.once('exit', (code) => {
147
+ if (code !== 0)
148
+ fail(new Error('the digest worker exited with code ' + String(code)));
149
+ });
150
+ });
151
+ }
152
+ /**
153
+ * Digest an installed package with a bounded worker pool (task-28).
154
+ *
155
+ * Byte-identical to {@link digestInstalledContent}: the per-file sha256 values are gathered
156
+ * (in parallel) and then the final sha256 is updated in the same sorted order, with the same
157
+ * relative name, size and separators. A worker failure falls back to bounded async I/O, which
158
+ * produces the same values; the parallelism can only change how fast the digest is computed.
159
+ * @param directory - the installed package directory.
160
+ * @param options - concurrency override (defaults to min(8, cpus - 1)).
161
+ * @returns the content digest, lowercase hex.
162
+ */
163
+ export async function digestInstalledContentAsync(directory, options = {}) {
164
+ const files = installedFilesForDigest(directory);
165
+ const requested = options.concurrency ?? digestConcurrency();
166
+ const concurrency = Math.max(1, Math.min(requested, files.length === 0 ? 1 : files.length));
167
+ let digests = [];
168
+ if (files.length > 0) {
169
+ if (concurrency === 1) {
170
+ digests = await digestFilesInline(files, 1);
171
+ }
172
+ else {
173
+ const chunks = Array.from({ length: concurrency }, () => []);
174
+ for (let index = 0; index < files.length; index += 1) {
175
+ const file = files[index];
176
+ if (file !== undefined)
177
+ chunks[index % concurrency]?.push(file);
178
+ }
179
+ try {
180
+ const parts = await Promise.all(chunks.filter((chunk) => chunk.length > 0).map((chunk) => digestFilesInWorker(chunk)));
181
+ digests = parts.flat();
182
+ }
183
+ catch {
184
+ digests = await digestFilesInline(files, concurrency);
185
+ }
186
+ }
187
+ }
188
+ const byFile = new Map(digests.map((entry) => [entry.file, entry]));
189
+ const hash = createHash('sha256');
190
+ for (const file of files) {
191
+ const name = relativeContentName(directory, file);
192
+ if (name === '.tool-mode-install.json')
193
+ continue;
194
+ const entry = byFile.get(file);
195
+ if (entry === undefined)
196
+ throw new Error('the async digest did not hash ' + JSON.stringify(name));
197
+ hash.update(name);
198
+ hash.update('\0');
199
+ hash.update(String(entry.size));
200
+ hash.update('\0');
201
+ hash.update(Buffer.from(entry.digest, 'hex'));
202
+ hash.update('\0');
203
+ }
204
+ return hash.digest('hex');
205
+ }
206
+ /**
207
+ * The cheap metadata fingerprint verifyUnchangedAsync caches against (task-28).
208
+ *
209
+ * It walks the tree (directory reads and stat calls only, never file contents) and records the
210
+ * content-file count, their total size, the newest modification time and the newest change time.
211
+ * The install receipt is excluded so rewriting it cannot invalidate an otherwise unchanged tree.
212
+ * @param directory - the installed package directory.
213
+ * @returns the fingerprint.
214
+ */
215
+ export function installContentFingerprint(directory) {
216
+ const files = installedFilesForDigest(directory);
217
+ let fileCount = 0;
218
+ let totalSize = 0;
219
+ let maxMtimeMs = 0;
220
+ let maxChangeTimeMs = 0;
221
+ for (const file of files) {
222
+ if (relativeContentName(directory, file) === '.tool-mode-install.json')
223
+ continue;
224
+ const stats = statSync(file);
225
+ fileCount += 1;
226
+ totalSize += stats.size;
227
+ if (stats.mtimeMs > maxMtimeMs)
228
+ maxMtimeMs = stats.mtimeMs;
229
+ if (stats.ctimeMs > maxChangeTimeMs)
230
+ maxChangeTimeMs = stats.ctimeMs;
231
+ }
232
+ return { fileCount, totalSize, maxMtimeMs, maxChangeTimeMs };
233
+ }
234
+ /** Whether two fingerprints describe the same metadata state. */
235
+ function sameFingerprint(left, right) {
236
+ return left.fileCount === right.fileCount
237
+ && left.totalSize === right.totalSize
238
+ && left.maxMtimeMs === right.maxMtimeMs
239
+ && left.maxChangeTimeMs === right.maxChangeTimeMs;
240
+ }
67
241
  /**
68
242
  * Whether a process with this pid exists. `process.kill(pid, 0)` is the probe.
69
243
  *
@@ -127,6 +301,12 @@ function readJsonBounded(path, maxBytes = 4 * 1024 * 1024) {
127
301
  export class ExtensionStore {
128
302
  /** Absolute path of the store root. */
129
303
  rootDir;
304
+ /**
305
+ * Verified digests per install path (task-28). A process-local performance cache: it may only
306
+ * short-circuit the full digest when the cheap fingerprint is identical AND the record's
307
+ * digest equals the digest that was verified for that fingerprint.
308
+ */
309
+ #verifiedContent = new Map();
130
310
  constructor(rootDir) {
131
311
  this.rootDir = resolve(rootDir);
132
312
  }
@@ -358,6 +538,52 @@ export class ExtensionStore {
358
538
  }
359
539
  return { unchanged: true, contentDigest };
360
540
  }
541
+ /**
542
+ * Async, cached form of {@link verifyUnchanged} (task-28).
543
+ *
544
+ * Uses the worker-pool digest so a multi-GB installation does not block the event loop for
545
+ * minutes, and reuses the last verified answer while the cheap fingerprint and the record's
546
+ * digest both still match. A stale or forged record is never served from the cache: the
547
+ * cache entry must carry the SAME recorded digest, and any fingerprint change falls back to a
548
+ * full digest. A failed check removes the entry, so a tampered tree is re-digested next time.
549
+ *
550
+ * Residual limitation: a rewrite that preserved byte size, mtime AND ctime would not change
551
+ * the cheap fingerprint, so a warm cache could not see it without re-reading the bytes. That
552
+ * is why the full digest remains the authority on a fresh process and on every fingerprint
553
+ * change; the ctime component makes ordinary "restore the timestamps" tampering detectable.
554
+ * @param record - the recorded installation.
555
+ * @returns whether the content is unchanged, the current digest when computed, and whether
556
+ * the answer came from the cache.
557
+ */
558
+ async verifyUnchangedAsync(record) {
559
+ if (!existsSync(record.installPath)) {
560
+ this.#verifiedContent.delete(record.installPath);
561
+ return { unchanged: false, diagnostic: 'the installation directory is missing', cached: false };
562
+ }
563
+ const before = installContentFingerprint(record.installPath);
564
+ const cached = this.#verifiedContent.get(record.installPath);
565
+ if (cached !== undefined && cached.contentDigest === record.contentDigest && sameFingerprint(cached.fingerprint, before)) {
566
+ return { unchanged: true, contentDigest: cached.contentDigest, cached: true };
567
+ }
568
+ const contentDigest = await digestInstalledContentAsync(record.installPath);
569
+ if (contentDigest !== record.contentDigest) {
570
+ this.#verifiedContent.delete(record.installPath);
571
+ return {
572
+ unchanged: false,
573
+ contentDigest,
574
+ diagnostic: 'the installed content differs from the recorded digest; the package changed on disk after installation',
575
+ cached: false,
576
+ };
577
+ }
578
+ // Cache only if the tree did not move while it was being hashed (otherwise the entry would
579
+ // pair the new digest with the old fingerprint and hide a later change).
580
+ const after = installContentFingerprint(record.installPath);
581
+ if (sameFingerprint(before, after))
582
+ this.#verifiedContent.set(record.installPath, { contentDigest, fingerprint: after });
583
+ else
584
+ this.#verifiedContent.delete(record.installPath);
585
+ return { unchanged: true, contentDigest, cached: false };
586
+ }
361
587
  /**
362
588
  * Read one profile's activation state.
363
589
  *
@@ -51,4 +51,3 @@
51
51
  "dsh-tool-mode": "./bin/dsh-tool-mode.mjs"
52
52
  }
53
53
  }
54
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@try-works/dsh-tool-mode",
3
- "version": "0.5.49",
3
+ "version": "0.5.51",
4
4
  "description": "Install Desert Ant Labs on-device models as DSH tools and skills, with per-platform capability gating",
5
5
  "keywords": [
6
6
  "dsh",