@outerlayer/cli 0.5.1 → 0.7.0
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/CHANGELOG.md +29 -0
- package/README.md +19 -0
- package/dist/{agent-setup-IFH3FB5X.js → agent-setup-TXLDY5RV.js} +7 -6
- package/dist/{build-PAEKVYVK.js → build-JF5UOWKJ.js} +2 -1
- package/dist/build-info.json +1 -1
- package/dist/{check-4Q33B5ZE.js → check-ASZL5BEO.js} +39 -23
- package/dist/chunk-2VO25HHO.js +75 -0
- package/dist/{chunk-XDDW4FRS.js → chunk-5FWNEQNZ.js} +3 -3
- package/dist/{chunk-CHLVJNTE.js → chunk-6IYLDODX.js} +18 -6
- package/dist/{chunk-W7UTFZDH.js → chunk-6QWV3YDJ.js} +2 -2
- package/dist/{chunk-EGABNHZG.js → chunk-6ZZHWY2Z.js} +149 -18
- package/dist/{lima-XN65D7GN.js → chunk-77MM5RYD.js} +0 -1
- package/dist/chunk-7FTNIAHS.js +211 -0
- package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
- package/dist/{chunk-F4NU4H3V.js → chunk-AII7CKTH.js} +133 -35
- package/dist/{chunk-ZXBITXTS.js → chunk-AIW6GLET.js} +1 -1
- package/dist/{chunk-UWH5DSUP.js → chunk-AJKEHABI.js} +507 -90
- package/dist/{chunk-RTXKYLCA.js → chunk-AQ54MKSQ.js} +2 -2
- package/dist/{chunk-Z62HNKEJ.js → chunk-CEBIA5FD.js} +31 -5
- package/dist/{chunk-EX6M5JPR.js → chunk-D6FXM5OW.js} +6302 -28611
- package/dist/{chunk-RMAZ2NWA.js → chunk-DGAIVMMN.js} +23 -2
- package/dist/{chunk-3DD6AOWC.js → chunk-DTXOJDEH.js} +26 -2
- package/dist/{chunk-T52PKE2Y.js → chunk-E4PIFIC3.js} +244 -17
- package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
- package/dist/chunk-FBTE2A2X.js +38 -0
- package/dist/{chunk-DVDEBNQJ.js → chunk-GQD22KKN.js} +17 -6
- package/dist/{chunk-BCJNHMZT.js → chunk-HHJDN6AU.js} +18 -3
- package/dist/chunk-HKMPVPO7.js +55 -0
- package/dist/{chunk-UFFXNXLQ.js → chunk-JPR2WHHF.js} +31 -29
- package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
- package/dist/{chunk-H4CK2YK4.js → chunk-MQPRB5K7.js} +18 -10
- package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
- package/dist/chunk-OUUINEYB.js +27 -0
- package/dist/chunk-PUN7LMNS.js +39 -0
- package/dist/{install-cmd-7WXOIFDO.js → chunk-Q5G2ODUZ.js} +1 -2
- package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
- package/dist/{chunk-OR6AEEDO.js → chunk-SSU747O6.js} +85 -25
- package/dist/chunk-T6OIJQRT.js +31 -0
- package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
- package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
- package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
- package/dist/{chunk-JLDZTG3A.js → chunk-X2FSFU4C.js} +4 -1
- package/dist/chunk-YNJEOGDL.js +22434 -0
- package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
- package/dist/{chunk-WOBNRVQT.js → chunk-ZYHKJKSU.js} +1 -1
- package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
- package/dist/{cli-LHSUYYMI.js → cli-LEVCGAQV.js} +154 -79
- package/dist/command-FLSYCGIB.js +187 -0
- package/dist/config-I3TVFYLH.js +10 -0
- package/dist/{connect-cmd-OJBFHZWP.js → connect-cmd-MJMUONDY.js} +4 -4
- package/dist/{context-adopt-UMA4O5NY.js → context-adopt-CE4KDXS3.js} +5 -4
- package/dist/{context-materialize-G2FUFC72.js → context-materialize-QL33HDJN.js} +5 -4
- package/dist/{dist-WDV7U7UJ.js → dist-PXBSA7QX.js} +2 -1
- package/dist/{doctor-MOA3RIEP.js → doctor-FVDT3KJZ.js} +46 -19
- package/dist/{emit-artifact-cmd-FDWYKURA.js → emit-artifact-cmd-7RPMRSVP.js} +13 -7
- package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
- package/dist/{emit-criteria-cmd-OCXHLK34.js → emit-criteria-cmd-MKI7WETO.js} +12 -3
- package/dist/{emit-finding-cmd-POW7PKIA.js → emit-finding-cmd-RMLGZASB.js} +14 -3
- package/dist/{emit-result-cmd-ID35SH53.js → emit-result-cmd-MTXAZ2GV.js} +15 -9
- package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
- package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
- package/dist/{hook-fast-EYENPK6F.js → hook-fast-XBOZ3N6L.js} +1 -1
- package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
- package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
- package/dist/index.js +3 -2
- package/dist/{init-FYDJAKTM.js → init-BACXESVV.js} +21 -14
- package/dist/{init-2IPOIXJV.js → init-VLW7H6RW.js} +40 -62
- package/dist/{init-cmd-KLIDRVXQ.js → init-cmd-VJFB5L7X.js} +10 -9
- package/dist/inspect-XAUSB7L3.js +63 -0
- package/dist/install-NMAPLLBQ.js +14 -0
- package/dist/install-cmd-B5SEU3G7.js +8 -0
- package/dist/lima-7NPCNGWT.js +6 -0
- package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
- package/dist/loop-D3243JKT.js +64 -0
- package/dist/{machine-ECU3QCZD.js → machine-EB3GEVI4.js} +20 -13
- package/dist/session-sender-LMACEJJS.js +29 -0
- package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
- package/dist/{status-CLATHCTQ.js → status-F4THTJJK.js} +36 -16
- package/dist/{sync-cmd-SWQ5KLPL.js → sync-cmd-M6JA3OEE.js} +7 -7
- package/dist/{watch-3YW6Z3DQ.js → watch-NB5TGPEZ.js} +7 -7
- package/dist/{work-claim-cmd-3OPWA77E.js → work-claim-cmd-UHMWOS3G.js} +14 -7
- package/dist/{work-cmd-NUR4CAG6.js → work-cmd-6UMCFTAW.js} +9 -3
- package/dist/{work-comment-cmd-6TTTYGHM.js → work-comment-cmd-E4LEUIXZ.js} +9 -3
- package/dist/{work-launch-YI4CJDAP.js → work-launch-R5HTAP6X.js} +1 -1
- package/dist/{work-open-pr-cmd-KZ7QQFLD.js → work-open-pr-cmd-OPZWGSEQ.js} +10 -4
- package/dist/{work-pr-cmd-QNUBE6IQ.js → work-pr-cmd-IDIAFFRU.js} +9 -2
- package/package.json +2 -1
- package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
- package/dist/chunk-D2KWEAN6.js +0 -55
- package/dist/chunk-ZOC7JSYC.js +0 -83
- package/dist/config-HL2AIR3K.js +0 -9
- package/dist/loop-NEBUGD2Q.js +0 -45
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
|
|
4
|
+
createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
// src/runner/commit-identity.ts
|
|
7
|
+
var NOREPLY_SUFFIX = "@users.noreply.github.com";
|
|
8
|
+
var MAX_LENGTH = 200;
|
|
9
|
+
function parseIdentity(value) {
|
|
10
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
11
|
+
const { name, email } = value;
|
|
12
|
+
if (typeof name !== "string" || typeof email !== "string") return void 0;
|
|
13
|
+
if (name.trim() === "" || name.length > MAX_LENGTH || /[\r\n\0<>]/.test(name)) return void 0;
|
|
14
|
+
if (email.length > MAX_LENGTH || !email.endsWith(NOREPLY_SUFFIX) || /[\s\0<>]/.test(email) || email.length === NOREPLY_SUFFIX.length) return void 0;
|
|
15
|
+
return { name, email };
|
|
16
|
+
}
|
|
17
|
+
function parseClaimIdentity(data) {
|
|
18
|
+
const author = parseIdentity(data.commitAuthor);
|
|
19
|
+
if (author === void 0) return void 0;
|
|
20
|
+
const coAuthor = parseIdentity(data.coAuthor);
|
|
21
|
+
return coAuthor === void 0 ? { author } : { author, coAuthor };
|
|
22
|
+
}
|
|
23
|
+
function authorEnvironment(identity) {
|
|
24
|
+
if (identity === void 0) return {};
|
|
25
|
+
return {
|
|
26
|
+
GIT_AUTHOR_NAME: identity.name,
|
|
27
|
+
GIT_AUTHOR_EMAIL: identity.email,
|
|
28
|
+
GIT_COMMITTER_NAME: identity.name,
|
|
29
|
+
GIT_COMMITTER_EMAIL: identity.email
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function configCount(env) {
|
|
33
|
+
const raw = String(env.GIT_CONFIG_COUNT);
|
|
34
|
+
return /^[0-9]+$/.test(raw) ? Number(raw) : 0;
|
|
35
|
+
}
|
|
36
|
+
function withGitConfig(env, key, value) {
|
|
37
|
+
const at = configCount(env);
|
|
38
|
+
return {
|
|
39
|
+
...env,
|
|
40
|
+
GIT_CONFIG_COUNT: String(at + 1),
|
|
41
|
+
[`GIT_CONFIG_KEY_${at}`]: key,
|
|
42
|
+
[`GIT_CONFIG_VALUE_${at}`]: value
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function withHooksPath(env, dir) {
|
|
46
|
+
return withGitConfig(env, "core.hooksPath", dir);
|
|
47
|
+
}
|
|
48
|
+
function commitIdentityRecord(identity) {
|
|
49
|
+
return {
|
|
50
|
+
author: identity === void 0 ? "host" : "app",
|
|
51
|
+
coAuthor: identity?.coAuthor !== void 0 && identity.hooksPath !== void 0 ? "credited" : "none"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { authorEnvironment, commitIdentityRecord, parseClaimIdentity, withGitConfig, withHooksPath };
|
|
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-XCCLFVXM.js';
|
|
4
4
|
import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
5
5
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
6
|
-
import { readFileSync, mkdirSync, writeFileSync, renameSync, existsSync, statSync, appendFileSync,
|
|
6
|
+
import { readFileSync, mkdirSync, writeFileSync, renameSync, existsSync, statSync, appendFileSync, opendirSync, unlinkSync } from 'fs';
|
|
7
7
|
import { spawn, execFileSync } from 'child_process';
|
|
8
8
|
import { createHash } from 'crypto';
|
|
9
9
|
import { join, dirname, resolve } from 'path';
|
|
@@ -347,18 +347,11 @@ var readStdin = () => {
|
|
|
347
347
|
}
|
|
348
348
|
};
|
|
349
349
|
var AUTO_SYNC_DEBOUNCE_MS = 5 * 60 * 1e3;
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
return openSync(path, "a");
|
|
354
|
-
} catch {
|
|
355
|
-
return "ignore";
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
var spawnDetached = (command, args, stderrPath, cwd) => {
|
|
350
|
+
var LOG_FAILURES_FLAG = "--log-failures";
|
|
351
|
+
var spawnDetached = (command, args, cwd) => {
|
|
359
352
|
const child = spawn(command, args, {
|
|
360
353
|
detached: true,
|
|
361
|
-
stdio: ["ignore", "ignore",
|
|
354
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
362
355
|
...cwd !== void 0 ? { cwd } : {}
|
|
363
356
|
});
|
|
364
357
|
child.on("error", () => {
|
|
@@ -382,7 +375,7 @@ function maybeAutoSync(event, home = homeFromEnv(), spawnImpl = spawnDetached, n
|
|
|
382
375
|
if (!config.appId) return;
|
|
383
376
|
} else if (!config.accountToken || readRepoConnection(cwd) === void 0) return;
|
|
384
377
|
writeFileSync(marker, String(now));
|
|
385
|
-
spawnImpl(process.execPath, [process.argv[1], "sync", "--quiet"],
|
|
378
|
+
spawnImpl(process.execPath, [process.argv[1], "sync", "--quiet"], cwd);
|
|
386
379
|
} catch {
|
|
387
380
|
}
|
|
388
381
|
}
|
|
@@ -395,13 +388,13 @@ function hookErrorsContext(home, writtenBytes, seenBytes) {
|
|
|
395
388
|
}
|
|
396
389
|
async function handleWorkLaunch(sessionId, home, env, spawnImpl = spawnDetached, cwd = process.cwd()) {
|
|
397
390
|
if (!sessionId || env.OUTERLAYER_WORK === void 0) return void 0;
|
|
398
|
-
const { parseWorkItemEnv, appendLaunchRecord } = await import('./work-launch-
|
|
391
|
+
const { parseWorkItemEnv, appendLaunchRecord } = await import('./work-launch-R5HTAP6X.js');
|
|
399
392
|
const parsed = parseWorkItemEnv(env.OUTERLAYER_WORK);
|
|
400
393
|
if ("reason" in parsed) {
|
|
401
394
|
logHookError(home, new Error(`OUTERLAYER_WORK ignored: ${parsed.reason}`));
|
|
402
395
|
return `OuterLayer ignored this session's OUTERLAYER_WORK value: ${sanitizeForContext(parsed.reason)}. The session is not attached to a work item and will not upload. Hook failures are logged to ${join(spoolDir(home), "hook-errors.log")}.`;
|
|
403
396
|
}
|
|
404
|
-
appendLaunchRecord({ sessionId, item: parsed.number }, home);
|
|
397
|
+
appendLaunchRecord({ sessionId, item: parsed.number, ...env.OUTERLAYER_JOB_DIR === void 0 ? {} : { job: env.OUTERLAYER_JOB_DIR } }, home);
|
|
405
398
|
const args = [
|
|
406
399
|
process.argv[1],
|
|
407
400
|
"work",
|
|
@@ -417,17 +410,16 @@ async function handleWorkLaunch(sessionId, home, env, spawnImpl = spawnDetached,
|
|
|
417
410
|
// hook has already returned) and cannot double-link, because the
|
|
418
411
|
// link is keyed by the session id passed above.
|
|
419
412
|
"--retry",
|
|
420
|
-
String(WORK_LINK_RETRIES)
|
|
413
|
+
String(WORK_LINK_RETRIES),
|
|
414
|
+
LOG_FAILURES_FLAG
|
|
421
415
|
];
|
|
422
416
|
if (env.OUTERLAYER_JOB_DIR !== void 0) args.push("--no-lease");
|
|
423
417
|
spawnImpl(
|
|
424
418
|
process.execPath,
|
|
425
419
|
args,
|
|
426
|
-
// The link
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
// no trace of why.
|
|
430
|
-
join(spoolDir(home), "hook-errors.log"),
|
|
420
|
+
// The link appends its own failure line to hook-errors.log (see
|
|
421
|
+
// `--log-failures`), so a Node warning on a link that worked never
|
|
422
|
+
// reaches the log.
|
|
431
423
|
cwd
|
|
432
424
|
);
|
|
433
425
|
return void 0;
|
|
@@ -456,30 +448,28 @@ async function maybeRenewWorkLease(event, sessionId, home = homeFromEnv(), env =
|
|
|
456
448
|
if (now - statSync(marker).mtimeMs < WORK_LEASE_RENEW_DEBOUNCE_MS) return;
|
|
457
449
|
} catch {
|
|
458
450
|
}
|
|
459
|
-
const { parseWorkItemEnv } = await import('./work-launch-
|
|
451
|
+
const { parseWorkItemEnv } = await import('./work-launch-R5HTAP6X.js');
|
|
460
452
|
const parsed = parseWorkItemEnv(env.OUTERLAYER_WORK);
|
|
461
453
|
if ("reason" in parsed) return;
|
|
462
454
|
writeFileSync(marker, String(now));
|
|
463
455
|
spawnImpl(
|
|
464
456
|
process.execPath,
|
|
465
|
-
[process.argv[1], "work", "link-session", String(parsed.number), "--session-id", sessionId],
|
|
466
|
-
join(spoolDir(home), "hook-errors.log"),
|
|
457
|
+
[process.argv[1], "work", "link-session", String(parsed.number), "--session-id", sessionId, LOG_FAILURES_FLAG],
|
|
467
458
|
cwd
|
|
468
459
|
);
|
|
469
460
|
} catch {
|
|
470
461
|
}
|
|
471
462
|
}
|
|
472
|
-
async function handleWorkSessionEnd(event, sessionId,
|
|
463
|
+
async function handleWorkSessionEnd(event, sessionId, _home = homeFromEnv(), env = process.env, spawnImpl = spawnDetached, cwd = process.cwd()) {
|
|
473
464
|
try {
|
|
474
465
|
if (event !== "SessionEnd") return;
|
|
475
466
|
if (!sessionId || env.OUTERLAYER_WORK === void 0) return;
|
|
476
|
-
const { parseWorkItemEnv } = await import('./work-launch-
|
|
467
|
+
const { parseWorkItemEnv } = await import('./work-launch-R5HTAP6X.js');
|
|
477
468
|
const parsed = parseWorkItemEnv(env.OUTERLAYER_WORK);
|
|
478
469
|
if ("reason" in parsed) return;
|
|
479
470
|
spawnImpl(
|
|
480
471
|
process.execPath,
|
|
481
|
-
[process.argv[1], "work", "link-session", String(parsed.number), "--session-id", sessionId, "--ended"],
|
|
482
|
-
join(spoolDir(home), "hook-errors.log"),
|
|
472
|
+
[process.argv[1], "work", "link-session", String(parsed.number), "--session-id", sessionId, "--ended", LOG_FAILURES_FLAG],
|
|
483
473
|
cwd
|
|
484
474
|
);
|
|
485
475
|
} catch {
|
|
@@ -638,7 +628,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
638
628
|
recordHookErrorsSeen(home, hookErrorsBytes);
|
|
639
629
|
if (contextPossiblyGoverned(sessionCwd, home)) {
|
|
640
630
|
try {
|
|
641
|
-
const { materializeContext: materialize } = await import('./context-materialize-
|
|
631
|
+
const { materializeContext: materialize } = await import('./context-materialize-QL33HDJN.js');
|
|
642
632
|
const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
|
|
643
633
|
const result = await materialize({ cwd: sessionCwd, sessionId, home });
|
|
644
634
|
materializeMessage = result.message;
|
|
@@ -677,7 +667,9 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
677
667
|
logHookError(home, err);
|
|
678
668
|
}
|
|
679
669
|
}
|
|
670
|
+
var hookErrorsLogged = 0;
|
|
680
671
|
function logHookError(home, err) {
|
|
672
|
+
hookErrorsLogged++;
|
|
681
673
|
try {
|
|
682
674
|
const dir = spoolDir(home);
|
|
683
675
|
mkdirSync(dir, { recursive: true });
|
|
@@ -690,5 +682,15 @@ function logHookError(home, err) {
|
|
|
690
682
|
} catch {
|
|
691
683
|
}
|
|
692
684
|
}
|
|
685
|
+
function recordLinkExitFailure(argv, home = homeFromEnv(), target = process) {
|
|
686
|
+
const at = argv.indexOf("link-session");
|
|
687
|
+
if (at < 0 || !argv.includes(LOG_FAILURES_FLAG)) return;
|
|
688
|
+
const number = argv[at + 1] ?? "?";
|
|
689
|
+
target.once("exit", (code) => {
|
|
690
|
+
if (code !== 0 && hookErrorsLogged === 0) {
|
|
691
|
+
logHookError(home, new Error(`work link-session #${number} exited with code ${code} before it reported a failure`));
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
693
695
|
|
|
694
|
-
export { AUTO_SYNC_DEBOUNCE_MS, SYNC_STALE_AFTER_MS, WORK_LEASE_RENEW_DEBOUNCE_MS, WORK_LINK_RETRIES, assessSyncHealth, checkInstalledCliStaleness, contextPossiblyGoverned, formatAgo, handleWorkLaunch, handleWorkSessionEnd, hookFiredMarkerPath, installedCliDistDir, maybeAutoSync, maybeRenewWorkLease, readSyncStatus, refreshCommand, runHookFast, sanitizeForContext, spoolDir, workspaceRootOf, writeSyncStatus };
|
|
696
|
+
export { AUTO_SYNC_DEBOUNCE_MS, SYNC_STALE_AFTER_MS, WORK_LEASE_RENEW_DEBOUNCE_MS, WORK_LINK_RETRIES, assessSyncHealth, checkInstalledCliStaleness, contextPossiblyGoverned, formatAgo, handleWorkLaunch, handleWorkSessionEnd, hookFiredMarkerPath, installedCliDistDir, logHookError, maybeAutoSync, maybeRenewWorkLease, readSyncStatus, recordLinkExitFailure, refreshCommand, runHookFast, sanitizeForContext, spoolDir, workspaceRootOf, writeSyncStatus };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { C } from './chunk-YRYMNBGQ.js';
|
|
4
|
-
import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-
|
|
4
|
+
import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-VXLJORHL.js';
|
|
5
5
|
import { resolvePackageVersion } from './chunk-RA3O54FC.js';
|
|
6
6
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
7
7
|
import { join, dirname } from 'path';
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { isLinkedRepository } from './chunk-D2KWEAN6.js';
|
|
4
3
|
import { readStatuslineState, STATE_FRESH_MS } from './chunk-F47JBIAW.js';
|
|
5
|
-
import { resolveCredentials, getJson, WorkCommandError } from './chunk-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { resolveCredentials, getJson, WorkCommandError } from './chunk-DGAIVMMN.js';
|
|
5
|
+
import { isLinkedRepository } from './chunk-SSU747O6.js';
|
|
6
|
+
import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
|
|
7
|
+
import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-D6FXM5OW.js';
|
|
8
8
|
import { C } from './chunk-YRYMNBGQ.js';
|
|
9
9
|
import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-5QRP3MVS.js';
|
|
10
|
-
import { readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-
|
|
10
|
+
import { readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-ZZXLM64C.js';
|
|
11
11
|
import { defaultFetch } from './chunk-BCLJSQCV.js';
|
|
12
12
|
import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
|
|
13
13
|
import { readCloudConfig } from './chunk-EABW6AJQ.js';
|
|
14
|
-
import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-
|
|
14
|
+
import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-JPR2WHHF.js';
|
|
15
15
|
import { deadHooksState, preparePackageManagerCommand, contextExcludesPresent } from './chunk-XCCLFVXM.js';
|
|
16
16
|
import { findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
17
17
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
@@ -1004,7 +1004,7 @@ function doctorExitCode(checks) {
|
|
|
1004
1004
|
|
|
1005
1005
|
// src/doctor-report.ts
|
|
1006
1006
|
async function gatherDoctorChecks() {
|
|
1007
|
-
const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-
|
|
1007
|
+
const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-I3TVFYLH.js');
|
|
1008
1008
|
const configPath = defaultRunnerConfigPath();
|
|
1009
1009
|
const checks = runDoctor({ runnerHost: hasRunnerBlock(configPath) });
|
|
1010
1010
|
const credential = await credentialChecks();
|
|
@@ -1012,11 +1012,11 @@ async function gatherDoctorChecks() {
|
|
|
1012
1012
|
if (credential[0]?.status === "pass") checks.push(...await githubAppChecks());
|
|
1013
1013
|
const runnerVm = runnerVmOf(configPath);
|
|
1014
1014
|
if (runnerVm !== void 0) {
|
|
1015
|
-
const { realLima } = await import('./lima-
|
|
1015
|
+
const { realLima } = await import('./lima-7NPCNGWT.js');
|
|
1016
1016
|
const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
|
|
1017
1017
|
checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
|
|
1018
1018
|
} else if (hasRunnerBlock(configPath)) {
|
|
1019
|
-
const { runnerHostChecks } = await import('./doctor-
|
|
1019
|
+
const { runnerHostChecks } = await import('./doctor-FVDT3KJZ.js');
|
|
1020
1020
|
const hooks = (() => {
|
|
1021
1021
|
try {
|
|
1022
1022
|
return loadRunnerConfig(configPath).hooks;
|
|
@@ -1047,7 +1047,15 @@ async function gatherDoctorChecks() {
|
|
|
1047
1047
|
return void 0;
|
|
1048
1048
|
}
|
|
1049
1049
|
})();
|
|
1050
|
-
|
|
1050
|
+
const service = await (async () => {
|
|
1051
|
+
const { existsSync: existsSync2 } = await import('fs');
|
|
1052
|
+
if (process.platform !== "linux" || !existsSync2("/run/systemd/system")) return void 0;
|
|
1053
|
+
const { inspectService, realInspectProbes } = await import('./inspect-XAUSB7L3.js');
|
|
1054
|
+
const { DEFAULT_UNIT_NAME } = await import('./install-NMAPLLBQ.js');
|
|
1055
|
+
const { dirname: dirname2 } = await import('path');
|
|
1056
|
+
return inspectService(DEFAULT_UNIT_NAME, dirname2(configPath), realInspectProbes());
|
|
1057
|
+
})();
|
|
1058
|
+
checks.push(...await runnerHostChecks({ configPath, hooks, gateway, repos, runner, service }));
|
|
1051
1059
|
}
|
|
1052
1060
|
return checks;
|
|
1053
1061
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import { authorEnvironment, withHooksPath } from './chunk-HKMPVPO7.js';
|
|
3
4
|
import { existsSync, unlinkSync, chmodSync } from 'fs';
|
|
4
5
|
import { request as request$1, createServer } from 'http';
|
|
5
6
|
import { request } from 'https';
|
|
@@ -344,52 +345,6 @@ async function startBuildServices(input) {
|
|
|
344
345
|
}
|
|
345
346
|
}
|
|
346
347
|
|
|
347
|
-
// src/runner/commit-identity.ts
|
|
348
|
-
var NOREPLY_SUFFIX = "@users.noreply.github.com";
|
|
349
|
-
var MAX_LENGTH = 200;
|
|
350
|
-
function parseIdentity(value) {
|
|
351
|
-
if (typeof value !== "object" || value === null) return void 0;
|
|
352
|
-
const { name, email } = value;
|
|
353
|
-
if (typeof name !== "string" || typeof email !== "string") return void 0;
|
|
354
|
-
if (name.trim() === "" || name.length > MAX_LENGTH || /[\r\n\0<>]/.test(name)) return void 0;
|
|
355
|
-
if (email.length > MAX_LENGTH || !email.endsWith(NOREPLY_SUFFIX) || /[\s\0<>]/.test(email) || email.length === NOREPLY_SUFFIX.length) return void 0;
|
|
356
|
-
return { name, email };
|
|
357
|
-
}
|
|
358
|
-
function parseClaimIdentity(data) {
|
|
359
|
-
const author = parseIdentity(data.commitAuthor);
|
|
360
|
-
if (author === void 0) return void 0;
|
|
361
|
-
const coAuthor = parseIdentity(data.coAuthor);
|
|
362
|
-
return coAuthor === void 0 ? { author } : { author, coAuthor };
|
|
363
|
-
}
|
|
364
|
-
function authorEnvironment(identity) {
|
|
365
|
-
if (identity === void 0) return {};
|
|
366
|
-
return {
|
|
367
|
-
GIT_AUTHOR_NAME: identity.name,
|
|
368
|
-
GIT_AUTHOR_EMAIL: identity.email,
|
|
369
|
-
GIT_COMMITTER_NAME: identity.name,
|
|
370
|
-
GIT_COMMITTER_EMAIL: identity.email
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
function configCount(env) {
|
|
374
|
-
const raw = String(env.GIT_CONFIG_COUNT);
|
|
375
|
-
return /^[0-9]+$/.test(raw) ? Number(raw) : 0;
|
|
376
|
-
}
|
|
377
|
-
function withHooksPath(env, dir) {
|
|
378
|
-
const at = configCount(env);
|
|
379
|
-
return {
|
|
380
|
-
...env,
|
|
381
|
-
GIT_CONFIG_COUNT: String(at + 1),
|
|
382
|
-
[`GIT_CONFIG_KEY_${at}`]: "core.hooksPath",
|
|
383
|
-
[`GIT_CONFIG_VALUE_${at}`]: dir
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
function commitIdentityRecord(identity) {
|
|
387
|
-
return {
|
|
388
|
-
author: identity === void 0 ? "host" : "app",
|
|
389
|
-
coAuthor: identity?.coAuthor !== void 0 && identity.hooksPath !== void 0 ? "credited" : "none"
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
|
|
393
348
|
// src/runner/container/environment.ts
|
|
394
349
|
var RELAY_PORT = 3128;
|
|
395
350
|
var JOB_MOUNT = "/outerlayer/job";
|
|
@@ -498,6 +453,23 @@ function buildEnvironment(input) {
|
|
|
498
453
|
skippedTokenVariables
|
|
499
454
|
};
|
|
500
455
|
}
|
|
456
|
+
function checkEnvironment(input) {
|
|
457
|
+
const env = buildEnvironment({
|
|
458
|
+
config: input.config,
|
|
459
|
+
item: input.item,
|
|
460
|
+
itemKey: void 0,
|
|
461
|
+
repository: input.repository,
|
|
462
|
+
hostEnv: input.hostEnv,
|
|
463
|
+
containerEnv: input.containerEnv,
|
|
464
|
+
builtIns: false
|
|
465
|
+
});
|
|
466
|
+
const withheld = /* @__PURE__ */ new Set(["OUTERLAYER_URL", "OUTERLAYER_API_KEY", ...CLAUDE_CREDENTIAL_VARIABLES]);
|
|
467
|
+
const literals = {};
|
|
468
|
+
for (const [name, value] of Object.entries(env.literals)) if (!withheld.has(name)) literals[name] = value;
|
|
469
|
+
const passed = {};
|
|
470
|
+
for (const [name, value] of Object.entries(env.passed)) if (!withheld.has(name)) passed[name] = value;
|
|
471
|
+
return { literals, passed };
|
|
472
|
+
}
|
|
501
473
|
function parseIsolation(value) {
|
|
502
474
|
return value === "container" || value === "vm" ? value : "shared-user";
|
|
503
475
|
}
|
|
@@ -531,4 +503,4 @@ function withTunnelRecord(environment, record, onlyWhenUsed = false) {
|
|
|
531
503
|
};
|
|
532
504
|
}
|
|
533
505
|
|
|
534
|
-
export { AGENT_CREDENTIAL_MISSING, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT,
|
|
506
|
+
export { AGENT_CREDENTIAL_MISSING, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, buildEnvironment, builtInEnvironment, checkEnvironment, claudeCredential, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, parseIsolation, proxyEnvironment, resolveDestinations, sharedUserEnvironment, startBuildServices, withTunnelRecord };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { parseSize } from './chunk-F6GFZXZ3.js';
|
|
4
|
+
|
|
5
|
+
createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
// src/runner/service/fit.ts
|
|
8
|
+
var GIB = 1024 ** 3;
|
|
9
|
+
var RUNNER_RESERVE_BYTES = 2 * GIB;
|
|
10
|
+
function gib(bytes) {
|
|
11
|
+
return `${Number((bytes / GIB).toFixed(1))} GiB`;
|
|
12
|
+
}
|
|
13
|
+
function checkFit(input) {
|
|
14
|
+
const perBuild = parseSize(input.buildMemory);
|
|
15
|
+
if (perBuild === void 0) return { fits: true };
|
|
16
|
+
const neededBytes = input.concurrency * perBuild;
|
|
17
|
+
const availableBytes = Math.max(0, input.usableBytes - RUNNER_RESERVE_BYTES);
|
|
18
|
+
if (neededBytes <= availableBytes) return { fits: true };
|
|
19
|
+
return {
|
|
20
|
+
fits: false,
|
|
21
|
+
neededBytes,
|
|
22
|
+
availableBytes,
|
|
23
|
+
message: `runner.concurrency ${input.concurrency} times runner.build.memory ${input.buildMemory} needs ${gib(neededBytes)}, and ${gib(availableBytes)} is available (${gib(input.usableBytes)} of memory less ${gib(RUNNER_RESERVE_BYTES)} for the runner and the system)`
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { RUNNER_RESERVE_BYTES, checkFit };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-SSU747O6.js';
|
|
4
|
+
import { resolveRepoIdentity } from './chunk-D6FXM5OW.js';
|
|
5
|
+
import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
|
|
6
|
+
import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
|
|
7
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
8
|
+
|
|
9
|
+
createRequire(import.meta.url);
|
|
10
|
+
|
|
11
|
+
// src/auto-connect.ts
|
|
12
|
+
async function autoConnect(opts) {
|
|
13
|
+
const env = opts.env ?? process.env;
|
|
14
|
+
const home = opts.home ?? homeFromEnv(env);
|
|
15
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
16
|
+
const resolved = resolveGatewayCredentials({ url: opts.url, apiKey: opts.apiKey, appId: opts.appId, home, env, cwd });
|
|
17
|
+
if (resolved.ok || resolved.kind !== "login" || !resolved.credential || !resolved.url) return void 0;
|
|
18
|
+
const dirs = findGitDirs(cwd);
|
|
19
|
+
const repository = resolveRepoIdentity(cwd).gitRepo;
|
|
20
|
+
if (dirs === void 0 || repository === void 0) return void 0;
|
|
21
|
+
const listed = await fetchFactories(opts.fetchImpl ?? fetch, resolved.url, resolved.credential, repository);
|
|
22
|
+
if (!listed.ok || listed.factories.length === 0) return void 0;
|
|
23
|
+
const chosen = selectFactory(listed.factories, readRepoConnection(cwd), repository);
|
|
24
|
+
if (chosen.factory === void 0) {
|
|
25
|
+
return `you are logged in, but no factory is chosen for this repository, and more than one fits. Run \`outerlayer connect --factory <org>/<factory>\` with one of:
|
|
26
|
+
${chosen.text}
|
|
27
|
+
Or pass --app-id / set OUTERLAYER_APP_ID.`;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
saveFactoryConnection(dirs.gitCommonDir, void 0, chosen.factory, /* @__PURE__ */ new Date());
|
|
31
|
+
} catch {
|
|
32
|
+
return void 0;
|
|
33
|
+
}
|
|
34
|
+
process.stderr.write(`${connectedLine(repository, chosen.factory, chosen.reason)}
|
|
35
|
+
`);
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { autoConnect };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-
|
|
3
|
+
import { isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-TI7B7UEO.js';
|
|
4
4
|
import { RUNNER_DIR_MODE } from './chunk-ZM2IMMYN.js';
|
|
5
|
-
import './chunk-Z5GEFMRW.js';
|
|
6
5
|
import { realpathSync, readFileSync, mkdirSync, rmSync, cpSync, existsSync } from 'fs';
|
|
7
6
|
import { dirname, sep, join } from 'path';
|
|
8
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { RELAY_PORT, GATEWAY_SOCKET, GATEWAY_PORT, CLAUDE_SOCKET, CLAUDE_PORT, DESTINATION_BASE_PORT } from './chunk-
|
|
3
|
+
import { RELAY_PORT, GATEWAY_SOCKET, GATEWAY_PORT, CLAUDE_SOCKET, CLAUDE_PORT, DESTINATION_BASE_PORT } from './chunk-OD2VTIHN.js';
|
|
4
4
|
import { symlinkSync, unlinkSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
|
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
|
|
4
|
+
import { remoteLookupFailed } from './chunk-D6FXM5OW.js';
|
|
5
|
+
import { DEFAULT_DASHBOARD } from './chunk-USO2DKBD.js';
|
|
6
6
|
import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
|
|
7
|
-
import {
|
|
7
|
+
import { readCloudConfig } from './chunk-EABW6AJQ.js';
|
|
8
|
+
import { writeRepoConnection, findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
|
|
8
9
|
import { createInterface } from 'readline/promises';
|
|
9
10
|
|
|
10
11
|
createRequire(import.meta.url);
|
|
12
|
+
|
|
13
|
+
// src/repository-link.ts
|
|
14
|
+
var LINKS_TIMEOUT_MS = 15e3;
|
|
15
|
+
var GITHUB_PREFIX = "github.com/";
|
|
16
|
+
function isLinkedRepository(local, linked) {
|
|
17
|
+
if (linked.provider !== "github" || typeof linked.repository !== "string") return false;
|
|
18
|
+
return local.toLowerCase() === `${GITHUB_PREFIX}${linked.repository.toLowerCase()}`;
|
|
19
|
+
}
|
|
20
|
+
function ownerAndName(repository) {
|
|
21
|
+
return repository.toLowerCase().startsWith(GITHUB_PREFIX) ? repository.slice(GITHUB_PREFIX.length) : repository;
|
|
22
|
+
}
|
|
23
|
+
async function isRepositoryLinked(fetchImpl, gatewayUrl, token, appId, repository) {
|
|
24
|
+
if (!repository.toLowerCase().startsWith(GITHUB_PREFIX)) return null;
|
|
25
|
+
let res;
|
|
26
|
+
try {
|
|
27
|
+
res = await fetchImpl(`${gatewayUrl.replace(/\/+$/, "")}/v1/apps/${encodeURIComponent(appId)}/git/links`, {
|
|
28
|
+
method: "GET",
|
|
29
|
+
headers: { authorization: `Bearer ${token}`, "x-outerlayer-app-id": appId },
|
|
30
|
+
signal: AbortSignal.timeout(LINKS_TIMEOUT_MS)
|
|
31
|
+
});
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (!res.ok) return null;
|
|
36
|
+
const listed = (await res.json().catch(() => void 0))?.data;
|
|
37
|
+
if (!Array.isArray(listed)) return null;
|
|
38
|
+
return listed.some((entry) => isLinkedRepository(repository, entry ?? {}));
|
|
39
|
+
}
|
|
40
|
+
function dashboardBase(home) {
|
|
41
|
+
const saved = readCloudConfig(home).dashboard;
|
|
42
|
+
const base = typeof saved === "string" && saved.trim() !== "" ? saved : DEFAULT_DASHBOARD;
|
|
43
|
+
return base.replace(/\/+$/, "");
|
|
44
|
+
}
|
|
45
|
+
function workPageUrl(home, organization, factory) {
|
|
46
|
+
return `${dashboardBase(home)}/orgs/${encodeURIComponent(organization)}/factories/${encodeURIComponent(factory)}/work`;
|
|
47
|
+
}
|
|
48
|
+
function notLinkedText(factoryName, repository, url) {
|
|
49
|
+
const shown = sanitizeTerminal(repository);
|
|
50
|
+
const name = sanitizeTerminal(ownerAndName(repository));
|
|
51
|
+
return `${factoryName} has no link to ${shown} yet, so work from this repository cannot reach it.
|
|
52
|
+
Link it on the factory's Work page: ${url}
|
|
53
|
+
1. Connect GitHub repository, and grant the App access to ${name}.
|
|
54
|
+
2. Link repository, and pick ${name} and its default branch.
|
|
55
|
+
Then run \`outerlayer connect\` again.
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/connect-cmd.ts
|
|
11
60
|
var REQUEST_TIMEOUT_MS = 15e3;
|
|
12
61
|
var EXIT_NOT_LINKED = 2;
|
|
13
62
|
var REASON_TEXT = {
|
|
@@ -72,10 +121,10 @@ function parseFactories(body) {
|
|
|
72
121
|
function listText(factories, repository) {
|
|
73
122
|
return factories.map((f) => ` ${slug(f)} ${f.displayName}${f.linked === true ? ` (linked to ${repository})` : ""}`).join("\n");
|
|
74
123
|
}
|
|
75
|
-
async function fetchFactories(
|
|
124
|
+
async function fetchFactories(fetchImpl, url, token, repository) {
|
|
76
125
|
let res;
|
|
77
126
|
try {
|
|
78
|
-
res = await
|
|
127
|
+
res = await fetchImpl(`${url.replace(/\/+$/, "")}/v1/me/factories?${new URLSearchParams({ repository }).toString()}`, {
|
|
79
128
|
method: "GET",
|
|
80
129
|
headers: { authorization: `Bearer ${token}` },
|
|
81
130
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
@@ -99,6 +148,26 @@ async function fetchFactories(deps, url, token, repository) {
|
|
|
99
148
|
}
|
|
100
149
|
return { ok: true, factories };
|
|
101
150
|
}
|
|
151
|
+
function selectFactory(factories, saved, repository) {
|
|
152
|
+
const remembered = saved && factories.find((f) => f.id === saved.appId);
|
|
153
|
+
if (remembered) return { factory: remembered, reason: "saved" };
|
|
154
|
+
const linked = factories.filter((f) => f.linked === true);
|
|
155
|
+
if (linked.length === 1) return { factory: linked[0], reason: "linked" };
|
|
156
|
+
if (factories.length === 1) return { factory: factories[0], reason: "only" };
|
|
157
|
+
return { factory: void 0, values: factories.map(slug), text: listText(factories, repository) };
|
|
158
|
+
}
|
|
159
|
+
function saveFactoryConnection(gitCommonDir, saved, factory, now) {
|
|
160
|
+
if (saved?.appId === factory.id) return;
|
|
161
|
+
writeRepoConnection(gitCommonDir, {
|
|
162
|
+
appId: factory.id,
|
|
163
|
+
organization: { name: factory.organization.name, displayName: factory.organization.displayName },
|
|
164
|
+
factory: { name: factory.name, displayName: factory.displayName },
|
|
165
|
+
savedAt: now.toISOString()
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function connectedLine(repository, factory, reason) {
|
|
169
|
+
return `Connected ${repository} to factory "${factory.displayName}" in ${factory.organization.displayName} (${REASON_TEXT[reason]}).`;
|
|
170
|
+
}
|
|
102
171
|
async function choose(flags, deps, factories, saved, repository) {
|
|
103
172
|
if (flags.factory !== void 0) {
|
|
104
173
|
const wanted = flags.factory.toLowerCase();
|
|
@@ -108,11 +177,9 @@ async function choose(flags, deps, factories, saved, repository) {
|
|
|
108
177
|
${listText(factories, repository)}`;
|
|
109
178
|
return result(1, "failed", `--factory ${flags.factory} names no factory you can use`, message);
|
|
110
179
|
}
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
180
|
+
const decided = selectFactory(factories, saved, repository);
|
|
181
|
+
if (decided.factory) return { factory: decided.factory, reason: decided.reason };
|
|
113
182
|
const linked = factories.filter((f) => f.linked === true);
|
|
114
|
-
if (linked.length === 1) return { factory: linked[0], reason: "linked" };
|
|
115
|
-
if (factories.length === 1) return { factory: factories[0], reason: "only" };
|
|
116
183
|
if (!deps.isTerminal) {
|
|
117
184
|
const why = linked.length > 1 ? `${repository} is linked to more than one factory you can use` : `you can use more than one factory, and none is the only one ${repository} is linked to`;
|
|
118
185
|
const message = `${why}, and there is no terminal to ask on.
|
|
@@ -169,7 +236,7 @@ async function runConnect(flags, deps) {
|
|
|
169
236
|
const message = "no gateway address is saved. Run `outerlayer login` to sign in.";
|
|
170
237
|
return result(1, "failed", message, message);
|
|
171
238
|
}
|
|
172
|
-
const listed = await fetchFactories(deps, creds.url, creds.credential, repository);
|
|
239
|
+
const listed = await fetchFactories(deps.fetchImpl, creds.url, creds.credential, repository);
|
|
173
240
|
if (!listed.ok) return listed.result;
|
|
174
241
|
const { factories } = listed;
|
|
175
242
|
if (factories.length === 0) {
|
|
@@ -181,20 +248,13 @@ async function runConnect(flags, deps) {
|
|
|
181
248
|
const choice = await choose(flags, deps, factories, saved, repository);
|
|
182
249
|
if ("code" in choice) return choice;
|
|
183
250
|
const { factory, reason } = choice;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
factory: { name: factory.name, displayName: factory.displayName },
|
|
190
|
-
savedAt: deps.now().toISOString()
|
|
191
|
-
});
|
|
192
|
-
} catch (err) {
|
|
193
|
-
const message = `could not save the connection under ${dirs.gitCommonDir}: ${err instanceof Error ? err.message : String(err)}`;
|
|
194
|
-
return result(1, "failed", "could not save the connection", message);
|
|
195
|
-
}
|
|
251
|
+
try {
|
|
252
|
+
saveFactoryConnection(dirs.gitCommonDir, saved, factory, deps.now());
|
|
253
|
+
} catch (err) {
|
|
254
|
+
const message = `could not save the connection under ${dirs.gitCommonDir}: ${err instanceof Error ? err.message : String(err)}`;
|
|
255
|
+
return result(1, "failed", "could not save the connection", message);
|
|
196
256
|
}
|
|
197
|
-
const connected =
|
|
257
|
+
const connected = `${connectedLine(repository, factory, reason)}
|
|
198
258
|
`;
|
|
199
259
|
const why = `connected to ${slug(factory)}: ${REASON_TEXT[reason]}`;
|
|
200
260
|
const linked = await isRepositoryLinked(deps.fetchImpl, creds.url, creds.credential, factory.id, repository);
|
|
@@ -229,4 +289,4 @@ async function runConnectCommand(flags, deps, out) {
|
|
|
229
289
|
return r.code;
|
|
230
290
|
}
|
|
231
291
|
|
|
232
|
-
export { promptOnTerminal, realConnectDeps, runConnect, runConnectCommand };
|
|
292
|
+
export { connectedLine, fetchFactories, isLinkedRepository, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
|
|
4
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
5
|
+
import { dirname } from 'path';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
function readJobFile(path) {
|
|
9
|
+
if (!existsSync(path)) return null;
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function readJobFileChecked(path) {
|
|
17
|
+
if (!existsSync(path)) return { kind: "missing" };
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
20
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return { kind: "unreadable" };
|
|
21
|
+
return { kind: "ok", job: parsed };
|
|
22
|
+
} catch {
|
|
23
|
+
return { kind: "unreadable" };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function writeJobFile(path, job) {
|
|
27
|
+
mkdirSync(dirname(path), { recursive: true, mode: RUNNER_DIR_MODE });
|
|
28
|
+
writeFileSync(path, JSON.stringify(job, null, 2), { mode: RUNNER_FILE_MODE });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { readJobFile, readJobFileChecked, writeJobFile };
|