@bububuger/spanory 0.1.22 → 0.1.26
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/index.js +14 -143
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// dist/index.js
|
|
4
4
|
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
5
|
-
import {
|
|
5
|
+
import { copyFile, mkdir as mkdir4, readdir as readdir5, readFile as readFile8, rm, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
|
|
6
6
|
import path8 from "node:path";
|
|
7
7
|
import { createHash as createHash4 } from "node:crypto";
|
|
8
8
|
import { spawnSync } from "node:child_process";
|
|
@@ -4473,6 +4473,14 @@ async function backupIfExists(filePath) {
|
|
|
4473
4473
|
await copyFile(filePath, backupPath);
|
|
4474
4474
|
return backupPath;
|
|
4475
4475
|
}
|
|
4476
|
+
function isSpanoryCodexNotifyConfigured(configText) {
|
|
4477
|
+
return /notify\s*=\s*\[[^\]]*spanory-codex-notify\.sh[^\]]*\]/m.test(String(configText ?? ""));
|
|
4478
|
+
}
|
|
4479
|
+
function stripSpanoryCodexNotifyConfig(configText) {
|
|
4480
|
+
const next = String(configText ?? "").replace(/^notify\s*=\s*\[[^\]]*spanory-codex-notify\.sh[^\]]*\]\s*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
4481
|
+
return next ? `${next}
|
|
4482
|
+
` : "";
|
|
4483
|
+
}
|
|
4476
4484
|
function isSpanoryHookCommand(command) {
|
|
4477
4485
|
const text = String(command ?? "");
|
|
4478
4486
|
return /\bspanory\b/.test(text) && /\bhook\b/.test(text);
|
|
@@ -4525,118 +4533,6 @@ async function applyClaudeSetup({ homeRoot, spanoryBin, dryRun }) {
|
|
|
4525
4533
|
backup
|
|
4526
4534
|
};
|
|
4527
4535
|
}
|
|
4528
|
-
function upsertCodexNotifyConfig(configText, notifyScriptRef) {
|
|
4529
|
-
const notifyLine = `notify = ["${escapeTomlBasicString(notifyScriptRef)}"]`;
|
|
4530
|
-
if (/^notify\s*=.*$/m.test(configText)) {
|
|
4531
|
-
return configText.replace(/^notify\s*=.*$/m, notifyLine);
|
|
4532
|
-
}
|
|
4533
|
-
const withNewline = configText.trimEnd();
|
|
4534
|
-
if (!withNewline)
|
|
4535
|
-
return `${notifyLine}
|
|
4536
|
-
`;
|
|
4537
|
-
return `${withNewline}
|
|
4538
|
-
|
|
4539
|
-
${notifyLine}
|
|
4540
|
-
`;
|
|
4541
|
-
}
|
|
4542
|
-
function escapeTomlBasicString(value) {
|
|
4543
|
-
return String(value).replaceAll("\\", "\\\\").replaceAll('"', '\\"');
|
|
4544
|
-
}
|
|
4545
|
-
function isSpanoryCodexNotifyConfigured(configText) {
|
|
4546
|
-
return /notify\s*=\s*\[[^\]]*spanory-codex-notify\.sh[^\]]*\]/m.test(String(configText ?? ""));
|
|
4547
|
-
}
|
|
4548
|
-
function stripSpanoryCodexNotifyConfig(configText) {
|
|
4549
|
-
const next = String(configText ?? "").replace(/^notify\s*=\s*\[[^\]]*spanory-codex-notify\.sh[^\]]*\]\s*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
4550
|
-
return next ? `${next}
|
|
4551
|
-
` : "";
|
|
4552
|
-
}
|
|
4553
|
-
function codexNotifyScriptContent({ spanoryBin, codexHome, exportDir, logFile }) {
|
|
4554
|
-
return `#!/usr/bin/env bash
|
|
4555
|
-
set -euo pipefail
|
|
4556
|
-
payload="\${1:-}"
|
|
4557
|
-
if [[ -z "$payload" ]] && [[ ! -t 0 ]]; then
|
|
4558
|
-
IFS= read -r -t 0 payload || true
|
|
4559
|
-
fi
|
|
4560
|
-
if [[ -z "\${payload//[$'\\t\\r\\n ']/}" ]]; then
|
|
4561
|
-
echo "skip=empty-payload source=codex-notify args=$#" >> "${logFile}"
|
|
4562
|
-
exit 0
|
|
4563
|
-
fi
|
|
4564
|
-
payload_file="$(mktemp "\${TMPDIR:-/tmp}/spanory-codex-notify.XXXXXX")"
|
|
4565
|
-
printf '%s' "$payload" > "$payload_file"
|
|
4566
|
-
echo "$payload" | "${spanoryBin}" runtime codex hook \\
|
|
4567
|
-
--last-turn-only \\
|
|
4568
|
-
--runtime-home "${codexHome}" \\
|
|
4569
|
-
--export-json-dir "${exportDir}" \\
|
|
4570
|
-
>> "${logFile}" 2>&1 || true
|
|
4571
|
-
(
|
|
4572
|
-
sleep 2
|
|
4573
|
-
cat "$payload_file" | "${spanoryBin}" runtime codex hook \\
|
|
4574
|
-
--last-turn-only \\
|
|
4575
|
-
--force \\
|
|
4576
|
-
--runtime-home "${codexHome}" \\
|
|
4577
|
-
--export-json-dir "${exportDir}" \\
|
|
4578
|
-
>> "${logFile}" 2>&1 || true
|
|
4579
|
-
rm -f "$payload_file"
|
|
4580
|
-
) >/dev/null 2>&1 &
|
|
4581
|
-
`;
|
|
4582
|
-
}
|
|
4583
|
-
async function applyCodexSetup({ homeRoot, spanoryBin, dryRun }) {
|
|
4584
|
-
const codexHome = path8.join(homeRoot, ".codex");
|
|
4585
|
-
const spanoryHome = process.env.SPANORY_HOME ?? path8.join(homeRoot, ".spanory");
|
|
4586
|
-
const binDir = path8.join(codexHome, "bin");
|
|
4587
|
-
const stateDir = path8.join(codexHome, "state", "spanory");
|
|
4588
|
-
const scriptPath = path8.join(binDir, "spanory-codex-notify.sh");
|
|
4589
|
-
const logFile = path8.join(spanoryHome, "logs", "codex-notify.log");
|
|
4590
|
-
const configPath = path8.join(codexHome, "config.toml");
|
|
4591
|
-
const notifyScriptRef = scriptPath;
|
|
4592
|
-
const scriptContent = codexNotifyScriptContent({
|
|
4593
|
-
spanoryBin,
|
|
4594
|
-
codexHome,
|
|
4595
|
-
exportDir: stateDir,
|
|
4596
|
-
logFile
|
|
4597
|
-
});
|
|
4598
|
-
let currentConfig = "";
|
|
4599
|
-
try {
|
|
4600
|
-
currentConfig = await readFile8(configPath, "utf-8");
|
|
4601
|
-
} catch (error) {
|
|
4602
|
-
if (error?.code !== "ENOENT")
|
|
4603
|
-
throw error;
|
|
4604
|
-
}
|
|
4605
|
-
const nextConfig = upsertCodexNotifyConfig(currentConfig, notifyScriptRef);
|
|
4606
|
-
const configChanged = currentConfig !== nextConfig;
|
|
4607
|
-
let currentScript = "";
|
|
4608
|
-
try {
|
|
4609
|
-
currentScript = await readFile8(scriptPath, "utf-8");
|
|
4610
|
-
} catch (error) {
|
|
4611
|
-
if (error?.code !== "ENOENT")
|
|
4612
|
-
throw error;
|
|
4613
|
-
}
|
|
4614
|
-
const scriptChanged = currentScript !== scriptContent;
|
|
4615
|
-
const changed = configChanged || scriptChanged;
|
|
4616
|
-
let configBackup = null;
|
|
4617
|
-
if (changed && !dryRun) {
|
|
4618
|
-
await mkdir4(binDir, { recursive: true });
|
|
4619
|
-
await mkdir4(stateDir, { recursive: true });
|
|
4620
|
-
await mkdir4(path8.dirname(logFile), { recursive: true });
|
|
4621
|
-
if (configChanged) {
|
|
4622
|
-
configBackup = await backupIfExists(configPath);
|
|
4623
|
-
await writeFile4(configPath, nextConfig, "utf-8");
|
|
4624
|
-
}
|
|
4625
|
-
if (scriptChanged) {
|
|
4626
|
-
await writeFile4(scriptPath, scriptContent, "utf-8");
|
|
4627
|
-
await chmod(scriptPath, 493);
|
|
4628
|
-
}
|
|
4629
|
-
}
|
|
4630
|
-
return {
|
|
4631
|
-
runtime: "codex",
|
|
4632
|
-
ok: true,
|
|
4633
|
-
changed,
|
|
4634
|
-
dryRun,
|
|
4635
|
-
configPath,
|
|
4636
|
-
scriptPath,
|
|
4637
|
-
configBackup
|
|
4638
|
-
};
|
|
4639
|
-
}
|
|
4640
4536
|
async function applyCodexWatchSetup({ homeRoot, dryRun }) {
|
|
4641
4537
|
const codexHome = path8.join(homeRoot, ".codex");
|
|
4642
4538
|
const scriptPath = path8.join(codexHome, "bin", "spanory-codex-notify.sh");
|
|
@@ -5167,7 +5063,6 @@ async function runSetupApply(options) {
|
|
|
5167
5063
|
const selected = parseSetupRuntimes(options.runtimes);
|
|
5168
5064
|
const spanoryBin = options.spanoryBin ?? "spanory";
|
|
5169
5065
|
const dryRun = Boolean(options.dryRun);
|
|
5170
|
-
const codexMode = options.codexMode ?? process.env.SPANORY_CODEX_MODE ?? "watch";
|
|
5171
5066
|
const results = [];
|
|
5172
5067
|
if (selected.includes("claude-code")) {
|
|
5173
5068
|
try {
|
|
@@ -5182,35 +5077,11 @@ async function runSetupApply(options) {
|
|
|
5182
5077
|
}
|
|
5183
5078
|
}
|
|
5184
5079
|
if (selected.includes("codex")) {
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
results.push({
|
|
5191
|
-
runtime: "codex",
|
|
5192
|
-
ok: false,
|
|
5193
|
-
error: String(error?.message ?? error)
|
|
5194
|
-
});
|
|
5195
|
-
}
|
|
5196
|
-
} else if (codexMode === "watch") {
|
|
5197
|
-
try {
|
|
5198
|
-
const result = await applyCodexWatchSetup({ homeRoot, dryRun });
|
|
5199
|
-
results.push(result);
|
|
5200
|
-
} catch (error) {
|
|
5201
|
-
results.push({
|
|
5202
|
-
runtime: "codex",
|
|
5203
|
-
ok: false,
|
|
5204
|
-
error: String(error?.message ?? error)
|
|
5205
|
-
});
|
|
5206
|
-
}
|
|
5207
|
-
} else {
|
|
5208
|
-
results.push({
|
|
5209
|
-
runtime: "codex",
|
|
5210
|
-
ok: true,
|
|
5211
|
-
skipped: true,
|
|
5212
|
-
detail: `codex mode "${codexMode}" has no setup action`
|
|
5213
|
-
});
|
|
5080
|
+
try {
|
|
5081
|
+
const result = await applyCodexWatchSetup({ homeRoot, dryRun });
|
|
5082
|
+
results.push(result);
|
|
5083
|
+
} catch (error) {
|
|
5084
|
+
results.push({ runtime: "codex", ok: false, error: String(error?.message ?? error) });
|
|
5214
5085
|
}
|
|
5215
5086
|
}
|
|
5216
5087
|
if (selected.includes("openclaw")) {
|