forge-cw 0.1.10 → 0.1.12
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/cw/.bundle.json +1 -1
- package/cw/cw +15 -11
- package/dist/index.js +42 -9
- package/package.json +1 -1
package/cw/.bundle.json
CHANGED
package/cw/cw
CHANGED
|
@@ -2991,19 +2991,23 @@ $(cat "$wf_file")"
|
|
|
2991
2991
|
fi
|
|
2992
2992
|
fi
|
|
2993
2993
|
|
|
2994
|
-
# ──
|
|
2995
|
-
local
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
2994
|
+
# ── Work context (init): global first, then the account's ────────
|
|
2995
|
+
local init_tpl init_ctx
|
|
2996
|
+
for init_tpl in "$CW_HOME/templates/work_init.md" "$(_account_root "$account")/templates/work_init.md"; do
|
|
2997
|
+
[[ -f "$init_tpl" ]] || continue
|
|
2998
|
+
init_ctx=$(cat "$init_tpl")
|
|
2999
|
+
init_ctx="${init_ctx//\$\{task\}/$task}"
|
|
3000
|
+
init_ctx="${init_ctx//\$\{project\}/$name}"
|
|
3001
|
+
init_ctx="${init_ctx//\$\{branch\}/$task}"
|
|
3002
3002
|
init_prompt="$init_prompt
|
|
3003
3003
|
|
|
3004
|
-
$
|
|
3005
|
-
|
|
3006
|
-
|
|
3004
|
+
$init_ctx"
|
|
3005
|
+
if [[ "$init_tpl" == "$CW_HOME/templates/work_init.md" ]]; then
|
|
3006
|
+
_dim " Work context: global"
|
|
3007
|
+
else
|
|
3008
|
+
_dim " Account context: $account"
|
|
3009
|
+
fi
|
|
3010
|
+
done
|
|
3007
3011
|
|
|
3008
3012
|
# Exclude .tasks from git (but DON'T pre-create the task dir — worktree needs it empty)
|
|
3009
3013
|
mkdir -p "$path/.tasks"
|
package/dist/index.js
CHANGED
|
@@ -2642,8 +2642,18 @@ var init_plugins = __esm({
|
|
|
2642
2642
|
|
|
2643
2643
|
// ../core/dist/skill-routes.js
|
|
2644
2644
|
import { Hono as Hono2 } from "hono";
|
|
2645
|
-
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, existsSync as existsSync7, unlinkSync, cpSync } from "node:fs";
|
|
2645
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, rmSync as rmSync2, existsSync as existsSync7, unlinkSync, cpSync, readdirSync as readdirSync5 } from "node:fs";
|
|
2646
2646
|
import { dirname as dirname2, join as join9 } from "node:path";
|
|
2647
|
+
function backUpSkill(backupDir, scope, ref, name, dir) {
|
|
2648
|
+
const root = join9(backupDir, scope, ref, name);
|
|
2649
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2650
|
+
let dest = join9(root, stamp);
|
|
2651
|
+
for (let n = 1; existsSync7(dest); n++)
|
|
2652
|
+
dest = join9(root, `${stamp}-${String(n).padStart(3, "0")}`);
|
|
2653
|
+
cpSync(dir, dest, { recursive: true, dereference: true });
|
|
2654
|
+
for (const old of readdirSync5(root).sort().slice(0, -BACKUPS_KEPT))
|
|
2655
|
+
rmSync2(join9(root, old), { recursive: true, force: true });
|
|
2656
|
+
}
|
|
2647
2657
|
function installFailure(result2) {
|
|
2648
2658
|
try {
|
|
2649
2659
|
const entries = JSON.parse(result2.stdout);
|
|
@@ -2685,6 +2695,16 @@ function skillRoutes(reader, options = {}) {
|
|
|
2685
2695
|
}
|
|
2686
2696
|
};
|
|
2687
2697
|
const knownAccount = (account) => account && reader.getAccounts().includes(account) ? account : null;
|
|
2698
|
+
const backup = (scope, ref, name, dir) => {
|
|
2699
|
+
if (!options.backupDir)
|
|
2700
|
+
return null;
|
|
2701
|
+
try {
|
|
2702
|
+
backUpSkill(options.backupDir, scope, ref, name, dir);
|
|
2703
|
+
return null;
|
|
2704
|
+
} catch (err) {
|
|
2705
|
+
return `Could not back up ${name}, nothing was changed: ${err instanceof Error ? err.message : "Unknown error"}`;
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2688
2708
|
const refOf = (scope, scopeRef) => scope === "global" ? "global" : scopeRef ?? "";
|
|
2689
2709
|
const knownScope = (scope, ref) => scope === "global" || (scope === "account" ? reader.getAccounts().includes(ref) : scope === "project" && ref in reader.getProjects());
|
|
2690
2710
|
app.get("/", (c) => c.json(reader.getSkills()));
|
|
@@ -2765,6 +2785,9 @@ function skillRoutes(reader, options = {}) {
|
|
|
2765
2785
|
return c.json({ error: "Skill not found" }, 404);
|
|
2766
2786
|
}
|
|
2767
2787
|
const { content } = await c.req.json();
|
|
2788
|
+
const failed = backup(scope, scopeRef, name, dir);
|
|
2789
|
+
if (failed)
|
|
2790
|
+
return c.json({ error: failed }, 500);
|
|
2768
2791
|
try {
|
|
2769
2792
|
writeFileSync2(skillMd, content, "utf-8");
|
|
2770
2793
|
return c.json({ ok: true });
|
|
@@ -2784,6 +2807,9 @@ function skillRoutes(reader, options = {}) {
|
|
|
2784
2807
|
return c.json({ error: "Skill not found" }, 404);
|
|
2785
2808
|
}
|
|
2786
2809
|
const { content } = await c.req.json();
|
|
2810
|
+
const failed = backup(scope, scopeRef, name, dir);
|
|
2811
|
+
if (failed)
|
|
2812
|
+
return c.json({ error: failed }, 500);
|
|
2787
2813
|
try {
|
|
2788
2814
|
const refsDir = join9(dir, "references");
|
|
2789
2815
|
mkdirSync2(refsDir, { recursive: true });
|
|
@@ -2804,6 +2830,9 @@ function skillRoutes(reader, options = {}) {
|
|
|
2804
2830
|
if (!existsSync7(refFile)) {
|
|
2805
2831
|
return c.json({ error: "Reference not found" }, 404);
|
|
2806
2832
|
}
|
|
2833
|
+
const failed = backup(scope, scopeRef, name, dir);
|
|
2834
|
+
if (failed)
|
|
2835
|
+
return c.json({ error: failed }, 500);
|
|
2807
2836
|
try {
|
|
2808
2837
|
unlinkSync(refFile);
|
|
2809
2838
|
return c.json({ ok: true });
|
|
@@ -2820,6 +2849,9 @@ function skillRoutes(reader, options = {}) {
|
|
|
2820
2849
|
if (!existsSync7(join9(dir, "SKILL.md"))) {
|
|
2821
2850
|
return c.json({ error: "Skill not found" }, 404);
|
|
2822
2851
|
}
|
|
2852
|
+
const failed = backup(scope, scopeRef, name, dir);
|
|
2853
|
+
if (failed)
|
|
2854
|
+
return c.json({ error: failed }, 500);
|
|
2823
2855
|
try {
|
|
2824
2856
|
rmSync2(dir, { recursive: true, force: true });
|
|
2825
2857
|
return c.json({ ok: true });
|
|
@@ -2931,7 +2963,7 @@ function skillRoutes(reader, options = {}) {
|
|
|
2931
2963
|
});
|
|
2932
2964
|
return app;
|
|
2933
2965
|
}
|
|
2934
|
-
var INSTALL_TIMEOUT_MS, SKILL_NAME_RE, PLUGIN_ID_RE;
|
|
2966
|
+
var INSTALL_TIMEOUT_MS, SKILL_NAME_RE, PLUGIN_ID_RE, BACKUPS_KEPT;
|
|
2935
2967
|
var init_skill_routes = __esm({
|
|
2936
2968
|
"../core/dist/skill-routes.js"() {
|
|
2937
2969
|
"use strict";
|
|
@@ -2941,6 +2973,7 @@ var init_skill_routes = __esm({
|
|
|
2941
2973
|
INSTALL_TIMEOUT_MS = 12e4;
|
|
2942
2974
|
SKILL_NAME_RE = /^\w[\w.-]*$/;
|
|
2943
2975
|
PLUGIN_ID_RE = /^\w[\w.-]*@\w[\w.-]*$/;
|
|
2976
|
+
BACKUPS_KEPT = 10;
|
|
2944
2977
|
}
|
|
2945
2978
|
});
|
|
2946
2979
|
|
|
@@ -3747,7 +3780,7 @@ var init_general_sessions = __esm({
|
|
|
3747
3780
|
});
|
|
3748
3781
|
|
|
3749
3782
|
// ../core/dist/liveframe.js
|
|
3750
|
-
import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync as
|
|
3783
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync as readdirSync6 } from "node:fs";
|
|
3751
3784
|
import { mkdir, rm } from "node:fs/promises";
|
|
3752
3785
|
import { homedir as homedir4 } from "node:os";
|
|
3753
3786
|
import { join as join11 } from "node:path";
|
|
@@ -3843,10 +3876,10 @@ var init_liveframe = __esm({
|
|
|
3843
3876
|
return [];
|
|
3844
3877
|
const { api } = this.config();
|
|
3845
3878
|
const frames = [];
|
|
3846
|
-
for (const project of
|
|
3879
|
+
for (const project of readdirSync6(this.root, { withFileTypes: true })) {
|
|
3847
3880
|
if (!project.isDirectory() || !isFrameSegment(project.name))
|
|
3848
3881
|
continue;
|
|
3849
|
-
for (const frame of
|
|
3882
|
+
for (const frame of readdirSync6(join11(this.root, project.name), { withFileTypes: true })) {
|
|
3850
3883
|
if (!frame.isDirectory() || !isFrameSegment(frame.name))
|
|
3851
3884
|
continue;
|
|
3852
3885
|
const found = this.readFrame(project.name, frame.name, api);
|
|
@@ -3886,7 +3919,7 @@ var init_liveframe = __esm({
|
|
|
3886
3919
|
await this.lf(args(dir), this.root);
|
|
3887
3920
|
} catch (err) {
|
|
3888
3921
|
await rm(dir, { recursive: true, force: true });
|
|
3889
|
-
if (
|
|
3922
|
+
if (readdirSync6(projectDir).length === 0)
|
|
3890
3923
|
await rm(projectDir, { recursive: true, force: true });
|
|
3891
3924
|
throw err;
|
|
3892
3925
|
}
|
|
@@ -4534,7 +4567,7 @@ var init_kioku_routes = __esm({
|
|
|
4534
4567
|
import { Hono as Hono5 } from "hono";
|
|
4535
4568
|
import { cors } from "hono/cors";
|
|
4536
4569
|
import { join as join14, basename as basename3, resolve as resolve4 } from "node:path";
|
|
4537
|
-
import { readdirSync as
|
|
4570
|
+
import { readdirSync as readdirSync7, existsSync as existsSync13 } from "node:fs";
|
|
4538
4571
|
function createForgeServer(options) {
|
|
4539
4572
|
const { dataDir, db: externalDb, authToken, localOnly = true } = options;
|
|
4540
4573
|
const dbPath = join14(dataDir, "forge.db");
|
|
@@ -4551,7 +4584,7 @@ function createForgeServer(options) {
|
|
|
4551
4584
|
const cwReader = new CWReader(options.cwDir);
|
|
4552
4585
|
const loginManager = new LoginManager(resolveCwBin(cwReader.cwHome));
|
|
4553
4586
|
app.route("/api/cw", cwRoutes(cwReader, { loginManager, localOnly }));
|
|
4554
|
-
app.route("/api/skills", skillRoutes(cwReader));
|
|
4587
|
+
app.route("/api/skills", skillRoutes(cwReader, { backupDir: join14(dataDir, "skill-backups") }));
|
|
4555
4588
|
const { remote, shadow, warning } = remoteClassifierFromEnv();
|
|
4556
4589
|
if (warning)
|
|
4557
4590
|
console.warn(`[state] ${warning}`);
|
|
@@ -4739,7 +4772,7 @@ data: ${JSON.stringify(data)}
|
|
|
4739
4772
|
return c.json({ error: "Directory not found" }, 404);
|
|
4740
4773
|
}
|
|
4741
4774
|
try {
|
|
4742
|
-
const entries =
|
|
4775
|
+
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
4743
4776
|
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => ({
|
|
4744
4777
|
name: e.name,
|
|
4745
4778
|
path: join14(dir, e.name),
|