@appchy/jarvis 0.1.122 → 0.1.124
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/bin.js +164 -55
- package/dist/bin.js.map +1 -1
- package/harness/harness/config.py +30 -0
- package/harness/harness/git.py +9 -0
- package/harness/harness/kickoff.py +12 -2
- package/harness/harness/peers.cases.json +141 -0
- package/harness/harness/peers.py +189 -20
- package/harness/presets/appchy/PRESET.md +36 -0
- package/harness/test_work.py +159 -0
- package/harness/work.py +8 -2
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -4514,7 +4514,15 @@ function toHolders(commits) {
|
|
|
4514
4514
|
// Only a person's own machine reports an actor today; an unattended shift is
|
|
4515
4515
|
// the thing `next` records, and it commits the same way.
|
|
4516
4516
|
actor: /\bactor=automation\b/.test(commit.message) ? "automation" : "person",
|
|
4517
|
-
quiet: isQuiet(commit)
|
|
4517
|
+
quiet: isQuiet(commit),
|
|
4518
|
+
// Knowing nothing is the DEFAULT, and only a reader standing on the machine a
|
|
4519
|
+
// take was made on replaces it. The hosted app reads this same history out of
|
|
4520
|
+
// GitHub with no machine underneath it, so it keeps these and reports that it
|
|
4521
|
+
// cannot tell — which is the honest answer, where "nobody is running it" would
|
|
4522
|
+
// be a confident wrong one.
|
|
4523
|
+
live: "unknown",
|
|
4524
|
+
addresses: [],
|
|
4525
|
+
processes: 0
|
|
4518
4526
|
});
|
|
4519
4527
|
}
|
|
4520
4528
|
const bySession = /* @__PURE__ */ new Map();
|
|
@@ -4546,10 +4554,22 @@ function warning(holders, mine) {
|
|
|
4546
4554
|
const said = others.map((holder) => {
|
|
4547
4555
|
const ago = describeAge(holder.takenAt);
|
|
4548
4556
|
const quiet = holder.quiet ? ", and has made no commits for over eight hours" : "";
|
|
4549
|
-
return `${holder.by || holder.session} on ${holder.envId || "an unnamed machine"}, branch ${holder.branch || "unknown"}, ${ago}${quiet}`;
|
|
4557
|
+
return `${holder.by || holder.session} on ${holder.envId || "an unnamed machine"}, branch ${holder.branch || "unknown"}, ${ago}${quiet}${describeReach(holder)}`;
|
|
4550
4558
|
});
|
|
4551
4559
|
const took = others.some((holder) => holder.tookOverFrom) ? " Somebody has already taken over once." : "";
|
|
4552
|
-
|
|
4560
|
+
const anyone = others.some((holder) => holder.live !== "ended");
|
|
4561
|
+
const opener = anyone ? `Somebody else is on this: ${said.join("; ")}.` : `This was taken and abandoned rather than held \u2014 ${said.join("; ")}.`;
|
|
4562
|
+
return `${opener}${took} Nothing is stopping you \u2014 decide whether to go ahead, and your take is recorded beside theirs.`;
|
|
4563
|
+
}
|
|
4564
|
+
function describeReach(holder) {
|
|
4565
|
+
if (holder.live === "ended") return ", whose run has since ENDED";
|
|
4566
|
+
if (holder.live === "unknown") return "";
|
|
4567
|
+
if (holder.live === "forked") {
|
|
4568
|
+
const names = holder.addresses.map((each) => `\`${each.name}\``).join(" and ");
|
|
4569
|
+
return `, running as ${holder.processes} processes on one session` + (names ? ` \u2014 ${names}, either of which reaches it` : "");
|
|
4570
|
+
}
|
|
4571
|
+
const name = holder.addresses[0]?.name;
|
|
4572
|
+
return name ? `, still running as \`${name}\`` : ", still running";
|
|
4553
4573
|
}
|
|
4554
4574
|
function isQuiet(commit) {
|
|
4555
4575
|
const at = Date.parse(commit.branchLastCommitAt || commit.when);
|
|
@@ -4560,7 +4580,7 @@ function readTrailers(message) {
|
|
|
4560
4580
|
const events = [];
|
|
4561
4581
|
const items = [];
|
|
4562
4582
|
let session = "";
|
|
4563
|
-
let
|
|
4583
|
+
let machine2 = "";
|
|
4564
4584
|
for (const raw of message.split("\n")) {
|
|
4565
4585
|
const line = raw.trim();
|
|
4566
4586
|
const m = /^(Work-[A-Za-z]+):\s*(.*)$/.exec(line);
|
|
@@ -4568,9 +4588,9 @@ function readTrailers(message) {
|
|
|
4568
4588
|
if (m[1] === "Work-Event" && m[2]) events.push(m[2]);
|
|
4569
4589
|
if (m[1] === "Work-Item" && m[2]) items.push(m[2]);
|
|
4570
4590
|
if (m[1] === "Work-Session") session = m[2] ?? "";
|
|
4571
|
-
if (m[1] === "Work-Machine")
|
|
4591
|
+
if (m[1] === "Work-Machine") machine2 = m[2] ?? "";
|
|
4572
4592
|
}
|
|
4573
|
-
return { session, machine, events, items };
|
|
4593
|
+
return { session, machine: machine2, events, items };
|
|
4574
4594
|
}
|
|
4575
4595
|
function describeAge(when) {
|
|
4576
4596
|
const at = Date.parse(when);
|
|
@@ -4582,6 +4602,77 @@ function describeAge(when) {
|
|
|
4582
4602
|
return `${Math.round(hours / 24)} day(s) ago`;
|
|
4583
4603
|
}
|
|
4584
4604
|
|
|
4605
|
+
// ../../packages/board/src/peers.ts
|
|
4606
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
4607
|
+
import { hostname } from "os";
|
|
4608
|
+
import { homedir as homedir5 } from "os";
|
|
4609
|
+
import { join as join4 } from "path";
|
|
4610
|
+
var SESSIONS_DIR = "WORK_SESSIONS_DIR";
|
|
4611
|
+
var DOORS = { cli: "a terminal", "claude-vscode": "an editor" };
|
|
4612
|
+
function findPeers() {
|
|
4613
|
+
const where = process.env[SESSIONS_DIR] || join4(homedir5(), ".claude", "sessions");
|
|
4614
|
+
let files2;
|
|
4615
|
+
try {
|
|
4616
|
+
if (!statSync3(where).isDirectory()) return null;
|
|
4617
|
+
files2 = readdirSync4(where).filter((each) => each.endsWith(".json"));
|
|
4618
|
+
} catch {
|
|
4619
|
+
return null;
|
|
4620
|
+
}
|
|
4621
|
+
const live3 = /* @__PURE__ */ new Map();
|
|
4622
|
+
for (const file of files2.sort()) {
|
|
4623
|
+
let entry;
|
|
4624
|
+
try {
|
|
4625
|
+
entry = JSON.parse(readFileSync5(join4(where, file), "utf8"));
|
|
4626
|
+
} catch {
|
|
4627
|
+
continue;
|
|
4628
|
+
}
|
|
4629
|
+
if (!entry || typeof entry !== "object") continue;
|
|
4630
|
+
const session = String(entry.sessionId ?? "");
|
|
4631
|
+
const pid = Number(entry.pid);
|
|
4632
|
+
if (!session || !isAlive(pid)) continue;
|
|
4633
|
+
const peer = {
|
|
4634
|
+
session,
|
|
4635
|
+
name: String(entry.name ?? "").trim(),
|
|
4636
|
+
cwd: String(entry.cwd ?? ""),
|
|
4637
|
+
pid,
|
|
4638
|
+
from: String(entry.entrypoint ?? "").trim()
|
|
4639
|
+
};
|
|
4640
|
+
const already = live3.get(session);
|
|
4641
|
+
if (already) already.push(peer);
|
|
4642
|
+
else live3.set(session, [peer]);
|
|
4643
|
+
}
|
|
4644
|
+
return live3;
|
|
4645
|
+
}
|
|
4646
|
+
function toReach(holder, peers) {
|
|
4647
|
+
const away = Boolean(holder.envId) && Boolean(machine()) && holder.envId !== machine();
|
|
4648
|
+
const live3 = away ? null : peers;
|
|
4649
|
+
if (live3 === null || !holder.session) return { live: "unknown", addresses: [], processes: 0 };
|
|
4650
|
+
const running = live3.get(holder.session);
|
|
4651
|
+
if (!running || running.length === 0) return { live: "ended", addresses: [], processes: 0 };
|
|
4652
|
+
return {
|
|
4653
|
+
live: running.length > 1 ? "forked" : "running",
|
|
4654
|
+
// Counted from the processes, never from the addresses: one of them publishing
|
|
4655
|
+
// no name would otherwise make a fork report as though it were a single run.
|
|
4656
|
+
processes: running.length,
|
|
4657
|
+
addresses: toAddresses(running)
|
|
4658
|
+
};
|
|
4659
|
+
}
|
|
4660
|
+
function toAddresses(running) {
|
|
4661
|
+
return running.filter((each) => each.name).map((each) => ({ name: each.name, from: DOORS[each.from] ?? each.from })).sort((left, right) => left.name.localeCompare(right.name));
|
|
4662
|
+
}
|
|
4663
|
+
function machine() {
|
|
4664
|
+
return (process.env.WORK_MACHINE || hostname() || "").trim();
|
|
4665
|
+
}
|
|
4666
|
+
function isAlive(pid) {
|
|
4667
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
4668
|
+
try {
|
|
4669
|
+
process.kill(pid, 0);
|
|
4670
|
+
return true;
|
|
4671
|
+
} catch (error) {
|
|
4672
|
+
return error?.code === "EPERM";
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
|
|
4585
4676
|
// ../../packages/board/src/board.git.ts
|
|
4586
4677
|
var run3 = promisify4(execFile4);
|
|
4587
4678
|
var SOURCED = "%x1e%H%x1f%S%x1f%aI%x1f%an%x1f%B";
|
|
@@ -4648,7 +4739,15 @@ function shorten(ref) {
|
|
|
4648
4739
|
return ref.replace(/^refs\/(heads|remotes)\//, "");
|
|
4649
4740
|
}
|
|
4650
4741
|
async function listHoldersByItem(root) {
|
|
4651
|
-
|
|
4742
|
+
const byItem = toHoldersByItem(await boardHistory(root));
|
|
4743
|
+
const peers = findPeers();
|
|
4744
|
+
for (const [id, holders] of byItem) {
|
|
4745
|
+
byItem.set(
|
|
4746
|
+
id,
|
|
4747
|
+
holders.map((holder) => ({ ...holder, ...toReach(holder, peers) }))
|
|
4748
|
+
);
|
|
4749
|
+
}
|
|
4750
|
+
return byItem;
|
|
4652
4751
|
}
|
|
4653
4752
|
async function listHolders(root, id) {
|
|
4654
4753
|
const byItem = await listHoldersByItem(root);
|
|
@@ -4658,7 +4757,7 @@ async function listHolders(root, id) {
|
|
|
4658
4757
|
// ../../packages/board/src/board.tree.ts
|
|
4659
4758
|
import { execFile as execFile5 } from "child_process";
|
|
4660
4759
|
import { readdir, readFile, stat } from "fs/promises";
|
|
4661
|
-
import { join as
|
|
4760
|
+
import { join as join5, relative, sep } from "path";
|
|
4662
4761
|
import { promisify as promisify5 } from "util";
|
|
4663
4762
|
|
|
4664
4763
|
// ../../packages/errors/src/errors.ts
|
|
@@ -4819,8 +4918,8 @@ async function listWorkItems(_ctx, req, options) {
|
|
|
4819
4918
|
return toPage(await scanTree(options.root), req);
|
|
4820
4919
|
}
|
|
4821
4920
|
async function findWorkItem(_ctx, req, options) {
|
|
4822
|
-
const work =
|
|
4823
|
-
for (const file of await walk(
|
|
4921
|
+
const work = join5(options.root, "work");
|
|
4922
|
+
for (const file of await walk(join5(work, "versions"))) {
|
|
4824
4923
|
const path23 = pathIn(work, file);
|
|
4825
4924
|
if (path23.split("/").at(-2) === req.id) return readItem(work, file);
|
|
4826
4925
|
}
|
|
@@ -4833,7 +4932,7 @@ async function getWorkItem(ctx, req, options) {
|
|
|
4833
4932
|
}
|
|
4834
4933
|
async function getBrief(_ctx, req, options) {
|
|
4835
4934
|
try {
|
|
4836
|
-
return await readFile(
|
|
4935
|
+
return await readFile(join5(options.root, "work", req.path), "utf-8");
|
|
4837
4936
|
} catch {
|
|
4838
4937
|
return null;
|
|
4839
4938
|
}
|
|
@@ -4968,9 +5067,9 @@ function scanTree(root) {
|
|
|
4968
5067
|
var scanning = /* @__PURE__ */ new Map();
|
|
4969
5068
|
var LEFT_THE_BOARD = ["complete", "archive"];
|
|
4970
5069
|
async function readTree(root) {
|
|
4971
|
-
const work =
|
|
5070
|
+
const work = join5(root, "work");
|
|
4972
5071
|
const items = [];
|
|
4973
|
-
for (const file of await walk(
|
|
5072
|
+
for (const file of await walk(join5(work, "versions"))) {
|
|
4974
5073
|
const path23 = pathIn(work, file);
|
|
4975
5074
|
if (LEFT_THE_BOARD.some((home) => path23.startsWith(`versions/${home}/`))) continue;
|
|
4976
5075
|
const item2 = await readItem(work, file);
|
|
@@ -4996,7 +5095,7 @@ async function walk(dir, depth = 0) {
|
|
|
4996
5095
|
}
|
|
4997
5096
|
const found = [];
|
|
4998
5097
|
for (const entry of entries) {
|
|
4999
|
-
const full =
|
|
5098
|
+
const full = join5(dir, entry.name);
|
|
5000
5099
|
if (entry.isDirectory()) found.push(...await walk(full, depth + 1));
|
|
5001
5100
|
else if (entry.name === ITEM_FILE) found.push(full);
|
|
5002
5101
|
}
|
|
@@ -5114,16 +5213,16 @@ async function createWorkItem2(ctx, req, options) {
|
|
|
5114
5213
|
// src/harness.ts
|
|
5115
5214
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
5116
5215
|
import { existsSync as existsSync5 } from "fs";
|
|
5117
|
-
import { dirname as dirname3, join as
|
|
5216
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
5118
5217
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5119
|
-
var ENTRY =
|
|
5218
|
+
var ENTRY = join6("harness", "work.py");
|
|
5120
5219
|
var INTERPRETERS = ["python3", "python"];
|
|
5121
5220
|
var OLDEST = [3, 9];
|
|
5122
5221
|
var INSTALLED = ["jarvis", "work"];
|
|
5123
5222
|
function payload() {
|
|
5124
5223
|
let dir = dirname3(fileURLToPath2(import.meta.url));
|
|
5125
5224
|
for (let up = 0; up < 6; up++) {
|
|
5126
|
-
if (existsSync5(
|
|
5225
|
+
if (existsSync5(join6(dir, ENTRY))) return join6(dir, ENTRY);
|
|
5127
5226
|
const parent = dirname3(dir);
|
|
5128
5227
|
if (parent === dir) break;
|
|
5129
5228
|
dir = parent;
|
|
@@ -5642,7 +5741,7 @@ async function runEntries(req) {
|
|
|
5642
5741
|
await Promise.all(scopes.map((scope2) => shape(run6, scope2)));
|
|
5643
5742
|
for (const scope2 of scopes) await mint(run6, scope2);
|
|
5644
5743
|
for (const scope2 of scopes) link(run6, scope2);
|
|
5645
|
-
for (const spec of connects) await
|
|
5744
|
+
for (const spec of connects) await join7(run6, spec);
|
|
5646
5745
|
for (const diagnostic of silence(scopes)) run6.report(diagnostic);
|
|
5647
5746
|
return scopes.map((scope2) => scope2.ledger);
|
|
5648
5747
|
}
|
|
@@ -5884,7 +5983,7 @@ function emit(run6, scope2, request) {
|
|
|
5884
5983
|
);
|
|
5885
5984
|
scope2.ledger.edges[request.rel] = (scope2.ledger.edges[request.rel] ?? 0) + 1;
|
|
5886
5985
|
}
|
|
5887
|
-
async function
|
|
5986
|
+
async function join7(run6, spec) {
|
|
5888
5987
|
const ctx = finderContext(run6, spec.name);
|
|
5889
5988
|
const graph2 = {
|
|
5890
5989
|
nodes: (type) => run6.graph.nodes(type),
|
|
@@ -6214,7 +6313,7 @@ function edgeMatchesConfidence(edge, backendName, confidence) {
|
|
|
6214
6313
|
}
|
|
6215
6314
|
|
|
6216
6315
|
// ../../packages/data/src/config.ts
|
|
6217
|
-
import { existsSync as existsSync6, readFileSync as
|
|
6316
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
6218
6317
|
import { readFile as readFile4 } from "fs/promises";
|
|
6219
6318
|
import { dirname as dirname5, resolve as resolve4 } from "path";
|
|
6220
6319
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -6222,7 +6321,7 @@ import { createJiti } from "jiti";
|
|
|
6222
6321
|
|
|
6223
6322
|
// ../../packages/data/src/persistences/local.ts
|
|
6224
6323
|
import { mkdir, readFile as readFile3, writeFile } from "fs/promises";
|
|
6225
|
-
import { dirname as dirname4, join as
|
|
6324
|
+
import { dirname as dirname4, join as join8, resolve as resolve3 } from "path";
|
|
6226
6325
|
function localFiles(options = {}) {
|
|
6227
6326
|
const root = options.root ?? ".data";
|
|
6228
6327
|
const rel = {
|
|
@@ -6235,7 +6334,7 @@ function localFiles(options = {}) {
|
|
|
6235
6334
|
const pathOf = (ctx, key) => resolve3(
|
|
6236
6335
|
ctx.repoRoot,
|
|
6237
6336
|
root,
|
|
6238
|
-
key.startsWith("plugin:") ?
|
|
6337
|
+
key.startsWith("plugin:") ? join8("plugins", `${key.slice(7)}.json`) : rel[key]
|
|
6239
6338
|
);
|
|
6240
6339
|
return persistence({
|
|
6241
6340
|
name: "local-files",
|
|
@@ -6304,7 +6403,7 @@ function packageRoot() {
|
|
|
6304
6403
|
}
|
|
6305
6404
|
function selfAlias() {
|
|
6306
6405
|
const root = packageRoot();
|
|
6307
|
-
const pkg = JSON.parse(
|
|
6406
|
+
const pkg = JSON.parse(readFileSync6(resolve4(root, "package.json"), "utf8"));
|
|
6308
6407
|
if (pkg.name !== PACKAGE_NAME) {
|
|
6309
6408
|
const vendored = process.env[VENDOR_ENV];
|
|
6310
6409
|
if (!vendored) {
|
|
@@ -7595,7 +7694,7 @@ function leavesOf(ladder) {
|
|
|
7595
7694
|
}
|
|
7596
7695
|
|
|
7597
7696
|
// ../../packages/data/src/mcp/tools/cache.ts
|
|
7598
|
-
import { statSync as
|
|
7697
|
+
import { statSync as statSync4 } from "fs";
|
|
7599
7698
|
import { resolve as resolve6 } from "path";
|
|
7600
7699
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
7601
7700
|
async function cachedEnforcerDiags(ctx, freshPaths) {
|
|
@@ -7616,7 +7715,7 @@ function isFresh(snapshot, repoRoot, freshPaths) {
|
|
|
7616
7715
|
for (const path23 of freshPaths) {
|
|
7617
7716
|
let mtimeMs;
|
|
7618
7717
|
try {
|
|
7619
|
-
mtimeMs =
|
|
7718
|
+
mtimeMs = statSync4(resolve6(repoRoot, path23)).mtimeMs;
|
|
7620
7719
|
} catch {
|
|
7621
7720
|
return false;
|
|
7622
7721
|
}
|
|
@@ -10286,7 +10385,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
10286
10385
|
var _require = createRequire2(import.meta.url);
|
|
10287
10386
|
var VERSION2 = _require("../package.json").version ?? "0.0.0";
|
|
10288
10387
|
var IS_DEV = String(_require("../package.json").name ?? "").endsWith("-dev");
|
|
10289
|
-
var SHA = "
|
|
10388
|
+
var SHA = "03f6896";
|
|
10290
10389
|
var BUILT = "2026-09-12";
|
|
10291
10390
|
var BUILD = SHA ?? "source";
|
|
10292
10391
|
var BUILD_LABEL = `${SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`}${IS_DEV ? " \u2014 development build" : ""}`;
|
|
@@ -11315,14 +11414,14 @@ function register17(program) {
|
|
|
11315
11414
|
}
|
|
11316
11415
|
|
|
11317
11416
|
// src/graph/build.ts
|
|
11318
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
11417
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync8, rmSync, statSync as statSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
11319
11418
|
import { dirname as dirname6, resolve as resolve8 } from "path";
|
|
11320
11419
|
|
|
11321
11420
|
// src/graph/ratchet.ts
|
|
11322
11421
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
11323
|
-
import { readFileSync as
|
|
11324
|
-
import { join as
|
|
11325
|
-
var BASELINE =
|
|
11422
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
11423
|
+
import { join as join9 } from "path";
|
|
11424
|
+
var BASELINE = join9(".claude", "governance.baseline.json");
|
|
11326
11425
|
var GOVERNS = (finding) => finding.severity === "warn";
|
|
11327
11426
|
var REPORTED = (finding) => finding.severity === "info";
|
|
11328
11427
|
function countByRule(findings) {
|
|
@@ -11334,7 +11433,7 @@ function countByRule(findings) {
|
|
|
11334
11433
|
}
|
|
11335
11434
|
function readBaseline(repo) {
|
|
11336
11435
|
try {
|
|
11337
|
-
const parsed = JSON.parse(
|
|
11436
|
+
const parsed = JSON.parse(readFileSync7(join9(repo, BASELINE), "utf-8"));
|
|
11338
11437
|
const allowed = parsed?.allowed;
|
|
11339
11438
|
return { allowed: allowed && typeof allowed === "object" ? allowed : {}, adopted: true };
|
|
11340
11439
|
} catch {
|
|
@@ -11375,7 +11474,7 @@ function writeBaseline(repo, baseline) {
|
|
|
11375
11474
|
const ordered = Object.fromEntries(
|
|
11376
11475
|
Object.entries(baseline.allowed).filter(([, count2]) => count2 > 0).sort(([left], [right]) => left.localeCompare(right))
|
|
11377
11476
|
);
|
|
11378
|
-
writeFileSync3(
|
|
11477
|
+
writeFileSync3(join9(repo, BASELINE), `${JSON.stringify({ allowed: ordered }, null, 2)}
|
|
11379
11478
|
`);
|
|
11380
11479
|
}
|
|
11381
11480
|
var NAMED = 5;
|
|
@@ -11543,7 +11642,7 @@ function acquireBuildLock(repoRoot, options = {}) {
|
|
|
11543
11642
|
if (released) return;
|
|
11544
11643
|
released = true;
|
|
11545
11644
|
try {
|
|
11546
|
-
if (
|
|
11645
|
+
if (readFileSync8(lockPath, "utf8").trim() !== String(process.pid)) return;
|
|
11547
11646
|
} catch {
|
|
11548
11647
|
return;
|
|
11549
11648
|
}
|
|
@@ -11553,7 +11652,7 @@ function acquireBuildLock(repoRoot, options = {}) {
|
|
|
11553
11652
|
}
|
|
11554
11653
|
function isStale(lockPath, staleMs) {
|
|
11555
11654
|
try {
|
|
11556
|
-
return Math.max(0, Date.now() -
|
|
11655
|
+
return Math.max(0, Date.now() - statSync5(lockPath).mtimeMs) >= staleMs;
|
|
11557
11656
|
} catch {
|
|
11558
11657
|
return true;
|
|
11559
11658
|
}
|
|
@@ -12056,10 +12155,20 @@ function createTool(handlers) {
|
|
|
12056
12155
|
};
|
|
12057
12156
|
}
|
|
12058
12157
|
function describeItem(item2) {
|
|
12059
|
-
const held = item2.holders && item2.holders.length > 0 ? ` \xB7
|
|
12158
|
+
const held = item2.holders && item2.holders.length > 0 ? ` \xB7 ${item2.holders.map(describeHolder).join(", ")}` : "";
|
|
12060
12159
|
const priority = item2.priority ? ` ${item2.priority}` : "";
|
|
12061
12160
|
return `${item2.id} \xB7 ${item2.status}${priority}${held} \u2014 ${item2.title}`;
|
|
12062
12161
|
}
|
|
12162
|
+
function describeHolder(holder) {
|
|
12163
|
+
const who = holder.by || holder.session;
|
|
12164
|
+
const names = (holder.addresses ?? []).map((each) => `\`${each.name}\``).join(", ");
|
|
12165
|
+
if (holder.live === "ended") return `ABANDONED by ${who}, whose run has ended`;
|
|
12166
|
+
if (holder.live === "forked") {
|
|
12167
|
+
return names ? `held by ${who} \xB7 ${holder.processes} runs on one session, ${names} \u2014 either reaches it` : `held by ${who} \xB7 ${holder.processes} runs on one session, none addressable`;
|
|
12168
|
+
}
|
|
12169
|
+
if (holder.live === "running") return names ? `held by ${who} ${names}` : `held by ${who}, running`;
|
|
12170
|
+
return `held by ${who} (cannot tell if still running)`;
|
|
12171
|
+
}
|
|
12063
12172
|
function describeList(response) {
|
|
12064
12173
|
if (response.items.length === 0) return "No work items match.";
|
|
12065
12174
|
if (!response.hasMore) {
|
|
@@ -12211,7 +12320,7 @@ function describeStart(response) {
|
|
|
12211
12320
|
}
|
|
12212
12321
|
|
|
12213
12322
|
// src/serve/approvals.ts
|
|
12214
|
-
import { readFileSync as
|
|
12323
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
12215
12324
|
import os10 from "os";
|
|
12216
12325
|
import path22 from "path";
|
|
12217
12326
|
function pendingApproval(cwd) {
|
|
@@ -12242,7 +12351,7 @@ function unapprovedServers(cwd) {
|
|
|
12242
12351
|
}
|
|
12243
12352
|
function readJson2(file) {
|
|
12244
12353
|
try {
|
|
12245
|
-
return JSON.parse(
|
|
12354
|
+
return JSON.parse(readFileSync9(file, "utf-8"));
|
|
12246
12355
|
} catch {
|
|
12247
12356
|
return null;
|
|
12248
12357
|
}
|
|
@@ -12361,7 +12470,7 @@ import { basename as basename3 } from "path";
|
|
|
12361
12470
|
// src/ui/server.ts
|
|
12362
12471
|
import { createServer as createServer2 } from "http";
|
|
12363
12472
|
import { readFile as readFile7 } from "fs/promises";
|
|
12364
|
-
import { basename as basename2, dirname as dirname7, extname, join as
|
|
12473
|
+
import { basename as basename2, dirname as dirname7, extname, join as join10, resolve as resolve9 } from "path";
|
|
12365
12474
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12366
12475
|
|
|
12367
12476
|
// src/ui/machine.ts
|
|
@@ -12433,7 +12542,7 @@ async function item(repo, id, res) {
|
|
|
12433
12542
|
}
|
|
12434
12543
|
async function asset(repo, assets, url, res) {
|
|
12435
12544
|
const wanted = url.pathname === "/" || !extname(url.pathname) ? "/index.html" : url.pathname;
|
|
12436
|
-
const path23 =
|
|
12545
|
+
const path23 = join10(assets, wanted);
|
|
12437
12546
|
if (!path23.startsWith(assets)) {
|
|
12438
12547
|
res.writeHead(403, { "cache-control": "no-store" }).end("no");
|
|
12439
12548
|
return;
|
|
@@ -12524,13 +12633,13 @@ function serveUi(repo, port, options = {}) {
|
|
|
12524
12633
|
|
|
12525
12634
|
// src/ui/source.ts
|
|
12526
12635
|
import { spawn as spawn3 } from "child_process";
|
|
12527
|
-
import { existsSync as existsSync7, readFileSync as
|
|
12636
|
+
import { existsSync as existsSync7, readFileSync as readFileSync10, watch } from "fs";
|
|
12528
12637
|
import { stat as stat3 } from "fs/promises";
|
|
12529
|
-
import { dirname as dirname8, join as
|
|
12638
|
+
import { dirname as dirname8, join as join11, resolve as resolve10 } from "path";
|
|
12530
12639
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
12531
|
-
var PAGE =
|
|
12640
|
+
var PAGE = join11("apps", "cli", "dist", "ui");
|
|
12532
12641
|
var BUNDLE = "app.js";
|
|
12533
|
-
var WATCHED = [
|
|
12642
|
+
var WATCHED = [join11("apps", "cli", "src", "ui"), join11("packages", "ui", "src")];
|
|
12534
12643
|
function fromSource() {
|
|
12535
12644
|
return fileURLToPath5(import.meta.url).endsWith(".ts");
|
|
12536
12645
|
}
|
|
@@ -12543,8 +12652,8 @@ function sourceCheckout() {
|
|
|
12543
12652
|
}
|
|
12544
12653
|
function builtFrom() {
|
|
12545
12654
|
try {
|
|
12546
|
-
const manifest =
|
|
12547
|
-
const read3 = JSON.parse(
|
|
12655
|
+
const manifest = join11(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
|
|
12656
|
+
const read3 = JSON.parse(readFileSync10(manifest, "utf-8"));
|
|
12548
12657
|
return typeof read3.jarvis?.source === "string" ? read3.jarvis.source : null;
|
|
12549
12658
|
} catch {
|
|
12550
12659
|
return null;
|
|
@@ -12552,16 +12661,16 @@ function builtFrom() {
|
|
|
12552
12661
|
}
|
|
12553
12662
|
function usable(root) {
|
|
12554
12663
|
const files2 = [
|
|
12555
|
-
|
|
12556
|
-
|
|
12664
|
+
join11(root, "apps", "cli", "src", "ui", "browser", "App.tsx"),
|
|
12665
|
+
join11(root, "apps", "cli", "tsup.ui.config.ts")
|
|
12557
12666
|
];
|
|
12558
12667
|
const present = files2.every((path23) => existsSync7(path23)) && tool(root, "tsup") && tool(root, "tsx");
|
|
12559
12668
|
return present ? root : null;
|
|
12560
12669
|
}
|
|
12561
12670
|
function tool(root, name) {
|
|
12562
12671
|
const places = [
|
|
12563
|
-
|
|
12564
|
-
|
|
12672
|
+
join11(root, "apps", "cli", "node_modules", ".bin", name),
|
|
12673
|
+
join11(root, "node_modules", ".bin", name)
|
|
12565
12674
|
];
|
|
12566
12675
|
return places.find((path23) => existsSync7(path23)) ?? null;
|
|
12567
12676
|
}
|
|
@@ -12571,7 +12680,7 @@ function runFromCheckout(req) {
|
|
|
12571
12680
|
[
|
|
12572
12681
|
"watch",
|
|
12573
12682
|
"--clear-screen=false",
|
|
12574
|
-
|
|
12683
|
+
join11(req.root, "apps", "cli", "src", "bin.ts"),
|
|
12575
12684
|
"ui",
|
|
12576
12685
|
"--repo",
|
|
12577
12686
|
req.repo,
|
|
@@ -12594,25 +12703,25 @@ function runFromCheckout(req) {
|
|
|
12594
12703
|
return child;
|
|
12595
12704
|
}
|
|
12596
12705
|
async function watchPage(root) {
|
|
12597
|
-
const dir =
|
|
12598
|
-
const before = await changedAt(
|
|
12706
|
+
const dir = join11(root, PAGE);
|
|
12707
|
+
const before = await changedAt(join11(dir, BUNDLE));
|
|
12599
12708
|
const build2 = spawn3(
|
|
12600
12709
|
tool(root, "tsup") ?? "tsup",
|
|
12601
12710
|
[
|
|
12602
12711
|
"--config",
|
|
12603
12712
|
"tsup.ui.config.ts",
|
|
12604
|
-
...WATCHED.flatMap((where) => ["--watch",
|
|
12713
|
+
...WATCHED.flatMap((where) => ["--watch", join11(root, where)])
|
|
12605
12714
|
],
|
|
12606
12715
|
{
|
|
12607
12716
|
stdio: ["ignore", "ignore", "inherit"],
|
|
12608
|
-
cwd:
|
|
12717
|
+
cwd: join11(root, "apps", "cli")
|
|
12609
12718
|
}
|
|
12610
12719
|
);
|
|
12611
12720
|
const stop = () => {
|
|
12612
12721
|
build2.kill("SIGTERM");
|
|
12613
12722
|
};
|
|
12614
12723
|
try {
|
|
12615
|
-
await landed(
|
|
12724
|
+
await landed(join11(dir, BUNDLE), before);
|
|
12616
12725
|
} catch (err) {
|
|
12617
12726
|
stop();
|
|
12618
12727
|
throw err;
|