auxilo-mcp 0.9.15 → 0.9.16
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/bin/auxilo-cli.js +25 -2
- package/lib/installer.js +227 -3
- package/lib/runner-autoupdate.js +920 -0
- package/lib/semver-min.js +76 -0
- package/lib/tar-extract.js +175 -0
- package/mcp-server.js +1 -1
- package/package.json +6 -2
- package/scripts/runner.js +63 -0
package/bin/auxilo-cli.js
CHANGED
|
@@ -22,6 +22,7 @@ const readline = require('readline');
|
|
|
22
22
|
const { exec } = require('child_process');
|
|
23
23
|
const installer = require('../lib/installer.js');
|
|
24
24
|
const review = require('../lib/review.js');
|
|
25
|
+
const runnerAutoupdate = require('../lib/runner-autoupdate.js');
|
|
25
26
|
const providers = require('../scripts/providers/index.js');
|
|
26
27
|
const byoKeyProvider = require('../scripts/providers/byo-key.js');
|
|
27
28
|
|
|
@@ -186,6 +187,10 @@ const CONSENT_TEXT = `
|
|
|
186
187
|
other agents unlock your learnings and are not guaranteed. Earnings
|
|
187
188
|
accrue now. Withdrawals open soon, and auxilo.io/status shows where
|
|
188
189
|
things stand.
|
|
190
|
+
• UPDATES itself once a day from npm. A newer version installs only after
|
|
191
|
+
its signature and checksum both pass, and if either fails you keep the
|
|
192
|
+
copy you have. Run auxilo setup --no-autoupdate to decline. auxilo
|
|
193
|
+
status shows the setting and the last check.
|
|
189
194
|
You can stop any time with \`auxilo disable\` (local kill-switch) and review
|
|
190
195
|
every run in ~/.auxilo/extract.log. Saying No installs the MCP server only.
|
|
191
196
|
No session-end capture hook is written into any client config unless you say
|
|
@@ -291,6 +296,15 @@ async function cmdSetup(flags) {
|
|
|
291
296
|
process.exit(1);
|
|
292
297
|
}
|
|
293
298
|
|
|
299
|
+
// RUNNER-AUTO-UPDATE (0.9.16): `--no-autoupdate` persists the opt-out so
|
|
300
|
+
// every future hook-fired run skips the self-update network check, not
|
|
301
|
+
// just this invocation of `setup` (env AUXILO_RUNNER_AUTOUPDATE=0 is the
|
|
302
|
+
// other, per-run-only opt-out — see lib/runner-autoupdate.js).
|
|
303
|
+
if (flags['no-autoupdate']) {
|
|
304
|
+
installer.writeRunnerConfig(HOME, { autoupdate: false });
|
|
305
|
+
console.log(' ✓ Runner auto-update disabled (persisted to ~/.auxilo/runner-config.json)');
|
|
306
|
+
}
|
|
307
|
+
|
|
294
308
|
const claudeCode = chosen.find((c) => c.id === 'claude-code');
|
|
295
309
|
if (claudeCode) {
|
|
296
310
|
// LW-18: SessionStart held-count notice ("N learnings held for your
|
|
@@ -551,6 +565,13 @@ async function cmdStatus() {
|
|
|
551
565
|
if (s.runnerInstalled) {
|
|
552
566
|
const line = runnerSkewLine(installer.runnerVersionSkew(HOME));
|
|
553
567
|
if (line) console.log(line);
|
|
568
|
+
// RUNNER-AUTO-UPDATE (0.9.16): one more line in the same section, no new
|
|
569
|
+
// heading — auto-update on/off/paused-by-env, last check time, and the
|
|
570
|
+
// last verification result (if any check has ever run).
|
|
571
|
+
const autoupdateLine = runnerAutoupdate.runnerAutoupdateStatusLine(
|
|
572
|
+
runnerAutoupdate.getRunnerAutoupdateStatus(HOME)
|
|
573
|
+
);
|
|
574
|
+
if (autoupdateLine) console.log(autoupdateLine);
|
|
554
575
|
}
|
|
555
576
|
console.log(extractionProviderLine(await providers.resolveProvider({})));
|
|
556
577
|
// Lazy require: scripts/runner.js is a heavier module (sources, sensitivity
|
|
@@ -1435,10 +1456,12 @@ async function cmdProvider(flags) {
|
|
|
1435
1456
|
|
|
1436
1457
|
function usage(command) {
|
|
1437
1458
|
const blocks = {
|
|
1438
|
-
setup: `Usage: auxilo setup [--re-auth] [--base-url <url>]
|
|
1459
|
+
setup: `Usage: auxilo setup [--re-auth] [--base-url <url>] [--no-autoupdate]
|
|
1439
1460
|
|
|
1440
1461
|
Interactively detect clients, register Auxilo, sign in, install the optional
|
|
1441
|
-
extraction runner and SessionEnd hook, and record the extraction choice
|
|
1462
|
+
extraction runner and SessionEnd hook, and record the extraction choice.
|
|
1463
|
+
--no-autoupdate persists opt-out of the runner's self-update check (default:
|
|
1464
|
+
on — see AUXILO_RUNNER_AUTOUPDATE=0 for a per-run-only opt-out instead).`,
|
|
1442
1465
|
init: `Usage: auxilo init [--scope <read|earnings-read|contribute>] [--label <name>]
|
|
1443
1466
|
[--env-file <path>] [--save] [--json] [--no-browser]
|
|
1444
1467
|
[--base-url <url>]
|
package/lib/installer.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
const fs = require('fs');
|
|
26
26
|
const path = require('path');
|
|
27
|
+
const crypto = require('crypto');
|
|
27
28
|
const { hasAuxiloSessionEndHook } = require('./hook-status.js');
|
|
28
29
|
|
|
29
30
|
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
@@ -118,6 +119,16 @@ const RUNNER_STACK = Object.freeze([
|
|
|
118
119
|
['lib/similarity.js', 'lib/similarity.js', 0o644],
|
|
119
120
|
['lib/hook-status.js', 'lib/hook-status.js', 0o644],
|
|
120
121
|
['lib/ops-alert.js', 'lib/ops-alert.js', 0o644],
|
|
122
|
+
// RUNNER-AUTO-UPDATE (0.9.16): runner.js requires lib/runner-autoupdate.js,
|
|
123
|
+
// which in turn requires lib/installer.js (installRunner/binRootFor/
|
|
124
|
+
// readRunnerConfig/writeRunnerConfig — the atomic-swap seam) plus its own
|
|
125
|
+
// two small helpers. All four must ship or the installed runner's first
|
|
126
|
+
// auto-update check is a MODULE_NOT_FOUND (test/runner-packaging-closure.test.js
|
|
127
|
+
// guards this closure automatically).
|
|
128
|
+
['lib/runner-autoupdate.js', 'lib/runner-autoupdate.js', 0o644],
|
|
129
|
+
['lib/tar-extract.js', 'lib/tar-extract.js', 0o644],
|
|
130
|
+
['lib/semver-min.js', 'lib/semver-min.js', 0o644],
|
|
131
|
+
['lib/installer.js', 'lib/installer.js', 0o644],
|
|
121
132
|
['config/near-duplicate.json', 'config/near-duplicate.json', 0o644],
|
|
122
133
|
]);
|
|
123
134
|
|
|
@@ -629,6 +640,56 @@ function writeCredentials(homeDir, creds) {
|
|
|
629
640
|
return credPath;
|
|
630
641
|
}
|
|
631
642
|
|
|
643
|
+
// ─── Runner config (RUNNER-AUTO-UPDATE, 0.9.16 §6) ──────────────────────────
|
|
644
|
+
//
|
|
645
|
+
// Lightweight, NON-secret sibling to credentials.json: holds the persisted
|
|
646
|
+
// `auxilo setup --no-autoupdate` opt-out plus the auto-update check/
|
|
647
|
+
// verification state `auxilo status` reports (lib/runner-autoupdate.js is
|
|
648
|
+
// the only other reader/writer). Deliberately a separate file rather than
|
|
649
|
+
// folded into credentials.json — credentials.json is chmod 0600 and its
|
|
650
|
+
// shape is the auth contract (api_key/base_url/email/account_id); this file
|
|
651
|
+
// holds neither secrets nor auth state, so it stays plain (no forced chmod)
|
|
652
|
+
// and its shape can grow without touching the auth surface.
|
|
653
|
+
|
|
654
|
+
function runnerConfigPath(homeDir) {
|
|
655
|
+
return path.join(homeDir, '.auxilo', 'runner-config.json');
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** Malformed/absent → {} (same tolerance as readCredentials). */
|
|
659
|
+
function readRunnerConfig(homeDir) {
|
|
660
|
+
try {
|
|
661
|
+
const cfg = JSON.parse(fs.readFileSync(runnerConfigPath(homeDir), 'utf-8'));
|
|
662
|
+
return cfg && typeof cfg === 'object' && !Array.isArray(cfg) ? cfg : {};
|
|
663
|
+
} catch {
|
|
664
|
+
return {};
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Merge `patch` into the existing config and write it back (read-modify-
|
|
670
|
+
* write, tmp + rename — same discipline as writeCredentials/saveLedger).
|
|
671
|
+
* Never throws — a failed write must not break the caller (setup, or the
|
|
672
|
+
* best-effort auto-update state persistence).
|
|
673
|
+
*
|
|
674
|
+
* @param {string} homeDir
|
|
675
|
+
* @param {object} patch Shallow-merged into the existing config.
|
|
676
|
+
* @returns {object} the config as written (best-effort — may be stale if
|
|
677
|
+
* the write itself failed).
|
|
678
|
+
*/
|
|
679
|
+
function writeRunnerConfig(homeDir, patch) {
|
|
680
|
+
const merged = { ...readRunnerConfig(homeDir), ...(patch || {}) };
|
|
681
|
+
try {
|
|
682
|
+
const cfgPath = runnerConfigPath(homeDir);
|
|
683
|
+
fs.mkdirSync(path.dirname(cfgPath), { recursive: true });
|
|
684
|
+
const tmp = `${cfgPath}.tmp`;
|
|
685
|
+
fs.writeFileSync(tmp, JSON.stringify(merged, null, 2) + '\n');
|
|
686
|
+
fs.renameSync(tmp, cfgPath);
|
|
687
|
+
} catch {
|
|
688
|
+
/* best-effort — see doc comment above */
|
|
689
|
+
}
|
|
690
|
+
return merged;
|
|
691
|
+
}
|
|
692
|
+
|
|
632
693
|
// ─── Device-code auth (spec §LW-12 step 2; server.js /auth/device) ──────────
|
|
633
694
|
|
|
634
695
|
/**
|
|
@@ -843,12 +904,18 @@ exit 0
|
|
|
843
904
|
* @param {string} homeDir
|
|
844
905
|
* @param {object} [opts]
|
|
845
906
|
* @param {string} [opts.packageRoot=PACKAGE_ROOT]
|
|
907
|
+
* @param {string} [opts.binRootOverride] RUNNER-AUTO-UPDATE (0.9.16): build
|
|
908
|
+
* the stack somewhere OTHER than <home>/.auxilo/bin — e.g. `<bin>.new` —
|
|
909
|
+
* so the auto-updater can build+verify a full new stack in a scratch dir
|
|
910
|
+
* and only `fs.renameSync` it into place as the single atomic swap step.
|
|
911
|
+
* Defaults to `binRootFor(homeDir)`, so ordinary `setup` behavior (writes
|
|
912
|
+
* straight into <home>/.auxilo/bin) is completely unchanged.
|
|
846
913
|
* @returns {{ binRoot: string, hookPath: string, versionPath: string, version: string, installed: string[] }}
|
|
847
914
|
*/
|
|
848
915
|
function installRunner(homeDir, opts = {}) {
|
|
849
916
|
if (!homeDir) throw new Error('installRunner: homeDir is required');
|
|
850
917
|
const packageRoot = opts.packageRoot || PACKAGE_ROOT;
|
|
851
|
-
const binRoot = binRootFor(homeDir);
|
|
918
|
+
const binRoot = opts.binRootOverride || binRootFor(homeDir);
|
|
852
919
|
const installed = [];
|
|
853
920
|
|
|
854
921
|
for (const [src, dest, mode] of RUNNER_STACK) {
|
|
@@ -863,13 +930,20 @@ function installRunner(homeDir, opts = {}) {
|
|
|
863
930
|
installed.push(destPath);
|
|
864
931
|
}
|
|
865
932
|
|
|
866
|
-
|
|
933
|
+
// NOTE: the hook script's own CONTENT always names the real final
|
|
934
|
+
// <home>/.auxilo/bin location (renderHookScript is homeDir-based, not
|
|
935
|
+
// binRoot-based) — correct even while staging into a binRootOverride
|
|
936
|
+
// scratch dir, since that is where this tree lands after the swap. Only
|
|
937
|
+
// the WRITE TARGET (hookPath/versionPath below) follows binRoot, so a
|
|
938
|
+
// staged build never touches the real bin root until the caller renames
|
|
939
|
+
// the whole staged directory into place.
|
|
940
|
+
const hookPath = path.join(binRoot, path.basename(hookScriptPathFor(homeDir)));
|
|
867
941
|
fs.writeFileSync(hookPath, renderHookScript(homeDir));
|
|
868
942
|
fs.chmodSync(hookPath, 0o755);
|
|
869
943
|
installed.push(hookPath);
|
|
870
944
|
|
|
871
945
|
const version = packageVersion(packageRoot);
|
|
872
|
-
const versionPath = runnerVersionPath(homeDir);
|
|
946
|
+
const versionPath = path.join(binRoot, path.basename(runnerVersionPath(homeDir)));
|
|
873
947
|
fs.writeFileSync(versionPath, `${version}\n`);
|
|
874
948
|
fs.chmodSync(versionPath, 0o644);
|
|
875
949
|
installed.push(versionPath);
|
|
@@ -877,6 +951,151 @@ function installRunner(homeDir, opts = {}) {
|
|
|
877
951
|
return { binRoot, hookPath, versionPath, version, installed };
|
|
878
952
|
}
|
|
879
953
|
|
|
954
|
+
/**
|
|
955
|
+
* RUNNER-AUTO-UPDATE B1 fix: install the runner stack into the REAL
|
|
956
|
+
* `<home>/.auxilo/bin` (never a scratch `binRootOverride`) with every write
|
|
957
|
+
* ATOMIC PER FILE — a `<dest>.tmp-<pid>-<rand>` write followed by
|
|
958
|
+
* `fs.renameSync` onto the final path — instead of staging a whole tree
|
|
959
|
+
* elsewhere and `fs.renameSync`-ing the ENTIRE directory into place.
|
|
960
|
+
*
|
|
961
|
+
* Why this exists: the old auto-update swap renamed the whole `<bin>`
|
|
962
|
+
* directory. `installRunner` only ever writes the files listed in
|
|
963
|
+
* RUNNER_STACK plus the hook script and VERSION stamp — but `<bin>` also
|
|
964
|
+
* holds files installRunner never touches: the per-client capture shims
|
|
965
|
+
* (captureShimPath), the review-notice shim (noticeShimPath), the
|
|
966
|
+
* sweeper/backup wrappers, and jobs/ — all referenced by ABSOLUTE PATH from
|
|
967
|
+
* client settings files and launchd plists. A whole-directory rename
|
|
968
|
+
* silently deletes every one of those on the very first auto-update. Per-
|
|
969
|
+
* file atomic writes touch only the files this function actually knows
|
|
970
|
+
* about and leave every sibling entry in `<bin>` completely untouched.
|
|
971
|
+
*
|
|
972
|
+
* Each individual file lands atomically (a reader never observes a
|
|
973
|
+
* partially-written file), but there is no cross-file transaction — if this
|
|
974
|
+
* throws partway through, some stack files may already be updated and
|
|
975
|
+
* others not. That is an intentional trade for correctness over the old
|
|
976
|
+
* design's false all-or-nothing guarantee, which in practice deleted
|
|
977
|
+
* everything BUT the stack on every run. A crash mid-loop still leaves a
|
|
978
|
+
* fully-functional `<bin>` (old files for whatever wasn't reached yet, new
|
|
979
|
+
* files for what was) — never a missing directory.
|
|
980
|
+
*
|
|
981
|
+
* @param {string} homeDir
|
|
982
|
+
* @param {object} [opts]
|
|
983
|
+
* @param {string} [opts.packageRoot=PACKAGE_ROOT] Root to copy FROM — the
|
|
984
|
+
* caller passes the already-SRI+signature-verified extracted tarball dir.
|
|
985
|
+
* @returns {{ binRoot: string, hookPath: string, versionPath: string, version: string, installed: string[] }}
|
|
986
|
+
*/
|
|
987
|
+
/**
|
|
988
|
+
* MEDIUM-2 fix (0.9.16 fix pass 2). RUNNER_STACK's sources/providers/schemas
|
|
989
|
+
* rows are DERIVED by enumerating the package's own directories at require
|
|
990
|
+
* time (sourceAdapterRows/providerAdapterRows/providerSchemaRows above) — a
|
|
991
|
+
* file REMOVED from a newer release's package is simply absent from the
|
|
992
|
+
* NEW RUNNER_STACK, but installRunnerAtomic only ever WRITES what's in the
|
|
993
|
+
* stack; it never deleted what a PRIOR install left behind. A stale adapter
|
|
994
|
+
* (or provider/schema/lib module) from an old version therefore survived
|
|
995
|
+
* every auto-update indefinitely, still sitting in `<bin>` and still
|
|
996
|
+
* require()-able by anything that enumerates its directory the way
|
|
997
|
+
* scripts/runner.js's own loadSources() does.
|
|
998
|
+
*
|
|
999
|
+
* Scoped tightly on purpose: only the directories RUNNER_STACK actually
|
|
1000
|
+
* populates by enumeration are pruned — never the bin ROOT itself, and
|
|
1001
|
+
* never any other subdirectory. `<bin>` also holds files/dirs
|
|
1002
|
+
* installRunnerAtomic has never managed (capture shims, the review-notice
|
|
1003
|
+
* shim, sweeper/backup wrappers, jobs/ — see installRunnerAtomic's own doc
|
|
1004
|
+
* comment on why a whole-directory approach is unsafe here) — pruning must
|
|
1005
|
+
* leave every one of those completely untouched, exactly like the atomic
|
|
1006
|
+
* writes above already do.
|
|
1007
|
+
*
|
|
1008
|
+
* Also sweeps orphaned `<file>.tmp-<pid>-<hex>` scratch files left in a
|
|
1009
|
+
* pruned directory by a process that crashed between atomicWrite's write
|
|
1010
|
+
* and its rename (so a leftover partial write from a prior crashed install
|
|
1011
|
+
* doesn't accumulate forever either).
|
|
1012
|
+
*
|
|
1013
|
+
* @param {string} binRoot
|
|
1014
|
+
* @param {string[]} keepDestPaths Absolute dest paths this install just
|
|
1015
|
+
* wrote (the `installed` accumulator, stack rows only — hook/VERSION
|
|
1016
|
+
* live outside every prunable dir so including them would be harmless
|
|
1017
|
+
* but is unnecessary).
|
|
1018
|
+
*/
|
|
1019
|
+
const PRUNABLE_STACK_DIRS = Object.freeze([
|
|
1020
|
+
'scripts/sources',
|
|
1021
|
+
'scripts/providers',
|
|
1022
|
+
'scripts/providers/schemas',
|
|
1023
|
+
'lib',
|
|
1024
|
+
]);
|
|
1025
|
+
|
|
1026
|
+
const ORPHANED_TMP_RE = /\.tmp-\d+-[0-9a-f]+$/;
|
|
1027
|
+
|
|
1028
|
+
function pruneStaleStackFiles(binRoot, keepDestPaths) {
|
|
1029
|
+
const keep = new Set(keepDestPaths.map((p) => path.resolve(p)));
|
|
1030
|
+
for (const rel of PRUNABLE_STACK_DIRS) {
|
|
1031
|
+
const dir = path.join(binRoot, rel);
|
|
1032
|
+
let entries;
|
|
1033
|
+
try {
|
|
1034
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1035
|
+
} catch {
|
|
1036
|
+
continue; // directory doesn't exist (nothing shipped there) — nothing to prune
|
|
1037
|
+
}
|
|
1038
|
+
for (const entry of entries) {
|
|
1039
|
+
// Never descend into or remove subdirectories here — each prunable
|
|
1040
|
+
// subdirectory (e.g. scripts/providers/schemas) is enumerated in its
|
|
1041
|
+
// own PRUNABLE_STACK_DIRS row; a bare directory entry (like
|
|
1042
|
+
// scripts/providers/schemas itself, seen while walking
|
|
1043
|
+
// scripts/providers) is left alone.
|
|
1044
|
+
if (!entry.isFile()) continue;
|
|
1045
|
+
const full = path.join(dir, entry.name);
|
|
1046
|
+
if (ORPHANED_TMP_RE.test(entry.name)) {
|
|
1047
|
+
try { fs.rmSync(full, { force: true }); } catch { /* best-effort */ }
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
if (!keep.has(path.resolve(full))) {
|
|
1051
|
+
try { fs.rmSync(full, { force: true }); } catch { /* best-effort */ }
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function installRunnerAtomic(homeDir, opts = {}) {
|
|
1058
|
+
if (!homeDir) throw new Error('installRunnerAtomic: homeDir is required');
|
|
1059
|
+
const packageRoot = opts.packageRoot || PACKAGE_ROOT;
|
|
1060
|
+
const binRoot = binRootFor(homeDir);
|
|
1061
|
+
const installed = [];
|
|
1062
|
+
|
|
1063
|
+
function atomicWrite(destPath, writeTmp, mode) {
|
|
1064
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
1065
|
+
const tmp = `${destPath}.tmp-${process.pid}-${crypto.randomBytes(6).toString('hex')}`;
|
|
1066
|
+
writeTmp(tmp);
|
|
1067
|
+
fs.chmodSync(tmp, mode);
|
|
1068
|
+
fs.renameSync(tmp, destPath); // atomic on the same filesystem (same dir)
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
for (const [src, dest, mode] of RUNNER_STACK) {
|
|
1072
|
+
const srcPath = path.join(packageRoot, src);
|
|
1073
|
+
const destPath = path.join(binRoot, dest);
|
|
1074
|
+
if (!fs.existsSync(srcPath)) {
|
|
1075
|
+
throw new Error(`installRunnerAtomic: missing package file ${srcPath} — reinstall auxilo-mcp`);
|
|
1076
|
+
}
|
|
1077
|
+
atomicWrite(destPath, (tmp) => fs.copyFileSync(srcPath, tmp), mode);
|
|
1078
|
+
installed.push(destPath);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// MEDIUM-2: prune stale stack files (removed adapters/providers/schemas/
|
|
1082
|
+
// lib modules from a prior version) now that every file the NEW stack
|
|
1083
|
+
// wants is safely on disk. Scoped to the enumerated dirs only — see
|
|
1084
|
+
// pruneStaleStackFiles's doc comment.
|
|
1085
|
+
pruneStaleStackFiles(binRoot, installed);
|
|
1086
|
+
|
|
1087
|
+
const hookPath = path.join(binRoot, path.basename(hookScriptPathFor(homeDir)));
|
|
1088
|
+
atomicWrite(hookPath, (tmp) => fs.writeFileSync(tmp, renderHookScript(homeDir)), 0o755);
|
|
1089
|
+
installed.push(hookPath);
|
|
1090
|
+
|
|
1091
|
+
const version = packageVersion(packageRoot);
|
|
1092
|
+
const versionPath = path.join(binRoot, path.basename(runnerVersionPath(homeDir)));
|
|
1093
|
+
atomicWrite(versionPath, (tmp) => fs.writeFileSync(tmp, `${version}\n`), 0o644);
|
|
1094
|
+
installed.push(versionPath);
|
|
1095
|
+
|
|
1096
|
+
return { binRoot, hookPath, versionPath, version, installed };
|
|
1097
|
+
}
|
|
1098
|
+
|
|
880
1099
|
// ─── Runner-stack freshness (CLEAN-LANE-FLIP Phase B) ───────────────────────
|
|
881
1100
|
|
|
882
1101
|
/** <home>/.auxilo/bin/VERSION — the package version installRunner last copied. */
|
|
@@ -1794,12 +2013,17 @@ module.exports = {
|
|
|
1794
2013
|
credentialsPath,
|
|
1795
2014
|
readCredentials,
|
|
1796
2015
|
writeCredentials,
|
|
2016
|
+
runnerConfigPath,
|
|
2017
|
+
readRunnerConfig,
|
|
2018
|
+
writeRunnerConfig,
|
|
1797
2019
|
writeEnvFile,
|
|
1798
2020
|
deviceLogin,
|
|
1799
2021
|
binRootFor,
|
|
1800
2022
|
hookScriptPathFor,
|
|
1801
2023
|
renderHookScript,
|
|
1802
2024
|
installRunner,
|
|
2025
|
+
installRunnerAtomic,
|
|
2026
|
+
pruneStaleStackFiles,
|
|
1803
2027
|
runnerVersionPath,
|
|
1804
2028
|
packageVersion,
|
|
1805
2029
|
installedRunnerVersion,
|