orizu 0.5.49 → 0.5.50
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/dist/account-directory.d.ts +2 -2
- package/dist/account-directory.d.ts.map +1 -1
- package/dist/account-directory.js +7 -32
- package/dist/auth-commands.d.ts.map +1 -1
- package/dist/auth-commands.js +22 -30
- package/dist/credentials.d.ts +5 -0
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +84 -3
- package/dist/dataset-transfer-upload.d.ts.map +1 -1
- package/dist/dataset-transfer-upload.js +6 -1
- package/dist/directory-list-read.d.ts +37 -0
- package/dist/directory-list-read.d.ts.map +1 -0
- package/dist/directory-list-read.js +87 -0
- package/dist/hosted-boot.d.ts.map +1 -1
- package/dist/hosted-boot.js +59 -41
- package/dist/hosted-harness-opencode.d.ts +31 -0
- package/dist/hosted-harness-opencode.d.ts.map +1 -1
- package/dist/hosted-harness-opencode.js +45 -7
- package/dist/hosted-loop.d.ts +39 -2
- package/dist/hosted-loop.d.ts.map +1 -1
- package/dist/hosted-loop.js +127 -18
- package/dist/hosted-session-seed.d.ts +2 -0
- package/dist/hosted-session-seed.d.ts.map +1 -1
- package/dist/hosted-session-seed.js +27 -10
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +39 -234
- package/dist/keyboard-select.d.ts.map +1 -1
- package/dist/keyboard-select.js +23 -45
- package/dist/project-create-workflow.d.ts +18 -0
- package/dist/project-create-workflow.d.ts.map +1 -0
- package/dist/project-create-workflow.js +121 -0
- package/dist/self-update-command.d.ts +8 -0
- package/dist/self-update-command.d.ts.map +1 -0
- package/dist/self-update-command.js +390 -0
- package/dist/self-update.d.ts +29 -16
- package/dist/self-update.d.ts.map +1 -1
- package/dist/self-update.js +55 -244
- package/dist/setup-account.d.ts.map +1 -1
- package/dist/setup-account.js +4 -1
- package/dist/setup-and-skills-commands.d.ts.map +1 -1
- package/dist/setup-and-skills-commands.js +88 -102
- package/dist/skill-install-workflow.d.ts +23 -0
- package/dist/skill-install-workflow.d.ts.map +1 -0
- package/dist/skill-install-workflow.js +184 -0
- package/dist/skill-installer.d.ts +8 -3
- package/dist/skill-installer.d.ts.map +1 -1
- package/dist/skill-installer.js +26 -33
- package/dist/stored-session-requests.d.ts +27 -0
- package/dist/stored-session-requests.d.ts.map +1 -0
- package/dist/stored-session-requests.js +264 -0
- package/dist/terminal-key-session.d.ts +23 -0
- package/dist/terminal-key-session.d.ts.map +1 -0
- package/dist/terminal-key-session.js +74 -0
- package/package.json +1 -1
- package/src/account-directory.ts +8 -42
- package/src/auth-commands.ts +20 -29
- package/src/credentials.ts +83 -3
- package/src/dataset-transfer-upload.ts +7 -1
- package/src/directory-list-read.ts +123 -0
- package/src/hosted-boot.ts +65 -43
- package/src/hosted-harness-opencode.ts +65 -9
- package/src/hosted-loop.ts +152 -18
- package/src/hosted-session-seed.ts +25 -8
- package/src/http.ts +39 -317
- package/src/keyboard-select.ts +18 -55
- package/src/project-create-workflow.ts +139 -0
- package/src/self-update-command.ts +419 -0
- package/src/self-update.ts +70 -266
- package/src/setup-account.ts +4 -1
- package/src/setup-and-skills-commands.ts +89 -121
- package/src/skill-install-workflow.ts +215 -0
- package/src/skill-installer.ts +31 -38
- package/src/stored-session-requests.ts +316 -0
- package/src/terminal-key-session.ts +88 -0
package/src/self-update.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn
|
|
1
|
+
import { spawn } from 'child_process'
|
|
2
2
|
import {
|
|
3
3
|
closeSync,
|
|
4
4
|
existsSync,
|
|
@@ -13,38 +13,21 @@ import {
|
|
|
13
13
|
} from 'fs'
|
|
14
14
|
import { homedir } from 'os'
|
|
15
15
|
import { basename, dirname, join } from 'path'
|
|
16
|
-
import { stderr as errorOutput, stdout as output } from 'process'
|
|
17
16
|
|
|
18
17
|
import { parseGlobalFlags } from './global-flags.js'
|
|
19
|
-
import { sanitizeTerminalText } from './json-response.js'
|
|
20
18
|
import { findUnknownOption } from './option-validation.js'
|
|
21
19
|
|
|
22
|
-
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000, CHECK_TIMEOUT_MS = 5_000
|
|
20
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000, CHECK_TIMEOUT_MS = 5_000
|
|
23
21
|
// A claim file outliving this window belongs to a process that died mid-claim;
|
|
24
22
|
// treating it as live would silently disable the daily refresh forever.
|
|
25
23
|
const ABANDONED_CLAIM_MS = 60_000
|
|
26
|
-
const
|
|
27
|
-
const MANUAL_INSTALL_COMMAND = 'npm i -g orizu@latest'
|
|
24
|
+
export const MANUAL_INSTALL_COMMAND = 'npm i -g orizu@latest'
|
|
28
25
|
const UPDATE_OPTIONS = new Set(['--dry-run', '--json', '--refresh-cache'])
|
|
29
26
|
const UPDATE_USAGE = 'Usage: orizu update [--dry-run] [--json]'
|
|
30
27
|
|
|
31
28
|
interface UpdateCache { checkedAt: string; latest: string | null }
|
|
32
|
-
interface GlobalInstall { binPath: string; prefix: string }
|
|
33
|
-
interface
|
|
34
|
-
interface Invocation { command: string; args: string[] }
|
|
35
|
-
interface UpdateResult { installed: string; latest: string | null; action: string; prefix: string | null; skills: string }
|
|
36
|
-
|
|
37
|
-
export interface SelfUpdateIo {
|
|
38
|
-
dryRun: boolean; installed: string; json: boolean; refreshCache: boolean
|
|
39
|
-
printLine(message?: string): void; printError(message: string): void
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
interface UpdateCommandIo {
|
|
43
|
-
getCliVersion(): string
|
|
44
|
-
json: boolean
|
|
45
|
-
printLine(message?: string): void
|
|
46
|
-
printError(message: string): void
|
|
47
|
-
}
|
|
29
|
+
export interface GlobalInstall { binPath: string; prefix: string }
|
|
30
|
+
export interface Invocation { command: string; args: string[] }
|
|
48
31
|
|
|
49
32
|
export interface PassiveUpdateState { cache: UpdateCache | null; install: GlobalInstall; installed: string }
|
|
50
33
|
export interface PassiveUpdateIo { exit(code: number): void; spawn: typeof spawn }
|
|
@@ -136,7 +119,7 @@ function writeCache(latest: string | null): void {
|
|
|
136
119
|
renameSync(temporary, path)
|
|
137
120
|
}
|
|
138
121
|
|
|
139
|
-
function tryWriteCache(latest: string | null): void {
|
|
122
|
+
export function tryWriteCache(latest: string | null): void {
|
|
140
123
|
try {
|
|
141
124
|
writeCache(latest)
|
|
142
125
|
} catch {
|
|
@@ -189,7 +172,7 @@ function claimPassiveRefresh(previousCache: UpdateCache | null): boolean {
|
|
|
189
172
|
}
|
|
190
173
|
}
|
|
191
174
|
|
|
192
|
-
function resolveUpdateRegistry(): string {
|
|
175
|
+
export function resolveUpdateRegistry(): string {
|
|
193
176
|
const registry = process.env.ORIZU_UPDATE_REGISTRY ?? 'https://registry.npmjs.org'
|
|
194
177
|
let parsed: URL
|
|
195
178
|
try {
|
|
@@ -203,7 +186,7 @@ function resolveUpdateRegistry(): string {
|
|
|
203
186
|
return registry.replace(/\/+$/u, '')
|
|
204
187
|
}
|
|
205
188
|
|
|
206
|
-
async function resolveLatest(registry = resolveUpdateRegistry()): Promise<string> {
|
|
189
|
+
export async function resolveLatest(registry = resolveUpdateRegistry()): Promise<string> {
|
|
207
190
|
const response = await fetch(`${registry}/orizu/latest`, {
|
|
208
191
|
headers: { accept: 'application/json' },
|
|
209
192
|
signal: AbortSignal.timeout(CHECK_TIMEOUT_MS),
|
|
@@ -215,255 +198,16 @@ async function resolveLatest(registry = resolveUpdateRegistry()): Promise<string
|
|
|
215
198
|
return body.version
|
|
216
199
|
}
|
|
217
200
|
|
|
218
|
-
function npmInvocation(): Invocation {
|
|
201
|
+
export function npmInvocation(): Invocation {
|
|
219
202
|
// Windows is refused in detectNpmGlobalInstall, so only the POSIX layout is reachable here.
|
|
220
203
|
const sibling = join(dirname(process.execPath), 'npm')
|
|
221
204
|
return { command: existsSync(sibling) ? sibling : 'npm', args: [] }
|
|
222
205
|
}
|
|
223
206
|
|
|
224
|
-
function cliInvocation(install: GlobalInstall, args: string[]): Invocation {
|
|
207
|
+
export function cliInvocation(install: GlobalInstall, args: string[]): Invocation {
|
|
225
208
|
return { command: install.binPath, args }
|
|
226
209
|
}
|
|
227
210
|
|
|
228
|
-
function verifyTimeoutMs(): number {
|
|
229
|
-
const override = process.env.ORIZU_UPDATE_TEST_VERIFY_TIMEOUT_MS
|
|
230
|
-
if (override === undefined) return CHILD_TIMEOUT_MS
|
|
231
|
-
const parsed = Number(override)
|
|
232
|
-
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : CHILD_TIMEOUT_MS
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
type SkillsRefreshStatus = 'none' | 'refreshed' | 'already-current'
|
|
236
|
-
|
|
237
|
-
interface SkillsRefreshResult { status: number; timedOut: boolean; skills: SkillsRefreshStatus }
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Refresh managed skills through the given CLI binary and classify the outcome
|
|
241
|
-
* from the child's --json report, never from its human text: an install with
|
|
242
|
-
* no skill targets reports 'none', the one state a caller of `update --json`
|
|
243
|
-
* most needs to see (ADR-001 coupling).
|
|
244
|
-
*/
|
|
245
|
-
async function refreshManagedSkills(command: string, args: string[], io: SelfUpdateIo): Promise<SkillsRefreshResult> {
|
|
246
|
-
const child = await runStreaming(command, [...args, 'skills', 'update', '--json'], io, CHILD_TIMEOUT_MS, undefined, true)
|
|
247
|
-
if (child.status !== 0) return { status: child.status, timedOut: child.timedOut, skills: 'none' }
|
|
248
|
-
let updates: Array<{ path?: unknown; action?: unknown }>
|
|
249
|
-
try {
|
|
250
|
-
const parsed = JSON.parse(child.stdout || '') as { updates?: unknown }
|
|
251
|
-
if (!Array.isArray(parsed.updates)) throw new Error('missing updates')
|
|
252
|
-
updates = parsed.updates as Array<{ path?: unknown; action?: unknown }>
|
|
253
|
-
} catch {
|
|
254
|
-
return { status: 1, timedOut: false, skills: 'none' }
|
|
255
|
-
}
|
|
256
|
-
if (!io.json) {
|
|
257
|
-
if (updates.length === 0) io.printLine('No Orizu skill installs found. Run `orizu install-skill` first.')
|
|
258
|
-
for (const update of updates) {
|
|
259
|
-
const path = sanitizeTerminalText(String(update.path ?? ''))
|
|
260
|
-
if (update.action === 'already-current') io.printLine(`Current ${path}`)
|
|
261
|
-
else if (update.action === 'relinked') io.printLine(`Relinked ${path}`)
|
|
262
|
-
else io.printLine(`Updated ${path}`)
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (updates.length === 0) return { status: 0, timedOut: false, skills: 'none' }
|
|
266
|
-
const refreshed = updates.some(update => update.action !== 'already-current')
|
|
267
|
-
return { status: 0, timedOut: false, skills: refreshed ? 'refreshed' : 'already-current' }
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function runStreaming(
|
|
271
|
-
command: string,
|
|
272
|
-
args: string[],
|
|
273
|
-
io: SelfUpdateIo,
|
|
274
|
-
timeoutMs?: number,
|
|
275
|
-
onStdout?: (text: string) => void,
|
|
276
|
-
captureStdout = false
|
|
277
|
-
): Promise<CommandResult> {
|
|
278
|
-
return new Promise(resolve => {
|
|
279
|
-
let stderr = ''
|
|
280
|
-
let stdout = ''
|
|
281
|
-
let settled = false
|
|
282
|
-
let timedOut = false
|
|
283
|
-
let timer: NodeJS.Timeout | undefined
|
|
284
|
-
const finish = (status: number): void => {
|
|
285
|
-
if (settled) return
|
|
286
|
-
settled = true
|
|
287
|
-
if (timer) clearTimeout(timer)
|
|
288
|
-
resolve({ status, stderr: stderr.slice(-STDERR_TAIL_CHARS), stdout, timedOut })
|
|
289
|
-
}
|
|
290
|
-
const child = spawn(command, args, {
|
|
291
|
-
env: { ...process.env, ORIZU_NO_UPDATE_CHECK: '1' },
|
|
292
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
293
|
-
})
|
|
294
|
-
if (timeoutMs !== undefined) {
|
|
295
|
-
timer = setTimeout(() => {
|
|
296
|
-
timedOut = true
|
|
297
|
-
child.kill('SIGKILL')
|
|
298
|
-
}, timeoutMs)
|
|
299
|
-
}
|
|
300
|
-
child.stdout?.on('data', chunk => {
|
|
301
|
-
const text = sanitizeTerminalText(chunk)
|
|
302
|
-
onStdout?.(text)
|
|
303
|
-
if (captureStdout) {
|
|
304
|
-
stdout = `${stdout}${text}`
|
|
305
|
-
return
|
|
306
|
-
}
|
|
307
|
-
if (io.json) errorOutput.write(text)
|
|
308
|
-
else output.write(text)
|
|
309
|
-
})
|
|
310
|
-
child.stderr?.on('data', chunk => {
|
|
311
|
-
const text = sanitizeTerminalText(chunk)
|
|
312
|
-
stderr = `${stderr}${text}`.slice(-STDERR_TAIL_CHARS)
|
|
313
|
-
errorOutput.write(text)
|
|
314
|
-
})
|
|
315
|
-
child.once('error', error => {
|
|
316
|
-
stderr = `${stderr}${sanitizeTerminalText(error.message)}`
|
|
317
|
-
finish(1)
|
|
318
|
-
})
|
|
319
|
-
child.once('close', code => finish(code ?? 1))
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function emit(io: SelfUpdateIo, result: UpdateResult): void {
|
|
324
|
-
if (io.json) io.printLine(JSON.stringify(result))
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function fail(io: SelfUpdateIo, code: string, detail: string, result: UpdateResult): number {
|
|
328
|
-
io.printError(`${code}: ${detail}`)
|
|
329
|
-
emit(io, result)
|
|
330
|
-
return 1
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
export async function selfUpdateCommand(io: SelfUpdateIo): Promise<number> {
|
|
334
|
-
if (io.refreshCache) {
|
|
335
|
-
const oldCache = readCache()
|
|
336
|
-
try {
|
|
337
|
-
writeCache(await resolveLatest())
|
|
338
|
-
} catch {
|
|
339
|
-
tryWriteCache(oldCache?.latest ?? null)
|
|
340
|
-
}
|
|
341
|
-
return 0
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const install = detectNpmGlobalInstall()
|
|
345
|
-
if (!install) {
|
|
346
|
-
return fail(io, 'update_unsupported_install', `orizu is not installed npm-globally. Run \`${MANUAL_INSTALL_COMMAND}\`.`, {
|
|
347
|
-
installed: io.installed, latest: null, action: 'unsupported', prefix: null, skills: 'not-run',
|
|
348
|
-
})
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
let latest: string
|
|
352
|
-
let registry: string
|
|
353
|
-
try {
|
|
354
|
-
registry = resolveUpdateRegistry()
|
|
355
|
-
latest = await resolveLatest(registry)
|
|
356
|
-
tryWriteCache(latest)
|
|
357
|
-
} catch (error) {
|
|
358
|
-
return fail(io, 'update_check_failed', sanitizeTerminalText(error instanceof Error ? error.message : error), {
|
|
359
|
-
installed: io.installed, latest: null, action: 'check-failed', prefix: install.prefix, skills: 'not-run',
|
|
360
|
-
})
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (compareSemver(io.installed, latest) >= 0) {
|
|
364
|
-
if (!io.json) io.printLine(`orizu ${io.installed} is already the latest.`)
|
|
365
|
-
if (io.dryRun) {
|
|
366
|
-
emit(io, { installed: io.installed, latest, action: 'already-latest', prefix: install.prefix, skills: 'not-run' })
|
|
367
|
-
return 0
|
|
368
|
-
}
|
|
369
|
-
const skills = await refreshManagedSkills(install.binPath, [], io)
|
|
370
|
-
if (skills.status !== 0) {
|
|
371
|
-
const detail = skills.timedOut
|
|
372
|
-
? 'orizu is already the latest, but its managed skills refresh timed out.'
|
|
373
|
-
: 'orizu is already the latest, but its managed skills could not be refreshed.'
|
|
374
|
-
return fail(io, 'update_skills_refresh_failed', detail, {
|
|
375
|
-
installed: io.installed, latest, action: 'already-latest', prefix: install.prefix, skills: 'refresh-failed',
|
|
376
|
-
})
|
|
377
|
-
}
|
|
378
|
-
emit(io, { installed: io.installed, latest, action: 'already-latest', prefix: install.prefix, skills: skills.skills })
|
|
379
|
-
return 0
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (io.dryRun) {
|
|
383
|
-
if (!io.json) io.printLine(`Would update orizu ${io.installed} → ${latest} in ${install.prefix}.`)
|
|
384
|
-
emit(io, { installed: io.installed, latest, action: 'would-update', prefix: install.prefix, skills: 'would-refresh' })
|
|
385
|
-
return 0
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const npmCommand = npmInvocation()
|
|
389
|
-
const registryArgs = process.env.ORIZU_UPDATE_REGISTRY !== undefined
|
|
390
|
-
? ['--registry', registry]
|
|
391
|
-
: []
|
|
392
|
-
const npm = await runStreaming(npmCommand.command, [...npmCommand.args,
|
|
393
|
-
'install', '-g', `orizu@${latest}`, '--prefix', install.prefix, '--no-audit', '--no-fund',
|
|
394
|
-
...registryArgs,
|
|
395
|
-
], io)
|
|
396
|
-
if (npm.status !== 0) {
|
|
397
|
-
const tail = npm.stderr.trim() ? ` npm stderr tail: ${npm.stderr.trim()}` : ''
|
|
398
|
-
return fail(io, 'update_install_failed', `${tail} Run \`${MANUAL_INSTALL_COMMAND}\`.`, {
|
|
399
|
-
installed: io.installed, latest, action: 'install-failed', prefix: install.prefix, skills: 'not-run',
|
|
400
|
-
})
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const verifyCommand = cliInvocation(install, ['--version'])
|
|
404
|
-
const verificationTimeoutMs = verifyTimeoutMs()
|
|
405
|
-
const verified = spawnSync(verifyCommand.command, verifyCommand.args, {
|
|
406
|
-
encoding: 'utf8',
|
|
407
|
-
env: { ...process.env, ORIZU_NO_UPDATE_CHECK: '1' },
|
|
408
|
-
killSignal: 'SIGKILL',
|
|
409
|
-
timeout: verificationTimeoutMs,
|
|
410
|
-
})
|
|
411
|
-
const observed = sanitizeTerminalText(verified.stdout || '').trim()
|
|
412
|
-
if ((verified.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT') {
|
|
413
|
-
return fail(io, 'update_verify_mismatch', `verification timed out after ${verificationTimeoutMs} ms.`, {
|
|
414
|
-
installed: io.installed, latest, action: 'verify-mismatch', prefix: install.prefix, skills: 'not-run',
|
|
415
|
-
})
|
|
416
|
-
}
|
|
417
|
-
if (verified.status !== 0 || observed !== `orizu ${latest}`) {
|
|
418
|
-
const launchError = verified.error ? ` launch error: ${sanitizeTerminalText(verified.error.message)}.` : ''
|
|
419
|
-
const exit = verified.status === null ? `signal ${verified.signal ?? 'unknown'}` : `exit ${verified.status}`
|
|
420
|
-
const errorTail = sanitizeTerminalText(verified.stderr || '').trim().split('\n').slice(-3).join(' ')
|
|
421
|
-
const detail = `expected orizu ${latest}, observed ${observed || '<no version>'} (${exit}).${launchError}${errorTail ? ` ${errorTail}` : ''}`
|
|
422
|
-
return fail(io, 'update_verify_mismatch', `${detail} Run \`${MANUAL_INSTALL_COMMAND}\` to reinstall.`, {
|
|
423
|
-
installed: io.installed, latest, action: 'verify-mismatch', prefix: install.prefix, skills: 'not-run',
|
|
424
|
-
})
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (!io.json) io.printLine(`orizu ${latest} installed.`)
|
|
428
|
-
const skillsCommand = cliInvocation(install, [])
|
|
429
|
-
const skills = await refreshManagedSkills(skillsCommand.command, skillsCommand.args, io)
|
|
430
|
-
if (skills.status !== 0) {
|
|
431
|
-
const detail = skills.timedOut
|
|
432
|
-
? 'the CLI was updated, but its managed skills refresh timed out.'
|
|
433
|
-
: 'the CLI was updated, but its managed skills could not be refreshed.'
|
|
434
|
-
return fail(io, 'update_skills_refresh_failed', detail, {
|
|
435
|
-
installed: io.installed, latest, action: 'updated', prefix: install.prefix, skills: 'refresh-failed',
|
|
436
|
-
})
|
|
437
|
-
}
|
|
438
|
-
emit(io, { installed: io.installed, latest, action: 'updated', prefix: install.prefix, skills: skills.skills })
|
|
439
|
-
return 0
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
export async function runUpdateCommand(rawArgs: string[], io: UpdateCommandIo): Promise<number> {
|
|
443
|
-
const commandIndex = rawArgs.indexOf('update')
|
|
444
|
-
const args = commandIndex === -1
|
|
445
|
-
? rawArgs
|
|
446
|
-
: [...rawArgs.slice(0, commandIndex), ...rawArgs.slice(commandIndex + 1)]
|
|
447
|
-
const unknownOption = findUnknownOption(args, UPDATE_OPTIONS)
|
|
448
|
-
if (unknownOption) {
|
|
449
|
-
io.printError(`unknown option ${unknownOption}\n${UPDATE_USAGE}`)
|
|
450
|
-
return 1
|
|
451
|
-
}
|
|
452
|
-
const positional = args.find(argument => argument === '-' || !argument.startsWith('-'))
|
|
453
|
-
if (positional) {
|
|
454
|
-
io.printError(`unexpected argument ${positional}\n${UPDATE_USAGE}`)
|
|
455
|
-
return 1
|
|
456
|
-
}
|
|
457
|
-
return selfUpdateCommand({
|
|
458
|
-
dryRun: args.includes('--dry-run'),
|
|
459
|
-
installed: io.getCliVersion(),
|
|
460
|
-
json: io.json,
|
|
461
|
-
printLine: io.printLine,
|
|
462
|
-
printError: io.printError,
|
|
463
|
-
refreshCache: args.includes('--refresh-cache'),
|
|
464
|
-
})
|
|
465
|
-
}
|
|
466
|
-
|
|
467
211
|
function isPassiveUpdateDisabled(): boolean {
|
|
468
212
|
return process.env.ORIZU_NO_UPDATE_CHECK !== undefined || process.env.CI !== undefined ||
|
|
469
213
|
process.env.NO_UPDATE_NOTIFIER !== undefined
|
|
@@ -546,3 +290,63 @@ export function finishPassiveUpdate(
|
|
|
546
290
|
// Passive update checks never affect the command that just completed.
|
|
547
291
|
}
|
|
548
292
|
}
|
|
293
|
+
|
|
294
|
+
export interface SelfUpdateIo {
|
|
295
|
+
dryRun: boolean; installed: string; json: boolean
|
|
296
|
+
printLine(message?: string): void; printError(message: string): void
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
interface UpdateCommandIo {
|
|
300
|
+
getCliVersion(): string
|
|
301
|
+
json: boolean
|
|
302
|
+
printLine(message?: string): void
|
|
303
|
+
printError(message: string): void
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* `orizu update`. Checking the arguments, the daily background cache refresh
|
|
308
|
+
* and refusing an install npm doesn't own stay plain code; only an update of
|
|
309
|
+
* an npm-global install loads the Effect workflow (ORI-2424).
|
|
310
|
+
*/
|
|
311
|
+
export async function runUpdateCommand(rawArgs: string[], io: UpdateCommandIo): Promise<number> {
|
|
312
|
+
const commandIndex = rawArgs.indexOf('update')
|
|
313
|
+
const args = commandIndex === -1
|
|
314
|
+
? rawArgs
|
|
315
|
+
: [...rawArgs.slice(0, commandIndex), ...rawArgs.slice(commandIndex + 1)]
|
|
316
|
+
const unknownOption = findUnknownOption(args, UPDATE_OPTIONS)
|
|
317
|
+
if (unknownOption) {
|
|
318
|
+
io.printError(`unknown option ${unknownOption}\n${UPDATE_USAGE}`)
|
|
319
|
+
return 1
|
|
320
|
+
}
|
|
321
|
+
const positional = args.find(argument => argument === '-' || !argument.startsWith('-'))
|
|
322
|
+
if (positional) {
|
|
323
|
+
io.printError(`unexpected argument ${positional}\n${UPDATE_USAGE}`)
|
|
324
|
+
return 1
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (args.includes('--refresh-cache')) {
|
|
328
|
+
const oldCache = readCache()
|
|
329
|
+
try {
|
|
330
|
+
writeCache(await resolveLatest())
|
|
331
|
+
} catch {
|
|
332
|
+
tryWriteCache(oldCache?.latest ?? null)
|
|
333
|
+
}
|
|
334
|
+
return 0
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const installed = io.getCliVersion()
|
|
338
|
+
const install = detectNpmGlobalInstall()
|
|
339
|
+
if (!install) {
|
|
340
|
+
io.printError(`update_unsupported_install: orizu is not installed npm-globally. Run \`${MANUAL_INSTALL_COMMAND}\`.`)
|
|
341
|
+
if (io.json) io.printLine(JSON.stringify({ installed, latest: null, action: 'unsupported', prefix: null, skills: 'not-run' }))
|
|
342
|
+
return 1
|
|
343
|
+
}
|
|
344
|
+
const { runSelfUpdate } = await import('./self-update-command.js')
|
|
345
|
+
return runSelfUpdate({
|
|
346
|
+
dryRun: args.includes('--dry-run'),
|
|
347
|
+
installed,
|
|
348
|
+
json: io.json,
|
|
349
|
+
printLine: io.printLine,
|
|
350
|
+
printError: io.printError,
|
|
351
|
+
}, install)
|
|
352
|
+
}
|
package/src/setup-account.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hasResolvableAuth } from './credentials.js'
|
|
2
|
+
import { datasetTransferTimeoutMs } from './dataset-transfer-policy.js'
|
|
2
3
|
import {
|
|
3
4
|
getBaseUrl,
|
|
4
5
|
type AuthenticatedRequestContext,
|
|
@@ -74,9 +75,11 @@ function isCredentialStoreError(error: unknown): error is Error {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
async function fetchSetupDisplayIdentity(context: AuthenticatedRequestContext): Promise<string> {
|
|
78
|
+
// One limit covers the request and reading its reply.
|
|
79
|
+
const signal = AbortSignal.timeout(datasetTransferTimeoutMs())
|
|
77
80
|
let response: Response
|
|
78
81
|
try {
|
|
79
|
-
response = await context.fetch('/api/cli/auth/whoami')
|
|
82
|
+
response = await context.fetch('/api/cli/auth/whoami', { signal })
|
|
80
83
|
} catch (error) {
|
|
81
84
|
if (isCredentialStoreError(error)) throw error
|
|
82
85
|
throw new Error(`Could not identify the authenticated account. ${identityRecovery(context)}`)
|