@appchy/jarvis 0.1.109 → 0.1.111
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 +135 -143
- package/dist/bin.js.map +1 -1
- package/package.json +5 -5
package/dist/bin.js
CHANGED
|
@@ -1387,10 +1387,78 @@ async function ensureGraphify(options = {}) {
|
|
|
1387
1387
|
);
|
|
1388
1388
|
}
|
|
1389
1389
|
|
|
1390
|
+
// src/graph/hook.ts
|
|
1391
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, chmodSync } from "fs";
|
|
1392
|
+
import path7 from "path";
|
|
1393
|
+
var SIGNATURE = "# managed by jarvis";
|
|
1394
|
+
var SCRIPT = `#!/bin/sh
|
|
1395
|
+
${SIGNATURE} \u2014 keeps this repo's map current, so what an agent plans against is what is here.
|
|
1396
|
+
# Detached and silenced: git waits for a hook's output streams to close, so a build left on stdout
|
|
1397
|
+
# would hold up every commit by the length of a build. Never fails a commit.
|
|
1398
|
+
#
|
|
1399
|
+
# Run at the lowest priority the machine offers. A code commit still costs a real extract, and one
|
|
1400
|
+
# arriving at normal priority the instant you commit is felt as the machine going away for half a
|
|
1401
|
+
# minute \u2014 which is how a background job becomes something people turn off. Borrowed from the
|
|
1402
|
+
# docdoc-era hook in crispy, which had this right first.
|
|
1403
|
+
command -v jarvis >/dev/null 2>&1 || exit 0
|
|
1404
|
+
NICE=""
|
|
1405
|
+
command -v nice >/dev/null 2>&1 && NICE="nice -n 19"
|
|
1406
|
+
command -v taskpolicy >/dev/null 2>&1 && NICE="taskpolicy -b $NICE"
|
|
1407
|
+
( $NICE jarvis build graph >/dev/null 2>&1 & ) >/dev/null 2>&1
|
|
1408
|
+
exit 0
|
|
1409
|
+
`;
|
|
1410
|
+
function findRepoRoot(from) {
|
|
1411
|
+
let dir = path7.resolve(from);
|
|
1412
|
+
for (; ; ) {
|
|
1413
|
+
if (existsSync(path7.join(dir, ".git"))) return dir;
|
|
1414
|
+
const parent = path7.dirname(dir);
|
|
1415
|
+
if (parent === dir) return null;
|
|
1416
|
+
dir = parent;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
function installCommitHook(repoRoot) {
|
|
1420
|
+
const git4 = path7.join(repoRoot, ".git");
|
|
1421
|
+
const dir = path7.join(git4, "hooks");
|
|
1422
|
+
const file = path7.join(dir, "post-commit");
|
|
1423
|
+
if (!existsSync(git4)) return { installed: false, reason: "not-a-repo" };
|
|
1424
|
+
if (!statSync(git4).isDirectory()) return { installed: false, reason: "worktree" };
|
|
1425
|
+
if (!existsSync(path7.join(git4, "HEAD"))) return { installed: false, reason: "not-a-repo" };
|
|
1426
|
+
if (existsSync(file)) {
|
|
1427
|
+
try {
|
|
1428
|
+
if (!readFileSync(file, "utf8").includes(SIGNATURE))
|
|
1429
|
+
return { installed: false, reason: "foreign-hook", path: file };
|
|
1430
|
+
} catch {
|
|
1431
|
+
return { installed: false, reason: "unwritable", path: file };
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
try {
|
|
1435
|
+
mkdirSync(dir, { recursive: true });
|
|
1436
|
+
writeFileSync(file, SCRIPT, "utf8");
|
|
1437
|
+
chmodSync(file, 493);
|
|
1438
|
+
return { installed: true, path: file };
|
|
1439
|
+
} catch {
|
|
1440
|
+
return { installed: false, reason: "unwritable", path: file };
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
function describeCommitHook(outcome, repoRoot) {
|
|
1444
|
+
if (outcome.installed)
|
|
1445
|
+
return ` the map rebuilds itself on every commit here \u2713 (${path7.relative(repoRoot, outcome.path) || outcome.path})`;
|
|
1446
|
+
if (outcome.reason === "not-a-repo")
|
|
1447
|
+
return ` not a git repo, so there is no commit to rebuild on.
|
|
1448
|
+
Run this inside one, or rebuild by hand with 'jarvis build graph'.`;
|
|
1449
|
+
if (outcome.reason === "worktree")
|
|
1450
|
+
return ` this is a worktree or a submodule, and it shares the hooks of the checkout it
|
|
1451
|
+
was made from. Wire that one instead, or rebuild by hand with 'jarvis build graph'.`;
|
|
1452
|
+
if (outcome.reason === "foreign-hook")
|
|
1453
|
+
return ` a post-commit hook is already here and it is not ours \u2014 left untouched.
|
|
1454
|
+
Add this line to it to keep the map current: jarvis build graph >/dev/null 2>&1 &`;
|
|
1455
|
+
return ` could not write the hook \u2014 the map still builds, by hand, with 'jarvis build graph'.`;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1390
1458
|
// src/machine.ts
|
|
1391
1459
|
import crypto2 from "crypto";
|
|
1392
1460
|
import fs8 from "fs";
|
|
1393
|
-
import
|
|
1461
|
+
import path8 from "path";
|
|
1394
1462
|
var cached = null;
|
|
1395
1463
|
function getMachine() {
|
|
1396
1464
|
if (cached) return cached;
|
|
@@ -1405,7 +1473,7 @@ function getMachine() {
|
|
|
1405
1473
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1406
1474
|
schemaVersion: 1
|
|
1407
1475
|
};
|
|
1408
|
-
fs8.mkdirSync(
|
|
1476
|
+
fs8.mkdirSync(path8.dirname(file), { recursive: true });
|
|
1409
1477
|
fs8.writeFileSync(file, JSON.stringify(fresh, null, 2));
|
|
1410
1478
|
return cached = fresh;
|
|
1411
1479
|
}
|
|
@@ -1413,13 +1481,13 @@ function getMachine() {
|
|
|
1413
1481
|
// src/service.ts
|
|
1414
1482
|
import { execSync as execSync3, spawn } from "child_process";
|
|
1415
1483
|
import fs9 from "fs";
|
|
1416
|
-
import
|
|
1484
|
+
import path9 from "path";
|
|
1417
1485
|
import os4 from "os";
|
|
1418
1486
|
function serviceSuffix() {
|
|
1419
1487
|
const dir = getConfigDir();
|
|
1420
|
-
const base =
|
|
1488
|
+
const base = path9.join(os4.homedir(), ".jarvis");
|
|
1421
1489
|
if (dir === base) return "";
|
|
1422
|
-
const name = dir.startsWith(base +
|
|
1490
|
+
const name = dir.startsWith(base + path9.sep) ? dir.slice(base.length + 1) : path9.basename(dir);
|
|
1423
1491
|
return name.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1424
1492
|
}
|
|
1425
1493
|
var SERVICE_SUFFIX = serviceSuffix();
|
|
@@ -1430,8 +1498,8 @@ function createServiceManager() {
|
|
|
1430
1498
|
return new FallbackService();
|
|
1431
1499
|
}
|
|
1432
1500
|
var PLIST_LABEL = `com.appchy.jarvis${SERVICE_SUFFIX ? `.${SERVICE_SUFFIX}` : ""}`;
|
|
1433
|
-
var PLIST_DIR =
|
|
1434
|
-
var PLIST_PATH =
|
|
1501
|
+
var PLIST_DIR = path9.join(os4.homedir(), "Library", "LaunchAgents");
|
|
1502
|
+
var PLIST_PATH = path9.join(PLIST_DIR, `${PLIST_LABEL}.plist`);
|
|
1435
1503
|
function escapeXml(s) {
|
|
1436
1504
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1437
1505
|
}
|
|
@@ -1585,7 +1653,7 @@ ${Object.entries(opts.env ?? {}).map(([k, v]) => ` <key>${escapeXml(k)}</key>
|
|
|
1585
1653
|
</plist>
|
|
1586
1654
|
`;
|
|
1587
1655
|
fs9.mkdirSync(PLIST_DIR, { recursive: true });
|
|
1588
|
-
fs9.mkdirSync(
|
|
1656
|
+
fs9.mkdirSync(path9.dirname(logFile), { recursive: true });
|
|
1589
1657
|
unloadAgent();
|
|
1590
1658
|
fs9.writeFileSync(PLIST_PATH, plist);
|
|
1591
1659
|
loadAgent();
|
|
@@ -1687,7 +1755,7 @@ var WindowsService = class {
|
|
|
1687
1755
|
</Task>
|
|
1688
1756
|
`;
|
|
1689
1757
|
const tmpDir = os4.tmpdir();
|
|
1690
|
-
const tmpFile =
|
|
1758
|
+
const tmpFile = path9.join(tmpDir, `jarvis-task-${Date.now()}.xml`);
|
|
1691
1759
|
fs9.writeFileSync(tmpFile, xml, { encoding: "utf-16le" });
|
|
1692
1760
|
try {
|
|
1693
1761
|
execSync3(`schtasks /Create /TN "${TASK_NAME}" /XML "${tmpFile}" /F`, {
|
|
@@ -1733,9 +1801,9 @@ var WindowsService = class {
|
|
|
1733
1801
|
}
|
|
1734
1802
|
}
|
|
1735
1803
|
};
|
|
1736
|
-
var SYSTEMD_DIR =
|
|
1804
|
+
var SYSTEMD_DIR = path9.join(os4.homedir(), ".config", "systemd", "user");
|
|
1737
1805
|
var UNIT_NAME = `jarvis${SERVICE_SUFFIX ? `-${SERVICE_SUFFIX}` : ""}.service`;
|
|
1738
|
-
var UNIT_PATH =
|
|
1806
|
+
var UNIT_PATH = path9.join(SYSTEMD_DIR, UNIT_NAME);
|
|
1739
1807
|
var LinuxService = class {
|
|
1740
1808
|
install(opts) {
|
|
1741
1809
|
const args = [opts.entryPath, "start", "--foreground", "--workspace", opts.workspacePath];
|
|
@@ -1764,7 +1832,7 @@ StandardError=append:${logFile}
|
|
|
1764
1832
|
WantedBy=default.target
|
|
1765
1833
|
`;
|
|
1766
1834
|
fs9.mkdirSync(SYSTEMD_DIR, { recursive: true });
|
|
1767
|
-
fs9.mkdirSync(
|
|
1835
|
+
fs9.mkdirSync(path9.dirname(logFile), { recursive: true });
|
|
1768
1836
|
if (this.isInstalled()) {
|
|
1769
1837
|
try {
|
|
1770
1838
|
execSync3(`systemctl --user stop ${UNIT_NAME}`, { stdio: "ignore" });
|
|
@@ -1844,9 +1912,9 @@ WantedBy=default.target
|
|
|
1844
1912
|
};
|
|
1845
1913
|
var FallbackService = class {
|
|
1846
1914
|
baseDir = getJarvisDir();
|
|
1847
|
-
pidFile =
|
|
1848
|
-
logFile =
|
|
1849
|
-
markerFile =
|
|
1915
|
+
pidFile = path9.join(this.baseDir, "agent.pid");
|
|
1916
|
+
logFile = path9.join(this.baseDir, "agent.log");
|
|
1917
|
+
markerFile = path9.join(this.baseDir, "service-installed");
|
|
1850
1918
|
install(opts) {
|
|
1851
1919
|
fs9.mkdirSync(this.baseDir, { recursive: true });
|
|
1852
1920
|
this.stop();
|
|
@@ -1921,11 +1989,11 @@ var FallbackService = class {
|
|
|
1921
1989
|
};
|
|
1922
1990
|
|
|
1923
1991
|
// src/hooks/install.ts
|
|
1924
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
1992
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1925
1993
|
import os5 from "os";
|
|
1926
|
-
import
|
|
1927
|
-
var SETTINGS_DIR =
|
|
1928
|
-
var SETTINGS_FILE =
|
|
1994
|
+
import path10 from "path";
|
|
1995
|
+
var SETTINGS_DIR = path10.join(os5.homedir(), ".claude");
|
|
1996
|
+
var SETTINGS_FILE = path10.join(SETTINGS_DIR, "settings.json");
|
|
1929
1997
|
var HOOK_STEMS = [
|
|
1930
1998
|
"pre-tool-use",
|
|
1931
1999
|
"session-start",
|
|
@@ -1943,7 +2011,7 @@ function jarvisHooks() {
|
|
|
1943
2011
|
];
|
|
1944
2012
|
}
|
|
1945
2013
|
function isJarvisCommand(command) {
|
|
1946
|
-
const name =
|
|
2014
|
+
const name = path10.basename(command);
|
|
1947
2015
|
return HOOK_STEMS.some((stem) => name === `${stem}.mjs` || name === `${stem}.dev.mjs`);
|
|
1948
2016
|
}
|
|
1949
2017
|
function getCliRoot() {
|
|
@@ -1956,22 +2024,22 @@ function getCliRoot() {
|
|
|
1956
2024
|
entry = realpathSync(binPath);
|
|
1957
2025
|
} catch {
|
|
1958
2026
|
}
|
|
1959
|
-
return
|
|
2027
|
+
return path10.resolve(path10.dirname(entry), "..");
|
|
1960
2028
|
}
|
|
1961
2029
|
function resolveHooks() {
|
|
1962
2030
|
const cliRoot = getCliRoot();
|
|
1963
2031
|
return jarvisHooks().map((h) => ({
|
|
1964
2032
|
...h,
|
|
1965
|
-
binAbsPath:
|
|
2033
|
+
binAbsPath: path10.join(cliRoot, "bin", h.binBasename)
|
|
1966
2034
|
}));
|
|
1967
2035
|
}
|
|
1968
2036
|
function ownsClaudeCode() {
|
|
1969
|
-
return getConfigDir() ===
|
|
2037
|
+
return getConfigDir() === path10.join(os5.homedir(), ".jarvis");
|
|
1970
2038
|
}
|
|
1971
2039
|
function readSettings() {
|
|
1972
|
-
if (!
|
|
2040
|
+
if (!existsSync2(SETTINGS_FILE)) return {};
|
|
1973
2041
|
try {
|
|
1974
|
-
const raw =
|
|
2042
|
+
const raw = readFileSync2(SETTINGS_FILE, "utf-8");
|
|
1975
2043
|
return raw.trim() ? JSON.parse(raw) : {};
|
|
1976
2044
|
} catch (err) {
|
|
1977
2045
|
logger.sys.warn("[hooks.install] settings.json unreadable", {
|
|
@@ -1982,8 +2050,8 @@ function readSettings() {
|
|
|
1982
2050
|
}
|
|
1983
2051
|
function writeSettings(s) {
|
|
1984
2052
|
try {
|
|
1985
|
-
|
|
1986
|
-
|
|
2053
|
+
mkdirSync2(SETTINGS_DIR, { recursive: true });
|
|
2054
|
+
writeFileSync2(SETTINGS_FILE, JSON.stringify(s, null, 2) + "\n");
|
|
1987
2055
|
return true;
|
|
1988
2056
|
} catch (err) {
|
|
1989
2057
|
logger.sys.warn("[hooks.install] settings.json unwritable", {
|
|
@@ -2028,7 +2096,7 @@ function claudeCodeHooksState() {
|
|
|
2028
2096
|
return {
|
|
2029
2097
|
type: hook.type,
|
|
2030
2098
|
bin: hook.binAbsPath,
|
|
2031
|
-
exists:
|
|
2099
|
+
exists: existsSync2(hook.binAbsPath),
|
|
2032
2100
|
...command ? { command } : {}
|
|
2033
2101
|
};
|
|
2034
2102
|
});
|
|
@@ -2050,10 +2118,10 @@ function installClaudeCodeHooks() {
|
|
|
2050
2118
|
expected: resolved.map((h) => ({
|
|
2051
2119
|
type: h.type,
|
|
2052
2120
|
bin: h.binAbsPath,
|
|
2053
|
-
exists:
|
|
2121
|
+
exists: existsSync2(h.binAbsPath)
|
|
2054
2122
|
}))
|
|
2055
2123
|
});
|
|
2056
|
-
const missing = resolved.filter((h) => !
|
|
2124
|
+
const missing = resolved.filter((h) => !existsSync2(h.binAbsPath));
|
|
2057
2125
|
if (missing.length === resolved.length) {
|
|
2058
2126
|
logger.sys.warn("[hooks.install] no bin shims found, skipping", {
|
|
2059
2127
|
configDir: configDir2,
|
|
@@ -2064,7 +2132,7 @@ function installClaudeCodeHooks() {
|
|
|
2064
2132
|
let settings = readSettings();
|
|
2065
2133
|
const installed = [];
|
|
2066
2134
|
for (const hook of resolved) {
|
|
2067
|
-
if (!
|
|
2135
|
+
if (!existsSync2(hook.binAbsPath)) {
|
|
2068
2136
|
logger.sys.warn("[hooks.install] bin shim missing, skipping hook", {
|
|
2069
2137
|
configDir: configDir2,
|
|
2070
2138
|
type: hook.type,
|
|
@@ -2232,94 +2300,11 @@ Open Claude Code in a repo that has a work/ tree to see them.`);
|
|
|
2232
2300
|
});
|
|
2233
2301
|
}
|
|
2234
2302
|
|
|
2235
|
-
// src/graph/hook.ts
|
|
2236
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync, writeFileSync as writeFileSync2, chmodSync } from "fs";
|
|
2237
|
-
import path10 from "path";
|
|
2238
|
-
var SIGNATURE = "# managed by jarvis";
|
|
2239
|
-
var SCRIPT = `#!/bin/sh
|
|
2240
|
-
${SIGNATURE} \u2014 keeps this repo's map current, so what an agent plans against is what is here.
|
|
2241
|
-
# Detached and silenced: git waits for a hook's output streams to close, so a build left on stdout
|
|
2242
|
-
# would hold up every commit by the length of a build. Never fails a commit.
|
|
2243
|
-
#
|
|
2244
|
-
# Run at the lowest priority the machine offers. A code commit still costs a real extract, and one
|
|
2245
|
-
# arriving at normal priority the instant you commit is felt as the machine going away for half a
|
|
2246
|
-
# minute \u2014 which is how a background job becomes something people turn off. Borrowed from the
|
|
2247
|
-
# docdoc-era hook in crispy, which had this right first.
|
|
2248
|
-
command -v jarvis >/dev/null 2>&1 || exit 0
|
|
2249
|
-
NICE=""
|
|
2250
|
-
command -v nice >/dev/null 2>&1 && NICE="nice -n 19"
|
|
2251
|
-
command -v taskpolicy >/dev/null 2>&1 && NICE="taskpolicy -b $NICE"
|
|
2252
|
-
( $NICE jarvis build graph >/dev/null 2>&1 & ) >/dev/null 2>&1
|
|
2253
|
-
exit 0
|
|
2254
|
-
`;
|
|
2255
|
-
function findRepoRoot(from) {
|
|
2256
|
-
let dir = path10.resolve(from);
|
|
2257
|
-
for (; ; ) {
|
|
2258
|
-
if (existsSync2(path10.join(dir, ".git"))) return dir;
|
|
2259
|
-
const parent = path10.dirname(dir);
|
|
2260
|
-
if (parent === dir) return null;
|
|
2261
|
-
dir = parent;
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
function installCommitHook(repoRoot) {
|
|
2265
|
-
const git4 = path10.join(repoRoot, ".git");
|
|
2266
|
-
const dir = path10.join(git4, "hooks");
|
|
2267
|
-
const file = path10.join(dir, "post-commit");
|
|
2268
|
-
if (!existsSync2(git4)) return { installed: false, reason: "not-a-repo" };
|
|
2269
|
-
if (!statSync(git4).isDirectory()) return { installed: false, reason: "worktree" };
|
|
2270
|
-
if (!existsSync2(path10.join(git4, "HEAD"))) return { installed: false, reason: "not-a-repo" };
|
|
2271
|
-
if (existsSync2(file)) {
|
|
2272
|
-
try {
|
|
2273
|
-
if (!readFileSync2(file, "utf8").includes(SIGNATURE))
|
|
2274
|
-
return { installed: false, reason: "foreign-hook", path: file };
|
|
2275
|
-
} catch {
|
|
2276
|
-
return { installed: false, reason: "unwritable", path: file };
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
try {
|
|
2280
|
-
mkdirSync2(dir, { recursive: true });
|
|
2281
|
-
writeFileSync2(file, SCRIPT, "utf8");
|
|
2282
|
-
chmodSync(file, 493);
|
|
2283
|
-
return { installed: true, path: file };
|
|
2284
|
-
} catch {
|
|
2285
|
-
return { installed: false, reason: "unwritable", path: file };
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
function describeCommitHook(outcome, repoRoot) {
|
|
2289
|
-
if (outcome.installed)
|
|
2290
|
-
return ` the map rebuilds itself on every commit here \u2713 (${path10.relative(repoRoot, outcome.path) || outcome.path})`;
|
|
2291
|
-
if (outcome.reason === "not-a-repo")
|
|
2292
|
-
return ` not a git repo, so there is no commit to rebuild on.
|
|
2293
|
-
Run this inside one, or rebuild by hand with 'jarvis build graph'.`;
|
|
2294
|
-
if (outcome.reason === "worktree")
|
|
2295
|
-
return ` this is a worktree or a submodule, and it shares the hooks of the checkout it
|
|
2296
|
-
was made from. Wire that one instead, or rebuild by hand with 'jarvis build graph'.`;
|
|
2297
|
-
if (outcome.reason === "foreign-hook")
|
|
2298
|
-
return ` a post-commit hook is already here and it is not ours \u2014 left untouched.
|
|
2299
|
-
Add this line to it to keep the map current: jarvis build graph >/dev/null 2>&1 &`;
|
|
2300
|
-
return ` could not write the hook \u2014 the map still builds, by hand, with 'jarvis build graph'.`;
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
// src/commands/repo.ts
|
|
2304
|
-
function register3(program) {
|
|
2305
|
-
const repo = program.command("repo").description("Set up the repo you are standing in \u2014 no pairing, no daemon, no network");
|
|
2306
|
-
repo.command("init").description("Keep this repo's map current by rebuilding it on every commit").action(() => {
|
|
2307
|
-
if (!setUpThisRepo()) process.exit(1);
|
|
2308
|
-
console.log(" It rebuilds from your next commit. To build one now: jarvis build graph\n");
|
|
2309
|
-
});
|
|
2310
|
-
}
|
|
2311
|
-
function setUpThisRepo() {
|
|
2312
|
-
const root = findRepoRoot(process.cwd()) ?? process.cwd();
|
|
2313
|
-
console.log(" \u25B8 Keeping this repo's map current");
|
|
2314
|
-
const outcome = installCommitHook(root);
|
|
2315
|
-
console.log(`${describeCommitHook(outcome, root)}
|
|
2316
|
-
`);
|
|
2317
|
-
return outcome.installed;
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
2303
|
// src/commands/init.ts
|
|
2321
|
-
function
|
|
2322
|
-
program.command("init").description(
|
|
2304
|
+
function register3(program) {
|
|
2305
|
+
program.command("init").description(
|
|
2306
|
+
"Set up this machine and the repo you are standing in; join an instance only if you name one"
|
|
2307
|
+
).option("--url <url>", "Also join the jarvis instance at this address").option("--skip-daemon", "Skip the background daemon install step").option("--force", "Re-ask all prompts even when config already has answers").action(async (opts) => {
|
|
2323
2308
|
const ok = await runInit({
|
|
2324
2309
|
url: opts.url,
|
|
2325
2310
|
skipDaemonInstall: opts.skipDaemon,
|
|
@@ -2414,6 +2399,14 @@ async function setUpThisMachine(prompts) {
|
|
|
2414
2399
|
`
|
|
2415
2400
|
);
|
|
2416
2401
|
}
|
|
2402
|
+
function setUpThisRepo() {
|
|
2403
|
+
const root = findRepoRoot(process.cwd()) ?? process.cwd();
|
|
2404
|
+
console.log(" \u25B8 Keeping this repo's map current");
|
|
2405
|
+
const outcome = installCommitHook(root);
|
|
2406
|
+
console.log(`${describeCommitHook(outcome, root)}
|
|
2407
|
+
`);
|
|
2408
|
+
return outcome.installed;
|
|
2409
|
+
}
|
|
2417
2410
|
async function setUpMapTool(prompts) {
|
|
2418
2411
|
console.log(" \u25B8 The tool the map's code half is built from");
|
|
2419
2412
|
const state2 = resolveGraphify();
|
|
@@ -2476,7 +2469,7 @@ function reportSetUp(joined) {
|
|
|
2476
2469
|
console.log(" \u2714 Done. This machine works in any repo that has a work/ tree:");
|
|
2477
2470
|
console.log(" the board, the map, the session block, the rules that arrive on edit,");
|
|
2478
2471
|
console.log(" and 'jarvis serve' for any agent that speaks MCP.\n");
|
|
2479
|
-
console.log(" In a repo you have cloned: jarvis
|
|
2472
|
+
console.log(" In a repo you have cloned: jarvis init");
|
|
2480
2473
|
console.log(" jarvis build graph");
|
|
2481
2474
|
console.log(" jarvis work list\n");
|
|
2482
2475
|
if (joined) {
|
|
@@ -2695,7 +2688,7 @@ async function promptList(question, fallback) {
|
|
|
2695
2688
|
}
|
|
2696
2689
|
|
|
2697
2690
|
// src/commands/pair.ts
|
|
2698
|
-
function
|
|
2691
|
+
function register4(program) {
|
|
2699
2692
|
program.command("pair").description("Re-pair this machine (when token expired)").action(async () => {
|
|
2700
2693
|
try {
|
|
2701
2694
|
await runPair();
|
|
@@ -2809,7 +2802,7 @@ async function unpair() {
|
|
|
2809
2802
|
clearConfig();
|
|
2810
2803
|
return { attempted: true, serverStatus };
|
|
2811
2804
|
}
|
|
2812
|
-
function
|
|
2805
|
+
function register5(program) {
|
|
2813
2806
|
program.command("unpair").description("Unregister this env from cloud and wipe local config").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
|
2814
2807
|
try {
|
|
2815
2808
|
const config2 = loadConfig();
|
|
@@ -2864,7 +2857,7 @@ function getRoots() {
|
|
|
2864
2857
|
const cfg = readConfig();
|
|
2865
2858
|
return Array.isArray(cfg.roots) ? cfg.roots : [];
|
|
2866
2859
|
}
|
|
2867
|
-
function
|
|
2860
|
+
function register6(program) {
|
|
2868
2861
|
const cmd = program.command("roots").description("Manage code-root directories");
|
|
2869
2862
|
cmd.command("list", { isDefault: true }).description("List current roots").action(() => {
|
|
2870
2863
|
const roots = getRoots();
|
|
@@ -2909,7 +2902,7 @@ function readLocalConfig() {
|
|
|
2909
2902
|
return {};
|
|
2910
2903
|
}
|
|
2911
2904
|
}
|
|
2912
|
-
function
|
|
2905
|
+
function register7(program) {
|
|
2913
2906
|
program.command("settings").description("Show this env's settings (roots, repos map)").action(async () => {
|
|
2914
2907
|
try {
|
|
2915
2908
|
const config2 = loadConfig();
|
|
@@ -10291,7 +10284,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
10291
10284
|
var _require = createRequire2(import.meta.url);
|
|
10292
10285
|
var VERSION2 = _require("../package.json").version ?? "0.0.0";
|
|
10293
10286
|
var IS_DEV = String(_require("../package.json").name ?? "").endsWith("-dev");
|
|
10294
|
-
var SHA = "
|
|
10287
|
+
var SHA = "c1c24cf";
|
|
10295
10288
|
var BUILT = "2026-09-12";
|
|
10296
10289
|
var BUILD = SHA ?? "source";
|
|
10297
10290
|
var BUILD_LABEL = `${SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`}${IS_DEV ? " \u2014 development build" : ""}`;
|
|
@@ -10810,7 +10803,7 @@ async function fetchRoots(hubUrl, envId, token) {
|
|
|
10810
10803
|
}
|
|
10811
10804
|
|
|
10812
10805
|
// src/commands/start.ts
|
|
10813
|
-
function
|
|
10806
|
+
function register8(program) {
|
|
10814
10807
|
program.command("start").description("Start the local agent (authenticates, cleans up stale processes, starts fresh)").option("-w, --workspace <path>", "Workspace root path").option("--api-key <key>", "Anthropic API key (for local-only use)").option("--no-upstream", "Don't connect to cloud (local-only mode)").option("--foreground", "Run in foreground (don't daemonize)").option("--force", "Re-ask all prompts even when config has them").action(async (opts) => {
|
|
10815
10808
|
if (refuseWithoutInstance()) process.exit(1);
|
|
10816
10809
|
const config2 = loadConfig();
|
|
@@ -10947,7 +10940,7 @@ function buildUpstreamConfig(req) {
|
|
|
10947
10940
|
}
|
|
10948
10941
|
|
|
10949
10942
|
// src/commands/stop.ts
|
|
10950
|
-
function
|
|
10943
|
+
function register9(program) {
|
|
10951
10944
|
program.command("stop").description("Stop the running agent").action(() => {
|
|
10952
10945
|
uninstallClaudeCodeHooks();
|
|
10953
10946
|
const service = createServiceManager();
|
|
@@ -10974,7 +10967,7 @@ function register10(program) {
|
|
|
10974
10967
|
}
|
|
10975
10968
|
|
|
10976
10969
|
// src/commands/restart.ts
|
|
10977
|
-
function
|
|
10970
|
+
function register10(program) {
|
|
10978
10971
|
program.command("restart").description("Restart the agent (alias for start \u2014 start always does a clean restart)").action(async () => {
|
|
10979
10972
|
await program.parseAsync(["node", "jarvis", "start"]);
|
|
10980
10973
|
});
|
|
@@ -10983,7 +10976,7 @@ function register11(program) {
|
|
|
10983
10976
|
// src/commands/logs.ts
|
|
10984
10977
|
import { spawn as spawn2, execSync as execSync6 } from "child_process";
|
|
10985
10978
|
import fs16 from "fs";
|
|
10986
|
-
function
|
|
10979
|
+
function register11(program) {
|
|
10987
10980
|
program.command("logs").description("View agent logs").option("-f, --follow", "Follow log output (like tail -f)", true).option("-n, --lines <n>", "Number of lines to show", "50").action((opts) => {
|
|
10988
10981
|
const logFile = getLogFile();
|
|
10989
10982
|
if (!fs16.existsSync(logFile)) {
|
|
@@ -11058,7 +11051,7 @@ function portOf(url) {
|
|
|
11058
11051
|
// src/commands/status.ts
|
|
11059
11052
|
var GREEN2 = (text) => `\x1B[32m${text}\x1B[0m`;
|
|
11060
11053
|
var RED2 = (text) => `\x1B[31m${text}\x1B[0m`;
|
|
11061
|
-
function
|
|
11054
|
+
function register12(program) {
|
|
11062
11055
|
program.command("status").description("Show agent configuration and connection status").action(async () => {
|
|
11063
11056
|
const config2 = loadConfig();
|
|
11064
11057
|
const health = await getHealth();
|
|
@@ -11097,7 +11090,7 @@ function endpoint(probed) {
|
|
|
11097
11090
|
}
|
|
11098
11091
|
|
|
11099
11092
|
// src/commands/install.ts
|
|
11100
|
-
function
|
|
11093
|
+
function register13(program) {
|
|
11101
11094
|
program.command("install").description("Install as OS service for auto-start on login and crash recovery").option("-w, --workspace <path>", "Workspace root path").option("--no-upstream", "Don't connect to cloud").action(async (opts) => {
|
|
11102
11095
|
if (refuseWithoutInstance()) process.exit(1);
|
|
11103
11096
|
const config2 = loadConfig();
|
|
@@ -11146,7 +11139,7 @@ function register14(program) {
|
|
|
11146
11139
|
import fs17 from "fs";
|
|
11147
11140
|
import path19 from "path";
|
|
11148
11141
|
import { createInterface as createInterface5 } from "readline";
|
|
11149
|
-
function
|
|
11142
|
+
function register14(program) {
|
|
11150
11143
|
program.command("uninstall").description("Stop the agent, remove the OS service, and wipe local config + identity").option("--keep-data", "Skip the data-wipe prompt; preserve skills/prompts/cache/settings").option("--purge", "Skip the prompt and wipe ALL local data (skills, prompts, cache, settings)").action(async (opts) => {
|
|
11151
11144
|
try {
|
|
11152
11145
|
await runUninstall(opts);
|
|
@@ -11208,7 +11201,7 @@ function confirm2(prompt) {
|
|
|
11208
11201
|
}
|
|
11209
11202
|
|
|
11210
11203
|
// src/commands/logout.ts
|
|
11211
|
-
function
|
|
11204
|
+
function register15(program) {
|
|
11212
11205
|
program.command("logout").description("Clear saved configuration").action(() => {
|
|
11213
11206
|
clearConfig();
|
|
11214
11207
|
console.log("Configuration cleared.");
|
|
@@ -11239,7 +11232,7 @@ async function call(path23, method, body) {
|
|
|
11239
11232
|
}
|
|
11240
11233
|
return await resp.json();
|
|
11241
11234
|
}
|
|
11242
|
-
function
|
|
11235
|
+
function register16(program) {
|
|
11243
11236
|
const mcp = program.command("mcp").description("Connect an agent to this workspace's board");
|
|
11244
11237
|
mcp.command("token").description("Mint a personal token for the Jarvis MCP server").option("--name <name>", "Which machine this token is for, e.g. 'laptop'").option("--scopes <list>", "read | write | read,write", "read,write").option("--show", "Show the current token's details instead of minting").option("--revoke", "Revoke the current token").action(async (opts) => {
|
|
11245
11238
|
try {
|
|
@@ -11293,7 +11286,7 @@ function register17(program) {
|
|
|
11293
11286
|
}
|
|
11294
11287
|
|
|
11295
11288
|
// src/commands/model.ts
|
|
11296
|
-
function
|
|
11289
|
+
function register17(program) {
|
|
11297
11290
|
const model = program.command("model").description("Model access for the map's semantic search, on this machine");
|
|
11298
11291
|
model.command("key").argument("[key]", "The OpenAI key to store. Omit it to see what is set.").option("--show", "Say whether a key is set, without printing it").option("--clear", "Forget the stored key").description("Set the OpenAI key the map embeds with").action((key, opts) => {
|
|
11299
11292
|
const config2 = loadConfig();
|
|
@@ -11552,7 +11545,7 @@ function isStale(lockPath, staleMs) {
|
|
|
11552
11545
|
}
|
|
11553
11546
|
|
|
11554
11547
|
// src/commands/build.ts
|
|
11555
|
-
function
|
|
11548
|
+
function register18(program) {
|
|
11556
11549
|
const build2 = program.command("build").description("Build an artifact from this repo");
|
|
11557
11550
|
build2.command("graph").description("Read the repo's jarvis.config.ts, build the graph, and say what is wrong with it").option("--repo <path>", "The repo to map. Default: the working directory").option("--rebuild", "LAST RESORT: throw the graph away and re-extract from scratch").option("--label", "Re-name the detected communities through the configured labeler").option("--gate", "Fail when a governance class has more findings than this repo carries").action(async (opts) => {
|
|
11558
11551
|
const argv = [
|
|
@@ -11612,7 +11605,7 @@ function isRedirected(req) {
|
|
|
11612
11605
|
}
|
|
11613
11606
|
|
|
11614
11607
|
// src/commands/dev.ts
|
|
11615
|
-
function
|
|
11608
|
+
function register19(program) {
|
|
11616
11609
|
const dev = program.command("dev").description("Run a development build in a repo, without replacing the installed jarvis");
|
|
11617
11610
|
dev.command("use").argument("[where]", "'here' for the working directory, 'all' for every repo", "here").option("--root <path>", "The checkout to run. Default: the one already recorded").description("Point a repo at the development build").action((where, opts) => {
|
|
11618
11611
|
const current = readDevRedirect();
|
|
@@ -12329,7 +12322,7 @@ async function brief2(repo) {
|
|
|
12329
12322
|
}
|
|
12330
12323
|
|
|
12331
12324
|
// src/commands/serve.ts
|
|
12332
|
-
function
|
|
12325
|
+
function register20(program) {
|
|
12333
12326
|
program.command("serve").description("Serve this repo to an agent over stdio \u2014 what an .mcp.json launches").option("--repo <path>", "The repo to serve. Default: the working directory").action(async (opts) => {
|
|
12334
12327
|
const repo = resolveRepo(opts.repo);
|
|
12335
12328
|
const problem = harnessProblem();
|
|
@@ -12634,7 +12627,7 @@ function whenRebuilt(dir, reload) {
|
|
|
12634
12627
|
}
|
|
12635
12628
|
|
|
12636
12629
|
// src/commands/ui.ts
|
|
12637
|
-
function
|
|
12630
|
+
function register21(program) {
|
|
12638
12631
|
program.command("ui").description("Open this repo's board in a browser \u2014 nothing to configure, nothing to join").option("--repo <path>", "The repo to show. Default: the working directory").option("--port <number>", "The port to listen on. Default: 3402").option("--no-open", "Print the address instead of opening a browser").option("--packaged", "Serve the page this build shipped with, never a checkout's").action(async (opts) => {
|
|
12639
12632
|
const repo = resolveRepo(opts.repo);
|
|
12640
12633
|
const port = opts.port ? Number.parseInt(opts.port, 10) : 3402;
|
|
@@ -12704,7 +12697,7 @@ async function openWhenUp(port) {
|
|
|
12704
12697
|
|
|
12705
12698
|
// src/commands/work.ts
|
|
12706
12699
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
12707
|
-
function
|
|
12700
|
+
function register22(program) {
|
|
12708
12701
|
program.command("work").description("The board \u2014 take work, prove it, finish it").argument("[args...]", "Passed to the harness untouched").allowUnknownOption().passThroughOptions().helpOption(false).action((passed) => {
|
|
12709
12702
|
const problem = harnessProblem();
|
|
12710
12703
|
if (problem) {
|
|
@@ -12727,11 +12720,11 @@ function register23(program) {
|
|
|
12727
12720
|
// src/cli.ts
|
|
12728
12721
|
function createCli() {
|
|
12729
12722
|
const program = new Command().enablePositionalOptions().name("jarvis").description("Jarvis local agent \u2014 watches Claude Code sessions on your machine").version(BUILD_LABEL);
|
|
12730
|
-
register4(program);
|
|
12731
12723
|
register3(program);
|
|
12724
|
+
register4(program);
|
|
12732
12725
|
register5(program);
|
|
12733
|
-
register6(program);
|
|
12734
12726
|
register(program);
|
|
12727
|
+
register6(program);
|
|
12735
12728
|
register7(program);
|
|
12736
12729
|
register8(program);
|
|
12737
12730
|
register9(program);
|
|
@@ -12746,10 +12739,9 @@ function createCli() {
|
|
|
12746
12739
|
register18(program);
|
|
12747
12740
|
register19(program);
|
|
12748
12741
|
register20(program);
|
|
12749
|
-
register21(program);
|
|
12750
12742
|
register2(program);
|
|
12743
|
+
register21(program);
|
|
12751
12744
|
register22(program);
|
|
12752
|
-
register23(program);
|
|
12753
12745
|
return program;
|
|
12754
12746
|
}
|
|
12755
12747
|
|