@jpcasabiancai/cayenne 0.5.7 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +413 -242
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1325,7 +1325,7 @@ var init_local = __esm({
|
|
|
1325
1325
|
|
|
1326
1326
|
// ../../packages/shared/src/protocol/runner.ts
|
|
1327
1327
|
import { z as z14 } from "zod";
|
|
1328
|
-
var ProviderModel, ProviderCapability, UNAVAILABLE, RunnerCapabilities, CODEX_TOOL_NAMES;
|
|
1328
|
+
var ProviderModel, ProviderAuthMode, ProviderCapability, UNAVAILABLE, RunnerCapabilities, CODEX_TOOL_NAMES;
|
|
1329
1329
|
var init_runner = __esm({
|
|
1330
1330
|
"../../packages/shared/src/protocol/runner.ts"() {
|
|
1331
1331
|
"use strict";
|
|
@@ -1338,13 +1338,21 @@ var init_runner = __esm({
|
|
|
1338
1338
|
/** From the app-server's `supportedReasoningEfforts`; empty means the control is hidden. */
|
|
1339
1339
|
efforts: z14.array(Effort).default([]),
|
|
1340
1340
|
/** The effort a new chat on this model opens at, sent back on `session.start`. */
|
|
1341
|
-
defaultEffort: Effort.optional()
|
|
1341
|
+
defaultEffort: Effort.optional(),
|
|
1342
|
+
/** One line about the model in the provider's own words (Claude's `ModelInfo.description`). */
|
|
1343
|
+
description: z14.string().min(1).max(200).optional()
|
|
1342
1344
|
});
|
|
1345
|
+
ProviderAuthMode = z14.enum(["subscription", "api", "third_party"]);
|
|
1343
1346
|
ProviderCapability = z14.object({
|
|
1344
1347
|
available: z14.boolean(),
|
|
1345
1348
|
reason: z14.enum(["not_installed", "not_logged_in", "error"]).optional(),
|
|
1346
1349
|
version: z14.string().max(50).optional(),
|
|
1347
|
-
models: z14.array(ProviderModel).max(50).default([])
|
|
1350
|
+
models: z14.array(ProviderModel).max(50).default([]),
|
|
1351
|
+
/**
|
|
1352
|
+
* How the provider is signed in, when the runner can tell without opening a chat (Claude's
|
|
1353
|
+
* `accountInfo`, protocol §9). Absent means unknown. Optional so an older row still parses.
|
|
1354
|
+
*/
|
|
1355
|
+
authMode: ProviderAuthMode.optional()
|
|
1348
1356
|
});
|
|
1349
1357
|
UNAVAILABLE = { available: false, reason: "not_installed", models: [] };
|
|
1350
1358
|
RunnerCapabilities = z14.object({
|
|
@@ -2624,13 +2632,200 @@ var init_version = __esm({
|
|
|
2624
2632
|
}
|
|
2625
2633
|
});
|
|
2626
2634
|
|
|
2635
|
+
// src/providers/env.ts
|
|
2636
|
+
function definedEnv(env) {
|
|
2637
|
+
const out = {};
|
|
2638
|
+
for (const [key, value] of Object.entries(env)) if (value !== void 0) out[key] = value;
|
|
2639
|
+
return out;
|
|
2640
|
+
}
|
|
2641
|
+
var init_env = __esm({
|
|
2642
|
+
"src/providers/env.ts"() {
|
|
2643
|
+
"use strict";
|
|
2644
|
+
}
|
|
2645
|
+
});
|
|
2646
|
+
|
|
2647
|
+
// src/claude/auth-mode.ts
|
|
2648
|
+
function authModeFrom(info) {
|
|
2649
|
+
if (info.apiProvider && info.apiProvider !== "firstParty") return "third_party";
|
|
2650
|
+
if (info.apiKeySource && info.apiKeySource !== "none") return "api";
|
|
2651
|
+
if (info.subscriptionType) return "subscription";
|
|
2652
|
+
return null;
|
|
2653
|
+
}
|
|
2654
|
+
var init_auth_mode = __esm({
|
|
2655
|
+
"src/claude/auth-mode.ts"() {
|
|
2656
|
+
"use strict";
|
|
2657
|
+
}
|
|
2658
|
+
});
|
|
2659
|
+
|
|
2660
|
+
// src/claude/pushable.ts
|
|
2661
|
+
var Pushable;
|
|
2662
|
+
var init_pushable = __esm({
|
|
2663
|
+
"src/claude/pushable.ts"() {
|
|
2664
|
+
"use strict";
|
|
2665
|
+
Pushable = class {
|
|
2666
|
+
queue = [];
|
|
2667
|
+
waiters = [];
|
|
2668
|
+
ended = false;
|
|
2669
|
+
push(value) {
|
|
2670
|
+
if (this.ended) throw new Error("Pushable already ended");
|
|
2671
|
+
const waiter = this.waiters.shift();
|
|
2672
|
+
if (waiter) waiter({ value, done: false });
|
|
2673
|
+
else this.queue.push(value);
|
|
2674
|
+
}
|
|
2675
|
+
end() {
|
|
2676
|
+
this.ended = true;
|
|
2677
|
+
for (const waiter of this.waiters.splice(0)) waiter({ value: void 0, done: true });
|
|
2678
|
+
}
|
|
2679
|
+
[Symbol.asyncIterator]() {
|
|
2680
|
+
return {
|
|
2681
|
+
next: () => {
|
|
2682
|
+
const value = this.queue.shift();
|
|
2683
|
+
if (value !== void 0) return Promise.resolve({ value, done: false });
|
|
2684
|
+
if (this.ended) return Promise.resolve({ value: void 0, done: true });
|
|
2685
|
+
return new Promise((resolve6) => this.waiters.push(resolve6));
|
|
2686
|
+
}
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
});
|
|
2692
|
+
|
|
2693
|
+
// src/claude/detect.ts
|
|
2694
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
2695
|
+
import { createRequire as createRequire2 } from "module";
|
|
2696
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
2697
|
+
import {
|
|
2698
|
+
query as sdkQuery
|
|
2699
|
+
} from "@anthropic-ai/claude-agent-sdk";
|
|
2700
|
+
function claudeCodeVersion(resolve6 = createRequire2(import.meta.url).resolve) {
|
|
2701
|
+
try {
|
|
2702
|
+
const entry = resolve6("@anthropic-ai/claude-agent-sdk");
|
|
2703
|
+
const pkg = JSON.parse(readFileSync4(join8(dirname3(entry), "package.json"), "utf8"));
|
|
2704
|
+
return typeof pkg.claudeCodeVersion === "string" && pkg.claudeCodeVersion ? pkg.claudeCodeVersion.slice(0, MAX_VERSION) : void 0;
|
|
2705
|
+
} catch {
|
|
2706
|
+
return void 0;
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
async function probeClaude(opts) {
|
|
2710
|
+
const queryFn = opts.queryFn ?? sdkQuery;
|
|
2711
|
+
const prompt = new Pushable();
|
|
2712
|
+
const abortController = new AbortController();
|
|
2713
|
+
let timer;
|
|
2714
|
+
let q;
|
|
2715
|
+
try {
|
|
2716
|
+
q = queryFn({
|
|
2717
|
+
prompt,
|
|
2718
|
+
options: {
|
|
2719
|
+
cwd: opts.cwd,
|
|
2720
|
+
settingSources: opts.settingSources,
|
|
2721
|
+
strictMcpConfig: true,
|
|
2722
|
+
mcpServers: {},
|
|
2723
|
+
settings: { disableAllHooks: true },
|
|
2724
|
+
abortController,
|
|
2725
|
+
stderr: () => {
|
|
2726
|
+
},
|
|
2727
|
+
env: definedEnv({ ...process.env, ...opts.env })
|
|
2728
|
+
}
|
|
2729
|
+
});
|
|
2730
|
+
const init = q.initializationResult();
|
|
2731
|
+
init.catch(() => {
|
|
2732
|
+
});
|
|
2733
|
+
const timeoutMs = opts.timeoutMs ?? PROBE_TIMEOUT_MS;
|
|
2734
|
+
const timeout = new Promise((_, reject) => {
|
|
2735
|
+
timer = setTimeout(() => {
|
|
2736
|
+
abortController.abort();
|
|
2737
|
+
reject(new Error(`Claude probe timed out after ${timeoutMs} ms`));
|
|
2738
|
+
}, timeoutMs);
|
|
2739
|
+
});
|
|
2740
|
+
const res = await Promise.race([init, timeout]);
|
|
2741
|
+
return { account: res.account ?? {}, models: res.models ?? [] };
|
|
2742
|
+
} finally {
|
|
2743
|
+
clearTimeout(timer);
|
|
2744
|
+
prompt.end();
|
|
2745
|
+
try {
|
|
2746
|
+
q?.close();
|
|
2747
|
+
} catch {
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
function toProviderModel(m, id, isDefault) {
|
|
2752
|
+
const levels = m.supportedEffortLevels ?? [];
|
|
2753
|
+
const efforts = levels.filter((e) => Effort.options.includes(e));
|
|
2754
|
+
const description = (m.description ?? "").slice(0, MAX_NAME);
|
|
2755
|
+
return {
|
|
2756
|
+
id: id.slice(0, MAX_NAME),
|
|
2757
|
+
// `||`, not `??`: an empty display name would fail `label.min(1)` and take the whole
|
|
2758
|
+
// capability with it.
|
|
2759
|
+
label: (m.displayName || id).slice(0, MAX_NAME),
|
|
2760
|
+
...isDefault ? { default: true } : {},
|
|
2761
|
+
...description ? { description } : {},
|
|
2762
|
+
efforts
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
function toProviderModels(models) {
|
|
2766
|
+
const fallback = models.find((m) => m.value === "default");
|
|
2767
|
+
const resolved = fallback?.resolvedModel;
|
|
2768
|
+
const rows = models.filter((m) => m.value !== "default");
|
|
2769
|
+
const match = resolved ? rows.findIndex((m) => (m.resolvedModel ?? m.value) === resolved) : -1;
|
|
2770
|
+
const mapped = rows.map((m, i) => toProviderModel(m, m.value ?? "", i === match));
|
|
2771
|
+
if (fallback && resolved && match === -1) {
|
|
2772
|
+
mapped.unshift(toProviderModel(fallback, resolved, true));
|
|
2773
|
+
}
|
|
2774
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2775
|
+
return mapped.filter((m) => !seen.has(m.id) && seen.add(m.id)).slice(0, MAX_MODELS).filter((m) => ProviderModel.safeParse(m).success);
|
|
2776
|
+
}
|
|
2777
|
+
async function detectClaude(deps) {
|
|
2778
|
+
let version;
|
|
2779
|
+
try {
|
|
2780
|
+
version = deps.version();
|
|
2781
|
+
} catch {
|
|
2782
|
+
version = void 0;
|
|
2783
|
+
}
|
|
2784
|
+
const withVersion = version ? { version } : {};
|
|
2785
|
+
let res;
|
|
2786
|
+
try {
|
|
2787
|
+
res = await deps.probe();
|
|
2788
|
+
} catch (err) {
|
|
2789
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2790
|
+
if (/native binary not found/i.test(message)) {
|
|
2791
|
+
return { available: false, reason: "not_installed", ...withVersion, models: [] };
|
|
2792
|
+
}
|
|
2793
|
+
return { available: true, ...withVersion, models: [] };
|
|
2794
|
+
}
|
|
2795
|
+
const account = res.account ?? {};
|
|
2796
|
+
const authMode = authModeFrom(account);
|
|
2797
|
+
if (authMode === null && account.tokenSource === "none") {
|
|
2798
|
+
return { available: false, reason: "not_logged_in", ...withVersion, models: [] };
|
|
2799
|
+
}
|
|
2800
|
+
return {
|
|
2801
|
+
available: true,
|
|
2802
|
+
...withVersion,
|
|
2803
|
+
models: toProviderModels(res.models ?? []),
|
|
2804
|
+
...authMode ? { authMode } : {}
|
|
2805
|
+
};
|
|
2806
|
+
}
|
|
2807
|
+
var PROBE_TIMEOUT_MS, MAX_MODELS, MAX_NAME, MAX_VERSION;
|
|
2808
|
+
var init_detect = __esm({
|
|
2809
|
+
"src/claude/detect.ts"() {
|
|
2810
|
+
"use strict";
|
|
2811
|
+
init_src();
|
|
2812
|
+
init_env();
|
|
2813
|
+
init_auth_mode();
|
|
2814
|
+
init_pushable();
|
|
2815
|
+
PROBE_TIMEOUT_MS = 15e3;
|
|
2816
|
+
MAX_MODELS = 50;
|
|
2817
|
+
MAX_NAME = 200;
|
|
2818
|
+
MAX_VERSION = 50;
|
|
2819
|
+
}
|
|
2820
|
+
});
|
|
2821
|
+
|
|
2627
2822
|
// src/exec-path.ts
|
|
2628
2823
|
import { accessSync, constants, statSync as statSync3 } from "fs";
|
|
2629
|
-
import { delimiter, isAbsolute as isAbsolute5, join as
|
|
2824
|
+
import { delimiter, isAbsolute as isAbsolute5, join as join9 } from "path";
|
|
2630
2825
|
function findOnPath(name, path) {
|
|
2631
2826
|
for (const dir of (path ?? "").split(delimiter)) {
|
|
2632
2827
|
if (!isAbsolute5(dir)) continue;
|
|
2633
|
-
const candidate =
|
|
2828
|
+
const candidate = join9(dir, name);
|
|
2634
2829
|
try {
|
|
2635
2830
|
if (!statSync3(candidate).isFile()) continue;
|
|
2636
2831
|
accessSync(candidate, constants.X_OK);
|
|
@@ -2786,7 +2981,7 @@ async function allModels(request) {
|
|
|
2786
2981
|
const data = page.data ?? [];
|
|
2787
2982
|
models.push(...data);
|
|
2788
2983
|
cursor = data.length > 0 && page.nextCursor ? page.nextCursor : void 0;
|
|
2789
|
-
} while (cursor && models.length <
|
|
2984
|
+
} while (cursor && models.length < MAX_MODELS2);
|
|
2790
2985
|
return models;
|
|
2791
2986
|
}
|
|
2792
2987
|
function findCodexOnPath(env) {
|
|
@@ -2797,7 +2992,7 @@ function resolveCodexPath(cfg, env, onPath) {
|
|
|
2797
2992
|
}
|
|
2798
2993
|
async function runCodex(path, args) {
|
|
2799
2994
|
try {
|
|
2800
|
-
const { stdout, stderr } = await exec(path, args, { timeout:
|
|
2995
|
+
const { stdout, stderr } = await exec(path, args, { timeout: PROBE_TIMEOUT_MS2 });
|
|
2801
2996
|
return { code: 0, stdout, stderr };
|
|
2802
2997
|
} catch (err) {
|
|
2803
2998
|
const e = err;
|
|
@@ -2824,22 +3019,22 @@ async function listCodexModels(path) {
|
|
|
2824
3019
|
child.kill();
|
|
2825
3020
|
}
|
|
2826
3021
|
}
|
|
2827
|
-
function
|
|
3022
|
+
function toProviderModel2(m) {
|
|
2828
3023
|
const efforts = (m.supportedReasoningEfforts ?? []).map((e) => e.reasoningEffort).filter((e) => Effort.options.includes(e));
|
|
2829
3024
|
const fallback = Effort.options.includes(m.defaultReasoningEffort) ? m.defaultReasoningEffort : void 0;
|
|
2830
3025
|
return {
|
|
2831
|
-
id: (m.id ?? "").slice(0,
|
|
3026
|
+
id: (m.id ?? "").slice(0, MAX_NAME2),
|
|
2832
3027
|
// `||`, not `??`: an app-server that sends `displayName: ''` would otherwise publish an
|
|
2833
3028
|
// empty label, which `ProviderModel.label.min(1)` rejects — taking the whole capability
|
|
2834
3029
|
// with it.
|
|
2835
|
-
label: (m.displayName || m.id || "").slice(0,
|
|
3030
|
+
label: (m.displayName || m.id || "").slice(0, MAX_NAME2),
|
|
2836
3031
|
...m.isDefault ? { default: true } : {},
|
|
2837
3032
|
efforts,
|
|
2838
3033
|
...fallback ? { defaultEffort: fallback } : {}
|
|
2839
3034
|
};
|
|
2840
3035
|
}
|
|
2841
|
-
function
|
|
2842
|
-
return models.filter((m) => m.hidden !== true).slice(0,
|
|
3036
|
+
function toProviderModels2(models) {
|
|
3037
|
+
return models.filter((m) => m.hidden !== true).slice(0, MAX_MODELS2).map(toProviderModel2).filter((m) => ProviderModel.safeParse(m).success);
|
|
2843
3038
|
}
|
|
2844
3039
|
async function detectCodex(deps) {
|
|
2845
3040
|
if (!deps.path) return { available: false, reason: "not_installed", models: [] };
|
|
@@ -2847,33 +3042,37 @@ async function detectCodex(deps) {
|
|
|
2847
3042
|
try {
|
|
2848
3043
|
const probe = await deps.run(deps.path, ["--version"]);
|
|
2849
3044
|
if (probe.code !== 0) return { available: false, reason: "not_installed", models: [] };
|
|
2850
|
-
version = probe.stdout.trim().split(/\s+/).at(-1)?.slice(0,
|
|
3045
|
+
version = probe.stdout.trim().split(/\s+/).at(-1)?.slice(0, MAX_VERSION2);
|
|
2851
3046
|
const login2 = await deps.run(deps.path, ["login", "status"]);
|
|
2852
3047
|
if (login2.code !== 0) {
|
|
2853
3048
|
return { available: false, reason: "not_logged_in", version, models: [] };
|
|
2854
3049
|
}
|
|
2855
3050
|
const models = await deps.listModels(deps.path);
|
|
2856
|
-
return { available: true, version, models:
|
|
3051
|
+
return { available: true, version, models: toProviderModels2(models) };
|
|
2857
3052
|
} catch {
|
|
2858
3053
|
return { available: false, reason: "error", ...version ? { version } : {}, models: [] };
|
|
2859
3054
|
}
|
|
2860
3055
|
}
|
|
2861
3056
|
async function detectProviders(deps) {
|
|
2862
|
-
|
|
3057
|
+
const [claude, codex] = await Promise.all([
|
|
3058
|
+
deps.claude().catch(() => ({ available: true, models: [] })),
|
|
3059
|
+
detectCodex(deps)
|
|
3060
|
+
]);
|
|
3061
|
+
return { claude, codex };
|
|
2863
3062
|
}
|
|
2864
|
-
var exec,
|
|
2865
|
-
var
|
|
3063
|
+
var exec, PROBE_TIMEOUT_MS2, LIST_TIMEOUT_MS, MAX_MODELS2, MAX_NAME2, MAX_VERSION2;
|
|
3064
|
+
var init_detect2 = __esm({
|
|
2866
3065
|
"src/codex/detect.ts"() {
|
|
2867
3066
|
"use strict";
|
|
2868
3067
|
init_src();
|
|
2869
3068
|
init_exec_path();
|
|
2870
3069
|
init_rpc();
|
|
2871
3070
|
exec = promisify(execFile2);
|
|
2872
|
-
|
|
3071
|
+
PROBE_TIMEOUT_MS2 = 5e3;
|
|
2873
3072
|
LIST_TIMEOUT_MS = 1e4;
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
3073
|
+
MAX_MODELS2 = 50;
|
|
3074
|
+
MAX_NAME2 = 200;
|
|
3075
|
+
MAX_VERSION2 = 50;
|
|
2877
3076
|
}
|
|
2878
3077
|
});
|
|
2879
3078
|
|
|
@@ -3517,7 +3716,7 @@ var init_source = __esm({
|
|
|
3517
3716
|
|
|
3518
3717
|
// src/paths.ts
|
|
3519
3718
|
import { lstatSync, realpathSync as realpathSync5 } from "fs";
|
|
3520
|
-
import { dirname as
|
|
3719
|
+
import { dirname as dirname4, isAbsolute as isAbsolute6, join as join10, relative as relative2, sep as sep2 } from "path";
|
|
3521
3720
|
function assertInsideRoots(target, roots) {
|
|
3522
3721
|
return resolveInsideRoots(target, roots).real;
|
|
3523
3722
|
}
|
|
@@ -3537,8 +3736,8 @@ function assertInsideRootsOrAncestor(target, roots) {
|
|
|
3537
3736
|
assertRoots(roots);
|
|
3538
3737
|
const absolute = isAbsolute6(target) ? target : `${process.cwd()}${sep2}${target}`;
|
|
3539
3738
|
let walked = walk(target, absolute);
|
|
3540
|
-
if (walked.tail.includes("..")) walked = walk(target,
|
|
3541
|
-
const checked = walked.tail.length === 0 ? walked.real :
|
|
3739
|
+
if (walked.tail.includes("..")) walked = walk(target, join10(walked.real, ...walked.tail));
|
|
3740
|
+
const checked = walked.tail.length === 0 ? walked.real : join10(walked.real, ...walked.tail);
|
|
3542
3741
|
if (!insideAny(checked, roots)) throw new Error(`ROOT_NOT_ALLOWED: ${target}`);
|
|
3543
3742
|
return checked;
|
|
3544
3743
|
}
|
|
@@ -3555,7 +3754,7 @@ function walk(target, absolute) {
|
|
|
3555
3754
|
tail.push(segment);
|
|
3556
3755
|
continue;
|
|
3557
3756
|
}
|
|
3558
|
-
const next = segment === ".." ?
|
|
3757
|
+
const next = segment === ".." ? dirname4(real) : join10(real, segment);
|
|
3559
3758
|
if (!lstatSync(next, { throwIfNoEntry: false })) {
|
|
3560
3759
|
tail.push(segment);
|
|
3561
3760
|
continue;
|
|
@@ -3603,8 +3802,8 @@ var init_paths = __esm({
|
|
|
3603
3802
|
|
|
3604
3803
|
// src/git/introspect.ts
|
|
3605
3804
|
import { execFile as execFile3 } from "child_process";
|
|
3606
|
-
import { readFileSync as
|
|
3607
|
-
import { delimiter as delimiter2, dirname as
|
|
3805
|
+
import { readFileSync as readFileSync5, realpathSync as realpathSync6 } from "fs";
|
|
3806
|
+
import { delimiter as delimiter2, dirname as dirname5, isAbsolute as isAbsolute7, join as join11, resolve as resolve2 } from "path";
|
|
3608
3807
|
import { promisify as promisify2 } from "util";
|
|
3609
3808
|
function parseGitHubRemote(url) {
|
|
3610
3809
|
const trimmed = url.trim();
|
|
@@ -3690,10 +3889,10 @@ function insideRoot(path, root) {
|
|
|
3690
3889
|
}
|
|
3691
3890
|
}
|
|
3692
3891
|
function isLinkedWorktree(gitDir, commonDir, repoRoot) {
|
|
3693
|
-
if (gitDir === commonDir ||
|
|
3892
|
+
if (gitDir === commonDir || dirname5(gitDir) !== join11(commonDir, "worktrees")) return false;
|
|
3694
3893
|
try {
|
|
3695
|
-
const back =
|
|
3696
|
-
const mine = canonical(
|
|
3894
|
+
const back = readFileSync5(join11(gitDir, "gitdir"), "utf8").trim();
|
|
3895
|
+
const mine = canonical(join11(repoRoot, ".git"), repoRoot);
|
|
3697
3896
|
return mine !== null && canonical(back, gitDir) === mine;
|
|
3698
3897
|
} catch {
|
|
3699
3898
|
return false;
|
|
@@ -3701,7 +3900,7 @@ function isLinkedWorktree(gitDir, commonDir, repoRoot) {
|
|
|
3701
3900
|
}
|
|
3702
3901
|
async function introspectRepo(cwd, run, root, { names = true } = {}) {
|
|
3703
3902
|
try {
|
|
3704
|
-
const ceiling =
|
|
3903
|
+
const ceiling = dirname5(root);
|
|
3705
3904
|
if (ceiling.includes(delimiter2)) return { ...NONE };
|
|
3706
3905
|
const line = async (args) => {
|
|
3707
3906
|
const { code, stdout } = await run(args, cwd, ceiling);
|
|
@@ -3798,9 +3997,9 @@ var init_introspect = __esm({
|
|
|
3798
3997
|
});
|
|
3799
3998
|
|
|
3800
3999
|
// src/repos/credentials.ts
|
|
3801
|
-
import { chmodSync as chmodSync4, mkdirSync as mkdirSync4, readFileSync as
|
|
4000
|
+
import { chmodSync as chmodSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
3802
4001
|
import { devNull, homedir as homedir4 } from "os";
|
|
3803
|
-
import { delimiter as delimiter3, isAbsolute as isAbsolute8, join as
|
|
4002
|
+
import { delimiter as delimiter3, isAbsolute as isAbsolute8, join as join12 } from "path";
|
|
3804
4003
|
function gitWrapper(git, gitHome) {
|
|
3805
4004
|
if (git === null || !isAbsolute8(git)) {
|
|
3806
4005
|
return `#!/bin/sh
|
|
@@ -3815,7 +4014,7 @@ exec ${shellQuote(git)} "$@"
|
|
|
3815
4014
|
`;
|
|
3816
4015
|
}
|
|
3817
4016
|
function repositoryGitHome(runDir) {
|
|
3818
|
-
return
|
|
4017
|
+
return join12(runDir, GIT_HOME);
|
|
3819
4018
|
}
|
|
3820
4019
|
function gitCredentialEnv(token, readOnlyText, opts = {}) {
|
|
3821
4020
|
const env = {
|
|
@@ -3836,7 +4035,7 @@ function gitCredentialEnv(token, readOnlyText, opts = {}) {
|
|
|
3836
4035
|
CAYENNE_READ_ONLY: readOnlyText
|
|
3837
4036
|
};
|
|
3838
4037
|
if (token !== null) env.GH_TOKEN = token;
|
|
3839
|
-
if (opts.runDir !== void 0) env.GIT_SSH_COMMAND = shellQuote(
|
|
4038
|
+
if (opts.runDir !== void 0) env.GIT_SSH_COMMAND = shellQuote(join12(opts.runDir, NO_SSH));
|
|
3840
4039
|
if (opts.home !== void 0) env.HOME = opts.home;
|
|
3841
4040
|
return env;
|
|
3842
4041
|
}
|
|
@@ -3848,14 +4047,14 @@ function repositoryChatEnv(input) {
|
|
|
3848
4047
|
SSH_AUTH_SOCK: void 0,
|
|
3849
4048
|
GIT_CONFIG_PARAMETERS: void 0,
|
|
3850
4049
|
...Object.fromEntries(TRACE_AND_TLS_VARS.map((key) => [key, void 0])),
|
|
3851
|
-
GH_CONFIG_DIR:
|
|
4050
|
+
GH_CONFIG_DIR: join12(input.runDir, GH_CONFIG),
|
|
3852
4051
|
GH_PROMPT_DISABLED: "1",
|
|
3853
4052
|
// A replace ref another chat planted in the shared clone must not change what a sha reads as.
|
|
3854
4053
|
GIT_NO_REPLACE_OBJECTS: "1",
|
|
3855
4054
|
// Only git runs with HOME at the git home. Go, SwiftPM and python-requests read `$NETRC` first:
|
|
3856
4055
|
// this one never exists. curl reads the first `.curlrc` of `$CURL_HOME`, then `$HOME`: the git
|
|
3857
4056
|
// home's is empty, so the owner's (`netrc`, `user = …`) never applies.
|
|
3858
|
-
NETRC:
|
|
4057
|
+
NETRC: join12(repositoryGitHome(input.runDir), NETRC_NAME),
|
|
3859
4058
|
CURL_HOME: repositoryGitHome(input.runDir),
|
|
3860
4059
|
// With it and CLAUDE_CONFIG_DIR both set, the CLI names its project dir by it rather than by
|
|
3861
4060
|
// the cwd's slug: every chat's tool outputs would share one dir the worktree bound lets it read.
|
|
@@ -3870,8 +4069,8 @@ function repositoryChatEnv(input) {
|
|
|
3870
4069
|
};
|
|
3871
4070
|
if (input.token === null) env.GH_TOKEN = void 0;
|
|
3872
4071
|
const bins = [
|
|
3873
|
-
...input.token === null ? [
|
|
3874
|
-
|
|
4072
|
+
...input.token === null ? [join12(input.runDir, READONLY_BIN)] : [],
|
|
4073
|
+
join12(input.runDir, GIT_BIN)
|
|
3875
4074
|
];
|
|
3876
4075
|
env.PATH = [...bins, ...input.path ? [input.path] : []].join(delimiter3);
|
|
3877
4076
|
for (const key of Object.keys(input.inherited ?? process.env)) {
|
|
@@ -3882,17 +4081,17 @@ function repositoryChatEnv(input) {
|
|
|
3882
4081
|
}
|
|
3883
4082
|
function prepareRunDir(runDir, opts) {
|
|
3884
4083
|
mkdirSync4(runDir, { recursive: true, mode: 448 });
|
|
3885
|
-
freshDir(
|
|
4084
|
+
freshDir(join12(runDir, GH_CONFIG));
|
|
3886
4085
|
freshDir(repositoryGitHome(runDir));
|
|
3887
|
-
writeFileSync4(
|
|
3888
|
-
chmodSync4(
|
|
3889
|
-
const bin =
|
|
4086
|
+
writeFileSync4(join12(repositoryGitHome(runDir), CURLRC_NAME), "", { mode: 384, flag: "wx" });
|
|
4087
|
+
chmodSync4(join12(repositoryGitHome(runDir), CURLRC_NAME), 384);
|
|
4088
|
+
const bin = join12(runDir, READONLY_BIN);
|
|
3890
4089
|
freshDir(bin);
|
|
3891
|
-
writeShim(
|
|
3892
|
-
writeShim(
|
|
3893
|
-
const gitBin =
|
|
4090
|
+
writeShim(join12(bin, "gh"), GH_SHIM);
|
|
4091
|
+
writeShim(join12(runDir, NO_SSH), NO_SSH_SHIM);
|
|
4092
|
+
const gitBin = join12(runDir, GIT_BIN);
|
|
3894
4093
|
freshDir(gitBin);
|
|
3895
|
-
writeShim(
|
|
4094
|
+
writeShim(join12(gitBin, "git"), gitWrapper(opts.git, repositoryGitHome(runDir)));
|
|
3896
4095
|
}
|
|
3897
4096
|
function freshDir(path) {
|
|
3898
4097
|
rmSync3(path, { recursive: true, force: true });
|
|
@@ -3900,12 +4099,12 @@ function freshDir(path) {
|
|
|
3900
4099
|
chmodSync4(path, 448);
|
|
3901
4100
|
}
|
|
3902
4101
|
function githubNetrcFiles(home = homedir4(), env = process.env) {
|
|
3903
|
-
const candidates = [env.NETRC,
|
|
4102
|
+
const candidates = [env.NETRC, join12(home, ".netrc")].filter(
|
|
3904
4103
|
(path) => typeof path === "string" && path !== ""
|
|
3905
4104
|
);
|
|
3906
4105
|
return [...new Set(candidates)].filter((path) => {
|
|
3907
4106
|
try {
|
|
3908
|
-
return netrcCoversGitHub(
|
|
4107
|
+
return netrcCoversGitHub(readFileSync6(path, "utf8"));
|
|
3909
4108
|
} catch {
|
|
3910
4109
|
return false;
|
|
3911
4110
|
}
|
|
@@ -3986,13 +4185,13 @@ exit 1
|
|
|
3986
4185
|
|
|
3987
4186
|
// src/git/commands.ts
|
|
3988
4187
|
import { lstatSync as lstatSync2, realpathSync as realpathSync7, statSync as statSync4 } from "fs";
|
|
3989
|
-
import { dirname as
|
|
4188
|
+
import { dirname as dirname6, isAbsolute as isAbsolute9, join as join13, relative as relative3, resolve as resolve3, sep as sep3 } from "path";
|
|
3990
4189
|
async function scopeRepo(cwd, run, root) {
|
|
3991
4190
|
const identity = await introspectRepo(cwd, run, root, { names: false });
|
|
3992
4191
|
if (identity.repo_root === null) {
|
|
3993
4192
|
throw new Error(`VALIDATION: ${cwd} is not inside a git repository under an allowed root`);
|
|
3994
4193
|
}
|
|
3995
|
-
return { repoRoot: identity.repo_root, ceiling:
|
|
4194
|
+
return { repoRoot: identity.repo_root, ceiling: dirname6(root) };
|
|
3996
4195
|
}
|
|
3997
4196
|
function fold(letter) {
|
|
3998
4197
|
switch (letter) {
|
|
@@ -4152,13 +4351,13 @@ async function gitDirs(scope, run) {
|
|
|
4152
4351
|
}
|
|
4153
4352
|
}
|
|
4154
4353
|
function isGitDirShape(dir) {
|
|
4155
|
-
const head = lstatSync2(
|
|
4354
|
+
const head = lstatSync2(join13(dir, "HEAD"), { throwIfNoEntry: false });
|
|
4156
4355
|
if (!head || !(head.isFile() || head.isSymbolicLink())) return false;
|
|
4157
|
-
const commondir = lstatSync2(
|
|
4356
|
+
const commondir = lstatSync2(join13(dir, "commondir"), { throwIfNoEntry: false });
|
|
4158
4357
|
if (commondir?.isFile()) return true;
|
|
4159
4358
|
const isDir = (name) => {
|
|
4160
4359
|
try {
|
|
4161
|
-
return statSync4(
|
|
4360
|
+
return statSync4(join13(dir, name), { throwIfNoEntry: false })?.isDirectory() === true;
|
|
4162
4361
|
} catch {
|
|
4163
4362
|
return false;
|
|
4164
4363
|
}
|
|
@@ -4179,13 +4378,13 @@ function enclosesHome(repoRoot, home) {
|
|
|
4179
4378
|
} catch {
|
|
4180
4379
|
return false;
|
|
4181
4380
|
}
|
|
4182
|
-
for (let cur = real; ; cur =
|
|
4381
|
+
for (let cur = real; ; cur = dirname6(cur)) {
|
|
4183
4382
|
try {
|
|
4184
4383
|
const st = statSync4(cur, { bigint: true, throwIfNoEntry: false });
|
|
4185
4384
|
if (st && st.dev === root.dev && st.ino === root.ino) return true;
|
|
4186
4385
|
} catch {
|
|
4187
4386
|
}
|
|
4188
|
-
if (
|
|
4387
|
+
if (dirname6(cur) === cur) return false;
|
|
4189
4388
|
}
|
|
4190
4389
|
}
|
|
4191
4390
|
function protectedTest(paths, exempt = []) {
|
|
@@ -4213,10 +4412,10 @@ function protectedTest(paths, exempt = []) {
|
|
|
4213
4412
|
return (path) => {
|
|
4214
4413
|
if (exempts.length === 0 && entries2.some((e) => within(path, e.real))) return true;
|
|
4215
4414
|
let exempted = false;
|
|
4216
|
-
for (let cur = path; ; cur =
|
|
4415
|
+
for (let cur = path; ; cur = dirname6(cur)) {
|
|
4217
4416
|
if (!exempted && isOneOf(cur, entries2)) return true;
|
|
4218
4417
|
if (exempts.length > 0 && isOneOf(cur, exempts)) exempted = true;
|
|
4219
|
-
if (
|
|
4418
|
+
if (dirname6(cur) === cur) return false;
|
|
4220
4419
|
}
|
|
4221
4420
|
};
|
|
4222
4421
|
}
|
|
@@ -4233,7 +4432,7 @@ function identities(paths) {
|
|
|
4233
4432
|
return out;
|
|
4234
4433
|
}
|
|
4235
4434
|
function insideOtherGitDir(real, repoRoot) {
|
|
4236
|
-
for (let dir =
|
|
4435
|
+
for (let dir = dirname6(real); within(dir, repoRoot) && dir !== repoRoot; dir = dirname6(dir)) {
|
|
4237
4436
|
if (isGitDirShape(dir)) return true;
|
|
4238
4437
|
}
|
|
4239
4438
|
return false;
|
|
@@ -4243,7 +4442,7 @@ async function gitDiff(scope, run, opts, guard = {}) {
|
|
|
4243
4442
|
const guarded = protectedTest(guard.protectedPaths ?? [], guard.exemptPaths ?? []);
|
|
4244
4443
|
const isProtected = (p) => guarded?.(p) === true;
|
|
4245
4444
|
if (opts.path) {
|
|
4246
|
-
const named =
|
|
4445
|
+
const named = join13(scope.repoRoot, opts.path);
|
|
4247
4446
|
let resolved = null;
|
|
4248
4447
|
try {
|
|
4249
4448
|
resolved = realpathSync7.native(named);
|
|
@@ -4273,7 +4472,7 @@ async function gitDiff(scope, run, opts, guard = {}) {
|
|
|
4273
4472
|
`VALIDATION: untracked files are not diffed in a repository at or above the home directory (${scope.repoRoot})`
|
|
4274
4473
|
);
|
|
4275
4474
|
}
|
|
4276
|
-
const absolute =
|
|
4475
|
+
const absolute = join13(scope.repoRoot, opts.path);
|
|
4277
4476
|
if (!lstatSync2(absolute, { throwIfNoEntry: false })) {
|
|
4278
4477
|
try {
|
|
4279
4478
|
assertInsideRootsOrAncestor(absolute, [scope.repoRoot]);
|
|
@@ -4316,7 +4515,7 @@ async function gitDiff(scope, run, opts, guard = {}) {
|
|
|
4316
4515
|
}
|
|
4317
4516
|
const diff = splitDiff(first.stdout);
|
|
4318
4517
|
if (guarded === null) return diff;
|
|
4319
|
-
const keep = (p) => p === void 0 || !isProtected(
|
|
4518
|
+
const keep = (p) => p === void 0 || !isProtected(join13(scope.repoRoot, p));
|
|
4320
4519
|
return { ...diff, files: diff.files.filter((f) => keep(f.path) && keep(f.oldPath)) };
|
|
4321
4520
|
}
|
|
4322
4521
|
function parseBranches(raw, head) {
|
|
@@ -4385,16 +4584,16 @@ import {
|
|
|
4385
4584
|
lstatSync as lstatSync3,
|
|
4386
4585
|
mkdirSync as mkdirSync5,
|
|
4387
4586
|
openSync,
|
|
4388
|
-
readFileSync as
|
|
4587
|
+
readFileSync as readFileSync7,
|
|
4389
4588
|
realpathSync as realpathSync8,
|
|
4390
4589
|
statSync as statSync5,
|
|
4391
4590
|
writeSync
|
|
4392
4591
|
} from "fs";
|
|
4393
4592
|
import { readdir } from "fs/promises";
|
|
4394
|
-
import { dirname as
|
|
4593
|
+
import { dirname as dirname7, isAbsolute as isAbsolute10, join as join14, relative as relative4, sep as sep4 } from "path";
|
|
4395
4594
|
import { setImmediate } from "timers/promises";
|
|
4396
4595
|
function worktreePathFor(repoRoot, name) {
|
|
4397
|
-
return
|
|
4596
|
+
return join14(repoRoot, WORKTREES_DIR, name);
|
|
4398
4597
|
}
|
|
4399
4598
|
async function listedWorktrees(scope, run) {
|
|
4400
4599
|
const r = await run(["worktree", "list", "--porcelain"], scope.repoRoot, scope.ceiling);
|
|
@@ -4417,7 +4616,7 @@ async function excludeCayenneDir(scope, run) {
|
|
|
4417
4616
|
);
|
|
4418
4617
|
const common = r.stdout.trim();
|
|
4419
4618
|
if (r.code !== 0 || !isAbsolute10(common)) return;
|
|
4420
|
-
const dotGit =
|
|
4619
|
+
const dotGit = join14(scope.repoRoot, ".git");
|
|
4421
4620
|
let dotGitIsRealDir;
|
|
4422
4621
|
try {
|
|
4423
4622
|
dotGitIsRealDir = lstatSync3(dotGit).isDirectory();
|
|
@@ -4434,16 +4633,16 @@ async function excludeCayenneDir(scope, run) {
|
|
|
4434
4633
|
return;
|
|
4435
4634
|
}
|
|
4436
4635
|
if (commonReal !== dotGitReal) return;
|
|
4437
|
-
const exclude =
|
|
4636
|
+
const exclude = join14(commonReal, "info", "exclude");
|
|
4438
4637
|
let checkedExclude;
|
|
4439
4638
|
try {
|
|
4440
4639
|
checkedExclude = assertInsideRootsOrAncestor(exclude, [scope.repoRoot]);
|
|
4441
4640
|
} catch {
|
|
4442
4641
|
return;
|
|
4443
4642
|
}
|
|
4444
|
-
const existing = existsSync4(checkedExclude) ?
|
|
4643
|
+
const existing = existsSync4(checkedExclude) ? readFileSync7(checkedExclude, "utf8") : "";
|
|
4445
4644
|
if (existing.split("\n").includes(".cayenne/")) return;
|
|
4446
|
-
mkdirSync5(
|
|
4645
|
+
mkdirSync5(dirname7(checkedExclude), { recursive: true });
|
|
4447
4646
|
const toAppend = `${existing.endsWith("\n") || existing === "" ? "" : "\n"}.cayenne/
|
|
4448
4647
|
`;
|
|
4449
4648
|
let fd;
|
|
@@ -4469,7 +4668,7 @@ function asNotADirectory(path, err) {
|
|
|
4469
4668
|
return err instanceof Error ? err : new Error(String(err));
|
|
4470
4669
|
}
|
|
4471
4670
|
function canonicalWorktreesDir(scope) {
|
|
4472
|
-
const dir =
|
|
4671
|
+
const dir = join14(scope.repoRoot, WORKTREES_DIR);
|
|
4473
4672
|
try {
|
|
4474
4673
|
assertInsideRootsOrAncestor(dir, [scope.repoRoot]);
|
|
4475
4674
|
} catch (err) {
|
|
@@ -4492,7 +4691,7 @@ async function createWorktree(scope, run, name, base) {
|
|
|
4492
4691
|
throw new Error(`VALIDATION: ${name} is not a worktree name`);
|
|
4493
4692
|
}
|
|
4494
4693
|
const worktreesDir = canonicalWorktreesDir(scope);
|
|
4495
|
-
const path =
|
|
4694
|
+
const path = join14(worktreesDir, name);
|
|
4496
4695
|
if (lstatSync3(path, { throwIfNoEntry: false })) {
|
|
4497
4696
|
try {
|
|
4498
4697
|
resolveInsideRoots(path, [scope.repoRoot]);
|
|
@@ -4541,7 +4740,7 @@ async function findNestedRepository(top, limits = NESTED_WALK_LIMITS) {
|
|
|
4541
4740
|
const lower = entry.name.toLowerCase();
|
|
4542
4741
|
if (lower === ".git" && !(depth === 0 && entry.name === ".git")) return "repository";
|
|
4543
4742
|
if (lower === "head") hasHead = true;
|
|
4544
|
-
const path =
|
|
4743
|
+
const path = join14(dir, entry.name);
|
|
4545
4744
|
let isDir;
|
|
4546
4745
|
try {
|
|
4547
4746
|
isDir = entry.isDirectory() || // Some filesystems report no type; lstat decides, still without following.
|
|
@@ -4577,7 +4776,7 @@ async function worktreeIdentity(scope, run) {
|
|
|
4577
4776
|
}
|
|
4578
4777
|
}
|
|
4579
4778
|
async function removeWorktree(scope, run, worktreePath, force) {
|
|
4580
|
-
const worktreesDir =
|
|
4779
|
+
const worktreesDir = join14(scope.repoRoot, WORKTREES_DIR);
|
|
4581
4780
|
let base;
|
|
4582
4781
|
try {
|
|
4583
4782
|
base = realpathSync8.native(worktreesDir);
|
|
@@ -4682,10 +4881,10 @@ var init_ops = __esm({
|
|
|
4682
4881
|
|
|
4683
4882
|
// src/git/worktree-owners.ts
|
|
4684
4883
|
import { createHash, randomBytes } from "crypto";
|
|
4685
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
4686
|
-
import { join as
|
|
4884
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
4885
|
+
import { join as join15 } from "path";
|
|
4687
4886
|
function createWorktreeOwners(dir) {
|
|
4688
|
-
const fileFor = (path) =>
|
|
4887
|
+
const fileFor = (path) => join15(dir, `${createHash("sha256").update(path).digest("hex")}.json`);
|
|
4689
4888
|
return {
|
|
4690
4889
|
record(path, rec) {
|
|
4691
4890
|
const body = {
|
|
@@ -4728,7 +4927,7 @@ function writeRecordFile(dir, file, body) {
|
|
|
4728
4927
|
}
|
|
4729
4928
|
function readRecordFile(file) {
|
|
4730
4929
|
try {
|
|
4731
|
-
const parsed = JSON.parse(
|
|
4930
|
+
const parsed = JSON.parse(readFileSync8(file, "utf8"));
|
|
4732
4931
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
4733
4932
|
} catch {
|
|
4734
4933
|
return null;
|
|
@@ -4742,9 +4941,9 @@ var init_worktree_owners = __esm({
|
|
|
4742
4941
|
|
|
4743
4942
|
// src/git/session-worktrees.ts
|
|
4744
4943
|
import { rmSync as rmSync5 } from "fs";
|
|
4745
|
-
import { join as
|
|
4944
|
+
import { join as join16 } from "path";
|
|
4746
4945
|
function createSessionWorktrees(dir) {
|
|
4747
|
-
const fileFor = (sessionId) => UUID2.test(sessionId) ?
|
|
4946
|
+
const fileFor = (sessionId) => UUID2.test(sessionId) ? join16(dir, `${sessionId}.json`) : null;
|
|
4748
4947
|
return {
|
|
4749
4948
|
record(rec) {
|
|
4750
4949
|
const file = fileFor(rec.sessionId);
|
|
@@ -5564,16 +5763,16 @@ import {
|
|
|
5564
5763
|
mkdirSync as mkdirSync7,
|
|
5565
5764
|
openSync as openSync2,
|
|
5566
5765
|
readdirSync,
|
|
5567
|
-
readFileSync as
|
|
5766
|
+
readFileSync as readFileSync9,
|
|
5568
5767
|
realpathSync as realpathSync9,
|
|
5569
5768
|
renameSync as renameSync3,
|
|
5570
5769
|
rmSync as rmSync6,
|
|
5571
5770
|
statSync as statSync6,
|
|
5572
5771
|
writeSync as writeSync2
|
|
5573
5772
|
} from "fs";
|
|
5574
|
-
import { dirname as
|
|
5773
|
+
import { dirname as dirname8, join as join17 } from "path";
|
|
5575
5774
|
function managedReposRoot(profileDir2) {
|
|
5576
|
-
return
|
|
5775
|
+
return join17(profileDir2, "repos");
|
|
5577
5776
|
}
|
|
5578
5777
|
function githubRemoteUrl(repo) {
|
|
5579
5778
|
return `https://github.com/${repo.owner}/${repo.name}.git`;
|
|
@@ -5608,9 +5807,9 @@ function createManagedRepos(deps) {
|
|
|
5608
5807
|
}
|
|
5609
5808
|
};
|
|
5610
5809
|
async function cloneInto(repo, env) {
|
|
5611
|
-
const ownerDir =
|
|
5612
|
-
const path =
|
|
5613
|
-
const tmp =
|
|
5810
|
+
const ownerDir = join17(root, repo.owner);
|
|
5811
|
+
const path = join17(ownerDir, repo.name);
|
|
5812
|
+
const tmp = join17(ownerDir, `.${repo.name}.clone-${randomBytes2(4).toString("hex")}`);
|
|
5614
5813
|
inflight.add(tmp);
|
|
5615
5814
|
try {
|
|
5616
5815
|
mkdirSync7(ownerDir, { recursive: true, mode: 448 });
|
|
@@ -5655,7 +5854,7 @@ function createManagedRepos(deps) {
|
|
|
5655
5854
|
const listed = await run(
|
|
5656
5855
|
["config", "--local", "--no-includes", "--list", "-z"],
|
|
5657
5856
|
path,
|
|
5658
|
-
|
|
5857
|
+
dirname8(path)
|
|
5659
5858
|
);
|
|
5660
5859
|
const entries2 = listed.code === 0 ? parseConfigList(listed.stdout) : [];
|
|
5661
5860
|
const mark = entries2.filter((e) => e.section === "cayenne" && e.subsection === null && e.name === "repositoryid").at(-1)?.value;
|
|
@@ -5680,8 +5879,8 @@ function createManagedRepos(deps) {
|
|
|
5680
5879
|
}
|
|
5681
5880
|
async function sync(repo, tok) {
|
|
5682
5881
|
const slug = `${repo.owner}/${repo.name}`;
|
|
5683
|
-
const ownerDir =
|
|
5684
|
-
const path =
|
|
5882
|
+
const ownerDir = join17(root, repo.owner);
|
|
5883
|
+
const path = join17(ownerDir, repo.name);
|
|
5685
5884
|
assertRealDirs(ownerDir, path);
|
|
5686
5885
|
const env = gitCredentialEnv(tok.token, "", { home: deps.gitHome });
|
|
5687
5886
|
const run = makeGitRun({ timeoutMs: GIT_SLOW_TIMEOUT_MS, env });
|
|
@@ -5721,9 +5920,9 @@ function createManagedRepos(deps) {
|
|
|
5721
5920
|
return { clonePath: real, defaultBranch: branch, baseSha };
|
|
5722
5921
|
}
|
|
5723
5922
|
function excludePlans(path) {
|
|
5724
|
-
const gitDir =
|
|
5725
|
-
const info =
|
|
5726
|
-
const file =
|
|
5923
|
+
const gitDir = join17(path, ".git");
|
|
5924
|
+
const info = join17(gitDir, "info");
|
|
5925
|
+
const file = join17(info, "exclude");
|
|
5727
5926
|
try {
|
|
5728
5927
|
if (!lstatSync4(gitDir).isDirectory()) throw new Error(".git is not a directory");
|
|
5729
5928
|
const infoStat = lstatSync4(info, { throwIfNoEntry: false });
|
|
@@ -5739,7 +5938,7 @@ function createManagedRepos(deps) {
|
|
|
5739
5938
|
420
|
|
5740
5939
|
);
|
|
5741
5940
|
try {
|
|
5742
|
-
const text =
|
|
5941
|
+
const text = readFileSync9(fd, "utf8");
|
|
5743
5942
|
const lines = text.split("\n");
|
|
5744
5943
|
const isOld = (line) => line.replace(/\r$/, "") === OLD_PLANS_EXCLUDE_LINE;
|
|
5745
5944
|
const has = lines.some((line) => line.replace(/\r$/, "") === PLANS_EXCLUDE_LINE);
|
|
@@ -5780,9 +5979,9 @@ function createManagedRepos(deps) {
|
|
|
5780
5979
|
}
|
|
5781
5980
|
async function markOf(path) {
|
|
5782
5981
|
const { code, stdout } = await scanRun(
|
|
5783
|
-
["config", "--file",
|
|
5982
|
+
["config", "--file", join17(path, ".git", "config"), "--get", ID_KEY],
|
|
5784
5983
|
path,
|
|
5785
|
-
|
|
5984
|
+
dirname8(path)
|
|
5786
5985
|
);
|
|
5787
5986
|
const text = stdout.trim();
|
|
5788
5987
|
if (code !== 0 || !ID_TEXT.test(text)) return null;
|
|
@@ -5809,8 +6008,8 @@ function createManagedRepos(deps) {
|
|
|
5809
6008
|
});
|
|
5810
6009
|
},
|
|
5811
6010
|
verifyConfig(repo) {
|
|
5812
|
-
const ownerDir =
|
|
5813
|
-
const path =
|
|
6011
|
+
const ownerDir = join17(root, repo.owner);
|
|
6012
|
+
const path = join17(ownerDir, repo.name);
|
|
5814
6013
|
const check = async () => {
|
|
5815
6014
|
assertRealDirs(ownerDir, path);
|
|
5816
6015
|
await checkConfig(repo, path, scanRun);
|
|
@@ -5831,12 +6030,12 @@ function createManagedRepos(deps) {
|
|
|
5831
6030
|
const candidates = [];
|
|
5832
6031
|
for (const owner of entries(root)) {
|
|
5833
6032
|
if (!owner.isDirectory()) continue;
|
|
5834
|
-
const ownerDir =
|
|
6033
|
+
const ownerDir = join17(root, owner.name);
|
|
5835
6034
|
for (const entry of entries(ownerDir)) {
|
|
5836
|
-
const path =
|
|
6035
|
+
const path = join17(ownerDir, entry.name);
|
|
5837
6036
|
if (TEMP_CLONE.test(entry.name)) {
|
|
5838
6037
|
if (inflight.has(path)) continue;
|
|
5839
|
-
if (!present(
|
|
6038
|
+
if (!present(join17(path, ".cayenne"))) {
|
|
5840
6039
|
rmSync6(path, { recursive: true, force: true });
|
|
5841
6040
|
deps.log.info({ path }, "removed an interrupted managed clone");
|
|
5842
6041
|
continue;
|
|
@@ -5912,7 +6111,7 @@ function keyText(e) {
|
|
|
5912
6111
|
return `${e.section}.${subsection}.${e.name}`;
|
|
5913
6112
|
}
|
|
5914
6113
|
function recency(path) {
|
|
5915
|
-
for (const file of [
|
|
6114
|
+
for (const file of [join17(path, ".git", "FETCH_HEAD"), join17(path, ".git")]) {
|
|
5916
6115
|
try {
|
|
5917
6116
|
const stat = statSync6(file, { throwIfNoEntry: false });
|
|
5918
6117
|
if (stat) return stat.mtimeMs;
|
|
@@ -6041,7 +6240,7 @@ var init_managed = __esm({
|
|
|
6041
6240
|
|
|
6042
6241
|
// src/repos/sweep.ts
|
|
6043
6242
|
import { lstatSync as lstatSync5, realpathSync as realpathSync10 } from "fs";
|
|
6044
|
-
import { isAbsolute as isAbsolute12, join as
|
|
6243
|
+
import { isAbsolute as isAbsolute12, join as join18, relative as relative5, sep as sep7 } from "path";
|
|
6045
6244
|
function createRepoWorktreeSweep(deps) {
|
|
6046
6245
|
const { log } = deps;
|
|
6047
6246
|
const said3 = /* @__PURE__ */ new Set();
|
|
@@ -6056,8 +6255,8 @@ function createRepoWorktreeSweep(deps) {
|
|
|
6056
6255
|
return null;
|
|
6057
6256
|
}
|
|
6058
6257
|
const leaf = worktreeName(sessionId);
|
|
6059
|
-
const repoRoot =
|
|
6060
|
-
if (leaf === null || rec.path !==
|
|
6258
|
+
const repoRoot = join18(deps.managedRoot, owner, name);
|
|
6259
|
+
if (leaf === null || rec.path !== join18(repoRoot, WORKTREES_DIR, leaf)) return null;
|
|
6061
6260
|
return { sessionId, path: rec.path, repoRoot, record: rec };
|
|
6062
6261
|
}
|
|
6063
6262
|
async function readRows(ids) {
|
|
@@ -6499,7 +6698,7 @@ var init_roster = __esm({
|
|
|
6499
6698
|
|
|
6500
6699
|
// src/sessions/attachments.ts
|
|
6501
6700
|
import { readdirSync as readdirSync2, rmSync as rmSync7 } from "fs";
|
|
6502
|
-
import { join as
|
|
6701
|
+
import { join as join19 } from "path";
|
|
6503
6702
|
async function loadAttachments(db, scope, attachments) {
|
|
6504
6703
|
const prefix = `${scope.workspaceId.toLowerCase()}/${scope.sessionId.toLowerCase()}/`;
|
|
6505
6704
|
const named = attachments.map(({ storagePath }, i) => {
|
|
@@ -6536,13 +6735,13 @@ async function loadAttachments(db, scope, attachments) {
|
|
|
6536
6735
|
return loaded;
|
|
6537
6736
|
}
|
|
6538
6737
|
function attachmentsTempDir(home, runnerId, sessionId) {
|
|
6539
|
-
return
|
|
6738
|
+
return join19(home, "tmp", "attachments", runnerId, sessionId);
|
|
6540
6739
|
}
|
|
6541
6740
|
function assertStagingInsideHome(home, dir) {
|
|
6542
6741
|
return assertInsideRootsOrAncestor(dir, [home]);
|
|
6543
6742
|
}
|
|
6544
6743
|
function clearAttachmentsTemp(home, runnerId, heldBy) {
|
|
6545
|
-
clearRunnerStaging(home,
|
|
6744
|
+
clearRunnerStaging(home, join19(home, "tmp", "attachments"), runnerId, heldBy);
|
|
6546
6745
|
}
|
|
6547
6746
|
function clearRunnerStaging(home, dir, runnerId, heldBy = (id) => holderOf({ root: home, runnerId: id }) !== null) {
|
|
6548
6747
|
const proved = assertStagingInsideHome(home, dir);
|
|
@@ -6553,9 +6752,9 @@ function clearRunnerStaging(home, dir, runnerId, heldBy = (id) => holderOf({ roo
|
|
|
6553
6752
|
return;
|
|
6554
6753
|
}
|
|
6555
6754
|
for (const name of names) {
|
|
6556
|
-
assertStagingInsideHome(home,
|
|
6755
|
+
assertStagingInsideHome(home, join19(proved, name));
|
|
6557
6756
|
if (name !== runnerId && heldBy(name)) continue;
|
|
6558
|
-
rmSync7(
|
|
6757
|
+
rmSync7(join19(proved, name), { recursive: true, force: true });
|
|
6559
6758
|
}
|
|
6560
6759
|
}
|
|
6561
6760
|
var ATTACHMENTS_BUCKET, TYPE_OF_EXT, refuse;
|
|
@@ -6575,7 +6774,7 @@ var init_attachments2 = __esm({
|
|
|
6575
6774
|
|
|
6576
6775
|
// src/fs/list.ts
|
|
6577
6776
|
import { readdirSync as readdirSync3, realpathSync as realpathSync11, statSync as statSync7 } from "fs";
|
|
6578
|
-
import { join as
|
|
6777
|
+
import { join as join20, relative as relative6, sep as sep8 } from "path";
|
|
6579
6778
|
function order(a, b) {
|
|
6580
6779
|
const aDir = a.kind === "dir" ? 0 : 1;
|
|
6581
6780
|
const bDir = b.kind === "dir" ? 0 : 1;
|
|
@@ -6616,7 +6815,7 @@ function listDirectory(dir, root, depth) {
|
|
|
6616
6815
|
return;
|
|
6617
6816
|
}
|
|
6618
6817
|
const level = dirents.map((dirent) => {
|
|
6619
|
-
const path =
|
|
6818
|
+
const path = join20(current, dirent.name);
|
|
6620
6819
|
const link = dirent.isSymbolicLink();
|
|
6621
6820
|
const resolved = link ? symlinkKind(path, root) : null;
|
|
6622
6821
|
const isDir = link ? resolved?.kind === "dir" : dirent.isDirectory();
|
|
@@ -7061,7 +7260,7 @@ var init_broadcast = __esm({
|
|
|
7061
7260
|
|
|
7062
7261
|
// src/documents/paths.ts
|
|
7063
7262
|
import { realpathSync as realpathSync12 } from "fs";
|
|
7064
|
-
import { isAbsolute as isAbsolute13, join as
|
|
7263
|
+
import { isAbsolute as isAbsolute13, join as join21, relative as relative7, sep as sep10 } from "path";
|
|
7065
7264
|
function contained(dir, candidate) {
|
|
7066
7265
|
const rel = relative7(dir, candidate);
|
|
7067
7266
|
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep10}`) && !isAbsolute13(rel);
|
|
@@ -7098,7 +7297,7 @@ var init_paths2 = __esm({
|
|
|
7098
7297
|
"src/documents/paths.ts"() {
|
|
7099
7298
|
"use strict";
|
|
7100
7299
|
init_src();
|
|
7101
|
-
docsDir = (cwd) =>
|
|
7300
|
+
docsDir = (cwd) => join21(cwd, ...DOCUMENTS_DIR.split("/"));
|
|
7102
7301
|
}
|
|
7103
7302
|
});
|
|
7104
7303
|
|
|
@@ -7275,10 +7474,10 @@ import {
|
|
|
7275
7474
|
lstatSync as lstatSync6,
|
|
7276
7475
|
opendirSync,
|
|
7277
7476
|
openSync as openSync3,
|
|
7278
|
-
readFileSync as
|
|
7477
|
+
readFileSync as readFileSync10
|
|
7279
7478
|
} from "fs";
|
|
7280
7479
|
import { open } from "fs/promises";
|
|
7281
|
-
import { join as
|
|
7480
|
+
import { join as join22 } from "path";
|
|
7282
7481
|
function isNew(baseline, relPath, contentHash) {
|
|
7283
7482
|
const before = baseline.hashes.get(relPath);
|
|
7284
7483
|
if (before === void 0) return baseline.complete;
|
|
@@ -7365,7 +7564,7 @@ function walk2(st, dir, rel, depth) {
|
|
|
7365
7564
|
for (const entry of entries2) {
|
|
7366
7565
|
if (st.stop) return;
|
|
7367
7566
|
if (entry.name.startsWith(".")) continue;
|
|
7368
|
-
const path =
|
|
7567
|
+
const path = join22(dir, entry.name);
|
|
7369
7568
|
const relPath = rel === "" ? entry.name : `${rel}/${entry.name}`;
|
|
7370
7569
|
if (entry.isSymbolicLink()) {
|
|
7371
7570
|
st.log.warn({ path, relPath }, `document skipped: ${SYMLINK_SKIPPED}`);
|
|
@@ -7476,7 +7675,7 @@ function baselineOf(root, log) {
|
|
|
7476
7675
|
continue;
|
|
7477
7676
|
}
|
|
7478
7677
|
try {
|
|
7479
|
-
hashes.set(file.relPath, sha256(
|
|
7678
|
+
hashes.set(file.relPath, sha256(readFileSync10(fd)));
|
|
7480
7679
|
} catch {
|
|
7481
7680
|
hashes.set(file.relPath, UNREADABLE);
|
|
7482
7681
|
} finally {
|
|
@@ -7598,31 +7797,6 @@ var init_service = __esm({
|
|
|
7598
7797
|
}
|
|
7599
7798
|
});
|
|
7600
7799
|
|
|
7601
|
-
// src/providers/env.ts
|
|
7602
|
-
function definedEnv(env) {
|
|
7603
|
-
const out = {};
|
|
7604
|
-
for (const [key, value] of Object.entries(env)) if (value !== void 0) out[key] = value;
|
|
7605
|
-
return out;
|
|
7606
|
-
}
|
|
7607
|
-
var init_env = __esm({
|
|
7608
|
-
"src/providers/env.ts"() {
|
|
7609
|
-
"use strict";
|
|
7610
|
-
}
|
|
7611
|
-
});
|
|
7612
|
-
|
|
7613
|
-
// src/claude/auth-mode.ts
|
|
7614
|
-
function authModeFrom(info) {
|
|
7615
|
-
if (info.apiProvider && info.apiProvider !== "firstParty") return "third_party";
|
|
7616
|
-
if (info.apiKeySource && info.apiKeySource !== "none") return "api";
|
|
7617
|
-
if (info.subscriptionType) return "subscription";
|
|
7618
|
-
return null;
|
|
7619
|
-
}
|
|
7620
|
-
var init_auth_mode = __esm({
|
|
7621
|
-
"src/claude/auth-mode.ts"() {
|
|
7622
|
-
"use strict";
|
|
7623
|
-
}
|
|
7624
|
-
});
|
|
7625
|
-
|
|
7626
7800
|
// src/claude/normalize.ts
|
|
7627
7801
|
function normalizeSdkMessage(msg) {
|
|
7628
7802
|
switch (msg.type) {
|
|
@@ -7726,43 +7900,10 @@ var init_normalize = __esm({
|
|
|
7726
7900
|
}
|
|
7727
7901
|
});
|
|
7728
7902
|
|
|
7729
|
-
// src/claude/pushable.ts
|
|
7730
|
-
var Pushable;
|
|
7731
|
-
var init_pushable = __esm({
|
|
7732
|
-
"src/claude/pushable.ts"() {
|
|
7733
|
-
"use strict";
|
|
7734
|
-
Pushable = class {
|
|
7735
|
-
queue = [];
|
|
7736
|
-
waiters = [];
|
|
7737
|
-
ended = false;
|
|
7738
|
-
push(value) {
|
|
7739
|
-
if (this.ended) throw new Error("Pushable already ended");
|
|
7740
|
-
const waiter = this.waiters.shift();
|
|
7741
|
-
if (waiter) waiter({ value, done: false });
|
|
7742
|
-
else this.queue.push(value);
|
|
7743
|
-
}
|
|
7744
|
-
end() {
|
|
7745
|
-
this.ended = true;
|
|
7746
|
-
for (const waiter of this.waiters.splice(0)) waiter({ value: void 0, done: true });
|
|
7747
|
-
}
|
|
7748
|
-
[Symbol.asyncIterator]() {
|
|
7749
|
-
return {
|
|
7750
|
-
next: () => {
|
|
7751
|
-
const value = this.queue.shift();
|
|
7752
|
-
if (value !== void 0) return Promise.resolve({ value, done: false });
|
|
7753
|
-
if (this.ended) return Promise.resolve({ value: void 0, done: true });
|
|
7754
|
-
return new Promise((resolve6) => this.waiters.push(resolve6));
|
|
7755
|
-
}
|
|
7756
|
-
};
|
|
7757
|
-
}
|
|
7758
|
-
};
|
|
7759
|
-
}
|
|
7760
|
-
});
|
|
7761
|
-
|
|
7762
7903
|
// src/claude/session.ts
|
|
7763
7904
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
7764
7905
|
import { EventEmitter } from "events";
|
|
7765
|
-
import { query as
|
|
7906
|
+
import { query as sdkQuery2 } from "@anthropic-ai/claude-agent-sdk";
|
|
7766
7907
|
async function askGuard(guard, toolName2, input) {
|
|
7767
7908
|
try {
|
|
7768
7909
|
const refusal = await guard(toolName2, input);
|
|
@@ -7823,7 +7964,7 @@ var init_session2 = __esm({
|
|
|
7823
7964
|
stopAsked = false;
|
|
7824
7965
|
start() {
|
|
7825
7966
|
if (this.q) throw new Error("VALIDATION: session already started");
|
|
7826
|
-
const queryFn = this.opts.queryFn ??
|
|
7967
|
+
const queryFn = this.opts.queryFn ?? sdkQuery2;
|
|
7827
7968
|
const guard = this.opts.toolGuard;
|
|
7828
7969
|
const canUseTool = async (toolName2, input, options) => {
|
|
7829
7970
|
if (guard) {
|
|
@@ -8213,7 +8354,7 @@ import { spawn as spawn2 } from "child_process";
|
|
|
8213
8354
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
8214
8355
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
8215
8356
|
import { chmodSync as chmodSync5, lstatSync as lstatSync7, mkdirSync as mkdirSync8, rmdirSync, rmSync as rmSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
8216
|
-
import { dirname as
|
|
8357
|
+
import { dirname as dirname9, join as join23 } from "path";
|
|
8217
8358
|
import { z as z18 } from "zod";
|
|
8218
8359
|
function newStop() {
|
|
8219
8360
|
let resolve6;
|
|
@@ -8445,7 +8586,7 @@ ${scrubSecrets(this.stderrTail.join("")).slice(-STDERR_TAIL_MAX)}` : "";
|
|
|
8445
8586
|
assertStagingInsideHome(home, dir);
|
|
8446
8587
|
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
8447
8588
|
assertStagingInsideHome(home, dir);
|
|
8448
|
-
for (const path of [
|
|
8589
|
+
for (const path of [dirname9(dir), dir]) {
|
|
8449
8590
|
const st = lstatSync7(path);
|
|
8450
8591
|
if (st.isSymbolicLink() || !st.isDirectory()) {
|
|
8451
8592
|
throw new Error(`${path} is not a plain directory`);
|
|
@@ -8453,7 +8594,7 @@ ${scrubSecrets(this.stderrTail.join("")).slice(-STDERR_TAIL_MAX)}` : "";
|
|
|
8453
8594
|
}
|
|
8454
8595
|
chmodSync5(dir, 448);
|
|
8455
8596
|
for (const image of images) {
|
|
8456
|
-
const path =
|
|
8597
|
+
const path = join23(dir, `${randomUUID4()}.${ATTACHMENT_MEDIA_TYPES[image.mediaType]}`);
|
|
8457
8598
|
writeFileSync6(path, image.data, { mode: 384, flag: "wx" });
|
|
8458
8599
|
written.push(path);
|
|
8459
8600
|
}
|
|
@@ -8920,9 +9061,9 @@ var init_types = __esm({
|
|
|
8920
9061
|
|
|
8921
9062
|
// src/skills/paths.ts
|
|
8922
9063
|
import { realpathSync as realpathSync13 } from "fs";
|
|
8923
|
-
import { isAbsolute as isAbsolute14, join as
|
|
9064
|
+
import { isAbsolute as isAbsolute14, join as join24, relative as relative8, sep as sep11 } from "path";
|
|
8924
9065
|
function clearSessionSkills(home, runnerId, heldBy) {
|
|
8925
|
-
clearRunnerStaging(home,
|
|
9066
|
+
clearRunnerStaging(home, join24(home, "session-skills"), runnerId, heldBy);
|
|
8926
9067
|
}
|
|
8927
9068
|
function assertInsideScopeDir(path, scopeDir) {
|
|
8928
9069
|
let dirNow;
|
|
@@ -8947,8 +9088,8 @@ var init_paths3 = __esm({
|
|
|
8947
9088
|
"use strict";
|
|
8948
9089
|
init_paths();
|
|
8949
9090
|
init_attachments2();
|
|
8950
|
-
sessionSkillsRoot = (home, runnerId) =>
|
|
8951
|
-
sessionSkillsDir = (home, runnerId, sessionId) =>
|
|
9091
|
+
sessionSkillsRoot = (home, runnerId) => join24(home, "session-skills", runnerId);
|
|
9092
|
+
sessionSkillsDir = (home, runnerId, sessionId) => join24(sessionSkillsRoot(home, runnerId), sessionId);
|
|
8952
9093
|
}
|
|
8953
9094
|
});
|
|
8954
9095
|
|
|
@@ -9087,7 +9228,7 @@ import {
|
|
|
9087
9228
|
realpathSync as realpathSync14
|
|
9088
9229
|
} from "fs";
|
|
9089
9230
|
import { open as open2, opendir } from "fs/promises";
|
|
9090
|
-
import { isAbsolute as isAbsolute15, join as
|
|
9231
|
+
import { isAbsolute as isAbsolute15, join as join25, relative as relative9, sep as sep12 } from "path";
|
|
9091
9232
|
function inside2(root, candidate) {
|
|
9092
9233
|
const rel = relative9(root, candidate);
|
|
9093
9234
|
return rel === "" || !rel.startsWith(`..${sep12}`) && rel !== ".." && !isAbsolute15(rel);
|
|
@@ -9116,7 +9257,7 @@ function scopeRoots(opts) {
|
|
|
9116
9257
|
const isGitRepo = opts.isGitRepo ?? defaultIsGitRepo;
|
|
9117
9258
|
const home = canonical2(opts.home);
|
|
9118
9259
|
const homes = protectedHomes(opts);
|
|
9119
|
-
const found = [{ scope: "personal", dir:
|
|
9260
|
+
const found = [{ scope: "personal", dir: join25(home, "skills"), base: home }];
|
|
9120
9261
|
let skillsRepo;
|
|
9121
9262
|
if (opts.skillsRepo !== void 0) {
|
|
9122
9263
|
try {
|
|
@@ -9137,7 +9278,7 @@ function scopeRoots(opts) {
|
|
|
9137
9278
|
continue;
|
|
9138
9279
|
}
|
|
9139
9280
|
if (!isGitRepo(real)) continue;
|
|
9140
|
-
const dir =
|
|
9281
|
+
const dir = join25(real, ".cayenne", "skills");
|
|
9141
9282
|
const shared = skillsRepo !== void 0 && real === skillsRepo ? "workspace" : "project";
|
|
9142
9283
|
if (overlapsHome(canonical2(dir), homes, shared, log)) continue;
|
|
9143
9284
|
if (skillsRepo !== void 0 && real === skillsRepo) {
|
|
@@ -9199,7 +9340,7 @@ async function scanSkills(opts) {
|
|
|
9199
9340
|
} catch (err) {
|
|
9200
9341
|
log.warn(
|
|
9201
9342
|
{
|
|
9202
|
-
path:
|
|
9343
|
+
path: join25(root.dirReal, entry.name),
|
|
9203
9344
|
scope: root.scope,
|
|
9204
9345
|
err: err instanceof Error ? err.message : String(err)
|
|
9205
9346
|
},
|
|
@@ -9244,13 +9385,13 @@ async function readAtMost2(fh, limit) {
|
|
|
9244
9385
|
return buffer.subarray(0, filled);
|
|
9245
9386
|
}
|
|
9246
9387
|
async function readEntry(root, entry, log, budget) {
|
|
9247
|
-
const path =
|
|
9388
|
+
const path = join25(root.dirReal, entry.name);
|
|
9248
9389
|
const skip = (reason) => {
|
|
9249
9390
|
log.warn({ path, scope: root.scope }, `skill skipped: ${reason}`);
|
|
9250
9391
|
return null;
|
|
9251
9392
|
};
|
|
9252
9393
|
if (entry.isDirectory()) {
|
|
9253
|
-
const nested = existsSync5(
|
|
9394
|
+
const nested = existsSync5(join25(path, "SKILL.md"));
|
|
9254
9395
|
return skip(
|
|
9255
9396
|
nested ? `a directory holding SKILL.md: Cayenne's store is flat, so move it to ${entry.name}.md beside this directory` : "a directory, and the scan does not recurse"
|
|
9256
9397
|
);
|
|
@@ -9410,7 +9551,7 @@ var init_scan2 = __esm({
|
|
|
9410
9551
|
SKILL_SCAN_MAX_PER_DIR = 500;
|
|
9411
9552
|
SKILL_SCAN_MAX_SKILLS = 500;
|
|
9412
9553
|
SKILL_SCAN_MAX_BYTES = 32 * 1024 * 1024;
|
|
9413
|
-
defaultIsGitRepo = (dir) => lstatSync8(
|
|
9554
|
+
defaultIsGitRepo = (dir) => lstatSync8(join25(dir, ".git"), { throwIfNoEntry: false }) !== void 0;
|
|
9414
9555
|
summariesOf = (scan) => scan.map((s) => s.summary);
|
|
9415
9556
|
FRONTMATTER = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/;
|
|
9416
9557
|
KEY = /^([A-Za-z_][A-Za-z0-9_-]*):[ \t]*(.*)$/;
|
|
@@ -9429,7 +9570,7 @@ import {
|
|
|
9429
9570
|
rmSync as rmSync9
|
|
9430
9571
|
} from "fs";
|
|
9431
9572
|
import { open as open3, writeFile } from "fs/promises";
|
|
9432
|
-
import { dirname as
|
|
9573
|
+
import { dirname as dirname10, isAbsolute as isAbsolute16, join as join26, relative as relative10, sep as sep13 } from "path";
|
|
9433
9574
|
function isSkillRefusal(err) {
|
|
9434
9575
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9435
9576
|
return msg.startsWith("ROOT_NOT_ALLOWED") || msg.startsWith(BUDGET) || msg.includes("is not a plain directory") || msg.includes("is not part of the session skills plugin");
|
|
@@ -9476,7 +9617,7 @@ async function materialiseSkills(scan, t) {
|
|
|
9476
9617
|
}
|
|
9477
9618
|
const path = plainDirectory(t.home, sessionSkillsDir(t.home, t.runnerId, t.sessionId));
|
|
9478
9619
|
await writeFile(
|
|
9479
|
-
|
|
9620
|
+
join26(plainDirectory(t.home, join26(path, ".claude-plugin")), "plugin.json"),
|
|
9480
9621
|
`${JSON.stringify(
|
|
9481
9622
|
{
|
|
9482
9623
|
name: SKILL_PLUGIN_NAME,
|
|
@@ -9506,13 +9647,13 @@ async function materialiseSkills(scan, t) {
|
|
|
9506
9647
|
);
|
|
9507
9648
|
}
|
|
9508
9649
|
try {
|
|
9509
|
-
const dir = plainDirectory(t.home,
|
|
9510
|
-
await writeFile(
|
|
9650
|
+
const dir = plainDirectory(t.home, join26(path, "skills", slug));
|
|
9651
|
+
await writeFile(join26(dir, "SKILL.md"), bytes, { mode: 384, flag: "wx" });
|
|
9511
9652
|
slugs.push(slug);
|
|
9512
9653
|
} catch (err) {
|
|
9513
9654
|
note(log, err, { slug, scope, path: skill.path }, "skill not materialised for this session");
|
|
9514
9655
|
try {
|
|
9515
|
-
rmSync9(assertStagingInsideHome(t.home,
|
|
9656
|
+
rmSync9(assertStagingInsideHome(t.home, join26(path, "skills", slug)), {
|
|
9516
9657
|
recursive: true,
|
|
9517
9658
|
force: true
|
|
9518
9659
|
});
|
|
@@ -9576,20 +9717,20 @@ function assertSealed(path, slugs) {
|
|
|
9576
9717
|
const want = new Set(expected);
|
|
9577
9718
|
for (const entry of entries2) {
|
|
9578
9719
|
const ok = kind === "dir" ? entry.isDirectory() : entry.isFile();
|
|
9579
|
-
if (!ok || !want.has(entry.name)) throw stray(
|
|
9720
|
+
if (!ok || !want.has(entry.name)) throw stray(join26(dir, entry.name));
|
|
9580
9721
|
}
|
|
9581
|
-
if (entries2.length !== want.size) throw stray(
|
|
9722
|
+
if (entries2.length !== want.size) throw stray(join26(dir, [...want].join("|")));
|
|
9582
9723
|
};
|
|
9583
9724
|
named(path, [".claude-plugin", "skills"], "dir");
|
|
9584
|
-
named(
|
|
9585
|
-
named(
|
|
9586
|
-
for (const slug of slugs) named(
|
|
9725
|
+
named(join26(path, ".claude-plugin"), ["plugin.json"], "file");
|
|
9726
|
+
named(join26(path, "skills"), slugs, "dir");
|
|
9727
|
+
for (const slug of slugs) named(join26(path, "skills", slug), ["SKILL.md"], "file");
|
|
9587
9728
|
}
|
|
9588
9729
|
function plainDirectory(home, dir) {
|
|
9589
9730
|
const intended = assertStagingInsideHome(home, dir);
|
|
9590
9731
|
mkdirSync9(intended, { recursive: true, mode: 448 });
|
|
9591
9732
|
const proved = assertStagingInsideHome(home, intended);
|
|
9592
|
-
for (const p of [
|
|
9733
|
+
for (const p of [dirname10(proved), proved]) {
|
|
9593
9734
|
const st = lstatSync9(p);
|
|
9594
9735
|
if (st.isSymbolicLink() || !st.isDirectory()) throw new Error(`${p} is not a plain directory`);
|
|
9595
9736
|
}
|
|
@@ -10146,13 +10287,13 @@ var init_secret_files = __esm({
|
|
|
10146
10287
|
|
|
10147
10288
|
// src/sessions/task-sessions.ts
|
|
10148
10289
|
import { existsSync as existsSync6 } from "fs";
|
|
10149
|
-
import { join as
|
|
10290
|
+
import { join as join27 } from "path";
|
|
10150
10291
|
function createTaskSessions(dir) {
|
|
10151
10292
|
const fileFor = (sessionId) => {
|
|
10152
10293
|
if (!UUID3.test(sessionId)) {
|
|
10153
10294
|
throw new Error(`VALIDATION: ${sessionId.slice(0, 40)} is not a session id`);
|
|
10154
10295
|
}
|
|
10155
|
-
return
|
|
10296
|
+
return join27(dir, `${sessionId.toLowerCase()}.json`);
|
|
10156
10297
|
};
|
|
10157
10298
|
return {
|
|
10158
10299
|
mark(sessionId) {
|
|
@@ -10173,10 +10314,10 @@ var init_task_sessions = __esm({
|
|
|
10173
10314
|
});
|
|
10174
10315
|
|
|
10175
10316
|
// src/sessions/user-guards.ts
|
|
10176
|
-
import { closeSync as closeSync4, constants as constants4, fstatSync, openSync as openSync4, readFileSync as
|
|
10177
|
-
import { isAbsolute as isAbsolute20, join as
|
|
10317
|
+
import { closeSync as closeSync4, constants as constants4, fstatSync, openSync as openSync4, readFileSync as readFileSync11 } from "fs";
|
|
10318
|
+
import { isAbsolute as isAbsolute20, join as join28 } from "path";
|
|
10178
10319
|
function readUserGuards(configDir) {
|
|
10179
|
-
const settingsFile =
|
|
10320
|
+
const settingsFile = join28(configDir, "settings.json");
|
|
10180
10321
|
const none = { settingsFile, preToolUseHooks: 0, denyRules: 0 };
|
|
10181
10322
|
if (!isAbsolute20(configDir)) return none;
|
|
10182
10323
|
const text = readSmallFile(settingsFile);
|
|
@@ -10211,7 +10352,7 @@ function readSmallFile(path) {
|
|
|
10211
10352
|
try {
|
|
10212
10353
|
const stats = fstatSync(fd);
|
|
10213
10354
|
if (!stats.isFile() || stats.size > USER_SETTINGS_MAX_BYTES) return null;
|
|
10214
|
-
return
|
|
10355
|
+
return readFileSync11(fd, "utf8");
|
|
10215
10356
|
} catch {
|
|
10216
10357
|
return null;
|
|
10217
10358
|
} finally {
|
|
@@ -10245,7 +10386,7 @@ var init_user_guards = __esm({
|
|
|
10245
10386
|
// src/sessions/manager.ts
|
|
10246
10387
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
10247
10388
|
import { realpathSync as realpathSync17 } from "fs";
|
|
10248
|
-
import { isAbsolute as isAbsolute21, join as
|
|
10389
|
+
import { isAbsolute as isAbsolute21, join as join29, relative as relative14, sep as sep17 } from "path";
|
|
10249
10390
|
import { isDeepStrictEqual } from "util";
|
|
10250
10391
|
function releaseCreds(creds) {
|
|
10251
10392
|
if (creds?.state === "ok") creds.release();
|
|
@@ -11635,7 +11776,7 @@ var init_manager = __esm({
|
|
|
11635
11776
|
const id = sessionId === void 0 ? null : this.live.get(sessionId)?.session.providerSessionId;
|
|
11636
11777
|
if (projectDir === null || typeof id !== "string" || !PROVIDER_SESSION_ID.test(id))
|
|
11637
11778
|
return [];
|
|
11638
|
-
return [
|
|
11779
|
+
return [join29(projectDir, id, "tool-results")];
|
|
11639
11780
|
};
|
|
11640
11781
|
const policy2 = this.settingsPolicy(createdBy, cwd, permissionMode, []);
|
|
11641
11782
|
this.warnBypassWithoutUserGuards(createdBy, permissionMode, policy2, sessionId);
|
|
@@ -11683,7 +11824,7 @@ var init_manager = __esm({
|
|
|
11683
11824
|
canonical3 = realpathSync17.native(configDir);
|
|
11684
11825
|
} catch {
|
|
11685
11826
|
}
|
|
11686
|
-
return
|
|
11827
|
+
return join29(canonical3, "projects", claudeProjectDirName(cwd));
|
|
11687
11828
|
}
|
|
11688
11829
|
/** Whether one of `roots` contains the managed root, as an allowed root such as `~` can. */
|
|
11689
11830
|
reachesManagedRoot(roots) {
|
|
@@ -11714,7 +11855,7 @@ var init_manager = __esm({
|
|
|
11714
11855
|
return parsed.data;
|
|
11715
11856
|
}
|
|
11716
11857
|
taskSessions() {
|
|
11717
|
-
return this.deps.taskSessions ?? createTaskSessions(
|
|
11858
|
+
return this.deps.taskSessions ?? createTaskSessions(join29(this.deps.cayenneHome ?? cayenneHome(), "task-sessions"));
|
|
11718
11859
|
}
|
|
11719
11860
|
markTaskSession(sessionId) {
|
|
11720
11861
|
try {
|
|
@@ -12858,10 +12999,10 @@ var init_manager = __esm({
|
|
|
12858
12999
|
});
|
|
12859
13000
|
|
|
12860
13001
|
// src/sessions/repo-sessions.ts
|
|
12861
|
-
import { readdirSync as readdirSync5, readFileSync as
|
|
12862
|
-
import { join as
|
|
13002
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
|
|
13003
|
+
import { join as join30 } from "path";
|
|
12863
13004
|
function createRepoSessions(dir) {
|
|
12864
|
-
const fileFor = (sessionId) => UUID4.test(sessionId) ?
|
|
13005
|
+
const fileFor = (sessionId) => UUID4.test(sessionId) ? join30(dir, `${sessionId.toLowerCase()}.json`) : null;
|
|
12865
13006
|
return {
|
|
12866
13007
|
mark(sessionId, mark) {
|
|
12867
13008
|
const file = fileFor(sessionId);
|
|
@@ -12881,7 +13022,7 @@ function createRepoSessions(dir) {
|
|
|
12881
13022
|
if (file === null) return null;
|
|
12882
13023
|
let text;
|
|
12883
13024
|
try {
|
|
12884
|
-
text =
|
|
13025
|
+
text = readFileSync12(file, "utf8");
|
|
12885
13026
|
} catch (err) {
|
|
12886
13027
|
return isMissing(err) ? null : "unreadable";
|
|
12887
13028
|
}
|
|
@@ -13265,9 +13406,9 @@ function createTerminalChannels({
|
|
|
13265
13406
|
const inflight = joining.get(terminalId);
|
|
13266
13407
|
if (inflight) return inflight;
|
|
13267
13408
|
if (joined.has(terminalId)) return;
|
|
13268
|
-
const
|
|
13269
|
-
joining.set(terminalId,
|
|
13270
|
-
return
|
|
13409
|
+
const join33 = attachOne(terminalId).finally(() => joining.delete(terminalId));
|
|
13410
|
+
joining.set(terminalId, join33);
|
|
13411
|
+
return join33;
|
|
13271
13412
|
},
|
|
13272
13413
|
flush,
|
|
13273
13414
|
detach,
|
|
@@ -13328,9 +13469,9 @@ var init_channels = __esm({
|
|
|
13328
13469
|
});
|
|
13329
13470
|
|
|
13330
13471
|
// src/terminal/env.ts
|
|
13331
|
-
import { readFileSync as
|
|
13472
|
+
import { readFileSync as readFileSync13, realpathSync as realpathSync19 } from "fs";
|
|
13332
13473
|
import { lstat } from "fs/promises";
|
|
13333
|
-
import { dirname as
|
|
13474
|
+
import { dirname as dirname11, isAbsolute as isAbsolute22, relative as relative15 } from "path";
|
|
13334
13475
|
function terminalEnv(base, { runnerOwner, claudeConfigDir }) {
|
|
13335
13476
|
const env = {};
|
|
13336
13477
|
for (const [key, value] of Object.entries(base)) {
|
|
@@ -13389,7 +13530,7 @@ async function rootOwnedPath(fs, real) {
|
|
|
13389
13530
|
return false;
|
|
13390
13531
|
}
|
|
13391
13532
|
if (st.isSymbolicLink() || st.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
13392
|
-
const parent =
|
|
13533
|
+
const parent = dirname11(path);
|
|
13393
13534
|
if (parent === path) return true;
|
|
13394
13535
|
path = parent;
|
|
13395
13536
|
}
|
|
@@ -13428,7 +13569,7 @@ var init_env2 = __esm({
|
|
|
13428
13569
|
nodeShellFs = {
|
|
13429
13570
|
readEtcShells: () => {
|
|
13430
13571
|
try {
|
|
13431
|
-
return
|
|
13572
|
+
return readFileSync13("/etc/shells", "utf8");
|
|
13432
13573
|
} catch {
|
|
13433
13574
|
return "";
|
|
13434
13575
|
}
|
|
@@ -14474,7 +14615,7 @@ __export(start_exports, {
|
|
|
14474
14615
|
start: () => start
|
|
14475
14616
|
});
|
|
14476
14617
|
import { homedir as homedir6, hostname } from "os";
|
|
14477
|
-
import { join as
|
|
14618
|
+
import { join as join31 } from "path";
|
|
14478
14619
|
function protectedPaths(claudeConfigDir, home = homedir6()) {
|
|
14479
14620
|
const inHome = [
|
|
14480
14621
|
".claude",
|
|
@@ -14482,12 +14623,12 @@ function protectedPaths(claudeConfigDir, home = homedir6()) {
|
|
|
14482
14623
|
".codex",
|
|
14483
14624
|
".ssh",
|
|
14484
14625
|
".aws",
|
|
14485
|
-
|
|
14626
|
+
join31(".config", "gh"),
|
|
14486
14627
|
".gnupg",
|
|
14487
14628
|
".git-credentials",
|
|
14488
14629
|
".npmrc",
|
|
14489
14630
|
".netrc"
|
|
14490
|
-
].map((p) =>
|
|
14631
|
+
].map((p) => join31(home, p));
|
|
14491
14632
|
return [cayenneHome(), ...claudeConfigDir ? [claudeConfigDir] : [], ...inHome];
|
|
14492
14633
|
}
|
|
14493
14634
|
function withRepoClone(repoClone) {
|
|
@@ -14503,6 +14644,16 @@ function logCodex(codex) {
|
|
|
14503
14644
|
`codex available on ${codex.models.map((m) => m.id).join(", ") || "its default model"}`
|
|
14504
14645
|
);
|
|
14505
14646
|
}
|
|
14647
|
+
function logClaude(claude) {
|
|
14648
|
+
if (!claude.available) {
|
|
14649
|
+
logger.info({ reason: claude.reason }, `claude ${claude.reason ?? "unavailable"}`);
|
|
14650
|
+
return;
|
|
14651
|
+
}
|
|
14652
|
+
logger.info(
|
|
14653
|
+
{ version: claude.version, models: claude.models.map((m) => m.id), authMode: claude.authMode },
|
|
14654
|
+
`claude available on ${claude.models.map((m) => m.id).join(", ") || "the curated model list"}`
|
|
14655
|
+
);
|
|
14656
|
+
}
|
|
14506
14657
|
function holdLock(root, record) {
|
|
14507
14658
|
let held;
|
|
14508
14659
|
return {
|
|
@@ -14595,7 +14746,6 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14595
14746
|
);
|
|
14596
14747
|
});
|
|
14597
14748
|
const codexPath = resolveCodexPath(cfg, process.env, () => findCodexOnPath(process.env));
|
|
14598
|
-
const detect = () => detectProviders({ path: codexPath, run: runCodex, listModels: listCodexModels });
|
|
14599
14749
|
let providers = {
|
|
14600
14750
|
claude: { available: true, models: [] },
|
|
14601
14751
|
codex: { available: false, reason: "not_installed", models: [] }
|
|
@@ -14603,9 +14753,23 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14603
14753
|
const pty = await loadPty();
|
|
14604
14754
|
const memberTerminalIds = memberTerminalIdsOf(cfg);
|
|
14605
14755
|
const kinds2 = handledKinds({ terminal: pty !== null });
|
|
14606
|
-
const runDir =
|
|
14756
|
+
const runDir = join31(cayenneDir(), "run");
|
|
14607
14757
|
prepareRunDir(runDir, { git: findOnPath("git", process.env.PATH) });
|
|
14608
14758
|
const gitHome = repositoryGitHome(runDir);
|
|
14759
|
+
const claudeProbeEnv = claudeEnv(claudeConfigDir);
|
|
14760
|
+
const detect = () => detectProviders({
|
|
14761
|
+
path: codexPath,
|
|
14762
|
+
run: runCodex,
|
|
14763
|
+
listModels: listCodexModels,
|
|
14764
|
+
claude: () => detectClaude({
|
|
14765
|
+
version: claudeCodeVersion,
|
|
14766
|
+
probe: () => probeClaude({
|
|
14767
|
+
env: claudeProbeEnv,
|
|
14768
|
+
cwd: runDir,
|
|
14769
|
+
settingSources: cfg.loadUserSettings ? ["user"] : []
|
|
14770
|
+
})
|
|
14771
|
+
})
|
|
14772
|
+
});
|
|
14609
14773
|
for (const path of githubNetrcFiles()) {
|
|
14610
14774
|
logger.warn(
|
|
14611
14775
|
{ path },
|
|
@@ -14685,6 +14849,7 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14685
14849
|
});
|
|
14686
14850
|
const registered = capabilities();
|
|
14687
14851
|
let loggedCodex = null;
|
|
14852
|
+
let loggedClaude = null;
|
|
14688
14853
|
const refresh = async () => {
|
|
14689
14854
|
providers = await detect();
|
|
14690
14855
|
const line = JSON.stringify(providers.codex);
|
|
@@ -14692,6 +14857,11 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14692
14857
|
loggedCodex = line;
|
|
14693
14858
|
logCodex(providers.codex);
|
|
14694
14859
|
}
|
|
14860
|
+
const claudeLine = JSON.stringify(providers.claude);
|
|
14861
|
+
if (claudeLine !== loggedClaude) {
|
|
14862
|
+
loggedClaude = claudeLine;
|
|
14863
|
+
logClaude(providers.claude);
|
|
14864
|
+
}
|
|
14695
14865
|
return capabilities();
|
|
14696
14866
|
};
|
|
14697
14867
|
let identity;
|
|
@@ -14752,15 +14922,15 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14752
14922
|
const trustedRoots = trustedRepoRoots(cfg.trustRepoSettings);
|
|
14753
14923
|
if (!cfg.loadUserSettings) {
|
|
14754
14924
|
const guards = readUserGuards(sessionClaudeConfigDir(claudeEnv(claudeConfigDir)));
|
|
14755
|
-
const warning = userGuardsWarning(guards,
|
|
14925
|
+
const warning = userGuardsWarning(guards, join31(cayenneDir(), "config.json"));
|
|
14756
14926
|
if (warning) {
|
|
14757
14927
|
const { settingsFile, preToolUseHooks, denyRules } = guards;
|
|
14758
14928
|
logger.warn({ settingsFile, preToolUseHooks, denyRules }, warning);
|
|
14759
14929
|
}
|
|
14760
14930
|
}
|
|
14761
|
-
const repoSessions = createRepoSessions(
|
|
14762
|
-
const worktreeOwners = createWorktreeOwners(
|
|
14763
|
-
const sessionWorktrees = createSessionWorktrees(
|
|
14931
|
+
const repoSessions = createRepoSessions(join31(cayenneHome(), "repo-sessions"));
|
|
14932
|
+
const worktreeOwners = createWorktreeOwners(join31(cayenneHome(), "worktrees"));
|
|
14933
|
+
const sessionWorktrees = createSessionWorktrees(join31(cayenneHome(), "session-worktrees"));
|
|
14764
14934
|
const git = createGitOps({
|
|
14765
14935
|
protectedPaths: protectedPaths(claudeConfigDir),
|
|
14766
14936
|
home: homedir6(),
|
|
@@ -14788,7 +14958,7 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
14788
14958
|
worktreeOwners,
|
|
14789
14959
|
sessionWorktrees,
|
|
14790
14960
|
// And which sessions were started from a task, so their secret-file guard outlives a restart.
|
|
14791
|
-
taskSessions: createTaskSessions(
|
|
14961
|
+
taskSessions: createTaskSessions(join31(cayenneHome(), "task-sessions")),
|
|
14792
14962
|
// The paths no `git.diff` returns are paths no task session reads (protocol §2.8).
|
|
14793
14963
|
protectedPaths: protectedPaths(claudeConfigDir),
|
|
14794
14964
|
// D50: where repository chats run, which of them are, and their credentials' run dir. A
|
|
@@ -15147,9 +15317,10 @@ var init_start = __esm({
|
|
|
15147
15317
|
"src/start.ts"() {
|
|
15148
15318
|
"use strict";
|
|
15149
15319
|
init_src();
|
|
15320
|
+
init_detect();
|
|
15150
15321
|
init_claude_dir();
|
|
15151
15322
|
init_cloud();
|
|
15152
|
-
|
|
15323
|
+
init_detect2();
|
|
15153
15324
|
init_dispatcher();
|
|
15154
15325
|
init_source();
|
|
15155
15326
|
init_config();
|
|
@@ -15192,9 +15363,9 @@ var init_start = __esm({
|
|
|
15192
15363
|
});
|
|
15193
15364
|
|
|
15194
15365
|
// src/cli.ts
|
|
15195
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync10, readFileSync as
|
|
15366
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync10, readFileSync as readFileSync14, realpathSync as realpathSync20, rmSync as rmSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
15196
15367
|
import { homedir as homedir7, hostname as hostname2, userInfo } from "os";
|
|
15197
|
-
import { dirname as
|
|
15368
|
+
import { dirname as dirname12, join as join32 } from "path";
|
|
15198
15369
|
import { Command } from "commander";
|
|
15199
15370
|
import prompts from "prompts";
|
|
15200
15371
|
|
|
@@ -15699,7 +15870,7 @@ var service = () => {
|
|
|
15699
15870
|
return { exec: exec4, launchd: makeLaunchd(exec4, userInfo().uid), label: plistLabel(currentProfile()) };
|
|
15700
15871
|
};
|
|
15701
15872
|
var writePlistFile = (path, xml2) => {
|
|
15702
|
-
mkdirSync10(
|
|
15873
|
+
mkdirSync10(dirname12(path), { recursive: true });
|
|
15703
15874
|
writeFileSync7(path, xml2, { mode: 420 });
|
|
15704
15875
|
};
|
|
15705
15876
|
var requireMac = () => {
|
|
@@ -15848,7 +16019,7 @@ program.command("doctor").description("Check the install and say how to fix what
|
|
|
15848
16019
|
if (checks.some((c) => !c.ok)) process.exitCode = 1;
|
|
15849
16020
|
});
|
|
15850
16021
|
program.command("logs").description("Show the service log").option("-f, --follow", "keep streaming").action(async (opts) => {
|
|
15851
|
-
const file =
|
|
16022
|
+
const file = join32(cayenneDir(), "logs", "runner.log");
|
|
15852
16023
|
if (!existsSync7(file)) throw new Error(`no log yet at ${file}. Run \`cayenne up\` first.`);
|
|
15853
16024
|
const print = (chunk) => {
|
|
15854
16025
|
for (const line of chunk.split("\n")) {
|
|
@@ -15861,12 +16032,12 @@ program.command("logs").description("Show the service log").option("-f, --follow
|
|
|
15861
16032
|
}
|
|
15862
16033
|
}
|
|
15863
16034
|
};
|
|
15864
|
-
print(
|
|
16035
|
+
print(readFileSync14(file, "utf8"));
|
|
15865
16036
|
if (opts.follow) {
|
|
15866
16037
|
const { watch: watch2 } = await import("fs");
|
|
15867
|
-
let size =
|
|
16038
|
+
let size = readFileSync14(file).length;
|
|
15868
16039
|
watch2(file, () => {
|
|
15869
|
-
const buf =
|
|
16040
|
+
const buf = readFileSync14(file);
|
|
15870
16041
|
if (buf.length > size) print(buf.subarray(size).toString("utf8"));
|
|
15871
16042
|
size = buf.length;
|
|
15872
16043
|
});
|
|
@@ -15894,7 +16065,7 @@ program.command("update").description("Re-pin the installed app and restart the
|
|
|
15894
16065
|
cliPath: record.cliPath,
|
|
15895
16066
|
profile: currentProfile(),
|
|
15896
16067
|
pathEnv: record.pathEnv,
|
|
15897
|
-
logDir:
|
|
16068
|
+
logDir: join32(dir, "logs")
|
|
15898
16069
|
})
|
|
15899
16070
|
);
|
|
15900
16071
|
await launchd.bootout(label);
|
|
@@ -15915,7 +16086,7 @@ program.command("uninstall").description("Stop the service and remove the launch
|
|
|
15915
16086
|
if (dir === "/" || dir === home || home.startsWith(`${dir}/`)) {
|
|
15916
16087
|
throw new Error(`refusing to purge ${dir}: it is the home directory or an ancestor of it`);
|
|
15917
16088
|
}
|
|
15918
|
-
if (!existsSync7(
|
|
16089
|
+
if (!existsSync7(join32(dir, "config.json")) && !existsSync7(join32(dir, "app", "install.json"))) {
|
|
15919
16090
|
throw new Error(`refusing to purge ${dir}: it does not look like a Cayenne profile`);
|
|
15920
16091
|
}
|
|
15921
16092
|
if (!opts.yes) {
|