ttsc 0.14.0-dev.20260528.1 → 0.14.0-dev.20260529.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,17 +2,11 @@
2
2
 
3
3
  ![banner of ttsc](https://ttsc.dev/og.jpg)
4
4
 
5
- [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/samchon/ttsc/blob/master/LICENSE)
6
- [![NPM Version](https://img.shields.io/npm/v/ttsc.svg)](https://www.npmjs.com/package/ttsc)
7
- [![NPM Downloads](https://img.shields.io/npm/dm/ttsc.svg)](https://www.npmjs.com/package/ttsc)
8
- [![Build Status](https://github.com/samchon/ttsc/workflows/test/badge.svg)](https://github.com/samchon/ttsc/actions?query=workflow%3Atest)
9
- [![Guide Documents](https://img.shields.io/badge/Guide-Documents-forestgreen)](https://ttsc.dev/docs)
10
- [![Discord Badge](https://img.shields.io/badge/discord-samchon-d91965?style=flat&labelColor=5866f2&logo=discord&logoColor=white&link=https://discord.gg/E94XhzrUCZ)](https://discord.gg/E94XhzrUCZ)
5
+ [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/samchon/ttsc/blob/master/LICENSE) [![NPM Version](https://img.shields.io/npm/v/ttsc.svg)](https://www.npmjs.com/package/ttsc) [![NPM Downloads](https://img.shields.io/npm/dm/ttsc.svg)](https://www.npmjs.com/package/ttsc) [![Build Status](https://github.com/samchon/ttsc/workflows/test/badge.svg)](https://github.com/samchon/ttsc/actions?query=workflow%3Atest) [![Guide Documents](https://img.shields.io/badge/Guide-Documents-forestgreen)](https://ttsc.dev/docs) [![Discord Badge](https://img.shields.io/badge/discord-samchon-d91965?style=flat&labelColor=5866f2&logo=discord&logoColor=white&link=https://discord.gg/E94XhzrUCZ)](https://discord.gg/E94XhzrUCZ)
11
6
 
12
7
  A `typescript-go` toolchain for compiler-powered plugins and type-safe execution.
13
8
 
14
- Benchmarked on the VS Code fixture: up to **10x** faster type checks and a
15
- **500x** faster measured lint pass.
9
+ Benchmarked on the VS Code fixture: up to **10x** faster type checks and a **500x** faster measured lint pass.
16
10
 
17
11
  - **`ttsc`**: build, check, and transform.
18
12
  - **`ttsx`**: execute TypeScript with type checking.
@@ -55,14 +49,23 @@ Rewrite source files in place with the `@ttsc/lint` format rules:
55
49
  npx ttsc format
56
50
  ```
57
51
 
58
- ### Editor
52
+ ### VSCode Extension
59
53
 
60
- Install the VS Code extension for live TypeScript-Go editor features plus
61
- saved-state ttsc plugin diagnostics and actions:
54
+ Install the VS Code extension for live TypeScript-Go editor features plus saved-state ttsc plugin diagnostics and actions:
62
55
 
63
56
  ```bash
57
+ npm install -D ttsc @ttsc/lint @typescript/native-preview
64
58
  npm install -D @ttsc/vscode
65
- npx ttsc-vscode
59
+ npx @ttsc/vscode
60
+ ```
61
+
62
+ Then turn on format-on-save in `.vscode/settings.json`:
63
+
64
+ ```jsonc
65
+ "[typescript][typescriptreact]": {
66
+ "editor.defaultFormatter": "samchon.ttsc",
67
+ "editor.formatOnSave": true
68
+ }
66
69
  ```
67
70
 
68
71
  See [`@ttsc/vscode`](https://github.com/samchon/ttsc/tree/master/packages/vscode) for requirements, settings, and uninstall.
@@ -191,11 +194,7 @@ if (result.type === "success") {
191
194
  }
192
195
  ```
193
196
 
194
- See the [Programmatic API guide](https://ttsc.dev/docs/ttsc/api) for the full
195
- lifecycle, plugin overrides, and patterns. For browser embedding, see
196
- [`@ttsc/wasm`](https://github.com/samchon/ttsc/tree/master/packages/wasm) and
197
- the higher-level [`@ttsc/playground`](https://github.com/samchon/ttsc/tree/master/packages/playground)
198
- package.
197
+ See the [Programmatic API guide](https://ttsc.dev/docs/ttsc/api) for the full lifecycle, plugin overrides, and patterns. For browser embedding, see [`@ttsc/wasm`](https://github.com/samchon/ttsc/tree/master/packages/wasm) and the higher-level [`@ttsc/playground`](https://github.com/samchon/ttsc/tree/master/packages/playground) package.
199
198
 
200
199
  ### List of Plugins
201
200
 
@@ -191,6 +191,19 @@ func (s *NativePluginSource) CodeActions(uri string, rng LSPRange, ctx LSPCodeAc
191
191
  // ExecuteCommand routes a ttsc-owned workspace command to the sidecar that
192
192
  // advertised it through lsp-command-ids.
193
193
  func (s *NativePluginSource) ExecuteCommand(command string, args []json.RawMessage) (*LSPWorkspaceEdit, error) {
194
+ return s.ExecuteCommandWithContent(command, args, "", false)
195
+ }
196
+
197
+ // ExecuteCommandWithContent runs a ttsc-owned workspace command like
198
+ // ExecuteCommand, but when hasContent is true it asks the sidecar to format the
199
+ // supplied buffer text instead of the on-disk file. The buffer is passed by
200
+ // adding the --content-stdin flag and piping content to the sidecar's stdin, so
201
+ // the proxy can format dirty editor buffers (formatOnSave) without first writing
202
+ // them to disk. hasContent — not content != "" — gates the in-memory path: an
203
+ // empty buffer the user cleared is a valid document state and must still format
204
+ // in-memory (to a no-op) rather than falling through to stale disk content.
205
+ // Decoding of the returned WorkspaceEdit is identical to ExecuteCommand.
206
+ func (s *NativePluginSource) ExecuteCommandWithContent(command string, args []json.RawMessage, content string, hasContent bool) (*LSPWorkspaceEdit, error) {
194
207
  if s == nil {
195
208
  return nil, ErrCommandNotHandled
196
209
  }
@@ -199,12 +212,16 @@ func (s *NativePluginSource) ExecuteCommand(command string, args []json.RawMessa
199
212
  return nil, ErrCommandNotHandled
200
213
  }
201
214
  argsJSON, _ := json.Marshal(args)
202
- body, err := s.run(
203
- plugin,
204
- "lsp-execute-command",
205
- "--command="+command,
206
- "--arguments-json="+string(argsJSON),
207
- )
215
+ cmdArgs := []string{
216
+ "--command=" + command,
217
+ "--arguments-json=" + string(argsJSON),
218
+ }
219
+ var stdin io.Reader
220
+ if hasContent {
221
+ cmdArgs = append(cmdArgs, "--content-stdin")
222
+ stdin = strings.NewReader(content)
223
+ }
224
+ body, err := s.runWithStdin(plugin, "lsp-execute-command", stdin, cmdArgs...)
208
225
  if err != nil {
209
226
  return nil, err
210
227
  }
@@ -317,6 +334,14 @@ func (s *NativePluginSource) pluginOwnsCommand(plugin NativeLSPPluginEntry, comm
317
334
  }
318
335
 
319
336
  func (s *NativePluginSource) run(plugin NativeLSPPluginEntry, command string, args ...string) ([]byte, error) {
337
+ return s.runWithStdin(plugin, command, nil, args...)
338
+ }
339
+
340
+ // runWithStdin runs a sidecar subcommand like run, additionally wiring stdin to
341
+ // the supplied reader when it is non-nil. Callers that do not pass buffer text
342
+ // (Diagnostics, CodeActions, discovery) reach this through run with a nil
343
+ // reader, leaving the sidecar's stdin unset exactly as before.
344
+ func (s *NativePluginSource) runWithStdin(plugin NativeLSPPluginEntry, command string, stdin io.Reader, args ...string) ([]byte, error) {
320
345
  if strings.TrimSpace(plugin.Binary) == "" {
321
346
  return nil, fmt.Errorf("ttscserver: %s has no binary", pluginLabel(plugin))
322
347
  }
@@ -332,6 +357,9 @@ func (s *NativePluginSource) run(plugin NativeLSPPluginEntry, command string, ar
332
357
  cmd := exec.CommandContext(ctx, plugin.Binary, allArgs...)
333
358
  cmd.Dir = s.cwd
334
359
  cmd.Env = os.Environ()
360
+ if stdin != nil {
361
+ cmd.Stdin = stdin
362
+ }
335
363
  stdout := limitedBuffer{limit: nativePluginCommandStdoutLimit}
336
364
  stderr := limitedBuffer{limit: nativePluginCommandStderrLimit}
337
365
  cmd.Stdout = &stdout
@@ -31,8 +31,15 @@ const (
31
31
  methodCodeAction = "textDocument/codeAction"
32
32
  methodExecuteCommand = "workspace/executeCommand"
33
33
  methodCancelRequest = "$/cancelRequest"
34
+ methodFormatting = "textDocument/formatting"
34
35
  )
35
36
 
37
+ // formatDocumentCommand is the ttsc-owned workspace command that the lint
38
+ // sidecar advertises for whole-document formatting. The textDocument/formatting
39
+ // handler routes the cached editor buffer through this command so formatOnSave
40
+ // formats the live (possibly dirty) buffer rather than the on-disk file.
41
+ const formatDocumentCommand = "ttsc.format.document"
42
+
36
43
  // ProxyOptions wires the byte-level proxy together. ttscserver creates
37
44
  // the upstream pipes around `tsgo --lsp --stdio` and hands the proxy
38
45
  // editor stdio plus those pipe ends.
@@ -88,6 +95,15 @@ type Proxy struct {
88
95
  documentGeneration map[string]uint64
89
96
  dirtyDocuments map[string]struct{}
90
97
  dirtyVersions map[string]*int
98
+ // documentText caches the live editor buffer per uri so the
99
+ // textDocument/formatting handler can format the in-memory text instead
100
+ // of the on-disk file. Entries are present only while the proxy holds a
101
+ // trustworthy full-document copy: didOpen / full-sync didChange populate
102
+ // it, incremental didChange (a contentChange carrying a range) and
103
+ // didClose evict it, and the formatting handler falls back to a disk read
104
+ // when no entry is cached. Guarded by diagnosticsMu like the other
105
+ // per-uri document state.
106
+ documentText map[string]string
91
107
  }
92
108
 
93
109
  type pendingCodeActionRequest struct {
@@ -137,6 +153,7 @@ func NewProxy(opts ProxyOptions) *Proxy {
137
153
  documentGeneration: make(map[string]uint64),
138
154
  dirtyDocuments: make(map[string]struct{}),
139
155
  dirtyVersions: make(map[string]*int),
156
+ documentText: make(map[string]string),
140
157
  }
141
158
  }
142
159
 
@@ -232,6 +249,7 @@ func (p *Proxy) handleEditorEnvelope(env Envelope, body []byte) (bool, error) {
232
249
  }
233
250
  case methodDidOpen:
234
251
  if env.IsNotification() {
252
+ p.cacheDidOpenText(env)
235
253
  if err := p.publishPluginDiagnosticsForDidOpen(env); err != nil {
236
254
  return false, err
237
255
  }
@@ -242,18 +260,24 @@ func (p *Proxy) handleEditorEnvelope(env Envelope, body []byte) (bool, error) {
242
260
  }
243
261
  case methodDidChange:
244
262
  if env.IsNotification() {
263
+ p.cacheDidChangeText(env)
245
264
  if err := p.markDocumentDirty(env); err != nil {
246
265
  return false, err
247
266
  }
248
267
  }
249
268
  case methodDidClose:
250
269
  if env.IsNotification() {
270
+ p.evictDocumentText(env)
251
271
  p.clearDocumentDiagnostics(env)
252
272
  }
253
273
  case methodExecuteCommand:
254
274
  if env.IsRequest() {
255
275
  return p.tryExecuteCommand(env)
256
276
  }
277
+ case methodFormatting:
278
+ if env.IsRequest() {
279
+ return p.handleFormattingRequest(env)
280
+ }
257
281
  case methodCodeAction:
258
282
  if env.IsRequest() {
259
283
  return p.handleCodeActionRequest(env)
@@ -433,7 +457,7 @@ func (p *Proxy) pluginOnlyCodeActionKinds() map[string]struct{} {
433
457
  kinds := map[string]struct{}{
434
458
  "source.fixAll.ttsc": {},
435
459
  }
436
- if p.ownsCommand("ttsc.format.document") {
460
+ if p.ownsCommand(formatDocumentCommand) {
437
461
  kinds["source.format"] = struct{}{}
438
462
  }
439
463
  return kinds
@@ -493,6 +517,102 @@ func (p *Proxy) completeExecuteCommand(env Envelope, key string, command string,
493
517
  p.reportAsyncError(p.writeExecuteCommandResultIfClean(env.ID, pending, edit))
494
518
  }
495
519
 
520
+ // contentExecutor is the optional capability a PluginSource exposes to format an
521
+ // in-memory buffer instead of the on-disk file. NativePluginSource implements it
522
+ // by piping the buffer to the sidecar's stdin with --content-stdin; sources that
523
+ // do not implement it fall back to plain ExecuteCommand (disk).
524
+ type contentExecutor interface {
525
+ ExecuteCommandWithContent(command string, args []json.RawMessage, content string, hasContent bool) (*LSPWorkspaceEdit, error)
526
+ }
527
+
528
+ // handleFormattingRequest answers textDocument/formatting for the ttsc-owned
529
+ // document formatter. Unlike the workspace/executeCommand path, this handler
530
+ // intentionally formats the live (possibly dirty) editor buffer: it reads the
531
+ // cached buffer text and passes it to the sidecar so formatOnSave works before
532
+ // the file is written to disk. It therefore does NOT go through the
533
+ // dirty-document guard that writeExecuteCommandResultIfClean applies to the
534
+ // executeCommand path.
535
+ //
536
+ // When ttsc does not own ttsc.format.document the request is forwarded to
537
+ // upstream tsgo (return false). The handler never surfaces an error to the
538
+ // editor: on any failure it replies with an empty TextEdit array so a failed
539
+ // formatter cannot break the save.
540
+ func (p *Proxy) handleFormattingRequest(env Envelope) (bool, error) {
541
+ if !p.ownsCommand(formatDocumentCommand) {
542
+ return false, nil
543
+ }
544
+ var params struct {
545
+ TextDocument struct {
546
+ URI string `json:"uri"`
547
+ } `json:"textDocument"`
548
+ }
549
+ if err := json.Unmarshal(env.Params, &params); err != nil || params.TextDocument.URI == "" {
550
+ return false, nil
551
+ }
552
+ uri := params.TextDocument.URI
553
+ go p.completeFormattingRequest(env, uri)
554
+ return true, nil
555
+ }
556
+
557
+ func (p *Proxy) completeFormattingRequest(env Envelope, uri string) {
558
+ // hasContent distinguishes "the proxy has a buffer to format in-memory" from
559
+ // "no buffer; let the sidecar read disk". An empty cached buffer is a valid
560
+ // document state (the user cleared the file), so the empty string must NOT be
561
+ // overloaded as the no-buffer sentinel: a cache hit always yields
562
+ // hasContent=true even when the buffer is "".
563
+ content, hasContent := p.cachedDocumentText(uri)
564
+ if !hasContent {
565
+ if file, fileOK := filePathFromURI(uri); fileOK {
566
+ if disk, err := os.ReadFile(file); err == nil {
567
+ // Preserve the existing disk-fallback behavior: pipe the disk bytes
568
+ // via stdin so the sidecar formats exactly what the proxy read.
569
+ content = string(disk)
570
+ hasContent = true
571
+ }
572
+ }
573
+ }
574
+ // A formatter failure must never break the editor's save: reply with an
575
+ // empty TextEdit[] regardless of the error. The NativePluginSource already
576
+ // logs the underlying sidecar failure to its own stderr writer, so the proxy
577
+ // does not need a separate log sink here.
578
+ edit, err := p.executeFormatCommand(uri, content, hasContent)
579
+ if err != nil {
580
+ p.reportAsyncError(p.writeResult(env.ID, []LSPTextEdit{}))
581
+ return
582
+ }
583
+ edits := formattingTextEdits(edit, uri)
584
+ p.reportAsyncError(p.writeResult(env.ID, edits))
585
+ }
586
+
587
+ // executeFormatCommand runs ttsc.format.document against the supplied buffer
588
+ // text. The single command argument is the document uri, matching the
589
+ // executeCommand path the sidecar already implements; --content-stdin makes the
590
+ // sidecar format the piped text instead of the disk file when the source
591
+ // supports it.
592
+ func (p *Proxy) executeFormatCommand(uri string, content string, hasContent bool) (*LSPWorkspaceEdit, error) {
593
+ arg, _ := json.Marshal(uri)
594
+ args := []json.RawMessage{arg}
595
+ if executor, ok := p.source.(contentExecutor); ok {
596
+ return executor.ExecuteCommandWithContent(formatDocumentCommand, args, content, hasContent)
597
+ }
598
+ return p.source.ExecuteCommand(formatDocumentCommand, args)
599
+ }
600
+
601
+ // formattingTextEdits projects a WorkspaceEdit returned by the formatter onto
602
+ // the LSP textDocument/formatting response shape: the array of TextEdits that
603
+ // target uri. A nil edit or a no-op (no changes for uri) yields an empty,
604
+ // non-nil slice so the editor always receives a valid TextEdit[].
605
+ func formattingTextEdits(edit *LSPWorkspaceEdit, uri string) []LSPTextEdit {
606
+ if edit == nil {
607
+ return []LSPTextEdit{}
608
+ }
609
+ edits, ok := edit.Changes[uri]
610
+ if !ok || edits == nil {
611
+ return []LSPTextEdit{}
612
+ }
613
+ return edits
614
+ }
615
+
496
616
  // ownsCommand reports whether command is registered with the PluginSource
497
617
  // and should be handled locally rather than forwarded to upstream tsgo.
498
618
  func (p *Proxy) ownsCommand(command string) bool {
@@ -928,6 +1048,89 @@ func (p *Proxy) clearDocumentDiagnostics(env Envelope) {
928
1048
  p.documentGeneration[params.TextDocument.URI]++
929
1049
  }
930
1050
 
1051
+ // cacheDidOpenText stores the buffer text the editor opened so the
1052
+ // formatting handler can format the live document. didOpen always carries the
1053
+ // full text, so the cache is unconditionally trustworthy here.
1054
+ func (p *Proxy) cacheDidOpenText(env Envelope) {
1055
+ var params struct {
1056
+ TextDocument struct {
1057
+ URI string `json:"uri"`
1058
+ Text string `json:"text"`
1059
+ } `json:"textDocument"`
1060
+ }
1061
+ if err := json.Unmarshal(env.Params, &params); err != nil || params.TextDocument.URI == "" {
1062
+ return
1063
+ }
1064
+ p.diagnosticsMu.Lock()
1065
+ defer p.diagnosticsMu.Unlock()
1066
+ p.documentText[params.TextDocument.URI] = params.TextDocument.Text
1067
+ }
1068
+
1069
+ // cacheDidChangeText refreshes the buffer cache from a didChange notification.
1070
+ // LSP delivers contentChanges either as full-document replacements (no range)
1071
+ // or incremental range edits (a range present). The proxy does not control the
1072
+ // advertised textDocumentSync kind — tsgo owns the initialize response and ttsc
1073
+ // only augments code-action/executeCommand capabilities — so a client may send
1074
+ // either shape. The cache is only trustworthy when every change is a full
1075
+ // replacement; on an incremental change the proxy evicts the entry so the
1076
+ // formatting handler falls back to reading disk rather than formatting stale
1077
+ // text.
1078
+ func (p *Proxy) cacheDidChangeText(env Envelope) {
1079
+ var params struct {
1080
+ TextDocument struct {
1081
+ URI string `json:"uri"`
1082
+ } `json:"textDocument"`
1083
+ ContentChanges []struct {
1084
+ Range *json.RawMessage `json:"range"`
1085
+ Text string `json:"text"`
1086
+ } `json:"contentChanges"`
1087
+ }
1088
+ if err := json.Unmarshal(env.Params, &params); err != nil || params.TextDocument.URI == "" {
1089
+ return
1090
+ }
1091
+ if len(params.ContentChanges) == 0 {
1092
+ return
1093
+ }
1094
+ fullText := ""
1095
+ for _, change := range params.ContentChanges {
1096
+ if change.Range != nil {
1097
+ p.diagnosticsMu.Lock()
1098
+ delete(p.documentText, params.TextDocument.URI)
1099
+ p.diagnosticsMu.Unlock()
1100
+ return
1101
+ }
1102
+ fullText = change.Text
1103
+ }
1104
+ p.diagnosticsMu.Lock()
1105
+ defer p.diagnosticsMu.Unlock()
1106
+ p.documentText[params.TextDocument.URI] = fullText
1107
+ }
1108
+
1109
+ // evictDocumentText drops the cached buffer for a closed document so a later
1110
+ // reopen does not format against the previous session's text.
1111
+ func (p *Proxy) evictDocumentText(env Envelope) {
1112
+ var params struct {
1113
+ TextDocument struct {
1114
+ URI string `json:"uri"`
1115
+ } `json:"textDocument"`
1116
+ }
1117
+ if err := json.Unmarshal(env.Params, &params); err != nil || params.TextDocument.URI == "" {
1118
+ return
1119
+ }
1120
+ p.diagnosticsMu.Lock()
1121
+ defer p.diagnosticsMu.Unlock()
1122
+ delete(p.documentText, params.TextDocument.URI)
1123
+ }
1124
+
1125
+ // cachedDocumentText returns the cached buffer text for uri and whether an
1126
+ // entry was present.
1127
+ func (p *Proxy) cachedDocumentText(uri string) (string, bool) {
1128
+ p.diagnosticsMu.Lock()
1129
+ defer p.diagnosticsMu.Unlock()
1130
+ text, ok := p.documentText[uri]
1131
+ return text, ok
1132
+ }
1133
+
931
1134
  func (p *Proxy) markDocumentDirty(env Envelope) error {
932
1135
  var params struct {
933
1136
  TextDocument struct {
@@ -1176,6 +1379,17 @@ func (p *Proxy) augmentInitializeResult(env Envelope) ([]byte, bool) {
1176
1379
  caps["executeCommandProvider"] = provider
1177
1380
  changed = true
1178
1381
  }
1382
+ // Advertise documentFormattingProvider when ttsc owns the document
1383
+ // formatter so editors send textDocument/formatting (formatOnSave). The
1384
+ // proxy intercepts that method and formats the live buffer, so it forces
1385
+ // the capability on even if upstream tsgo already advertised one — tsgo's
1386
+ // formatter would otherwise format the on-disk file and lose unsaved edits.
1387
+ if p.ownsCommand(formatDocumentCommand) {
1388
+ if existing, ok := caps["documentFormattingProvider"].(bool); !ok || !existing {
1389
+ caps["documentFormattingProvider"] = true
1390
+ changed = true
1391
+ }
1392
+ }
1179
1393
  if !changed {
1180
1394
  return nil, false
1181
1395
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ttsc",
3
- "version": "0.14.0-dev.20260528.1",
3
+ "version": "0.14.0-dev.20260529.2",
4
4
  "description": "General-purpose TypeScript-Go compiler, runtime, plugin host, and LSP host.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -32,13 +32,13 @@
32
32
  "rimraf": "^6.1.2"
33
33
  },
34
34
  "optionalDependencies": {
35
- "@ttsc/linux-x64": "0.14.0-dev.20260528.1",
36
- "@ttsc/linux-arm": "0.14.0-dev.20260528.1",
37
- "@ttsc/linux-arm64": "0.14.0-dev.20260528.1",
38
- "@ttsc/darwin-x64": "0.14.0-dev.20260528.1",
39
- "@ttsc/darwin-arm64": "0.14.0-dev.20260528.1",
40
- "@ttsc/win32-x64": "0.14.0-dev.20260528.1",
41
- "@ttsc/win32-arm64": "0.14.0-dev.20260528.1"
35
+ "@ttsc/linux-x64": "0.14.0-dev.20260529.2",
36
+ "@ttsc/linux-arm": "0.14.0-dev.20260529.2",
37
+ "@ttsc/linux-arm64": "0.14.0-dev.20260529.2",
38
+ "@ttsc/darwin-x64": "0.14.0-dev.20260529.2",
39
+ "@ttsc/darwin-arm64": "0.14.0-dev.20260529.2",
40
+ "@ttsc/win32-x64": "0.14.0-dev.20260529.2",
41
+ "@ttsc/win32-arm64": "0.14.0-dev.20260529.2"
42
42
  },
43
43
  "sideEffects": false,
44
44
  "files": [