@factiii/runner 0.12.1 → 0.12.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/dist/cli.js +257 -113
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3984,7 +3984,7 @@ var require_has_flag = __commonJS({
|
|
|
3984
3984
|
var require_supports_color = __commonJS({
|
|
3985
3985
|
"../../node_modules/debug/node_modules/supports-color/index.js"(exports2, module2) {
|
|
3986
3986
|
"use strict";
|
|
3987
|
-
var
|
|
3987
|
+
var os8 = require("os");
|
|
3988
3988
|
var hasFlag = require_has_flag();
|
|
3989
3989
|
var env = process.env;
|
|
3990
3990
|
var forceColor;
|
|
@@ -4022,7 +4022,7 @@ var require_supports_color = __commonJS({
|
|
|
4022
4022
|
}
|
|
4023
4023
|
const min = forceColor ? 1 : 0;
|
|
4024
4024
|
if (process.platform === "win32") {
|
|
4025
|
-
const osRelease =
|
|
4025
|
+
const osRelease = os8.release().split(".");
|
|
4026
4026
|
if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
4027
4027
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
4028
4028
|
}
|
|
@@ -14161,6 +14161,18 @@ var import_promises5 = __toESM(require("fs/promises"));
|
|
|
14161
14161
|
var import_os2 = __toESM(require("os"));
|
|
14162
14162
|
var import_path7 = __toESM(require("path"));
|
|
14163
14163
|
|
|
14164
|
+
// ../../shared/all/domains/products.ts
|
|
14165
|
+
var TRONS_PER_USD = 1e6;
|
|
14166
|
+
var TRONS_PER_CENT = TRONS_PER_USD / 100;
|
|
14167
|
+
var FOUNDERS_REFUND_WINDOW_DAYS = 60;
|
|
14168
|
+
var FOUNDERS_REFUND_POLICY = `Refundable within ${FOUNDERS_REFUND_WINDOW_DAYS} days of purchase \u2014 after that, all sales are final.`;
|
|
14169
|
+
|
|
14170
|
+
// ../../shared/all/domains/autoTopUp.ts
|
|
14171
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
14172
|
+
var MONTH_MS = 30 * DAY_MS;
|
|
14173
|
+
var CLAIM_STALE_MS = 5 * 60 * 1e3;
|
|
14174
|
+
var MIN_THRESHOLD_TRONS = TRONS_PER_CENT;
|
|
14175
|
+
|
|
14164
14176
|
// ../../shared/all/domains/posts.ts
|
|
14165
14177
|
var postDataSort = /* @__PURE__ */ ((postDataSort2) => {
|
|
14166
14178
|
postDataSort2["DAILY"] = "DAILY";
|
|
@@ -14363,7 +14375,11 @@ var checkPurchaseSchema = external_exports.object({
|
|
|
14363
14375
|
productId: external_exports.string(),
|
|
14364
14376
|
type: external_exports.enum(["STRIPE", "GOOGLE", "APPLE"]),
|
|
14365
14377
|
receivedPrice: external_exports.number().int().min(0, "Received price must be a positive integer in cents"),
|
|
14366
|
-
currency: external_exports.string().length(3).default("USD")
|
|
14378
|
+
currency: external_exports.string().length(3).default("USD"),
|
|
14379
|
+
// Explicit consent to keep this card for auto top-up. Card-network rules
|
|
14380
|
+
// require the buyer to agree before a card may be charged while they are not
|
|
14381
|
+
// present, so this must come from a checkbox they ticked — never a default.
|
|
14382
|
+
saveCardForAutoTopUp: external_exports.boolean().default(false)
|
|
14367
14383
|
});
|
|
14368
14384
|
var creditPurchaseSchema = external_exports.object({
|
|
14369
14385
|
orderId: external_exports.string(),
|
|
@@ -14666,6 +14682,19 @@ var skillFrontmatterSchema = external_exports.object({
|
|
|
14666
14682
|
}).strict();
|
|
14667
14683
|
var skillAgentSchema = external_exports.enum(["claude", "codex"]);
|
|
14668
14684
|
var skillScopeSchema = external_exports.enum(["global", "repo"]);
|
|
14685
|
+
var autoTopUpSchema = external_exports.object({
|
|
14686
|
+
enabled: external_exports.boolean(),
|
|
14687
|
+
productId: external_exports.number().int().positive(),
|
|
14688
|
+
thresholdTrons: external_exports.number().int().min(MIN_THRESHOLD_TRONS),
|
|
14689
|
+
dailyCapCents: external_exports.number().int().min(0),
|
|
14690
|
+
monthlyCapCents: external_exports.number().int().min(0),
|
|
14691
|
+
// Alerts. `alertBalanceTrons` is null when the low-balance warning is off;
|
|
14692
|
+
// it works independently of `enabled`, since with auto top-up off it is the
|
|
14693
|
+
// only safety net there is.
|
|
14694
|
+
alertOnTopUp: external_exports.boolean(),
|
|
14695
|
+
alertBalanceTrons: external_exports.number().int().min(MIN_THRESHOLD_TRONS).nullable(),
|
|
14696
|
+
alertNearCap: external_exports.boolean()
|
|
14697
|
+
});
|
|
14669
14698
|
|
|
14670
14699
|
// ../../shared/all/helpers/board-agent-core/host-deploy.ts
|
|
14671
14700
|
var import_child_process3 = require("child_process");
|
|
@@ -22329,11 +22358,58 @@ ${c.content.trim() || "(no description)"}`
|
|
|
22329
22358
|
// ../../shared/all/helpers/board-agent-core/index-service.ts
|
|
22330
22359
|
var import_child_process5 = require("child_process");
|
|
22331
22360
|
var import_crypto7 = require("crypto");
|
|
22332
|
-
var
|
|
22361
|
+
var import_fs6 = require("fs");
|
|
22333
22362
|
var import_promises11 = __toESM(require("fs/promises"));
|
|
22334
22363
|
var import_net3 = require("net");
|
|
22335
|
-
var
|
|
22364
|
+
var import_path17 = require("path");
|
|
22336
22365
|
var import_util7 = require("util");
|
|
22366
|
+
|
|
22367
|
+
// ../../shared/all/helpers/board-agent-core/node-version.ts
|
|
22368
|
+
var import_fs5 = require("fs");
|
|
22369
|
+
var import_os4 = __toESM(require("os"));
|
|
22370
|
+
var import_path16 = require("path");
|
|
22371
|
+
var MIN_INDEX_NODE_MAJOR = 20;
|
|
22372
|
+
var MAX_INDEX_NODE_MAJOR = 24;
|
|
22373
|
+
var NODE_OVERRIDE_ENV = "FACTIII_INDEX_NODE";
|
|
22374
|
+
function nodeMajor(version) {
|
|
22375
|
+
return Number(version.replace(/^v/, "").split(".")[0]);
|
|
22376
|
+
}
|
|
22377
|
+
function indexNodeSupported(version = process.versions.node) {
|
|
22378
|
+
const major = nodeMajor(version);
|
|
22379
|
+
return !Number.isNaN(major) && major >= MIN_INDEX_NODE_MAJOR && major <= MAX_INDEX_NODE_MAJOR;
|
|
22380
|
+
}
|
|
22381
|
+
function candidateNodes() {
|
|
22382
|
+
const paths = [];
|
|
22383
|
+
const home = import_os4.default.homedir();
|
|
22384
|
+
const nvmRoot = (0, import_path16.join)(home, ".nvm", "versions", "node");
|
|
22385
|
+
try {
|
|
22386
|
+
const versions = (0, import_fs5.readdirSync)(nvmRoot).filter((v) => indexNodeSupported(v)).sort((a, b) => nodeMajor(b) - nodeMajor(a));
|
|
22387
|
+
for (const v of versions) paths.push((0, import_path16.join)(nvmRoot, v, "bin", "node"));
|
|
22388
|
+
} catch {
|
|
22389
|
+
}
|
|
22390
|
+
for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
|
|
22391
|
+
for (let major = MAX_INDEX_NODE_MAJOR; major >= MIN_INDEX_NODE_MAJOR; major -= 1) {
|
|
22392
|
+
paths.push((0, import_path16.join)(prefix, `node@${major}`, "bin", "node"));
|
|
22393
|
+
}
|
|
22394
|
+
}
|
|
22395
|
+
return paths;
|
|
22396
|
+
}
|
|
22397
|
+
function findIndexNode() {
|
|
22398
|
+
const override = process.env[NODE_OVERRIDE_ENV];
|
|
22399
|
+
if (override && (0, import_fs5.existsSync)(override)) return override;
|
|
22400
|
+
if (indexNodeSupported()) return process.execPath;
|
|
22401
|
+
return candidateNodes().find((p) => (0, import_fs5.existsSync)(p)) ?? null;
|
|
22402
|
+
}
|
|
22403
|
+
function unsupportedNodeMessage() {
|
|
22404
|
+
return `The OneDrive index needs Node ${MIN_INDEX_NODE_MAJOR}-${MAX_INDEX_NODE_MAJOR} (pinned 24.11.1); this host runs Node ${process.versions.node} and has no supported Node installed. It compiles better-sqlite3 from source, and that build fails on Node ${MAX_INDEX_NODE_MAJOR + 1}+.
|
|
22405
|
+
|
|
22406
|
+
Install one: nvm install 24.11.1
|
|
22407
|
+
or point the runner at an existing one: export ${NODE_OVERRIDE_ENV}=/path/to/node
|
|
22408
|
+
|
|
22409
|
+
Everything else on this runner works meanwhile \u2014 only OneDrive search is off.`;
|
|
22410
|
+
}
|
|
22411
|
+
|
|
22412
|
+
// ../../shared/all/helpers/board-agent-core/index-service.ts
|
|
22337
22413
|
var execFileAsync4 = (0, import_util7.promisify)(import_child_process5.execFile);
|
|
22338
22414
|
var IndexService = class {
|
|
22339
22415
|
constructor(opts) {
|
|
@@ -22386,27 +22462,25 @@ var IndexService = class {
|
|
|
22386
22462
|
await this.waitReady(this.port);
|
|
22387
22463
|
return;
|
|
22388
22464
|
}
|
|
22389
|
-
|
|
22465
|
+
const nodeBin = findIndexNode();
|
|
22466
|
+
if (!nodeBin) throw new Error(unsupportedNodeMessage());
|
|
22467
|
+
await this.installDeps(nodeBin);
|
|
22390
22468
|
const port = await this.stablePort();
|
|
22391
22469
|
const log = await this.openLog();
|
|
22392
|
-
this.proc = (0, import_child_process5.spawn)(
|
|
22393
|
-
|
|
22394
|
-
|
|
22395
|
-
|
|
22396
|
-
|
|
22397
|
-
|
|
22398
|
-
|
|
22399
|
-
|
|
22400
|
-
|
|
22401
|
-
|
|
22402
|
-
|
|
22403
|
-
|
|
22404
|
-
|
|
22405
|
-
|
|
22406
|
-
// Own process group so stop() reaps it; nothing else reaps orphans here.
|
|
22407
|
-
detached: true
|
|
22408
|
-
}
|
|
22409
|
-
);
|
|
22470
|
+
this.proc = (0, import_child_process5.spawn)(nodeBin, [(0, import_path17.join)(this.opts.indexDir, "index.js")], {
|
|
22471
|
+
cwd: this.opts.indexDir,
|
|
22472
|
+
env: {
|
|
22473
|
+
...process.env,
|
|
22474
|
+
NODE_ENV: "production",
|
|
22475
|
+
PORT: String(port),
|
|
22476
|
+
CONTROL_TOKEN: this.opts.controlToken,
|
|
22477
|
+
EMBED_URL: this.opts.embedUrl(),
|
|
22478
|
+
INDEX_DATA_DIR: this.opts.dataDir
|
|
22479
|
+
},
|
|
22480
|
+
stdio: log ? ["ignore", log, log] : "ignore",
|
|
22481
|
+
// Own process group so stop() reaps it; nothing else reaps orphans here.
|
|
22482
|
+
detached: true
|
|
22483
|
+
});
|
|
22410
22484
|
this.proc.on("exit", () => {
|
|
22411
22485
|
this.proc = null;
|
|
22412
22486
|
this.ready = null;
|
|
@@ -22420,31 +22494,58 @@ var IndexService = class {
|
|
|
22420
22494
|
async openLog() {
|
|
22421
22495
|
try {
|
|
22422
22496
|
await import_promises11.default.mkdir(this.opts.dataDir, { recursive: true });
|
|
22423
|
-
return (0,
|
|
22497
|
+
return (0, import_fs6.openSync)((0, import_path17.join)(this.opts.dataDir, "index.log"), "a");
|
|
22424
22498
|
} catch {
|
|
22425
22499
|
return null;
|
|
22426
22500
|
}
|
|
22427
22501
|
}
|
|
22428
|
-
/** Install the index's native deps against
|
|
22429
|
-
* platform needing node-gyp fails here rather than at query time.
|
|
22430
|
-
|
|
22502
|
+
/** Install the index's native deps against the node that will RUN it, so a
|
|
22503
|
+
* platform needing node-gyp fails here rather than at query time.
|
|
22504
|
+
*
|
|
22505
|
+
* The deps are compiled per ABI, so they are only reusable under the node
|
|
22506
|
+
* that built them. The stamp records which ABI is on disk and forces a
|
|
22507
|
+
* rebuild when the interpreter changes — otherwise a host that switches
|
|
22508
|
+
* node versions loads a binding built for the old one and dies with
|
|
22509
|
+
* "compiled against a different Node.js version". */
|
|
22510
|
+
async installDeps(nodeBin) {
|
|
22431
22511
|
const dir = this.opts.indexDir;
|
|
22432
|
-
|
|
22512
|
+
const { stdout } = await execFileAsync4(nodeBin, [
|
|
22513
|
+
"-p",
|
|
22514
|
+
"process.versions.modules"
|
|
22515
|
+
]);
|
|
22516
|
+
const abi = stdout.trim();
|
|
22517
|
+
const stamp = (0, import_path17.join)(dir, ".node-abi");
|
|
22518
|
+
if ((0, import_fs6.existsSync)((0, import_path17.join)(dir, "node_modules"))) {
|
|
22519
|
+
const built = await import_promises11.default.readFile(stamp, "utf-8").catch(() => "");
|
|
22520
|
+
if (built.trim() === abi) return;
|
|
22521
|
+
await import_promises11.default.rm((0, import_path17.join)(dir, "node_modules"), { recursive: true, force: true });
|
|
22522
|
+
}
|
|
22433
22523
|
await import_promises11.default.copyFile(
|
|
22434
|
-
(0,
|
|
22435
|
-
(0,
|
|
22524
|
+
(0, import_path17.join)(dir, "image-package.json"),
|
|
22525
|
+
(0, import_path17.join)(dir, "package.json")
|
|
22436
22526
|
);
|
|
22437
22527
|
await execFileAsync4(
|
|
22438
22528
|
"npm",
|
|
22439
22529
|
["install", "--omit=dev", "--no-audit", "--no-fund"],
|
|
22440
|
-
{
|
|
22530
|
+
{
|
|
22531
|
+
cwd: dir,
|
|
22532
|
+
// npm resolves node-gyp's target from the node running it, so the
|
|
22533
|
+
// chosen interpreter has to lead PATH or the build targets the wrong ABI.
|
|
22534
|
+
env: {
|
|
22535
|
+
...process.env,
|
|
22536
|
+
PATH: `${(0, import_path17.dirname)(nodeBin)}:${process.env.PATH ?? ""}`
|
|
22537
|
+
}
|
|
22538
|
+
}
|
|
22441
22539
|
);
|
|
22540
|
+
await import_promises11.default.writeFile(stamp, `${abi}
|
|
22541
|
+
`, "utf-8").catch(() => {
|
|
22542
|
+
});
|
|
22442
22543
|
}
|
|
22443
22544
|
/** The port to listen on, kept stable across restarts. The URL goes into the
|
|
22444
22545
|
* CLIs' persistent MCP config, so a fresh port each start would leave every
|
|
22445
22546
|
* registration pointing at a dead one. */
|
|
22446
22547
|
async stablePort() {
|
|
22447
|
-
const file = (0,
|
|
22548
|
+
const file = (0, import_path17.join)(this.opts.dataDir, ".port");
|
|
22448
22549
|
const saved = Number(await import_promises11.default.readFile(file, "utf-8").catch(() => ""));
|
|
22449
22550
|
if (Number.isInteger(saved) && saved > 0 && await isFree(saved)) {
|
|
22450
22551
|
return saved;
|
|
@@ -22619,25 +22720,25 @@ async function pairWithBrowser(serverUrl) {
|
|
|
22619
22720
|
}
|
|
22620
22721
|
|
|
22621
22722
|
// src/config.ts
|
|
22622
|
-
var
|
|
22623
|
-
var
|
|
22624
|
-
var
|
|
22723
|
+
var import_fs10 = __toESM(require("fs"));
|
|
22724
|
+
var import_os7 = __toESM(require("os"));
|
|
22725
|
+
var import_path22 = __toESM(require("path"));
|
|
22625
22726
|
|
|
22626
22727
|
// src/secureFile.ts
|
|
22627
22728
|
var import_crypto10 = __toESM(require("crypto"));
|
|
22628
|
-
var
|
|
22629
|
-
var
|
|
22729
|
+
var import_fs9 = __toESM(require("fs"));
|
|
22730
|
+
var import_path21 = __toESM(require("path"));
|
|
22630
22731
|
|
|
22631
22732
|
// src/keychain.ts
|
|
22632
22733
|
var import_child_process7 = require("child_process");
|
|
22633
22734
|
var import_crypto8 = __toESM(require("crypto"));
|
|
22634
|
-
var
|
|
22635
|
-
var
|
|
22636
|
-
var
|
|
22735
|
+
var import_fs7 = __toESM(require("fs"));
|
|
22736
|
+
var import_os5 = __toESM(require("os"));
|
|
22737
|
+
var import_path18 = __toESM(require("path"));
|
|
22637
22738
|
var SERVICE = "factiii-runner";
|
|
22638
22739
|
var ACCOUNT = "config-encryption-key";
|
|
22639
|
-
var DPAPI_KEY_FILE =
|
|
22640
|
-
|
|
22740
|
+
var DPAPI_KEY_FILE = import_path18.default.join(
|
|
22741
|
+
import_os5.default.homedir(),
|
|
22641
22742
|
".factiii-runner",
|
|
22642
22743
|
"config-key.dpapi"
|
|
22643
22744
|
);
|
|
@@ -22717,7 +22818,7 @@ function linuxWrite(key) {
|
|
|
22717
22818
|
function winRead() {
|
|
22718
22819
|
let wrapped;
|
|
22719
22820
|
try {
|
|
22720
|
-
wrapped =
|
|
22821
|
+
wrapped = import_fs7.default.readFileSync(DPAPI_KEY_FILE, "utf-8").trim();
|
|
22721
22822
|
} catch {
|
|
22722
22823
|
return { state: "missing" };
|
|
22723
22824
|
}
|
|
@@ -22742,8 +22843,8 @@ function winWrite(key) {
|
|
|
22742
22843
|
"-Command",
|
|
22743
22844
|
`ConvertTo-SecureString -String '${key.toString("base64")}' -AsPlainText -Force | ConvertFrom-SecureString`
|
|
22744
22845
|
]);
|
|
22745
|
-
|
|
22746
|
-
|
|
22846
|
+
import_fs7.default.mkdirSync(import_path18.default.dirname(DPAPI_KEY_FILE), { recursive: true });
|
|
22847
|
+
import_fs7.default.writeFileSync(DPAPI_KEY_FILE, `${out.trim()}
|
|
22747
22848
|
`, { mode: 384 });
|
|
22748
22849
|
}
|
|
22749
22850
|
function keychainBackend() {
|
|
@@ -22905,22 +23006,22 @@ function keychainStatus() {
|
|
|
22905
23006
|
|
|
22906
23007
|
// src/secureStore.ts
|
|
22907
23008
|
var import_crypto9 = __toESM(require("crypto"));
|
|
22908
|
-
var
|
|
22909
|
-
var
|
|
23009
|
+
var import_fs8 = __toESM(require("fs"));
|
|
23010
|
+
var import_path20 = __toESM(require("path"));
|
|
22910
23011
|
|
|
22911
23012
|
// src/paths.ts
|
|
22912
|
-
var
|
|
22913
|
-
var
|
|
22914
|
-
var CONFIG_DIR =
|
|
23013
|
+
var import_os6 = __toESM(require("os"));
|
|
23014
|
+
var import_path19 = __toESM(require("path"));
|
|
23015
|
+
var CONFIG_DIR = import_path19.default.join(import_os6.default.homedir(), ".factiii-runner");
|
|
22915
23016
|
function safeSlug(spaceSlug) {
|
|
22916
23017
|
return spaceSlug.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
22917
23018
|
}
|
|
22918
23019
|
function spaceDirPath(spaceSlug) {
|
|
22919
|
-
return
|
|
23020
|
+
return import_path19.default.join(CONFIG_DIR, safeSlug(spaceSlug));
|
|
22920
23021
|
}
|
|
22921
23022
|
|
|
22922
23023
|
// src/secureStore.ts
|
|
22923
|
-
var VAULT_KEY_FILE =
|
|
23024
|
+
var VAULT_KEY_FILE = import_path20.default.join(CONFIG_DIR, "vault-key.json");
|
|
22924
23025
|
var SCRYPT_N2 = 1 << 15;
|
|
22925
23026
|
var MIN_PASSWORD_LENGTH = 8;
|
|
22926
23027
|
var SecureStoreError = class extends Error {
|
|
@@ -22993,7 +23094,7 @@ function unseal(box, key) {
|
|
|
22993
23094
|
function readVaultFile() {
|
|
22994
23095
|
try {
|
|
22995
23096
|
const parsed = JSON.parse(
|
|
22996
|
-
|
|
23097
|
+
import_fs8.default.readFileSync(VAULT_KEY_FILE, "utf-8")
|
|
22997
23098
|
);
|
|
22998
23099
|
return parsed.v === 1 ? parsed : null;
|
|
22999
23100
|
} catch {
|
|
@@ -23001,11 +23102,11 @@ function readVaultFile() {
|
|
|
23001
23102
|
}
|
|
23002
23103
|
}
|
|
23003
23104
|
function writeVaultFile(file) {
|
|
23004
|
-
|
|
23105
|
+
import_fs8.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
23005
23106
|
const tmp = `${VAULT_KEY_FILE}.${process.pid}.tmp`;
|
|
23006
|
-
|
|
23107
|
+
import_fs8.default.writeFileSync(tmp, `${JSON.stringify(file, null, 2)}
|
|
23007
23108
|
`, { mode: 384 });
|
|
23008
|
-
|
|
23109
|
+
import_fs8.default.renameSync(tmp, VAULT_KEY_FILE);
|
|
23009
23110
|
}
|
|
23010
23111
|
var unlockedDek = null;
|
|
23011
23112
|
function createVault(machineKey) {
|
|
@@ -23242,15 +23343,15 @@ function parseEnvelope(raw) {
|
|
|
23242
23343
|
}
|
|
23243
23344
|
}
|
|
23244
23345
|
function atomicWrite(filePath, body) {
|
|
23245
|
-
|
|
23346
|
+
import_fs9.default.mkdirSync(import_path21.default.dirname(filePath), { recursive: true });
|
|
23246
23347
|
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
23247
|
-
|
|
23248
|
-
|
|
23348
|
+
import_fs9.default.writeFileSync(tmp, body, { mode: 384 });
|
|
23349
|
+
import_fs9.default.renameSync(tmp, filePath);
|
|
23249
23350
|
}
|
|
23250
23351
|
function readSecureBuffer(filePath) {
|
|
23251
23352
|
let raw;
|
|
23252
23353
|
try {
|
|
23253
|
-
raw =
|
|
23354
|
+
raw = import_fs9.default.readFileSync(filePath, "utf-8");
|
|
23254
23355
|
} catch {
|
|
23255
23356
|
return null;
|
|
23256
23357
|
}
|
|
@@ -23307,7 +23408,7 @@ function writeSecureJson(filePath, value2) {
|
|
|
23307
23408
|
function readBootJson(filePath) {
|
|
23308
23409
|
let raw;
|
|
23309
23410
|
try {
|
|
23310
|
-
raw =
|
|
23411
|
+
raw = import_fs9.default.readFileSync(filePath, "utf-8");
|
|
23311
23412
|
} catch {
|
|
23312
23413
|
return null;
|
|
23313
23414
|
}
|
|
@@ -23357,8 +23458,8 @@ function writeBootJson(filePath, value2) {
|
|
|
23357
23458
|
}
|
|
23358
23459
|
|
|
23359
23460
|
// src/config.ts
|
|
23360
|
-
var CONFIG_DIR2 =
|
|
23361
|
-
var CONFIG_FILE =
|
|
23461
|
+
var CONFIG_DIR2 = import_path22.default.join(import_os7.default.homedir(), ".factiii-runner");
|
|
23462
|
+
var CONFIG_FILE = import_path22.default.join(CONFIG_DIR2, "config.json");
|
|
23362
23463
|
function readRunnerConfig() {
|
|
23363
23464
|
return readBootJson(CONFIG_FILE);
|
|
23364
23465
|
}
|
|
@@ -23366,7 +23467,7 @@ function writeRunnerConfig(config) {
|
|
|
23366
23467
|
writeBootJson(CONFIG_FILE, config);
|
|
23367
23468
|
}
|
|
23368
23469
|
function configExists() {
|
|
23369
|
-
return
|
|
23470
|
+
return import_fs10.default.existsSync(CONFIG_FILE);
|
|
23370
23471
|
}
|
|
23371
23472
|
|
|
23372
23473
|
// src/promptPassword.ts
|
|
@@ -23459,7 +23560,54 @@ function currentVersion() {
|
|
|
23459
23560
|
return "0.0.0";
|
|
23460
23561
|
}
|
|
23461
23562
|
}
|
|
23563
|
+
function hostSatisfiesTarget() {
|
|
23564
|
+
let engines = "";
|
|
23565
|
+
try {
|
|
23566
|
+
const res = (0, import_node_child_process.spawnSync)(
|
|
23567
|
+
"npm",
|
|
23568
|
+
["view", `${PACKAGE_NAME}@latest`, "engines.node"],
|
|
23569
|
+
{ encoding: "utf-8", shell: process.platform === "win32" }
|
|
23570
|
+
);
|
|
23571
|
+
if (res.status !== 0) return { ok: true, reason: "" };
|
|
23572
|
+
engines = (res.stdout ?? "").trim();
|
|
23573
|
+
} catch {
|
|
23574
|
+
return { ok: true, reason: "" };
|
|
23575
|
+
}
|
|
23576
|
+
if (!engines) return { ok: true, reason: "" };
|
|
23577
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
23578
|
+
if (Number.isNaN(major)) return { ok: true, reason: "" };
|
|
23579
|
+
const min = /(?:>=|\^|~)\s*v?(\d+)/.exec(engines);
|
|
23580
|
+
if (min && major < Number(min[1])) {
|
|
23581
|
+
return {
|
|
23582
|
+
ok: false,
|
|
23583
|
+
reason: `it needs Node ${engines} and this host runs Node ${process.versions.node}`
|
|
23584
|
+
};
|
|
23585
|
+
}
|
|
23586
|
+
const lessThan = /<\s*v?(\d+)/.exec(engines);
|
|
23587
|
+
if (lessThan && major >= Number(lessThan[1])) {
|
|
23588
|
+
return {
|
|
23589
|
+
ok: false,
|
|
23590
|
+
reason: `it needs Node ${engines} and this host runs Node ${process.versions.node}`
|
|
23591
|
+
};
|
|
23592
|
+
}
|
|
23593
|
+
const atMost = /<=\s*v?(\d+)/.exec(engines);
|
|
23594
|
+
if (atMost && major > Number(atMost[1])) {
|
|
23595
|
+
return {
|
|
23596
|
+
ok: false,
|
|
23597
|
+
reason: `it needs Node ${engines} and this host runs Node ${process.versions.node}`
|
|
23598
|
+
};
|
|
23599
|
+
}
|
|
23600
|
+
return { ok: true, reason: "" };
|
|
23601
|
+
}
|
|
23462
23602
|
function installLatest() {
|
|
23603
|
+
const fit = hostSatisfiesTarget();
|
|
23604
|
+
if (!fit.ok) {
|
|
23605
|
+
console.error(
|
|
23606
|
+
`[update] refusing to install ${PACKAGE_NAME}@latest: ${fit.reason}.
|
|
23607
|
+
[update] Staying on ${currentVersion()}. Install a supported Node (nvm install 24.11.1) and restart the runner to update.`
|
|
23608
|
+
);
|
|
23609
|
+
return false;
|
|
23610
|
+
}
|
|
23463
23611
|
console.log(`[update] installing ${PACKAGE_NAME}@latest...`);
|
|
23464
23612
|
const res = (0, import_node_child_process.spawnSync)("npm", ["install", "-g", `${PACKAGE_NAME}@latest`], {
|
|
23465
23613
|
stdio: "inherit",
|
|
@@ -23480,9 +23628,9 @@ var import_node_child_process2 = require("node:child_process");
|
|
|
23480
23628
|
|
|
23481
23629
|
// src/daemon.ts
|
|
23482
23630
|
var import_crypto11 = require("crypto");
|
|
23483
|
-
var
|
|
23631
|
+
var import_fs12 = __toESM(require("fs"));
|
|
23484
23632
|
var import_node_datachannel = require("node-datachannel");
|
|
23485
|
-
var
|
|
23633
|
+
var import_path24 = __toESM(require("path"));
|
|
23486
23634
|
|
|
23487
23635
|
// ../../node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.node.js
|
|
23488
23636
|
var XMLHttpRequestModule = __toESM(require_XMLHttpRequest(), 1);
|
|
@@ -26981,18 +27129,18 @@ Object.assign(lookup, {
|
|
|
26981
27129
|
});
|
|
26982
27130
|
|
|
26983
27131
|
// src/agent-adapter.ts
|
|
26984
|
-
var
|
|
26985
|
-
var
|
|
27132
|
+
var import_fs11 = __toESM(require("fs"));
|
|
27133
|
+
var import_path23 = __toESM(require("path"));
|
|
26986
27134
|
function credsDir(spaceSlug) {
|
|
26987
|
-
return
|
|
27135
|
+
return import_path23.default.join(spaceDirPath(spaceSlug), ".creds");
|
|
26988
27136
|
}
|
|
26989
27137
|
function githubPath(spaceSlug) {
|
|
26990
|
-
return
|
|
27138
|
+
return import_path23.default.join(credsDir(spaceSlug), "github.json");
|
|
26991
27139
|
}
|
|
26992
27140
|
function connectionPath(spaceSlug) {
|
|
26993
|
-
return
|
|
27141
|
+
return import_path23.default.join(credsDir(spaceSlug), "onedrive.json");
|
|
26994
27142
|
}
|
|
26995
|
-
var RUNNER_CONFIG_PATH =
|
|
27143
|
+
var RUNNER_CONFIG_PATH = import_path23.default.join(CONFIG_DIR, "runner-config.json");
|
|
26996
27144
|
function writeJson(filePath, value2) {
|
|
26997
27145
|
writeSecureJson(filePath, value2);
|
|
26998
27146
|
}
|
|
@@ -27008,14 +27156,14 @@ function fillDefaults(config) {
|
|
|
27008
27156
|
}
|
|
27009
27157
|
function configDirNames() {
|
|
27010
27158
|
try {
|
|
27011
|
-
return
|
|
27159
|
+
return import_fs11.default.readdirSync(CONFIG_DIR, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
27012
27160
|
} catch {
|
|
27013
27161
|
return [];
|
|
27014
27162
|
}
|
|
27015
27163
|
}
|
|
27016
27164
|
function provisionedSpaceSlugs() {
|
|
27017
27165
|
return configDirNames().filter(
|
|
27018
|
-
(name) =>
|
|
27166
|
+
(name) => import_fs11.default.existsSync(import_path23.default.join(CONFIG_DIR, name, "bin"))
|
|
27019
27167
|
);
|
|
27020
27168
|
}
|
|
27021
27169
|
var migrated = false;
|
|
@@ -27029,7 +27177,7 @@ function migrateToSpaceFolders() {
|
|
|
27029
27177
|
}
|
|
27030
27178
|
}
|
|
27031
27179
|
function readLegacy(filePath) {
|
|
27032
|
-
if (!
|
|
27180
|
+
if (!import_fs11.default.existsSync(filePath)) return { readable: true, value: null };
|
|
27033
27181
|
const value2 = readSecureJson(filePath);
|
|
27034
27182
|
return { readable: value2 !== null, value: value2 };
|
|
27035
27183
|
}
|
|
@@ -27047,14 +27195,14 @@ function migrateOnce() {
|
|
|
27047
27195
|
const consumed = [];
|
|
27048
27196
|
let strayFiles = [];
|
|
27049
27197
|
try {
|
|
27050
|
-
strayFiles =
|
|
27198
|
+
strayFiles = import_fs11.default.readdirSync(CONFIG_DIR).filter((f) => f.startsWith("space-") && f.endsWith(".json")).filter((f) => !f.endsWith(".onedrive.json"));
|
|
27051
27199
|
} catch {
|
|
27052
27200
|
strayFiles = [];
|
|
27053
27201
|
}
|
|
27054
27202
|
for (const name of strayFiles) {
|
|
27055
27203
|
const slug = name.slice("space-".length, -".json".length);
|
|
27056
27204
|
const parsed = readLegacy(
|
|
27057
|
-
|
|
27205
|
+
import_path23.default.join(CONFIG_DIR, name)
|
|
27058
27206
|
);
|
|
27059
27207
|
if (!parsed.readable) continue;
|
|
27060
27208
|
if (parsed.value) strays[slug] = parsed.value;
|
|
@@ -27067,7 +27215,7 @@ function migrateOnce() {
|
|
|
27067
27215
|
...provisionedSpaceSlugs()
|
|
27068
27216
|
]);
|
|
27069
27217
|
for (const slug of slugs) {
|
|
27070
|
-
if (
|
|
27218
|
+
if (import_fs11.default.existsSync(githubPath(slug))) continue;
|
|
27071
27219
|
const over = boards[slug] ?? strays[slug] ?? {};
|
|
27072
27220
|
if (!Object.keys(over).length && !Object.keys(base).length) continue;
|
|
27073
27221
|
const merged = fillDefaults({
|
|
@@ -27078,32 +27226,32 @@ function migrateOnce() {
|
|
|
27078
27226
|
githubToken: over.githubToken || base.githubToken,
|
|
27079
27227
|
provider: over.provider || base.provider
|
|
27080
27228
|
});
|
|
27081
|
-
|
|
27229
|
+
import_fs11.default.mkdirSync(credsDir(slug), { recursive: true });
|
|
27082
27230
|
writeJson(githubPath(slug), merged);
|
|
27083
27231
|
}
|
|
27084
27232
|
let odFiles = [];
|
|
27085
27233
|
try {
|
|
27086
|
-
odFiles =
|
|
27234
|
+
odFiles = import_fs11.default.readdirSync(CONFIG_DIR).filter((f) => f.startsWith("space-") && f.endsWith(".onedrive.json"));
|
|
27087
27235
|
} catch {
|
|
27088
27236
|
odFiles = [];
|
|
27089
27237
|
}
|
|
27090
27238
|
for (const name of odFiles) {
|
|
27091
27239
|
const slug = name.slice("space-".length, -".onedrive.json".length);
|
|
27092
|
-
if (
|
|
27240
|
+
if (import_fs11.default.existsSync(connectionPath(slug))) {
|
|
27093
27241
|
consumed.push(name);
|
|
27094
27242
|
continue;
|
|
27095
27243
|
}
|
|
27096
|
-
const conn = readLegacy(
|
|
27244
|
+
const conn = readLegacy(import_path23.default.join(CONFIG_DIR, name));
|
|
27097
27245
|
if (!conn.readable) continue;
|
|
27098
27246
|
if (conn.value) {
|
|
27099
|
-
|
|
27247
|
+
import_fs11.default.mkdirSync(credsDir(slug), { recursive: true });
|
|
27100
27248
|
writeJson(connectionPath(slug), conn.value);
|
|
27101
27249
|
}
|
|
27102
27250
|
consumed.push(name);
|
|
27103
27251
|
}
|
|
27104
27252
|
for (const name of [...consumed, "runner-config.json"]) {
|
|
27105
27253
|
try {
|
|
27106
|
-
|
|
27254
|
+
import_fs11.default.rmSync(import_path23.default.join(CONFIG_DIR, name), { force: true });
|
|
27107
27255
|
} catch {
|
|
27108
27256
|
}
|
|
27109
27257
|
}
|
|
@@ -27115,14 +27263,14 @@ function encryptStrayPlaintextConfigs() {
|
|
|
27115
27263
|
const OURS = /^(config|runner-config|space-.*)\.json(\.bak-\d+)?$/;
|
|
27116
27264
|
let names = [];
|
|
27117
27265
|
try {
|
|
27118
|
-
names =
|
|
27266
|
+
names = import_fs11.default.readdirSync(CONFIG_DIR).filter((f) => OURS.test(f));
|
|
27119
27267
|
} catch {
|
|
27120
27268
|
return;
|
|
27121
27269
|
}
|
|
27122
27270
|
for (const name of names) {
|
|
27123
|
-
const filePath =
|
|
27271
|
+
const filePath = import_path23.default.join(CONFIG_DIR, name);
|
|
27124
27272
|
try {
|
|
27125
|
-
const raw =
|
|
27273
|
+
const raw = import_fs11.default.readFileSync(filePath, "utf-8");
|
|
27126
27274
|
if (!raw.startsWith("{")) continue;
|
|
27127
27275
|
writeSecureJson(filePath, JSON.parse(raw));
|
|
27128
27276
|
} catch {
|
|
@@ -27145,7 +27293,7 @@ async function getConfiguredConnections() {
|
|
|
27145
27293
|
for (const slug of listConfiguredSlugs()) {
|
|
27146
27294
|
if (kinds.has("git") && kinds.has("onedrive")) break;
|
|
27147
27295
|
if (readBoard(slug).githubToken) kinds.add("git");
|
|
27148
|
-
if (
|
|
27296
|
+
if (import_fs11.default.existsSync(connectionPath(slug))) kinds.add("onedrive");
|
|
27149
27297
|
}
|
|
27150
27298
|
} catch {
|
|
27151
27299
|
return [];
|
|
@@ -27157,7 +27305,7 @@ function listConfiguredSlugs() {
|
|
|
27157
27305
|
try {
|
|
27158
27306
|
migrateToSpaceFolders();
|
|
27159
27307
|
return configDirNames().filter(
|
|
27160
|
-
(slug) =>
|
|
27308
|
+
(slug) => import_fs11.default.existsSync(githubPath(slug)) || import_fs11.default.existsSync(connectionPath(slug))
|
|
27161
27309
|
);
|
|
27162
27310
|
} catch {
|
|
27163
27311
|
return [];
|
|
@@ -27176,7 +27324,7 @@ var localConfigProvider = {
|
|
|
27176
27324
|
// which is what makes disconnect stick.
|
|
27177
27325
|
writeConfig(spaceSlug, config) {
|
|
27178
27326
|
migrateToSpaceFolders();
|
|
27179
|
-
|
|
27327
|
+
import_fs11.default.mkdirSync(credsDir(spaceSlug), { recursive: true });
|
|
27180
27328
|
writeJson(githubPath(spaceSlug), config);
|
|
27181
27329
|
},
|
|
27182
27330
|
readOneDriveConnection(spaceSlug) {
|
|
@@ -27190,7 +27338,7 @@ var localConfigProvider = {
|
|
|
27190
27338
|
writeOneDriveConnection(spaceSlug, connection) {
|
|
27191
27339
|
const filePath = connectionPath(spaceSlug);
|
|
27192
27340
|
if (!connection) {
|
|
27193
|
-
|
|
27341
|
+
import_fs11.default.rmSync(filePath, { force: true });
|
|
27194
27342
|
return;
|
|
27195
27343
|
}
|
|
27196
27344
|
writeJson(filePath, connection);
|
|
@@ -27215,7 +27363,7 @@ var localConfigProvider = {
|
|
|
27215
27363
|
"claude",
|
|
27216
27364
|
"codex"
|
|
27217
27365
|
]) {
|
|
27218
|
-
|
|
27366
|
+
import_fs11.default.mkdirSync(import_path23.default.join(dir, sub), { recursive: true });
|
|
27219
27367
|
}
|
|
27220
27368
|
return dir;
|
|
27221
27369
|
}
|
|
@@ -27389,15 +27537,15 @@ async function startDaemon(config) {
|
|
|
27389
27537
|
}
|
|
27390
27538
|
);
|
|
27391
27539
|
const indexCandidates = [
|
|
27392
|
-
|
|
27393
|
-
|
|
27540
|
+
import_path24.default.join(__dirname, "..", "index"),
|
|
27541
|
+
import_path24.default.join(__dirname, "..", "..", "index", "image")
|
|
27394
27542
|
];
|
|
27395
|
-
const indexDir = indexCandidates.find((p) =>
|
|
27543
|
+
const indexDir = indexCandidates.find((p) => import_fs12.default.existsSync(p)) ?? indexCandidates[0];
|
|
27396
27544
|
const odIndex = new IndexService({
|
|
27397
27545
|
controlToken: (0, import_crypto11.createHash)("sha256").update(config.authToken).digest("hex"),
|
|
27398
27546
|
embedUrl: () => config.serverUrl,
|
|
27399
27547
|
indexDir,
|
|
27400
|
-
dataDir:
|
|
27548
|
+
dataDir: import_path24.default.join(CONFIG_DIR, "index-data")
|
|
27401
27549
|
});
|
|
27402
27550
|
void odIndex.ensureRunning().catch((err) => {
|
|
27403
27551
|
console.error(
|
|
@@ -28013,27 +28161,24 @@ ${err.fix}`);
|
|
|
28013
28161
|
console.error("");
|
|
28014
28162
|
process.exit(1);
|
|
28015
28163
|
}
|
|
28016
|
-
|
|
28017
|
-
|
|
28018
|
-
const
|
|
28019
|
-
|
|
28020
|
-
console.error(
|
|
28164
|
+
function warnUnsupportedNode() {
|
|
28165
|
+
if (indexNodeSupported()) return;
|
|
28166
|
+
const alternative = findIndexNode();
|
|
28167
|
+
console.warn(
|
|
28021
28168
|
`
|
|
28022
|
-
|
|
28023
|
-
The
|
|
28024
|
-
|
|
28025
|
-
|
|
28026
|
-
|
|
28027
|
-
`
|
|
28169
|
+
Node ${process.versions.node} is outside the range the OneDrive index supports (${MIN_INDEX_NODE_MAJOR}-${MAX_INDEX_NODE_MAJOR}, pinned 24.11.1).` + (alternative ? `
|
|
28170
|
+
The index will run under ${alternative}. Everything else is unaffected.
|
|
28171
|
+
` : `
|
|
28172
|
+
OneDrive search will be unavailable until a supported Node is installed (nvm install 24.11.1). Everything else works.
|
|
28173
|
+
`)
|
|
28028
28174
|
);
|
|
28029
|
-
process.exit(1);
|
|
28030
28175
|
}
|
|
28031
28176
|
import_node_dns.default.setDefaultResultOrder("ipv4first");
|
|
28032
28177
|
var program2 = new Command();
|
|
28033
28178
|
program2.name("factiii-runner").description("Factiii Runner - run Board AI agents on remote servers").version(currentVersion());
|
|
28034
28179
|
program2.command("setup").description("Verify the host toolchain and pair this runner").option("-s, --server <url>", "API server URL", "https://api.factiii.com").action(async (opts) => {
|
|
28035
28180
|
try {
|
|
28036
|
-
|
|
28181
|
+
warnUnsupportedNode();
|
|
28037
28182
|
await setup(opts.server);
|
|
28038
28183
|
} catch (err) {
|
|
28039
28184
|
console.error(
|
|
@@ -28062,7 +28207,7 @@ program2.command("connect").description("Pair this runner with a Factiii account
|
|
|
28062
28207
|
}
|
|
28063
28208
|
});
|
|
28064
28209
|
program2.command("start").description("Start the runner daemon").action(async () => {
|
|
28065
|
-
|
|
28210
|
+
warnUnsupportedNode();
|
|
28066
28211
|
if (!configExists()) {
|
|
28067
28212
|
console.error('No config found. Run "factiii-runner setup" first.');
|
|
28068
28213
|
process.exit(1);
|
|
@@ -28108,8 +28253,7 @@ program2.command("status").description("Show current runner configuration").acti
|
|
|
28108
28253
|
console.log(`Token: \xB7\xB7\xB7\xB7${config.authToken.slice(-4)}`);
|
|
28109
28254
|
});
|
|
28110
28255
|
program2.command("doctor").description("Show where each host tool resolves, for a failed environment").action(async () => {
|
|
28111
|
-
const
|
|
28112
|
-
const nodeNote = nodeMajor > MAX_SUPPORTED_NODE_MAJOR ? " (UNSUPPORTED \u2014 use 24.11.1)" : "";
|
|
28256
|
+
const nodeNote = indexNodeSupported() ? "" : ` (OneDrive index needs ${MIN_INDEX_NODE_MAJOR}-${MAX_INDEX_NODE_MAJOR}; ${findIndexNode() ?? "no supported node found"})`;
|
|
28113
28257
|
console.log(`${"node".padEnd(14)} ${process.execPath} v${process.versions.node}${nodeNote}`);
|
|
28114
28258
|
const report = await reportToolchain(hostTarget(CONFIG_DIR));
|
|
28115
28259
|
for (const tool of report.tools) {
|
package/package.json
CHANGED