zam-core 0.4.1 → 0.4.3
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/index.js +312 -76
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { readFileSync as readFileSync14 } from "fs";
|
|
5
|
-
import { dirname as dirname10, join as
|
|
5
|
+
import { dirname as dirname10, join as join23 } from "path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7
7
|
import { Command as Command24 } from "commander";
|
|
8
8
|
|
|
@@ -4932,10 +4932,10 @@ var agentCommand = new Command("agent").description("Provision and inspect the a
|
|
|
4932
4932
|
|
|
4933
4933
|
// src/cli/commands/bridge.ts
|
|
4934
4934
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
4935
|
-
import { randomBytes } from "crypto";
|
|
4935
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
4936
4936
|
import { readdirSync as readdirSync2, readFileSync as readFileSync10, rmSync as rmSync2 } from "fs";
|
|
4937
|
-
import { homedir as homedir8, tmpdir } from "os";
|
|
4938
|
-
import { join as
|
|
4937
|
+
import { homedir as homedir8, tmpdir as tmpdir2 } from "os";
|
|
4938
|
+
import { join as join13 } from "path";
|
|
4939
4939
|
import { Command as Command2 } from "commander";
|
|
4940
4940
|
|
|
4941
4941
|
// src/cli/llm/client.ts
|
|
@@ -4955,12 +4955,15 @@ async function getLlmConfig(db) {
|
|
|
4955
4955
|
}
|
|
4956
4956
|
async function getVisionConfig(db) {
|
|
4957
4957
|
const base = await getLlmConfig(db);
|
|
4958
|
+
const maxFramesStr = await getSetting(db, "llm.vision.max_frames");
|
|
4959
|
+
const maxFrames = maxFramesStr ? parseInt(maxFramesStr, 10) : 100;
|
|
4958
4960
|
return {
|
|
4959
4961
|
enabled: await getSetting(db, "llm.vision.enabled") === "true",
|
|
4960
4962
|
url: await getSetting(db, "llm.vision.url") || base.url,
|
|
4961
4963
|
model: await getSetting(db, "llm.vision.model") || base.model,
|
|
4962
4964
|
apiKey: await getSetting(db, "llm.vision.api_key") || base.apiKey,
|
|
4963
|
-
locale: base.locale
|
|
4965
|
+
locale: base.locale,
|
|
4966
|
+
maxFrames: Number.isNaN(maxFrames) ? 100 : maxFrames
|
|
4964
4967
|
};
|
|
4965
4968
|
}
|
|
4966
4969
|
var LANGUAGE_NAMES = {
|
|
@@ -5497,8 +5500,10 @@ async function ensureHighQualityQuestion(db, token) {
|
|
|
5497
5500
|
}
|
|
5498
5501
|
|
|
5499
5502
|
// src/cli/llm/vision.ts
|
|
5503
|
+
import { randomBytes } from "crypto";
|
|
5500
5504
|
import { readFileSync as readFileSync9 } from "fs";
|
|
5501
|
-
import {
|
|
5505
|
+
import { tmpdir } from "os";
|
|
5506
|
+
import { basename as basename2, join as join12 } from "path";
|
|
5502
5507
|
var LANGUAGE_NAMES2 = {
|
|
5503
5508
|
en: "English",
|
|
5504
5509
|
de: "German",
|
|
@@ -5531,15 +5536,69 @@ async function observeUiSnapshotViaLLM(db, input8) {
|
|
|
5531
5536
|
"Vision observation is disabled in settings (llm.vision.enabled)"
|
|
5532
5537
|
);
|
|
5533
5538
|
}
|
|
5534
|
-
const
|
|
5535
|
-
const
|
|
5539
|
+
const imageUrls = [];
|
|
5540
|
+
const isVideo = /\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(input8.imagePath);
|
|
5541
|
+
if (isVideo) {
|
|
5542
|
+
const { mkdirSync: mkdirSync12, readdirSync: readdirSync3, rmSync: rmSync3 } = await import("fs");
|
|
5543
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
5544
|
+
const tempDir = join12(
|
|
5545
|
+
tmpdir(),
|
|
5546
|
+
`zam-frames-${randomBytes(4).toString("hex")}`
|
|
5547
|
+
);
|
|
5548
|
+
mkdirSync12(tempDir, { recursive: true });
|
|
5549
|
+
try {
|
|
5550
|
+
execSync7(
|
|
5551
|
+
`ffmpeg -i "${input8.imagePath}" -vf "fps=1/3,scale=1280:-1" -vsync vfr "${tempDir}/frame_%03d.png"`,
|
|
5552
|
+
{ stdio: "ignore" }
|
|
5553
|
+
);
|
|
5554
|
+
let files = readdirSync3(tempDir).filter((f) => f.endsWith(".png")).sort();
|
|
5555
|
+
if (files.length === 0) {
|
|
5556
|
+
execSync7(
|
|
5557
|
+
`ffmpeg -i "${input8.imagePath}" -vframes 1 "${tempDir}/frame_001.png"`,
|
|
5558
|
+
{ stdio: "ignore" }
|
|
5559
|
+
);
|
|
5560
|
+
files = readdirSync3(tempDir).filter((f) => f.endsWith(".png")).sort();
|
|
5561
|
+
}
|
|
5562
|
+
const maxFrames = cfg.maxFrames ?? 100;
|
|
5563
|
+
let sampledFiles = files;
|
|
5564
|
+
if (files.length > maxFrames) {
|
|
5565
|
+
if (maxFrames <= 1) {
|
|
5566
|
+
sampledFiles = [files[0]];
|
|
5567
|
+
} else {
|
|
5568
|
+
const step = (files.length - 1) / (maxFrames - 1);
|
|
5569
|
+
sampledFiles = [];
|
|
5570
|
+
for (let i = 0; i < maxFrames; i++) {
|
|
5571
|
+
const index = Math.round(i * step);
|
|
5572
|
+
sampledFiles.push(files[index]);
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
for (const file of sampledFiles) {
|
|
5577
|
+
const bytes = readFileSync9(join12(tempDir, file));
|
|
5578
|
+
imageUrls.push(`data:image/png;base64,${bytes.toString("base64")}`);
|
|
5579
|
+
}
|
|
5580
|
+
} finally {
|
|
5581
|
+
try {
|
|
5582
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
5583
|
+
} catch {
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
} else {
|
|
5587
|
+
const imageBytes = readFileSync9(input8.imagePath);
|
|
5588
|
+
const ext = input8.imagePath.split(".").pop()?.toLowerCase();
|
|
5589
|
+
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
|
|
5590
|
+
imageUrls.push(`data:${mime};base64,${imageBytes.toString("base64")}`);
|
|
5591
|
+
}
|
|
5592
|
+
if (imageUrls.length === 0) {
|
|
5593
|
+
throw new Error("No image data available for vision analysis");
|
|
5594
|
+
}
|
|
5536
5595
|
const model = input8.model ?? cfg.model;
|
|
5537
5596
|
const content = await requestVisionDraft({
|
|
5538
5597
|
url: cfg.url,
|
|
5539
5598
|
apiKey: cfg.apiKey || DEFAULT_LLM_API_KEY,
|
|
5540
5599
|
model,
|
|
5541
5600
|
locale: cfg.locale,
|
|
5542
|
-
|
|
5601
|
+
imageUrls,
|
|
5543
5602
|
input: input8
|
|
5544
5603
|
});
|
|
5545
5604
|
let draft;
|
|
@@ -5589,22 +5648,28 @@ async function requestVisionDraft(args) {
|
|
|
5589
5648
|
content: [
|
|
5590
5649
|
{
|
|
5591
5650
|
type: "text",
|
|
5592
|
-
text: `Observe this Windows application
|
|
5651
|
+
text: args.imageUrls.length > 1 ? `Observe this sequence of Windows/macOS application snapshots showing a task performed over time.
|
|
5652
|
+
Application process: ${args.input.application.processName}
|
|
5653
|
+
Window title: ${args.input.application.windowTitle ?? "(unknown)"}
|
|
5654
|
+
|
|
5655
|
+
Return this JSON draft only:
|
|
5656
|
+
${schema}` : `Observe this Windows/macOS application snapshot for a learning session.
|
|
5593
5657
|
Application process: ${args.input.application.processName}
|
|
5594
5658
|
Window title: ${args.input.application.windowTitle ?? "(unknown)"}
|
|
5595
5659
|
|
|
5596
5660
|
Return this JSON draft only:
|
|
5597
5661
|
${schema}`
|
|
5598
5662
|
},
|
|
5599
|
-
{
|
|
5663
|
+
...args.imageUrls.map((url) => ({
|
|
5600
5664
|
type: "image_url",
|
|
5601
|
-
image_url: { url
|
|
5602
|
-
}
|
|
5665
|
+
image_url: { url }
|
|
5666
|
+
}))
|
|
5603
5667
|
]
|
|
5604
5668
|
}
|
|
5605
5669
|
],
|
|
5606
5670
|
temperature: 0,
|
|
5607
|
-
max_tokens: args.input.maxTokens ?? 450
|
|
5671
|
+
max_tokens: args.input.maxTokens ?? 450,
|
|
5672
|
+
...args.url.includes("11434") || args.url.includes("localhost") || args.url.includes("127.0.0.1") ? { options: { num_ctx: 32768 } } : {}
|
|
5608
5673
|
}),
|
|
5609
5674
|
locale: args.locale,
|
|
5610
5675
|
hardTimeoutMs: args.input.hardTimeoutMs ?? 18e4
|
|
@@ -6239,7 +6304,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
6239
6304
|
"20"
|
|
6240
6305
|
).action(async (opts) => {
|
|
6241
6306
|
try {
|
|
6242
|
-
const monitorDir =
|
|
6307
|
+
const monitorDir = join13(homedir8(), ".zam", "monitor");
|
|
6243
6308
|
let files;
|
|
6244
6309
|
try {
|
|
6245
6310
|
files = readdirSync2(monitorDir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -6252,7 +6317,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
6252
6317
|
return;
|
|
6253
6318
|
}
|
|
6254
6319
|
const limit = Number(opts.limit);
|
|
6255
|
-
const sorted = files.map((f) => ({ name: f, path:
|
|
6320
|
+
const sorted = files.map((f) => ({ name: f, path: join13(monitorDir, f) })).sort((a, b) => b.name.localeCompare(a.name)).slice(0, limit);
|
|
6256
6321
|
const sessionCommands = /* @__PURE__ */ new Map();
|
|
6257
6322
|
for (const file of sorted) {
|
|
6258
6323
|
const sessionId = file.name.replace(".jsonl", "");
|
|
@@ -6332,8 +6397,8 @@ bridgeCommand.command("get-observations").description("Read UI observer reports
|
|
|
6332
6397
|
}
|
|
6333
6398
|
});
|
|
6334
6399
|
bridgeCommand.command("observe-ui-snapshot").description(
|
|
6335
|
-
"Analyze a captured UI snapshot with the configured vision LLM (JSON)"
|
|
6336
|
-
).requiredOption("--session <id>", "Observer session ID").requiredOption("--sequence <n>", "Monotonic observation sequence number").requiredOption("--image <path>", "PNG snapshot path").requiredOption("--observed-from <iso>", "Observation window start time").requiredOption("--observed-to <iso>", "Observation window end time").requiredOption("--process-name <name>", "Observed application process name").option("--process-id <n>", "Observed application process ID").option("--window-title <title>", "Observed window title").option("--evidence-ref <ref>", "Evidence reference to put in the report").option("--model <model>", "Override configured LLM model for this request").option("--max-tokens <n>", "Model response token budget").option("--timeout <ms>", "Hard request timeout in milliseconds").option("--redacted", "Mark the snapshot evidence as redacted").option("--write-log", "Append the generated report to the session JSONL").action(async (opts) => {
|
|
6400
|
+
"Analyze a captured UI snapshot or video recording with the configured vision LLM (JSON)"
|
|
6401
|
+
).requiredOption("--session <id>", "Observer session ID").requiredOption("--sequence <n>", "Monotonic observation sequence number").requiredOption("--image <path>", "PNG snapshot or video recording path").requiredOption("--observed-from <iso>", "Observation window start time").requiredOption("--observed-to <iso>", "Observation window end time").requiredOption("--process-name <name>", "Observed application process name").option("--process-id <n>", "Observed application process ID").option("--window-title <title>", "Observed window title").option("--evidence-ref <ref>", "Evidence reference to put in the report").option("--model <model>", "Override configured LLM model for this request").option("--max-tokens <n>", "Model response token budget").option("--timeout <ms>", "Hard request timeout in milliseconds").option("--redacted", "Mark the snapshot evidence as redacted").option("--write-log", "Append the generated report to the session JSONL").action(async (opts) => {
|
|
6337
6402
|
const sequence = parseNonNegativeIntegerOption("sequence", opts.sequence);
|
|
6338
6403
|
const processId = opts.processId === void 0 ? void 0 : parseNonNegativeIntegerOption("process-id", opts.processId);
|
|
6339
6404
|
const maxTokens = opts.maxTokens === void 0 ? void 0 : parseNonNegativeIntegerOption("max-tokens", opts.maxTokens);
|
|
@@ -6754,7 +6819,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
6754
6819
|
return;
|
|
6755
6820
|
}
|
|
6756
6821
|
}
|
|
6757
|
-
const outputPath = opts.image ?? opts.output ??
|
|
6822
|
+
const outputPath = opts.image ?? opts.output ?? join13(tmpdir2(), `zam-capture-${randomBytes2(4).toString("hex")}.png`);
|
|
6758
6823
|
const captureResult = isProvided ? { method: "provided", target: null } : captureScreenshot(outputPath, opts.hwnd, opts.processName);
|
|
6759
6824
|
if (!isProvided) {
|
|
6760
6825
|
const post = decidePostCapture(policy, {
|
|
@@ -6798,6 +6863,177 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
6798
6863
|
});
|
|
6799
6864
|
});
|
|
6800
6865
|
});
|
|
6866
|
+
bridgeCommand.command("start-recording").description("Start screen recording in the background (macOS only) (JSON)").requiredOption("--session <id>", "ZAM session ID").option("--output <path>", "Video output path").action(async (opts) => {
|
|
6867
|
+
const platform = process.platform;
|
|
6868
|
+
if (platform !== "darwin") {
|
|
6869
|
+
jsonOut2({
|
|
6870
|
+
sessionId: opts.session,
|
|
6871
|
+
started: false,
|
|
6872
|
+
error: "Screen recording is only supported on macOS (darwin)"
|
|
6873
|
+
});
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
const sessionId = opts.session;
|
|
6877
|
+
const statePath = join13(tmpdir2(), `zam-recording-${sessionId}.json`);
|
|
6878
|
+
const outputPath = opts.output ?? join13(tmpdir2(), `zam-recording-${sessionId}.mov`);
|
|
6879
|
+
const { existsSync: existsSync22, writeFileSync: writeFileSync12, openSync, closeSync } = await import("fs");
|
|
6880
|
+
if (existsSync22(statePath)) {
|
|
6881
|
+
jsonOut2({
|
|
6882
|
+
sessionId,
|
|
6883
|
+
started: false,
|
|
6884
|
+
error: `Recording is already active for session ${sessionId}`
|
|
6885
|
+
});
|
|
6886
|
+
return;
|
|
6887
|
+
}
|
|
6888
|
+
const logPath = join13(tmpdir2(), `zam-recording-${sessionId}.log`);
|
|
6889
|
+
let logFd;
|
|
6890
|
+
try {
|
|
6891
|
+
logFd = openSync(logPath, "w");
|
|
6892
|
+
} catch (e) {
|
|
6893
|
+
jsonOut2({
|
|
6894
|
+
sessionId,
|
|
6895
|
+
started: false,
|
|
6896
|
+
error: `Failed to open log file at ${logPath}: ${e.message}`
|
|
6897
|
+
});
|
|
6898
|
+
return;
|
|
6899
|
+
}
|
|
6900
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
6901
|
+
const child = spawn3(
|
|
6902
|
+
"ffmpeg",
|
|
6903
|
+
[
|
|
6904
|
+
"-y",
|
|
6905
|
+
"-f",
|
|
6906
|
+
"avfoundation",
|
|
6907
|
+
"-r",
|
|
6908
|
+
"5",
|
|
6909
|
+
"-i",
|
|
6910
|
+
"0",
|
|
6911
|
+
"-pix_fmt",
|
|
6912
|
+
"yuv420p",
|
|
6913
|
+
outputPath
|
|
6914
|
+
],
|
|
6915
|
+
{
|
|
6916
|
+
detached: true,
|
|
6917
|
+
stdio: ["pipe", logFd, logFd]
|
|
6918
|
+
}
|
|
6919
|
+
);
|
|
6920
|
+
try {
|
|
6921
|
+
closeSync(logFd);
|
|
6922
|
+
} catch {
|
|
6923
|
+
}
|
|
6924
|
+
child.unref();
|
|
6925
|
+
if (child.pid) {
|
|
6926
|
+
writeFileSync12(
|
|
6927
|
+
statePath,
|
|
6928
|
+
JSON.stringify({
|
|
6929
|
+
pid: child.pid,
|
|
6930
|
+
outputPath,
|
|
6931
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6932
|
+
}),
|
|
6933
|
+
"utf8"
|
|
6934
|
+
);
|
|
6935
|
+
jsonOut2({
|
|
6936
|
+
sessionId,
|
|
6937
|
+
started: true,
|
|
6938
|
+
outputPath,
|
|
6939
|
+
pid: child.pid
|
|
6940
|
+
});
|
|
6941
|
+
} else {
|
|
6942
|
+
jsonOut2({
|
|
6943
|
+
sessionId,
|
|
6944
|
+
started: false,
|
|
6945
|
+
error: "Failed to spawn ffmpeg process"
|
|
6946
|
+
});
|
|
6947
|
+
}
|
|
6948
|
+
});
|
|
6949
|
+
bridgeCommand.command("stop-recording").description(
|
|
6950
|
+
"Stop active screen recording and apply idle-frame compression (macOS only) (JSON)"
|
|
6951
|
+
).requiredOption("--session <id>", "ZAM session ID").action(async (opts) => {
|
|
6952
|
+
const platform = process.platform;
|
|
6953
|
+
if (platform !== "darwin") {
|
|
6954
|
+
jsonOut2({
|
|
6955
|
+
sessionId: opts.session,
|
|
6956
|
+
stopped: false,
|
|
6957
|
+
error: "Screen recording is only supported on macOS (darwin)"
|
|
6958
|
+
});
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6961
|
+
const sessionId = opts.session;
|
|
6962
|
+
const statePath = join13(tmpdir2(), `zam-recording-${sessionId}.json`);
|
|
6963
|
+
const { existsSync: existsSync22, readFileSync: readFileSync15, rmSync: rmSync3 } = await import("fs");
|
|
6964
|
+
if (!existsSync22(statePath)) {
|
|
6965
|
+
jsonOut2({
|
|
6966
|
+
sessionId,
|
|
6967
|
+
stopped: false,
|
|
6968
|
+
error: `No active recording found for session ${sessionId}`
|
|
6969
|
+
});
|
|
6970
|
+
return;
|
|
6971
|
+
}
|
|
6972
|
+
const state = JSON.parse(readFileSync15(statePath, "utf8"));
|
|
6973
|
+
const { pid, outputPath } = state;
|
|
6974
|
+
try {
|
|
6975
|
+
process.kill(pid, "SIGINT");
|
|
6976
|
+
} catch (_e) {
|
|
6977
|
+
}
|
|
6978
|
+
const isProcessRunning = (pId) => {
|
|
6979
|
+
try {
|
|
6980
|
+
process.kill(pId, 0);
|
|
6981
|
+
return true;
|
|
6982
|
+
} catch (_e) {
|
|
6983
|
+
return false;
|
|
6984
|
+
}
|
|
6985
|
+
};
|
|
6986
|
+
let attempts = 0;
|
|
6987
|
+
while (isProcessRunning(pid) && attempts < 20) {
|
|
6988
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
6989
|
+
attempts++;
|
|
6990
|
+
}
|
|
6991
|
+
if (isProcessRunning(pid)) {
|
|
6992
|
+
try {
|
|
6993
|
+
process.kill(pid, "SIGKILL");
|
|
6994
|
+
} catch (_e) {
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6997
|
+
try {
|
|
6998
|
+
rmSync3(statePath, { force: true });
|
|
6999
|
+
} catch {
|
|
7000
|
+
}
|
|
7001
|
+
if (!existsSync22(outputPath)) {
|
|
7002
|
+
jsonOut2({
|
|
7003
|
+
sessionId,
|
|
7004
|
+
stopped: false,
|
|
7005
|
+
error: `Recording file not found at ${outputPath}`
|
|
7006
|
+
});
|
|
7007
|
+
return;
|
|
7008
|
+
}
|
|
7009
|
+
const decimatedPath = outputPath.replace(/\.[^.]+$/, "-decimated.mp4");
|
|
7010
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
7011
|
+
try {
|
|
7012
|
+
execSync7(
|
|
7013
|
+
`ffmpeg -y -i "${outputPath}" -vf "mpdecimate,setpts=N/FRAME_RATE/TB" -an -pix_fmt yuv420p "${decimatedPath}"`,
|
|
7014
|
+
{ stdio: "ignore" }
|
|
7015
|
+
);
|
|
7016
|
+
} catch (ffmpegErr) {
|
|
7017
|
+
jsonOut2({
|
|
7018
|
+
sessionId,
|
|
7019
|
+
stopped: true,
|
|
7020
|
+
videoPath: outputPath,
|
|
7021
|
+
decimated: false,
|
|
7022
|
+
warning: `mpdecimate post-processing failed: ${ffmpegErr.message}`
|
|
7023
|
+
});
|
|
7024
|
+
return;
|
|
7025
|
+
}
|
|
7026
|
+
try {
|
|
7027
|
+
rmSync3(outputPath, { force: true });
|
|
7028
|
+
} catch {
|
|
7029
|
+
}
|
|
7030
|
+
jsonOut2({
|
|
7031
|
+
sessionId,
|
|
7032
|
+
stopped: true,
|
|
7033
|
+
videoPath: decimatedPath,
|
|
7034
|
+
decimated: true
|
|
7035
|
+
});
|
|
7036
|
+
});
|
|
6801
7037
|
bridgeCommand.command("get-observer-policy").description(
|
|
6802
7038
|
"Report the resolved observer policy so an agent can check before capturing (JSON)"
|
|
6803
7039
|
).action(async () => {
|
|
@@ -7506,18 +7742,18 @@ async function setupTurso(urlArg, tokenArg, mode) {
|
|
|
7506
7742
|
// src/cli/commands/git-sync.ts
|
|
7507
7743
|
import { execSync as execSync4 } from "child_process";
|
|
7508
7744
|
import { chmodSync as chmodSync2, existsSync as existsSync13, writeFileSync as writeFileSync6 } from "fs";
|
|
7509
|
-
import { join as
|
|
7745
|
+
import { join as join14 } from "path";
|
|
7510
7746
|
import { Command as Command5 } from "commander";
|
|
7511
7747
|
function installHook2() {
|
|
7512
|
-
const gitDir =
|
|
7748
|
+
const gitDir = join14(process.cwd(), ".git");
|
|
7513
7749
|
if (!existsSync13(gitDir)) {
|
|
7514
7750
|
console.error(
|
|
7515
7751
|
"Error: Current directory is not the root of a Git repository."
|
|
7516
7752
|
);
|
|
7517
7753
|
process.exit(1);
|
|
7518
7754
|
}
|
|
7519
|
-
const hooksDir =
|
|
7520
|
-
const hookPath =
|
|
7755
|
+
const hooksDir = join14(gitDir, "hooks");
|
|
7756
|
+
const hookPath = join14(hooksDir, "post-commit");
|
|
7521
7757
|
const hookContent = `#!/bin/sh
|
|
7522
7758
|
# ZAM Spaced Repetition Auto-Stale Hook
|
|
7523
7759
|
# Triggered automatically on git commits to decay modified concept cards.
|
|
@@ -7813,7 +8049,7 @@ goalCommand.command("status <slug> <status>").description("Update a goal's statu
|
|
|
7813
8049
|
// src/cli/commands/init.ts
|
|
7814
8050
|
import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
7815
8051
|
import { homedir as homedir9 } from "os";
|
|
7816
|
-
import { join as
|
|
8052
|
+
import { join as join15 } from "path";
|
|
7817
8053
|
import { confirm, input as input3 } from "@inquirer/prompts";
|
|
7818
8054
|
import { Command as Command7 } from "commander";
|
|
7819
8055
|
var HOME2 = homedir9();
|
|
@@ -7821,10 +8057,10 @@ function printLine(char = "\u2550", len = 60, color = "\x1B[36m") {
|
|
|
7821
8057
|
console.log(`${color}${char.repeat(len)}\x1B[0m`);
|
|
7822
8058
|
}
|
|
7823
8059
|
function bootstrapSandboxWorkspace(workspaceDir) {
|
|
7824
|
-
mkdirSync9(
|
|
7825
|
-
mkdirSync9(
|
|
7826
|
-
mkdirSync9(
|
|
7827
|
-
const worldviewFile =
|
|
8060
|
+
mkdirSync9(join15(workspaceDir, "beliefs"), { recursive: true });
|
|
8061
|
+
mkdirSync9(join15(workspaceDir, "goals"), { recursive: true });
|
|
8062
|
+
mkdirSync9(join15(workspaceDir, "skills"), { recursive: true });
|
|
8063
|
+
const worldviewFile = join15(workspaceDir, "beliefs", "worldview.md");
|
|
7828
8064
|
if (!existsSync15(worldviewFile)) {
|
|
7829
8065
|
writeFileSync7(
|
|
7830
8066
|
worldviewFile,
|
|
@@ -7838,7 +8074,7 @@ Here, I declare the core concepts and principles I want to master.
|
|
|
7838
8074
|
"utf8"
|
|
7839
8075
|
);
|
|
7840
8076
|
}
|
|
7841
|
-
const goalsFile =
|
|
8077
|
+
const goalsFile = join15(workspaceDir, "goals", "goals.md");
|
|
7842
8078
|
if (!existsSync15(goalsFile)) {
|
|
7843
8079
|
writeFileSync7(
|
|
7844
8080
|
goalsFile,
|
|
@@ -7862,7 +8098,7 @@ var initCommand = new Command7("init").description("Launch the guided interactiv
|
|
|
7862
8098
|
);
|
|
7863
8099
|
printLine();
|
|
7864
8100
|
console.log("\n\x1B[1m[1/5] Setting up Local Workspace Sandbox\x1B[0m");
|
|
7865
|
-
const defaultWorkspace =
|
|
8101
|
+
const defaultWorkspace = join15(HOME2, "Documents", "zam");
|
|
7866
8102
|
const workspacePath = await input3({
|
|
7867
8103
|
message: "Choose your ZAM workspace directory:",
|
|
7868
8104
|
default: defaultWorkspace
|
|
@@ -8561,8 +8797,8 @@ ${"\u2550".repeat(50)}`);
|
|
|
8561
8797
|
// src/cli/commands/monitor.ts
|
|
8562
8798
|
import { execFileSync as execFileSync3, execSync as execSync5 } from "child_process";
|
|
8563
8799
|
import { unlinkSync, writeFileSync as writeFileSync8 } from "fs";
|
|
8564
|
-
import { tmpdir as
|
|
8565
|
-
import { basename as basename3, join as
|
|
8800
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
8801
|
+
import { basename as basename3, join as join16 } from "path";
|
|
8566
8802
|
import { Command as Command9 } from "commander";
|
|
8567
8803
|
function isPowerShellShell(shell) {
|
|
8568
8804
|
return shell === "pwsh" || shell === "powershell";
|
|
@@ -8739,8 +8975,8 @@ function resolveZamInvocation(shell) {
|
|
|
8739
8975
|
if (installed) {
|
|
8740
8976
|
return isPowerShellShell(shell) ? `& ${psSingleQuoted2(installed)}` : installed;
|
|
8741
8977
|
}
|
|
8742
|
-
const projectRoot =
|
|
8743
|
-
const cliSource =
|
|
8978
|
+
const projectRoot = join16(import.meta.dirname, "..", "..", "..");
|
|
8979
|
+
const cliSource = join16(projectRoot, "src/cli/index.ts");
|
|
8744
8980
|
if (isPowerShellShell(shell)) {
|
|
8745
8981
|
return `& npx --prefix ${psSingleQuoted2(projectRoot)} tsx ${psSingleQuoted2(cliSource)}`;
|
|
8746
8982
|
}
|
|
@@ -8830,7 +9066,7 @@ end tell` : `tell application "Terminal"
|
|
|
8830
9066
|
activate
|
|
8831
9067
|
do script "${escaped}"
|
|
8832
9068
|
end tell`;
|
|
8833
|
-
const tmpFile =
|
|
9069
|
+
const tmpFile = join16(tmpdir3(), `zam-monitor-${sessionId}.scpt`);
|
|
8834
9070
|
try {
|
|
8835
9071
|
writeFileSync8(tmpFile, appleScript);
|
|
8836
9072
|
execSync5(`osascript ${JSON.stringify(tmpFile)}`, { stdio: "ignore" });
|
|
@@ -8946,7 +9182,7 @@ observerCommand.command("revoke <process>").description("Remove a process from o
|
|
|
8946
9182
|
|
|
8947
9183
|
// src/cli/commands/profile.ts
|
|
8948
9184
|
import { homedir as homedir10 } from "os";
|
|
8949
|
-
import { dirname as dirname5, join as
|
|
9185
|
+
import { dirname as dirname5, join as join17, resolve as resolve4 } from "path";
|
|
8950
9186
|
import { Command as Command11 } from "commander";
|
|
8951
9187
|
var C2 = {
|
|
8952
9188
|
reset: "\x1B[0m",
|
|
@@ -8956,7 +9192,7 @@ var C2 = {
|
|
|
8956
9192
|
green: "\x1B[32m"
|
|
8957
9193
|
};
|
|
8958
9194
|
function defaultPersonalDir() {
|
|
8959
|
-
return
|
|
9195
|
+
return join17(homedir10(), "Documents", "zam");
|
|
8960
9196
|
}
|
|
8961
9197
|
function render(profile) {
|
|
8962
9198
|
const sync = profile.syncProvider ? `${C2.green}${profile.syncProvider}${C2.reset} ${C2.dim}(good for cross-device snapshots)${C2.reset}` : `${C2.dim}local folder (use a synced folder or snapshots to move between machines)${C2.reset}`;
|
|
@@ -9677,31 +9913,31 @@ settingsCommand.command("repos").description("Show or set Personal, Team, and Or
|
|
|
9677
9913
|
|
|
9678
9914
|
// src/cli/commands/setup.ts
|
|
9679
9915
|
import { copyFileSync as copyFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
9680
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
9916
|
+
import { basename as basename4, dirname as dirname6, join as join18 } from "path";
|
|
9681
9917
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9682
9918
|
import { Command as Command15 } from "commander";
|
|
9683
9919
|
var packageRoot = [
|
|
9684
9920
|
fileURLToPath2(new URL("../..", import.meta.url)),
|
|
9685
9921
|
fileURLToPath2(new URL("../../..", import.meta.url))
|
|
9686
|
-
].find((candidate) => existsSync17(
|
|
9922
|
+
].find((candidate) => existsSync17(join18(candidate, "package.json"))) ?? fileURLToPath2(new URL("../..", import.meta.url));
|
|
9687
9923
|
var SKILL_PAIRS = [
|
|
9688
9924
|
{
|
|
9689
|
-
from:
|
|
9690
|
-
to:
|
|
9925
|
+
from: join18(packageRoot, ".claude", "skills", "zam", "SKILL.md"),
|
|
9926
|
+
to: join18(".claude", "skills", "zam", "SKILL.md")
|
|
9691
9927
|
},
|
|
9692
9928
|
{
|
|
9693
|
-
from:
|
|
9694
|
-
to:
|
|
9929
|
+
from: join18(packageRoot, ".agent", "skills", "zam", "SKILL.md"),
|
|
9930
|
+
to: join18(".agent", "skills", "zam", "SKILL.md")
|
|
9695
9931
|
},
|
|
9696
9932
|
{
|
|
9697
|
-
from:
|
|
9698
|
-
to:
|
|
9933
|
+
from: join18(packageRoot, ".agents", "skills", "zam", "SKILL.md"),
|
|
9934
|
+
to: join18(".agents", "skills", "zam", "SKILL.md")
|
|
9699
9935
|
}
|
|
9700
9936
|
];
|
|
9701
9937
|
function copySkills(force, cwd = process.cwd()) {
|
|
9702
9938
|
let anyAction = false;
|
|
9703
9939
|
for (const { from, to } of SKILL_PAIRS) {
|
|
9704
|
-
const dest =
|
|
9940
|
+
const dest = join18(cwd, to);
|
|
9705
9941
|
if (!existsSync17(from)) {
|
|
9706
9942
|
console.warn(` warn source not found, skipping: ${from}`);
|
|
9707
9943
|
continue;
|
|
@@ -9751,7 +9987,7 @@ async function initDatabase(skipInit) {
|
|
|
9751
9987
|
}
|
|
9752
9988
|
function writeClaudeMd(skipClaudeMd, cwd = process.cwd()) {
|
|
9753
9989
|
if (skipClaudeMd) return;
|
|
9754
|
-
const dest =
|
|
9990
|
+
const dest = join18(cwd, "CLAUDE.md");
|
|
9755
9991
|
if (existsSync17(dest)) {
|
|
9756
9992
|
console.log(` skip CLAUDE.md (already present)`);
|
|
9757
9993
|
return;
|
|
@@ -9785,7 +10021,7 @@ Use \`zam connector setup turso\` to store cloud credentials in
|
|
|
9785
10021
|
}
|
|
9786
10022
|
function writeAgentsMd(skipAgentsMd, cwd = process.cwd()) {
|
|
9787
10023
|
if (skipAgentsMd) return;
|
|
9788
|
-
const dest =
|
|
10024
|
+
const dest = join18(cwd, "AGENTS.md");
|
|
9789
10025
|
if (existsSync17(dest)) {
|
|
9790
10026
|
console.log(` skip AGENTS.md (already present)`);
|
|
9791
10027
|
return;
|
|
@@ -9933,7 +10169,7 @@ skillCommand.command("add").description("Register a new agent skill").requiredOp
|
|
|
9933
10169
|
// src/cli/commands/snapshot.ts
|
|
9934
10170
|
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
9935
10171
|
import { homedir as homedir11 } from "os";
|
|
9936
|
-
import { dirname as dirname7, join as
|
|
10172
|
+
import { dirname as dirname7, join as join19 } from "path";
|
|
9937
10173
|
import { Command as Command17 } from "commander";
|
|
9938
10174
|
function defaultOutName() {
|
|
9939
10175
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
|
|
@@ -9953,7 +10189,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
|
|
|
9953
10189
|
try {
|
|
9954
10190
|
db = await openDatabaseWithSync({ initialize: true });
|
|
9955
10191
|
const snapshot = await exportSnapshot(db);
|
|
9956
|
-
const personalDir = await getSetting(db, "personal.workspace_dir") ||
|
|
10192
|
+
const personalDir = await getSetting(db, "personal.workspace_dir") || join19(homedir11(), "Documents", "zam");
|
|
9957
10193
|
await db.close();
|
|
9958
10194
|
db = void 0;
|
|
9959
10195
|
const manifest = verifySnapshot(snapshot);
|
|
@@ -9962,7 +10198,7 @@ var exportCmd = new Command17("export").description("Write a portable SQL-text s
|
|
|
9962
10198
|
process.stdout.write(snapshot);
|
|
9963
10199
|
return;
|
|
9964
10200
|
}
|
|
9965
|
-
const out = opts.out ??
|
|
10201
|
+
const out = opts.out ?? join19(personalDir, "snapshots", defaultOutName());
|
|
9966
10202
|
const dir = dirname7(out);
|
|
9967
10203
|
if (dir && dir !== "." && !existsSync18(dir)) {
|
|
9968
10204
|
mkdirSync11(dir, { recursive: true });
|
|
@@ -10349,7 +10585,7 @@ tokenCommand.command("status").description("Show full status of a token for a us
|
|
|
10349
10585
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
10350
10586
|
import { existsSync as existsSync19 } from "fs";
|
|
10351
10587
|
import { homedir as homedir12 } from "os";
|
|
10352
|
-
import { dirname as dirname8, join as
|
|
10588
|
+
import { dirname as dirname8, join as join20 } from "path";
|
|
10353
10589
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10354
10590
|
import { Command as Command20 } from "commander";
|
|
10355
10591
|
var C3 = {
|
|
@@ -10365,8 +10601,8 @@ function findDesktopDir() {
|
|
|
10365
10601
|
for (const start of starts) {
|
|
10366
10602
|
let dir = start;
|
|
10367
10603
|
for (let i = 0; i < 10; i++) {
|
|
10368
|
-
if (existsSync19(
|
|
10369
|
-
return
|
|
10604
|
+
if (existsSync19(join20(dir, "desktop", "src-tauri", "tauri.conf.json"))) {
|
|
10605
|
+
return join20(dir, "desktop");
|
|
10370
10606
|
}
|
|
10371
10607
|
const parent = dirname8(dir);
|
|
10372
10608
|
if (parent === dir) break;
|
|
@@ -10376,18 +10612,18 @@ function findDesktopDir() {
|
|
|
10376
10612
|
return null;
|
|
10377
10613
|
}
|
|
10378
10614
|
function findBuiltApp(desktopDir) {
|
|
10379
|
-
const releaseDir =
|
|
10615
|
+
const releaseDir = join20(desktopDir, "src-tauri", "target", "release");
|
|
10380
10616
|
if (process.platform === "win32") {
|
|
10381
10617
|
for (const name of ["ZAM.exe", "zam.exe", "zam-desktop.exe"]) {
|
|
10382
|
-
const p =
|
|
10618
|
+
const p = join20(releaseDir, name);
|
|
10383
10619
|
if (existsSync19(p)) return p;
|
|
10384
10620
|
}
|
|
10385
10621
|
} else if (process.platform === "darwin") {
|
|
10386
|
-
const app =
|
|
10622
|
+
const app = join20(releaseDir, "bundle", "macos", "ZAM.app");
|
|
10387
10623
|
if (existsSync19(app)) return app;
|
|
10388
10624
|
} else {
|
|
10389
10625
|
for (const name of ["zam", "ZAM", "zam-desktop"]) {
|
|
10390
|
-
const p =
|
|
10626
|
+
const p = join20(releaseDir, name);
|
|
10391
10627
|
if (existsSync19(p)) return p;
|
|
10392
10628
|
}
|
|
10393
10629
|
}
|
|
@@ -10395,10 +10631,10 @@ function findBuiltApp(desktopDir) {
|
|
|
10395
10631
|
}
|
|
10396
10632
|
function findInstalledApp() {
|
|
10397
10633
|
const candidates = process.platform === "win32" ? [
|
|
10398
|
-
process.env.LOCALAPPDATA &&
|
|
10399
|
-
process.env.ProgramFiles &&
|
|
10400
|
-
process.env["ProgramFiles(x86)"] &&
|
|
10401
|
-
] : process.platform === "darwin" ? ["/Applications/ZAM.app",
|
|
10634
|
+
process.env.LOCALAPPDATA && join20(process.env.LOCALAPPDATA, "Programs", "ZAM", "ZAM.exe"),
|
|
10635
|
+
process.env.ProgramFiles && join20(process.env.ProgramFiles, "ZAM", "ZAM.exe"),
|
|
10636
|
+
process.env["ProgramFiles(x86)"] && join20(process.env["ProgramFiles(x86)"], "ZAM", "ZAM.exe")
|
|
10637
|
+
] : process.platform === "darwin" ? ["/Applications/ZAM.app", join20(homedir12(), "Applications", "ZAM.app")] : ["/opt/ZAM/zam", "/usr/bin/zam-desktop"];
|
|
10402
10638
|
return candidates.find((candidate) => candidate && existsSync19(candidate)) || null;
|
|
10403
10639
|
}
|
|
10404
10640
|
function runNpm(args, opts) {
|
|
@@ -10410,7 +10646,7 @@ function runNpm(args, opts) {
|
|
|
10410
10646
|
return res.status ?? 1;
|
|
10411
10647
|
}
|
|
10412
10648
|
function ensureDesktopDeps(desktopDir) {
|
|
10413
|
-
if (existsSync19(
|
|
10649
|
+
if (existsSync19(join20(desktopDir, "node_modules"))) return true;
|
|
10414
10650
|
console.log(
|
|
10415
10651
|
`${C3.cyan}Installing desktop dependencies (one-time)...${C3.reset}`
|
|
10416
10652
|
);
|
|
@@ -10436,7 +10672,7 @@ function requireRust() {
|
|
|
10436
10672
|
function hasMsvcBuildTools() {
|
|
10437
10673
|
if (process.platform !== "win32") return true;
|
|
10438
10674
|
const pf86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
|
|
10439
|
-
const vswhere =
|
|
10675
|
+
const vswhere = join20(
|
|
10440
10676
|
pf86,
|
|
10441
10677
|
"Microsoft Visual Studio",
|
|
10442
10678
|
"Installer",
|
|
@@ -10474,7 +10710,7 @@ function requireMsvcOnWindows() {
|
|
|
10474
10710
|
return false;
|
|
10475
10711
|
}
|
|
10476
10712
|
function warnIfCliMissing(repoRoot) {
|
|
10477
|
-
if (!existsSync19(
|
|
10713
|
+
if (!existsSync19(join20(repoRoot, "dist", "cli", "index.js"))) {
|
|
10478
10714
|
console.warn(
|
|
10479
10715
|
`${C3.yellow}\u26A0 CLI build not found (dist/cli/index.js). The GUI bridge needs it \u2014 run 'npm run build' at the repo root.${C3.reset}`
|
|
10480
10716
|
);
|
|
@@ -10558,7 +10794,7 @@ var uiCommand = new Command20("ui").description("Launch the ZAM Desktop GUI (Act
|
|
|
10558
10794
|
);
|
|
10559
10795
|
const code = runNpm(["run", "tauri", "build"], { cwd: desktopDir });
|
|
10560
10796
|
if (code === 0) {
|
|
10561
|
-
const bundle =
|
|
10797
|
+
const bundle = join20(
|
|
10562
10798
|
desktopDir,
|
|
10563
10799
|
"src-tauri",
|
|
10564
10800
|
"target",
|
|
@@ -10636,7 +10872,7 @@ ${C3.dim}After that, 'zam ui' launches it directly.${C3.reset}`
|
|
|
10636
10872
|
// src/cli/commands/update.ts
|
|
10637
10873
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10638
10874
|
import { existsSync as existsSync20, readFileSync as readFileSync13, realpathSync } from "fs";
|
|
10639
|
-
import { dirname as dirname9, join as
|
|
10875
|
+
import { dirname as dirname9, join as join21 } from "path";
|
|
10640
10876
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10641
10877
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
10642
10878
|
import { Command as Command21 } from "commander";
|
|
@@ -10661,7 +10897,7 @@ function currentVersion() {
|
|
|
10661
10897
|
for (const up of ["..", "../..", "../../.."]) {
|
|
10662
10898
|
try {
|
|
10663
10899
|
const pkg2 = JSON.parse(
|
|
10664
|
-
readFileSync13(
|
|
10900
|
+
readFileSync13(join21(here, up, "package.json"), "utf-8")
|
|
10665
10901
|
);
|
|
10666
10902
|
if (pkg2.version) return pkg2.version;
|
|
10667
10903
|
} catch {
|
|
@@ -10672,7 +10908,7 @@ function currentVersion() {
|
|
|
10672
10908
|
function versionAt(dir) {
|
|
10673
10909
|
try {
|
|
10674
10910
|
const pkg2 = JSON.parse(
|
|
10675
|
-
readFileSync13(
|
|
10911
|
+
readFileSync13(join21(dir, "package.json"), "utf-8")
|
|
10676
10912
|
);
|
|
10677
10913
|
return pkg2.version ?? "unknown";
|
|
10678
10914
|
} catch {
|
|
@@ -10752,11 +10988,11 @@ function findSourceRepo() {
|
|
|
10752
10988
|
let dir = realpathSync(dirname9(fileURLToPath4(import.meta.url)));
|
|
10753
10989
|
let parent = dirname9(dir);
|
|
10754
10990
|
while (parent !== dir) {
|
|
10755
|
-
if (existsSync20(
|
|
10991
|
+
if (existsSync20(join21(dir, ".git"))) return dir;
|
|
10756
10992
|
dir = parent;
|
|
10757
10993
|
parent = dirname9(dir);
|
|
10758
10994
|
}
|
|
10759
|
-
return existsSync20(
|
|
10995
|
+
return existsSync20(join21(dir, ".git")) ? dir : null;
|
|
10760
10996
|
}
|
|
10761
10997
|
function runGit(cwd, args, capture) {
|
|
10762
10998
|
const res = spawnSync2("git", args, {
|
|
@@ -10821,7 +11057,7 @@ Commit or stash them, or re-run with ${C4.cyan}--force${C4.reset}.`
|
|
|
10821
11057
|
console.log(`${C4.dim}\u2192 zam setup --force${C4.reset}`);
|
|
10822
11058
|
const setup = spawnSync2(
|
|
10823
11059
|
process.execPath,
|
|
10824
|
-
[
|
|
11060
|
+
[join21(src, "dist", "cli", "index.js"), "setup", "--force"],
|
|
10825
11061
|
{ cwd: process.cwd(), stdio: "inherit" }
|
|
10826
11062
|
);
|
|
10827
11063
|
if (setup.status !== 0) {
|
|
@@ -10933,7 +11169,7 @@ var whoamiCommand = new Command22("whoami").description("Show or set the default
|
|
|
10933
11169
|
// src/cli/commands/workspace.ts
|
|
10934
11170
|
import { execSync as execSync6 } from "child_process";
|
|
10935
11171
|
import { existsSync as existsSync21, writeFileSync as writeFileSync11 } from "fs";
|
|
10936
|
-
import { join as
|
|
11172
|
+
import { join as join22 } from "path";
|
|
10937
11173
|
import { confirm as confirm4, input as input7 } from "@inquirer/prompts";
|
|
10938
11174
|
import { Command as Command23 } from "commander";
|
|
10939
11175
|
function runGit2(cwd, args) {
|
|
@@ -10980,7 +11216,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
10980
11216
|
);
|
|
10981
11217
|
process.exit(1);
|
|
10982
11218
|
}
|
|
10983
|
-
const gitignorePath =
|
|
11219
|
+
const gitignorePath = join22(workspaceDir, ".gitignore");
|
|
10984
11220
|
if (!existsSync21(gitignorePath)) {
|
|
10985
11221
|
writeFileSync11(
|
|
10986
11222
|
gitignorePath,
|
|
@@ -10988,7 +11224,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
10988
11224
|
"utf8"
|
|
10989
11225
|
);
|
|
10990
11226
|
}
|
|
10991
|
-
const hasGitRepo = existsSync21(
|
|
11227
|
+
const hasGitRepo = existsSync21(join22(workspaceDir, ".git"));
|
|
10992
11228
|
if (!hasGitRepo) {
|
|
10993
11229
|
console.log("Initializing local Git repository...");
|
|
10994
11230
|
runGit2(workspaceDir, "init -b main");
|
|
@@ -11084,7 +11320,7 @@ Active workspace: \x1B[36m${workspaceDir}\x1B[0m`);
|
|
|
11084
11320
|
// src/cli/index.ts
|
|
11085
11321
|
var __dirname = dirname10(fileURLToPath5(import.meta.url));
|
|
11086
11322
|
var pkg = JSON.parse(
|
|
11087
|
-
readFileSync14(
|
|
11323
|
+
readFileSync14(join23(__dirname, "..", "..", "package.json"), "utf-8")
|
|
11088
11324
|
);
|
|
11089
11325
|
var program = new Command24();
|
|
11090
11326
|
program.name("zam").description(
|