autark-cli 0.7.1 → 0.7.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/autark.mjs +70 -25
- package/package.json +1 -1
package/autark.mjs
CHANGED
|
@@ -23,6 +23,19 @@ const CREDS_PATH = process.env.AUTARK_CREDENTIALS || path.join(AUTARK_HOME, 'cre
|
|
|
23
23
|
// main().catch() call below.
|
|
24
24
|
const RAW_RUNTIME_BASE = process.env.AUTARK_RUNTIME_RAW_BASE
|
|
25
25
|
|| 'https://autark.sh/runtime'
|
|
26
|
+
// ----------------------------------------------------------- update styling
|
|
27
|
+
// The autark vibe: calm, aligned, lowercase. Color only when a human is
|
|
28
|
+
// looking (TTY, no NO_COLOR); agents piping output get plain text.
|
|
29
|
+
const TTY = process.stdout.isTTY && !process.env.NO_COLOR
|
|
30
|
+
const paint = (code) => (s) => (TTY ? `\x1b[${code}m${s}\x1b[0m` : String(s))
|
|
31
|
+
const dim = paint('2')
|
|
32
|
+
const green = paint('32')
|
|
33
|
+
const gold = paint('33')
|
|
34
|
+
const red = paint('31')
|
|
35
|
+
const bold = paint('1')
|
|
36
|
+
const shortVer = (v) => (typeof v === 'string' && /^[0-9a-f-]{36}$/.test(v) ? v.slice(0, 8) : v)
|
|
37
|
+
const pad = (s, n) => String(s).padEnd(n)
|
|
38
|
+
|
|
26
39
|
const SKILL_NAMES = ['autark', 'plumcake', 'chrome-relay', 'email', 'outreach', 'email-finder']
|
|
27
40
|
const SKILL_AGENTS = ['claude-code', 'codex', 'pi', 'opencode']
|
|
28
41
|
const ECOSYSTEM_CLIS = ['autark-cli', 'plumcake-cli', 'chrome-relay']
|
|
@@ -361,26 +374,28 @@ async function update(rest) {
|
|
|
361
374
|
const log = (msg) => console.log(msg)
|
|
362
375
|
const sub = (msg) => console.log(` ${msg}`)
|
|
363
376
|
|
|
364
|
-
log('
|
|
377
|
+
log('')
|
|
378
|
+
log(` ${bold('autark')} ${dim('· update')}`)
|
|
379
|
+
log('')
|
|
365
380
|
|
|
366
381
|
// ---- Step 0: self-update CLI ecosystem ---------------------------------
|
|
367
382
|
if (!skipSelfUpdate) {
|
|
368
|
-
log('checking CLI ecosystem versions…')
|
|
369
383
|
const upgrades = []
|
|
370
384
|
for (const pkg of ECOSYSTEM_CLIS) {
|
|
371
385
|
const installed = readInstalledVersion(pkg)
|
|
372
386
|
const latest = await fetchNpmLatest(pkg)
|
|
373
|
-
if (!latest) { sub(
|
|
387
|
+
if (!latest) { sub(`${pad(pkg, 14)} ${gold('!')} npm unreachable, skipping`); continue }
|
|
374
388
|
if (!installed || cmpVersions(installed, latest) < 0) {
|
|
375
389
|
upgrades.push({ pkg, installed, latest })
|
|
376
|
-
sub(`${pkg}
|
|
390
|
+
sub(`${pad(pkg, 14)} ${installed || dim('(not installed)')} ${gold('→ ' + latest)}`)
|
|
377
391
|
} else {
|
|
378
|
-
sub(`${pkg}
|
|
392
|
+
sub(`${pad(pkg, 14)} ${pad(installed, 9)} ${green('✓')} ${dim('current')}`)
|
|
379
393
|
}
|
|
380
394
|
}
|
|
381
395
|
|
|
382
396
|
if (upgrades.length && !dryRun) {
|
|
383
|
-
log(
|
|
397
|
+
log('')
|
|
398
|
+
log(` ${gold('upgrading')} ${dim(`${upgrades.length} cli${upgrades.length === 1 ? '' : 's'} via pnpm`)}`)
|
|
384
399
|
const args = ['add', '-g', ...upgrades.map((u) => `${u.pkg}@latest`)]
|
|
385
400
|
const res = await spawnSync('pnpm', args)
|
|
386
401
|
if (res.status !== 0) {
|
|
@@ -408,7 +423,6 @@ async function update(rest) {
|
|
|
408
423
|
}
|
|
409
424
|
|
|
410
425
|
// ---- Step 1+2: compare /v1/me + refresh runtime + credentials ---------
|
|
411
|
-
log('fetching /v1/me…')
|
|
412
426
|
const me = await api('GET', '/v1/me')
|
|
413
427
|
const localVersion = readLocalVersion()
|
|
414
428
|
const localInbox = (loadCredentials() || {}).agentmail_email || ''
|
|
@@ -416,11 +430,13 @@ async function update(rest) {
|
|
|
416
430
|
const runtimeBehind = me.runtime_version && me.runtime_version !== localVersion
|
|
417
431
|
const inboxBehind = me.agentmail_email && me.agentmail_email !== localInbox
|
|
418
432
|
|
|
419
|
-
sub(
|
|
420
|
-
sub(
|
|
433
|
+
sub(`${pad('runtime', 14)} ${pad(shortVer(localVersion) || dim('<none>'), 9)} ${runtimeBehind ? gold(`→ ${shortVer(me.runtime_version)}`) : `${green('✓')} ${dim('matches cloud')}`}`)
|
|
434
|
+
sub(`${pad('inbox', 14)} ${localInbox || dim('<none>')} ${inboxBehind ? gold('→ rotate') : `${green('✓')} ${dim('matches cloud')}`}`)
|
|
421
435
|
|
|
422
436
|
if (!runtimeBehind && !inboxBehind) {
|
|
423
|
-
log('
|
|
437
|
+
log('')
|
|
438
|
+
log(` ${green('✓')} already up to date`)
|
|
439
|
+
log('')
|
|
424
440
|
return
|
|
425
441
|
}
|
|
426
442
|
if (dryRun) {
|
|
@@ -431,25 +447,26 @@ async function update(rest) {
|
|
|
431
447
|
// Refresh runtime files + skills (all-or-nothing for rollback safety).
|
|
432
448
|
if (runtimeBehind) {
|
|
433
449
|
try {
|
|
434
|
-
log('
|
|
450
|
+
log('')
|
|
451
|
+
sub(`${dim('refreshing')} runtime files`)
|
|
435
452
|
await refreshRuntimeFiles()
|
|
436
|
-
|
|
453
|
+
sub(`${dim('refreshing')} kstack skills`)
|
|
437
454
|
await refreshSkills()
|
|
438
|
-
|
|
455
|
+
sub(`${dim('reloading')} local scheduler`)
|
|
439
456
|
await reloadLocalScheduler()
|
|
440
457
|
// Only stamp the version AFTER every step succeeded.
|
|
441
458
|
writeLocalVersion(me.runtime_version)
|
|
442
|
-
sub(
|
|
459
|
+
sub(`${dim('stamped')} ${shortVer(me.runtime_version)} ${dim('→ ~/.autark/runtime/version.txt')}`)
|
|
443
460
|
} catch (e) {
|
|
444
|
-
console.error(` runtime refresh failed: ${e.message}`)
|
|
445
|
-
console.error('
|
|
461
|
+
console.error(` ${red('✗')} runtime refresh failed: ${e.message}`)
|
|
462
|
+
console.error(` ${dim('rolled back — version stamp not written. re-run autark update.')}`)
|
|
446
463
|
process.exit(2)
|
|
447
464
|
}
|
|
448
465
|
}
|
|
449
466
|
|
|
450
467
|
// Rotate credentials (separate from runtime refresh — independent stream).
|
|
451
468
|
if (inboxBehind) {
|
|
452
|
-
|
|
469
|
+
sub(`${dim('rotating')} agentmail credentials`)
|
|
453
470
|
const rotated = await api('POST', '/v1/inbox/rotate', {})
|
|
454
471
|
saveCredentials({
|
|
455
472
|
...loadCredentials(),
|
|
@@ -458,10 +475,12 @@ async function update(rest) {
|
|
|
458
475
|
agentmail_token: rotated.agentmail_token,
|
|
459
476
|
rotated_at: new Date().toISOString(),
|
|
460
477
|
})
|
|
461
|
-
sub(
|
|
478
|
+
sub(`${dim('new inbox')} ${rotated.agentmail_email}`)
|
|
462
479
|
}
|
|
463
480
|
|
|
464
|
-
log(
|
|
481
|
+
log('')
|
|
482
|
+
log(` ${green('✓')} updated ${dim('→')} ${shortVer(me.runtime_version)}`)
|
|
483
|
+
log('')
|
|
465
484
|
}
|
|
466
485
|
|
|
467
486
|
// -----------------------------------------------------------------------
|
|
@@ -724,19 +743,42 @@ async function leadStatus(rest) {
|
|
|
724
743
|
// status. "Who replied?" = `autark lead list <slug> --status replied`.
|
|
725
744
|
async function leadList(rest) {
|
|
726
745
|
const opts = parseArgs(rest)
|
|
727
|
-
|
|
746
|
+
// Accept <slug>, <slug>/Hxx, or <slug> --hypothesis Hxx. The /Hxx form reads
|
|
747
|
+
// a hypothesis the same way it's written (lead add / run start / context).
|
|
748
|
+
// --hypothesis wins if both are supplied.
|
|
749
|
+
const ref = required(opts.product || opts._[0], 'product slug (or <slug>/Hxx)')
|
|
750
|
+
let product = ref
|
|
751
|
+
let hypothesis = opts.hypothesis || opts.hyp || ''
|
|
752
|
+
if (ref.includes('/')) {
|
|
753
|
+
const [slug, code] = ref.split('/')
|
|
754
|
+
product = slug
|
|
755
|
+
if (!hypothesis) hypothesis = code
|
|
756
|
+
}
|
|
728
757
|
const status = opts.status || ''
|
|
729
|
-
const qs = `?product=${encodeURIComponent(product)}
|
|
758
|
+
const qs = `?product=${encodeURIComponent(product)}`
|
|
759
|
+
+ (status ? `&status=${encodeURIComponent(status)}` : '')
|
|
760
|
+
+ (hypothesis ? `&hypothesis=${encodeURIComponent(hypothesis)}` : '')
|
|
730
761
|
const data = await api('GET', `/v1/leads${qs}`)
|
|
731
762
|
if (opts.json) { console.log(JSON.stringify(data, null, 2)); return }
|
|
732
|
-
|
|
733
|
-
|
|
763
|
+
const scope = `${product}${hypothesis ? `/${hypothesis}` : ''}`
|
|
764
|
+
if (!data.leads.length) { console.log(`no leads${status ? ` with status ${status}` : ''} in ${scope}`); return }
|
|
765
|
+
const printRow = (l) => {
|
|
734
766
|
const who = [l.full_name, l.email && `<${l.email}>`].filter(Boolean).join(' ')
|
|
735
767
|
console.log(`${l.lead_id} ${l.status}${l.hypothesis ? ` ${l.hypothesis}` : ''} ${who}`)
|
|
736
768
|
if (l.replied_at) console.log(` replied_at=${l.replied_at}${l.last_in_at ? ` last_in=${l.last_in_at}` : ''}`)
|
|
737
769
|
if (l.thread_ref) console.log(` thread=${l.thread_ref} inbox=${l.inbox_ref || ''}`)
|
|
738
770
|
if (l.angle) console.log(` angle: ${l.angle.length > 140 ? l.angle.slice(0, 140) + '…' : l.angle}`)
|
|
739
771
|
}
|
|
772
|
+
// Same split as the dashboard replies tab: their message is the latest
|
|
773
|
+
// unanswered word → the ball is in our court.
|
|
774
|
+
const needsRows = data.leads.filter((l) => l.needs_reply)
|
|
775
|
+
const otherRows = data.leads.filter((l) => !l.needs_reply)
|
|
776
|
+
if (needsRows.length) {
|
|
777
|
+
console.log(`— needs your reply · ${needsRows.length}`)
|
|
778
|
+
for (const l of needsRows) printRow(l)
|
|
779
|
+
if (otherRows.length) console.log(`— answered / waiting · ${otherRows.length}`)
|
|
780
|
+
}
|
|
781
|
+
for (const l of otherRows) printRow(l)
|
|
740
782
|
console.error(`${data.count} lead(s). Next: autark lead show <id> · autark mail thread <thread> · autark mail reply --lead-id <id>`)
|
|
741
783
|
}
|
|
742
784
|
|
|
@@ -818,9 +860,12 @@ function leadUsage() {
|
|
|
818
860
|
add --hypothesis-id <id> --input @/tmp/lead.json [--run-id <id>]
|
|
819
861
|
add --hypothesis <slug>/<H01> --input @/tmp/lead.json [--run-id <id>]
|
|
820
862
|
|
|
821
|
-
list <slug> [--status replied|contacted
|
|
863
|
+
list <slug>[/Hxx] [--status replied,ready|contacted|...] [--hypothesis Hxx] [--json]
|
|
822
864
|
the front door: one line per lead, ids first, newest replies on top.
|
|
823
|
-
|
|
865
|
+
scope to one bet with <slug>/Hxx (or --hypothesis Hxx); --status takes a
|
|
866
|
+
comma list. both filters optional and combine.
|
|
867
|
+
"who replied?" = lead list <slug> --status replied
|
|
868
|
+
"ready leads in H23?" = lead list <slug>/H23 --status ready
|
|
824
869
|
|
|
825
870
|
show <lead-id>
|
|
826
871
|
person + bet + status + the ordered touch log with ids — run this
|
package/package.json
CHANGED