dimcode 0.0.67-beta.8 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/bin/dim.mjs +152 -53
  2. package/package.json +7 -8
  3. package/dist/ink.mjs +0 -1291
package/bin/dim.mjs CHANGED
@@ -4,21 +4,32 @@ import fs from 'node:fs'
4
4
  import os from 'node:os'
5
5
  import path from 'node:path'
6
6
  import process from 'node:process'
7
- import { fileURLToPath, pathToFileURL } from 'node:url'
7
+ import { fileURLToPath } from 'node:url'
8
8
 
9
9
  const __filename = fileURLToPath(import.meta.url)
10
10
  const __dirname = path.dirname(__filename)
11
11
  const isWindows = os.platform() === 'win32'
12
12
 
13
13
  let wrapperVersion = ''
14
+ let wrapperName = 'dimcode'
14
15
  try {
15
16
  const pkg = JSON.parse(
16
17
  fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'),
17
18
  )
18
19
  wrapperVersion = pkg.version || ''
20
+ if (pkg.name)
21
+ wrapperName = pkg.name
19
22
  }
20
23
  catch {}
21
24
 
25
+ // Inner binary file name shipped inside each platform sub-package's bin/.
26
+ // dimcode → bin/dimcode(.exe); goatchain-cli → bin/goatchain(.exe).
27
+ const BINARY_BASENAMES = {
28
+ 'dimcode': 'dimcode',
29
+ 'goatchain-cli': 'goatchain',
30
+ }
31
+ const binaryBasename = BINARY_BASENAMES[wrapperName] || wrapperName
32
+
22
33
  const wrapperDir = path.join(__dirname, '..').replace(/\\/g, '/').toLowerCase()
23
34
  const wrapperPm
24
35
  = wrapperDir.includes('.bun/') || wrapperDir.includes('bun/install/')
@@ -26,52 +37,13 @@ const wrapperPm
26
37
  : 'npm'
27
38
 
28
39
  const args = process.argv.slice(2)
29
- const routing = resolveRouting(args)
30
-
31
- if (routing.target === 'opentui') {
32
- runOpentui(routing.forwardArgs)
33
- }
34
- else {
35
- await runInk()
36
- }
37
-
38
- function resolveRouting(argv) {
39
- // Explicit `dim ink ...` forces the Ink TUI fallback.
40
- if (argv[0] === 'ink')
41
- return { target: 'ink', forwardArgs: argv.slice(1) }
42
- // Explicit `dim opentui ...` also routes to the opentui binary
43
- // (kept for symmetry; opentui is the default).
44
- if (argv[0] === 'opentui')
45
- return { target: 'opentui', forwardArgs: argv.slice(1) }
46
-
47
- // Default: everything goes to the opentui binary.
48
- return { target: 'opentui', forwardArgs: argv }
49
- }
40
+ const forwardArgs = args[0] === 'opentui' ? args.slice(1) : args
41
+ runOpentui(forwardArgs).catch((err) => {
42
+ console.error('[dim] Unexpected error: ' + (err && err.stack ? err.stack : err))
43
+ process.exit(1)
44
+ })
50
45
 
51
- async function runInk() {
52
- const inkEntry = path.join(__dirname, '..', 'dist', 'ink.mjs')
53
- if (!fs.existsSync(inkEntry)) {
54
- console.error('[dim] Ink bundle missing: ' + inkEntry)
55
- console.error('[dim] Try reinstalling dimcode@beta.')
56
- process.exit(1)
57
- }
58
- // Inner CLI's DEFAULT_PACKAGE_NAME is already 'dimcode', so no override
59
- // needed. Pass wrapper version through for diagnostics.
60
- process.env.DIMCODE_NPM_PACKAGE = 'dimcode'
61
- process.env.DIMCODE_NPM_PACKAGE_MANAGER = wrapperPm
62
- if (wrapperVersion)
63
- process.env.DIMCODE_NPM_PACKAGE_VERSION = wrapperVersion
64
- try {
65
- await import(pathToFileURL(inkEntry).href)
66
- }
67
- catch (err) {
68
- console.error('[dim] Failed to start Ink TUI:')
69
- console.error(err)
70
- process.exit(1)
71
- }
72
- }
73
-
74
- function runOpentui(restArgs) {
46
+ async function runOpentui(restArgs) {
75
47
  const envPath = process.env.DIMCODE_BIN_PATH
76
48
  if (envPath) {
77
49
  if (!fs.existsSync(envPath)) {
@@ -91,17 +63,22 @@ function runOpentui(restArgs) {
91
63
  const archMap = { x64: 'x64', arm64: 'arm64' }
92
64
  const platform = platformMap[os.platform()] || os.platform()
93
65
  const arch = archMap[os.arch()] || os.arch()
94
- const base = 'dimcode-' + platform + '-' + arch
95
- const binary = platform === 'windows' ? 'dimcode.exe' : 'dimcode'
66
+ const base = wrapperName + '-' + platform + '-' + arch
67
+ const binary = platform === 'windows' ? binaryBasename + '.exe' : binaryBasename
96
68
 
97
69
  if (process.env.DIMCODE_DEBUG) {
98
- console.error('[dim] Wrapper version: ' + wrapperVersion)
70
+ console.error('[dim] Wrapper: ' + wrapperName + '@' + wrapperVersion)
99
71
  console.error('[dim] Platform: ' + platform + ' Arch: ' + arch)
100
72
  console.error('[dim] Looking for package: ' + base)
101
73
  console.error('[dim] Script dir: ' + scriptDir)
102
74
  }
103
75
 
104
- const resolved = findBinary(scriptDir, base, binary)
76
+ let resolved = findBinary(scriptDir, base, binary)
77
+
78
+ if (!resolved) {
79
+ resolved = await ensureCachedBinary(base, binary, wrapperVersion)
80
+ }
81
+
105
82
  if (!resolved) {
106
83
  console.error(
107
84
  '[dim] Could not find the opentui binary for your platform.\n'
@@ -112,7 +89,7 @@ function runOpentui(restArgs) {
112
89
  + ' Searched: ' + scriptDir + ' (and parent directories)\n'
113
90
  + '\n'
114
91
  + 'Try uninstalling and reinstalling the beta channel:\n'
115
- + ' npm uninstall -g dimcode && npm install -g dimcode@beta\n',
92
+ + ' npm uninstall -g ' + wrapperName + ' && npm install -g ' + wrapperName + '@beta\n',
116
93
  )
117
94
  process.exit(1)
118
95
  }
@@ -123,6 +100,128 @@ function runOpentui(restArgs) {
123
100
  spawnBinary(resolved, restArgs)
124
101
  }
125
102
 
103
+ async function ensureCachedBinary(base, binary, version) {
104
+ if (!version) {
105
+ if (process.env.DIMCODE_DEBUG)
106
+ console.error('[dim] No wrapper version available; skipping registry fallback')
107
+ return null
108
+ }
109
+ if (process.env.DIMCODE_NO_DOWNLOAD === '1') {
110
+ if (process.env.DIMCODE_DEBUG)
111
+ console.error('[dim] DIMCODE_NO_DOWNLOAD=1; skipping registry fallback')
112
+ return null
113
+ }
114
+
115
+ const home = os.homedir()
116
+ const cacheDir = path.join(home, '.dimcode', 'binaries', base, version)
117
+ const cachedBin = path.join(cacheDir, 'bin', binary)
118
+ if (fs.existsSync(cachedBin)) {
119
+ if (process.env.DIMCODE_DEBUG)
120
+ console.error('[dim] Using cached binary: ' + cachedBin)
121
+ return cachedBin
122
+ }
123
+
124
+ if (typeof fetch !== 'function') {
125
+ console.error('[dim] Registry fallback requires Node 18+ (global fetch). Please reinstall after upgrading Node.')
126
+ return null
127
+ }
128
+
129
+ const registry = (process.env.DIMCODE_REGISTRY || 'https://registry.npmjs.org').replace(/\/+$/, '')
130
+ const url = registry + '/' + base + '/-/' + base + '-' + version + '.tgz'
131
+
132
+ console.error('[dim] Platform binary missing locally. Fetching ' + base + '@' + version + '...')
133
+ if (process.env.DIMCODE_DEBUG)
134
+ console.error('[dim] URL: ' + url)
135
+
136
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dimcode-dl-'))
137
+ const tgzPath = path.join(tmpDir, 'pkg.tgz')
138
+
139
+ try {
140
+ await downloadFile(url, tgzPath)
141
+ fs.mkdirSync(cacheDir, { recursive: true })
142
+ extractTarball(tgzPath, cacheDir)
143
+ if (!isWindows && fs.existsSync(cachedBin)) {
144
+ try { fs.chmodSync(cachedBin, 0o755) }
145
+ catch {}
146
+ }
147
+ }
148
+ catch (err) {
149
+ console.error('[dim] Failed to fetch platform binary: ' + (err && err.message ? err.message : err))
150
+ console.error('[dim] You can retry, set DIMCODE_BIN_PATH to a local binary, or reinstall with:')
151
+ console.error(' npm uninstall -g ' + wrapperName + ' && npm install -g ' + wrapperName + '@beta')
152
+ return null
153
+ }
154
+ finally {
155
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }) }
156
+ catch {}
157
+ }
158
+
159
+ if (!fs.existsSync(cachedBin)) {
160
+ console.error('[dim] Downloaded archive did not contain expected binary at ' + cachedBin)
161
+ return null
162
+ }
163
+
164
+ console.error('[dim] Cached at ' + cachedBin)
165
+ return cachedBin
166
+ }
167
+
168
+ async function downloadFile(url, dest) {
169
+ let currentUrl = url
170
+ for (let hop = 0; hop < 5; hop++) {
171
+ const res = await fetch(currentUrl, { redirect: 'manual' })
172
+ if (res.status >= 300 && res.status < 400 && res.headers.get('location')) {
173
+ currentUrl = new URL(res.headers.get('location'), currentUrl).toString()
174
+ continue
175
+ }
176
+ if (!res.ok)
177
+ throw new Error('HTTP ' + res.status + ' ' + res.statusText + ' for ' + currentUrl)
178
+
179
+ const total = Number(res.headers.get('content-length') || 0)
180
+ const out = fs.createWriteStream(dest)
181
+ let downloaded = 0
182
+ let lastShown = -1
183
+ const reader = res.body.getReader()
184
+ for (;;) {
185
+ const { done, value } = await reader.read()
186
+ if (done) break
187
+ out.write(Buffer.from(value))
188
+ downloaded += value.length
189
+ if (total && process.stderr.isTTY) {
190
+ const pct = Math.floor((downloaded / total) * 100)
191
+ if (pct !== lastShown && pct % 5 === 0) {
192
+ process.stderr.write('\r[dim] Downloading... ' + pct + '%')
193
+ lastShown = pct
194
+ }
195
+ }
196
+ }
197
+ out.end()
198
+ await new Promise((resolve, reject) => {
199
+ out.on('close', resolve)
200
+ out.on('error', reject)
201
+ })
202
+ if (process.stderr.isTTY)
203
+ process.stderr.write('\r[dim] Downloaded ' + (downloaded / 1024 / 1024).toFixed(1) + ' MB \n')
204
+ else
205
+ console.error('[dim] Downloaded ' + (downloaded / 1024 / 1024).toFixed(1) + ' MB')
206
+ return
207
+ }
208
+ throw new Error('Too many redirects')
209
+ }
210
+
211
+ function extractTarball(tgzPath, destDir) {
212
+ const result = childProcess.spawnSync(
213
+ 'tar',
214
+ ['-xzf', tgzPath, '-C', destDir, '--strip-components=1'],
215
+ { stdio: process.env.DIMCODE_DEBUG ? 'inherit' : 'pipe' },
216
+ )
217
+ if (result.error)
218
+ throw new Error('tar not available: ' + result.error.message)
219
+ if (result.status !== 0) {
220
+ const stderr = result.stderr ? result.stderr.toString() : ''
221
+ throw new Error('tar exited with status ' + result.status + (stderr ? ': ' + stderr.trim() : ''))
222
+ }
223
+ }
224
+
126
225
  function findBinary(startDir, base, binary) {
127
226
  let current = startDir
128
227
  for (;;) {
@@ -142,7 +241,7 @@ function findBinary(startDir, base, binary) {
142
241
  function spawnBinary(target, forwardedArgs) {
143
242
  const env = {
144
243
  ...process.env,
145
- DIMCODE_NPM_PACKAGE: 'dimcode',
244
+ DIMCODE_NPM_PACKAGE: wrapperName,
146
245
  DIMCODE_NPM_PACKAGE_MANAGER: wrapperPm,
147
246
  DIMCODE_NPM_PACKAGE_ROOT: path.resolve(__dirname, '..'),
148
247
  }
@@ -166,7 +265,7 @@ function spawnBinary(target, forwardedArgs) {
166
265
  '[dim] The binary file was not found. Try reinstalling:',
167
266
  )
168
267
  console.error(
169
- ' npm uninstall -g dimcode && npm install -g dimcode@beta',
268
+ ' npm uninstall -g ' + wrapperName + ' && npm install -g ' + wrapperName + '@beta',
170
269
  )
171
270
  }
172
271
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dimcode",
3
- "version": "0.0.67-beta.8",
3
+ "version": "0.0.67",
4
4
  "description": "AI coding agent CLI and terminal coding assistant with an interactive TUI (beta channel)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,14 +8,13 @@
8
8
  "dimcode": "./bin/dim.mjs"
9
9
  },
10
10
  "files": [
11
- "bin",
12
- "dist"
11
+ "bin"
13
12
  ],
14
13
  "optionalDependencies": {
15
- "dimcode-darwin-arm64": "0.0.67-beta.8",
16
- "dimcode-darwin-x64": "0.0.67-beta.8",
17
- "dimcode-linux-arm64": "0.0.67-beta.8",
18
- "dimcode-linux-x64": "0.0.67-beta.8",
19
- "dimcode-windows-x64": "0.0.67-beta.8"
14
+ "dimcode-darwin-arm64": "0.0.67",
15
+ "dimcode-darwin-x64": "0.0.67",
16
+ "dimcode-linux-arm64": "0.0.67",
17
+ "dimcode-linux-x64": "0.0.67",
18
+ "dimcode-windows-x64": "0.0.67"
20
19
  }
21
20
  }