sliccy 6.155.0 → 6.156.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/node-server/hostfs.d.ts +6 -1
- package/dist/node-server/hostfs.js +32 -0
- package/dist/ui/.vite/manifest.json +201 -201
- package/dist/ui/assets/CLAUDE-D8aRy6Y3.js +1 -0
- package/dist/ui/assets/{SKILL-C947OHCv.js → SKILL-CkA461kX.js} +1 -1
- package/dist/ui/assets/{account-store-FUhuBOfI.js → account-store-BlFA99H0.js} +1 -1
- package/dist/ui/assets/{account-store-BL68LrFT.js → account-store-DlBJje5p.js} +1 -1
- package/dist/ui/assets/{adobe-BaHLL9uH.js → adobe-Bb0HwmGi.js} +1 -1
- package/dist/ui/assets/{adobe-DNHcSDh3.js → adobe-Cf_urjYb.js} +1 -1
- package/dist/ui/assets/{agent-bridge-Vz3IOG0A.js → agent-bridge-DoFAHPGJ.js} +1 -1
- package/dist/ui/assets/{agent-panels-CPSe8uIz.js → agent-panels-CvyqP3Ii.js} +1 -1
- package/dist/ui/assets/{apply-layout-G6vw7FBS.js → apply-layout-lpl82E_y.js} +1 -1
- package/dist/ui/assets/{apps-CLm3AutR.js → apps-Cx1ihs6S.js} +1 -1
- package/dist/ui/assets/{auto-mount-table-BDyGIOIb.js → auto-mount-table-Bj59hmjV.js} +1 -1
- package/dist/ui/assets/{azure-openai--n3vcQWx.js → azure-openai-Bvik-NC0.js} +1 -1
- package/dist/ui/assets/{azure-openai-N9FaZSuP.js → azure-openai-Cc3KvQoJ.js} +1 -1
- package/dist/ui/assets/backend-hostfs-De2Zrx7a.js +1 -0
- package/dist/ui/assets/backend-hostfs-n_0O1LVt.js +1 -0
- package/dist/ui/assets/{browser-BxGToOGy.js → browser-CyOAI9cj.js} +3 -3
- package/dist/ui/assets/{budget-usage-source-C6vq4Afr.js → budget-usage-source-DJCk4Eol.js} +1 -1
- package/dist/ui/assets/{bunny-probe-Dk0BdUab.js → bunny-probe-BVjp9oI9.js} +1 -1
- package/dist/ui/assets/{bunny-run-DtVSvgJ8.js → bunny-run-E1D0_zTi.js} +1 -1
- package/dist/ui/assets/{cdp-C7C40sWI.js → cdp-B3b4fMbQ.js} +1 -1
- package/dist/ui/assets/{cerebras-B4z1b7WX.js → cerebras-CY_ZE7G8.js} +1 -1
- package/dist/ui/assets/{cerebras-BecGzlaM.js → cerebras-Dv9W7f69.js} +1 -1
- package/dist/ui/assets/{composer-speech-uDoOk80y.js → composer-speech-lUexnB3v.js} +1 -1
- package/dist/ui/assets/{connect-surface-CkYbO0v8.js → connect-surface-CYgHpfHt.js} +1 -1
- package/dist/ui/assets/{cost-command-BzdZ_evm.js → cost-command-XzcQb5EI.js} +1 -1
- package/dist/ui/assets/{directed-approval-DdGH8Fat.js → directed-approval-HCtoBBOI.js} +1 -1
- package/dist/ui/assets/{dist-CtH2hxRt.js → dist-0AIPb7H_.js} +9 -9
- package/dist/ui/assets/{dist-VS1DwNvU.js → dist-xOOa94QU.js} +10 -10
- package/dist/ui/assets/{ensure-speech-assets-DOu9EHnU.js → ensure-speech-assets-BfysPtlZ.js} +1 -1
- package/dist/ui/assets/{extension-ops-B05mAXsq.js → extension-ops-DcLzcAwt.js} +1 -1
- package/dist/ui/assets/{fast-path-CfBU0M0X.js → fast-path-CbwpSWFJ.js} +1 -1
- package/dist/ui/assets/{frozen-archive-writer--a4fMghf.js → frozen-archive-writer-Df5805od.js} +1 -1
- package/dist/ui/assets/fs-B5sS6_5I.js +2 -0
- package/dist/ui/assets/fs-C88g915Q.js +1 -0
- package/dist/ui/assets/{github-FRM6nHar.js → github-Bujm8ahG.js} +1 -1
- package/dist/ui/assets/github-HJvu_gac.js +2 -0
- package/dist/ui/assets/{github-auth-DgdBb7y7.js → github-auth-C641hcY1.js} +1 -1
- package/dist/ui/assets/{github-copilot-D6XJxicV.js → github-copilot-DbNXg7Dn.js} +1 -1
- package/dist/ui/assets/{github-copilot-CNY2SweM.js → github-copilot-ca4PJied.js} +1 -1
- package/dist/ui/assets/{github-install-PNSinMst.js → github-install-QZbYCNzS.js} +1 -1
- package/dist/ui/assets/{github-zip-BCXSTlT0.js → github-zip-DQai7euS.js} +1 -1
- package/dist/ui/assets/{hear-DAaE31Ez.js → hear-Co1rqszy.js} +1 -1
- package/dist/ui/assets/{help-HkZtBCNF.js → help-HaCQg57w.js} +1 -1
- package/dist/ui/assets/installer-3ZT0rXO0.js +4 -0
- package/dist/ui/assets/isomorphic-git-DRUhmZ5u.js +84 -0
- package/dist/ui/assets/{js-realm-worker-Bp1ohy2N.js → js-realm-worker-5lZp3zuB.js} +1 -1
- package/dist/ui/assets/kernel-worker-CdtrnwDB.js +4948 -0
- package/dist/ui/assets/{live-session-snapshot-CpwRZg6K.js → live-session-snapshot-BP6rxBrE.js} +1 -1
- package/dist/ui/assets/{local-llm-BL_WYiZZ.js → local-llm-CP69uiQv.js} +1 -1
- package/dist/ui/assets/{local-llm-BKrrjR68.js → local-llm-i_pLphdz.js} +1 -1
- package/dist/ui/assets/{main-DW-YS69h.js → main-B6KvjwxA.js} +3 -3
- package/dist/ui/assets/{main-cherry-B0AQVdvI.js → main-cherry-Bq-MY7_2.js} +1 -1
- package/dist/ui/assets/{memory-curation-seam-CD-ZRKzr.js → memory-curation-seam-DaXa0jXx.js} +1 -1
- package/dist/ui/assets/{mount-DlOEB7Cf.js → mount-BzmsDs-Q.js} +2 -2
- package/dist/ui/assets/{mount-igEB5Saa.js → mount-YnCWqYIR.js} +3 -3
- package/dist/ui/assets/{mount-bridge-client-DQaM1wCj.js → mount-bridge-client-DphjpUJQ.js} +1 -1
- package/dist/ui/assets/{mount-bridge-client-DWY67yip.js → mount-bridge-client-wfM0sGs5.js} +1 -1
- package/dist/ui/assets/{mount-index-D9w_zMSm.js → mount-index-DLLlduW0.js} +1 -1
- package/dist/ui/assets/{mount-recovery-WObwrrJB.js → mount-recovery-WIBwiZyX.js} +1 -1
- package/dist/ui/assets/mv-DUh51uEl.js +2 -0
- package/dist/ui/assets/{new-session-BlbJzLQE.js → new-session-CL_CInjb.js} +2 -2
- package/dist/ui/assets/{oauth-bootstrap-DHGSi_vM.js → oauth-bootstrap-p-eVw2wO.js} +2 -2
- package/dist/ui/assets/{onboarding-orchestrator-ILCQMWeH.js → onboarding-orchestrator-Qp_wc9Wi.js} +1 -1
- package/dist/ui/assets/{openai-codex-ByOwob9t.js → openai-codex-BpnvhpGf.js} +1 -1
- package/dist/ui/assets/{openai-codex-zHgcCFMl.js → openai-codex-SDOR649L.js} +1 -1
- package/dist/ui/assets/{openrouter-CvwSbwg3.js → openrouter-BSWGMR9L.js} +1 -1
- package/dist/ui/assets/{openrouter-ooroqv_7.js → openrouter-Csr12jOI.js} +1 -1
- package/dist/ui/assets/{openrouter-free-DAXjSSCv.js → openrouter-free-DRMsAIo_.js} +1 -1
- package/dist/ui/assets/{openrouter-free-Bw5mRfKy.js → openrouter-free-lmqj7iWQ.js} +1 -1
- package/dist/ui/assets/{openrouter-oauth-CsQP_eqX.js → openrouter-oauth-C4wVAVP0.js} +1 -1
- package/dist/ui/assets/{openrouter-oauth-DKr2TOOt.js → openrouter-oauth-DHX_fpIm.js} +1 -1
- package/dist/ui/assets/opfs-mount-B4BizFOR.js +2 -0
- package/dist/ui/assets/opfs-mount-BdgSw31f.js +2 -0
- package/dist/ui/assets/{panel-rpc-handlers-g22Ng2gw.js → panel-rpc-handlers-B-q4ku-f.js} +2 -2
- package/dist/ui/assets/{panelize-shell-25ZtCwHW.js → panelize-shell-DY2g5UXp.js} +1 -1
- package/dist/ui/assets/{pi-edit-execution-jG5wiCuj.js → pi-edit-execution-D9yRA2Fe.js} +1 -1
- package/dist/ui/assets/{probe-info-B9GqJE41.js → probe-info-CjsoArwT.js} +1 -1
- package/dist/ui/assets/provider-BwgylKFb.js +2 -0
- package/dist/ui/assets/{provider-iX6700HG.js → provider-Uec7ton3.js} +1 -1
- package/dist/ui/assets/provider-settings-D_IE6rMQ.js +1 -0
- package/dist/ui/assets/provider-store-access-DEDLOyhJ.js +1 -0
- package/dist/ui/assets/provider-store-access-DfqSh8G6.js +1 -0
- package/dist/ui/assets/{providers-DjUwvFlY.js → providers-CKwuqmbn.js} +2 -2
- package/dist/ui/assets/{providers-DAeL97z_.js → providers-CSPNJM6o.js} +1 -1
- package/dist/ui/assets/{quick-llm-CM0bq0Rp.js → quick-llm-Dl0Eh3p1.js} +1 -1
- package/dist/ui/assets/{recovery-screen-C2-cTzHe.js → recovery-screen-BIO2d0_k.js} +1 -1
- package/dist/ui/assets/{remote-sprinkle-vfs-BY9A-xsx.js → remote-sprinkle-vfs-C_-TfGu3.js} +1 -1
- package/dist/ui/assets/{remote-vfs-client-Dt3CesOI.js → remote-vfs-client-CEL8mUQ9.js} +1 -1
- package/dist/ui/assets/rename-via-fs-ckVY1Ljv.js +1 -0
- package/dist/ui/assets/{run-Cv106rZx.js → run-B7bNDge8.js} +2 -2
- package/dist/ui/assets/{run-CgQOlMuy.js → run-BAXE1Fgn.js} +2 -2
- package/dist/ui/assets/run-BbzzVjlq.js +13 -0
- package/dist/ui/assets/{run-BZq150_-.js → run-CFSW3zNE.js} +2 -2
- package/dist/ui/assets/{run-XqJwbPb4.js → run-CWenWZRy.js} +2 -2
- package/dist/ui/assets/{run-BmBPc42l.js → run-DZd7hQTI.js} +1 -1
- package/dist/ui/assets/{run-2dG-kPkW.js → run-enknJJEk.js} +1 -1
- package/dist/ui/assets/{run-wZKGk8f1.js → run-r5Uh0A1S.js} +1 -1
- package/dist/ui/assets/same-file-identity-C_JKwIh_.js +1 -0
- package/dist/ui/assets/{session-command-memory-CkF1Wu0O.js → session-command-memory-CzJDf01Z.js} +2 -2
- package/dist/ui/assets/{session-jsonl-eMNv3Qki.js → session-jsonl-BwqaD3jQ.js} +1 -1
- package/dist/ui/assets/{session-jsonl-BUM105sQ.js → session-jsonl-CjA27CdZ.js} +1 -1
- package/dist/ui/assets/{session-search-index-D2VtAM_Q.js → session-search-index-D6zcG95Z.js} +1 -1
- package/dist/ui/assets/{setup-feature-flags-remote-CYaTMUGI.js → setup-feature-flags-remote-DlXGCipy.js} +1 -1
- package/dist/ui/assets/shebang-exec-hint-BISPom3l.js +2 -0
- package/dist/ui/assets/sidecar-repair-CWpX6fJD.js +1 -0
- package/dist/ui/assets/{silent-renew-backoff-CMcARSwp.js → silent-renew-backoff-CTA85brT.js} +1 -1
- package/dist/ui/assets/{skills-BpO1a28c.js → skills-DMAKVN61.js} +1 -1
- package/dist/ui/assets/slicc-version-C_H-MY6l.js +1 -0
- package/dist/ui/assets/{snapshot-features-j6dx6n8x.js → snapshot-features-82ReCjaH.js} +1 -1
- package/dist/ui/assets/{snapshot-CUbnB6HL.js → snapshot-zhet1-8H.js} +1 -1
- package/dist/ui/assets/{soundscape-BswqsuUI.js → soundscape-lSRZkZE6.js} +1 -1
- package/dist/ui/assets/{speak-BjUpeuE_.js → speak-Cm1HeYCz.js} +1 -1
- package/dist/ui/assets/{sprinkle-manager--VjyaGhT.js → sprinkle-manager-CPuK8KeD.js} +1 -1
- package/dist/ui/assets/{sprinkle-renderer-DST9wDsJ.js → sprinkle-renderer-CF7WMbPy.js} +1 -1
- package/dist/ui/assets/src-D-Mukt_a.js +575 -0
- package/dist/ui/assets/{state-D4U_z-EK.js → state-C9R7OoLj.js} +5 -5
- package/dist/ui/assets/{store-B8MYU0Oj.js → store-Dpd801Yg.js} +1 -1
- package/dist/ui/assets/{store-DChdcXsg.js → store-wkip2iVX.js} +1 -1
- package/dist/ui/assets/{sudo-Zjjvq0o1.js → sudo-CtswsF2u.js} +1 -1
- package/dist/ui/assets/{sync-dialog-CQpxesIG.js → sync-dialog-BSpy8EFx.js} +1 -1
- package/dist/ui/assets/{transformers-env-Bfs2yK-G.js → transformers-env-kaOi2ojg.js} +1 -1
- package/dist/ui/assets/{tray-sidecar-DoJ0KYqF.js → tray-sidecar-DsOY4QHT.js} +1 -1
- package/dist/ui/assets/types-Bgy4zvr3.js +1 -0
- package/dist/ui/assets/{upgrade-detection-BJO1N35I.js → upgrade-detection-vrOmiqqS.js} +1 -1
- package/dist/ui/assets/{upskill-lick-skip-ETmK7gKp.js → upskill-lick-skip-xfV4fwlQ.js} +1 -1
- package/dist/ui/assets/{voice-reply-CxLeD2UU.js → voice-reply-CH76grIE.js} +1 -1
- package/dist/ui/assets/{wc-attach-BqTZtL4F.js → wc-attach-3nXTzstV.js} +2 -2
- package/dist/ui/assets/{wc-extension-C_P8Z5_f.js → wc-extension-Bt_trMqK.js} +2 -2
- package/dist/ui/assets/{wc-follower-w1PZlnC3.js → wc-follower-DuNcMcEQ.js} +3 -3
- package/dist/ui/assets/{wc-follower-oauth-CqVmKcTQ.js → wc-follower-oauth-B7gPBiE9.js} +1 -1
- package/dist/ui/assets/{wc-gelatiere-ErLykEqr.js → wc-gelatiere-DNYiiwtq.js} +1 -1
- package/dist/ui/assets/{wc-live-Kx0jpvxz.js → wc-live-r5pjjgYB.js} +5 -5
- package/dist/ui/assets/{wc-nav-DMxSQWF8.js → wc-nav-CE55zqTz.js} +2 -2
- package/dist/ui/assets/{wc-onboarding-W0FpgTat.js → wc-onboarding-DwuXDHj6.js} +2 -2
- package/dist/ui/assets/{wc-placeholder-CI7UKO4Z.js → wc-placeholder-Bk0Qt_En.js} +3 -3
- package/dist/ui/assets/{wc-secret-request-DaAszAFd.js → wc-secret-request-CVKjjntX.js} +1 -1
- package/dist/ui/assets/{wc-settings-B-FsPgww.js → wc-settings-qSUcx77z.js} +3 -3
- package/dist/ui/assets/wc-shell-CAp8GPMx.js +125 -0
- package/dist/ui/assets/{wc-shortcut-config-B5nHTfK6.js → wc-shortcut-config-Cy4oz3Dh.js} +1 -1
- package/dist/ui/assets/{wc-shortcuts-Cbk5hDbX.js → wc-shortcuts-BibvziEB.js} +1 -1
- package/dist/ui/assets/{wc-sprinkles-DnBxgn1Q.js → wc-sprinkles-CZtWuFtI.js} +2 -2
- package/dist/ui/assets/{wc-transcript-export-7tvwdvKC.js → wc-transcript-export-DOkXWZlo.js} +2 -2
- package/dist/ui/assets/{wc-tray-DwUCXdrJ.js → wc-tray-CbFgvHkE.js} +4 -4
- package/dist/ui/assets/welcome-detection-DU4qkHlr.js +1 -0
- package/dist/ui/assets/{whisper-session-DoxUb6hK.js → whisper-session-Bgp21V01.js} +2 -2
- package/dist/ui/assets/{writable-vfs-client-C4pTXDFX.js → writable-vfs-client-CuLQlJK0.js} +1 -1
- package/dist/ui/assets/{xai-grok-CIVOagKi.js → xai-grok-BVfIqjo2.js} +1 -1
- package/dist/ui/assets/{xai-grok-BHDMfFJ3.js → xai-grok-CPv2tY1e.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/packages/webapp/index.html +3 -3
- package/package.json +2 -1
- package/dist/ui/assets/CLAUDE-C4hj5z8T.js +0 -34
- package/dist/ui/assets/backend-hostfs-BH8uwRZG.js +0 -1
- package/dist/ui/assets/backend-hostfs-BJU2QL9q.js +0 -1
- package/dist/ui/assets/dist-BCg-GYyx.js +0 -2
- package/dist/ui/assets/dist-ByarBBEi.js +0 -2
- package/dist/ui/assets/fs-BOdMXcsi.js +0 -2
- package/dist/ui/assets/fs-CL93DUyC.js +0 -1
- package/dist/ui/assets/github-CQwdOEdJ.js +0 -2
- package/dist/ui/assets/installer-D4WxHb-C.js +0 -4
- package/dist/ui/assets/kernel-worker-dGdJLKhc.js +0 -5022
- package/dist/ui/assets/provider-B0ZPEVNo.js +0 -2
- package/dist/ui/assets/provider-settings-jhJRRTGA.js +0 -1
- package/dist/ui/assets/provider-store-access-BtES6Ln2.js +0 -1
- package/dist/ui/assets/provider-store-access-z34_fP_u.js +0 -1
- package/dist/ui/assets/sidecar-repair-CIHuOk7H.js +0 -1
- package/dist/ui/assets/sidecar-repair-Dyo_uNW9.js +0 -1
- package/dist/ui/assets/slicc-version-pkH5Cy8d.js +0 -1
- package/dist/ui/assets/src-DAuBIYcJ.js +0 -575
- package/dist/ui/assets/types-Dgm4REV3.js +0 -1
- package/dist/ui/assets/wc-shell-Bqj2G2_K.js +0 -125
- package/dist/ui/assets/welcome-detection-BePZ1gj8.js +0 -1
package/README.md
CHANGED
|
@@ -42,10 +42,14 @@ Once you're in, you can:
|
|
|
42
42
|
|
|
43
43
|
> Status: active working prototype. The macOS app is the easiest way in today; the extension has been submitted to the Chrome Web Store.
|
|
44
44
|
|
|
45
|
+
Scoop shells bound supported filesystem traversals and command buffers. See the
|
|
46
|
+
[shell work limits](docs/shell-reference.md#scoop-filesystem-work-limits) for limits
|
|
47
|
+
and command coverage.
|
|
48
|
+
|
|
45
49
|
## Why SLICC is different
|
|
46
50
|
|
|
47
51
|
- **Browser-native, not browser-adjacent.** The agent runtime lives in the browser, and the agent can act on the same browser it lives in. A great mix of power and containment. If you don't like what the AI does, close the browser tab and it's over.
|
|
48
|
-
- **A real shell environment.** Many browser agents are constrained by the tools provided to them. SLICC has an almost-too-real shell with commands like `git`, "`node`", `python`, `playwright`, built-in.
|
|
52
|
+
- **A real shell environment.** Many browser agents are constrained by the tools provided to them. SLICC has an almost-too-real shell with commands like `git`, "`node`", `python`, `playwright`, built-in. Text files use UTF-8 by default; binary pipelines and explicit file encodings preserve their bytes.
|
|
49
53
|
- **UI on the fly.** SLICC can generate rich user interfaces on the fly. These can be small visualizations in a chat response, or full-blown web applications that run in a sidebar, or even a separate tab.
|
|
50
54
|
- **Built around Skills.** Agents don't suffer from missing capabilities, they suffer from skill issues. SLICC can install native skills into `/workspace/skills`, and it also discovers compatible `.agents` / `.claude` skills read-only across the reachable VFS.
|
|
51
55
|
- **More than a coding panel.** Coding is one strong use case, but SLICC is built for practical browser work too: authenticated web apps, repetitive tab work, content operations, debugging, research, and automation.
|
|
@@ -280,6 +284,9 @@ SLICC would not have been possible without the pioneering inspiration of [OpenCl
|
|
|
280
284
|
|
|
281
285
|
## Development and deeper docs
|
|
282
286
|
|
|
287
|
+
Developers can verify native browser storage with `npm run test:opfs` and trial the
|
|
288
|
+
[optional OPFS preload setting](docs/filesystem-preload.md).
|
|
289
|
+
|
|
283
290
|
If you want to go deeper, the detailed docs live here:
|
|
284
291
|
|
|
285
292
|
- [Development guide](docs/development.md)
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
* HTML and the webapp cannot rethrow a faithful `FsError`.
|
|
58
58
|
*/
|
|
59
59
|
import type { ErrorRequestHandler, Express, Response } from 'express';
|
|
60
|
-
import { createReadStream } from 'fs';
|
|
60
|
+
import { createReadStream, type Stats } from 'fs';
|
|
61
61
|
import type { HostMountMapping } from './runtime-flags.js';
|
|
62
62
|
/**
|
|
63
63
|
* Cap on a WHOLE-FILE `GET /api/hostfs/read` (and on `PUT /write`). It exists
|
|
@@ -174,6 +174,11 @@ export declare function isHostFsStableBodyRequest(req: {
|
|
|
174
174
|
* passed through untouched.
|
|
175
175
|
*/
|
|
176
176
|
export declare const hostFsBodyErrorHandler: ErrorRequestHandler;
|
|
177
|
+
/**
|
|
178
|
+
* True when `a` and `b` are the same file (device + inode), not merely
|
|
179
|
+
* similar strings. Path comparison misses the APFS case / NFC-NFD collision.
|
|
180
|
+
*/
|
|
181
|
+
export declare function sameHostFileIdentity(a: Stats, b: Stats): boolean;
|
|
177
182
|
/**
|
|
178
183
|
* Register the /api/hostfs routes for the resolved mount roots. The route
|
|
179
184
|
* surface mirrors `MountBackend` 1:1 (webapp `backend-hostfs.ts`):
|
|
@@ -307,6 +307,7 @@ function statIdentity(s) {
|
|
|
307
307
|
return {
|
|
308
308
|
ctime: s.ctimeMs,
|
|
309
309
|
ino: Number(s.ino),
|
|
310
|
+
dev: Number(s.dev),
|
|
310
311
|
uid: s.uid,
|
|
311
312
|
gid: s.gid,
|
|
312
313
|
mode: s.mode,
|
|
@@ -515,7 +516,34 @@ async function mkdirOp(target) {
|
|
|
515
516
|
await mkdir(target, { recursive: true });
|
|
516
517
|
return { ok: true };
|
|
517
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* True when `a` and `b` are the same file (device + inode), not merely
|
|
521
|
+
* similar strings. Path comparison misses the APFS case / NFC-NFD collision.
|
|
522
|
+
*/
|
|
523
|
+
export function sameHostFileIdentity(a, b) {
|
|
524
|
+
return BigInt(a.dev) === BigInt(b.dev) && BigInt(a.ino) === BigInt(b.ino);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* POSIX `rename(2)`: if both operands name the same directory entry (or
|
|
528
|
+
* hard links to the same inode), succeed and do nothing.
|
|
529
|
+
*
|
|
530
|
+
* Node's `fs.rename` on APFS is not that no-op — a case-only or NFD→NFC
|
|
531
|
+
* rename rewrites the catalog name. A copy-then-unlink rename is worse:
|
|
532
|
+
* `open(dest, O_TRUNC)` zeros the only inode, then the subsequent read of
|
|
533
|
+
* source copies 0 bytes, and `readdir` still shows the original name
|
|
534
|
+
* (#3107). Compare identity before calling `rename`.
|
|
535
|
+
*/
|
|
518
536
|
async function renameOp(from, to) {
|
|
537
|
+
try {
|
|
538
|
+
const fromStat = await lstat(from);
|
|
539
|
+
const toStat = await lstat(to);
|
|
540
|
+
if (sameHostFileIdentity(fromStat, toStat))
|
|
541
|
+
return { ok: true, noop: true };
|
|
542
|
+
}
|
|
543
|
+
catch (err) {
|
|
544
|
+
if (errnoCode(err) !== 'ENOENT')
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
519
547
|
await rename(from, to);
|
|
520
548
|
return { ok: true };
|
|
521
549
|
}
|
|
@@ -644,6 +672,10 @@ export function registerHostFsRoutes(app, roots) {
|
|
|
644
672
|
}
|
|
645
673
|
await mkdir(dirname(target), { recursive: true });
|
|
646
674
|
const body = Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0);
|
|
675
|
+
// The body is fully buffered before this open. `createWriteStream`
|
|
676
|
+
// would O_TRUNC dest on open, before any byte arrived — the
|
|
677
|
+
// copy-then-unlink truncation in #3107. writeFile also truncates,
|
|
678
|
+
// but only with the complete payload already in hand.
|
|
647
679
|
// Write-then-rename would break hardlinks and xattrs on user files;
|
|
648
680
|
// plain writeFile matches what local tools do.
|
|
649
681
|
await writeFile(target, body);
|