@akanjs/cli 3.0.0-beta.19 → 3.0.0-beta.20
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/.build-stamp +1 -1
- package/{CodeAgent-6cm97kay.js → CodeAgent-awv258wb.js} +2 -2
- package/{CodeTui-za4jsm41.js → CodeTui-1nqh35ez.js} +20 -22
- package/TunnelShare-scf4e4pd.js +9 -0
- package/{agent.command-e0wpbbyg.js → agent.command-1s9ag7sb.js} +8 -9
- package/akanCode.js +4 -4
- package/{application.command-8wyxqc8q.js → application.command-49hwy6va.js} +25 -56
- package/{applicationBuildRunner-n9gzaxd0.js → applicationBuildRunner-ybyp97pv.js} +33 -59
- package/{applicationReleasePackager-vpggfqgq.js → applicationReleasePackager-esnrphw8.js} +40 -60
- package/buildBatch.proc.js +19 -24
- package/{capacitorApp-q3z0qht0.js → capacitorApp-1synz4en.js} +3 -4
- package/{cloud.command-4zwa5dsx.js → cloud.command-d7rqtzt9.js} +16 -26
- package/cloud.script-bkbpcr96.js +19 -0
- package/{code.command-468c9d7s.js → code.command-nn48xzej.js} +22 -37
- package/context.command-s3mcmvpa.js +48 -0
- package/context.runner-k99nb5pk.js +21 -0
- package/{dependencyScanner-0z2h2tks.js → dependencyScanner-ye2e6pdz.js} +2 -2
- package/{devTui-ffjsarqa.js → devTui-q7k7bakd.js} +5 -9
- package/fileSys-5ngz93ga.js +9 -0
- package/{guideline.command-vhw13pqr.js → guideline.command-sct4qnt5.js} +4 -5
- package/guidelines/conventions/conventions.instruction.md +5 -1
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/incrementalBuilder.proc.js +30 -48
- package/{index-s5rhm04y.js → index-0bq14vr1.js} +1 -1
- package/{index-10dkrrww.js → index-13ffe9wp.js} +4 -4
- package/{index-srmay5jw.js → index-22d57v4c.js} +84 -67
- package/{index-53176s7j.js → index-31yr441d.js} +10 -17
- package/index-3hx1z96c.js +87 -0
- package/{index-4m929vvn.js → index-3sq321ak.js} +10 -18
- package/{index-bhtmj233.js → index-3t7g9e4r.js} +41 -78
- package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
- package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
- package/{index-7ep8qtvp.js → index-5pc1qrbv.js} +5 -8
- package/{index-esk82rvk.js → index-8mna0947.js} +34 -71
- package/{index-sq2dzkzm.js → index-8sf7wmdr.js} +6 -6
- package/{index-crmeqnmf.js → index-9d9bgcx4.js} +283 -722
- package/{index-bwf965h6.js → index-ahemdr5n.js} +6 -6
- package/{index-ab0c38ea.js → index-as7xmyz8.js} +20 -20
- package/{index-bc88j1ry.js → index-axzjaqve.js} +94 -142
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/{index-667w0yah.js → index-c6eggbee.js} +2 -5
- package/{index-a1w6934z.js → index-ddxvdd1p.js} +169 -305
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-22xtgmhn.js → index-dzf3r49a.js} +1 -1
- package/{index-89hy31kf.js → index-fgq75haa.js} +172 -287
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
- package/{index-vqx8bdxz.js → index-mxav6j3c.js} +78 -231
- package/{index-2446k7b4.js → index-myhc3c1j.js} +512 -588
- package/{index-3jrp517k.js → index-nv5976x3.js} +45 -128
- package/{index-zqgj2rt2.js → index-przybvy5.js} +69 -147
- package/{index-n3cv0tm4.js → index-smme4r47.js} +1 -1
- package/{index-qdgzsnhg.js → index-w2zdcw3k.js} +110 -231
- package/{index-14zrtgfa.js → index-wa5jbxj1.js} +6 -39
- package/{index-bftkz6cp.js → index-ww4z397j.js} +198 -555
- package/{index-kwaq3n9n.js → index-xqjwd384.js} +4 -7
- package/{index-txr7dj2g.js → index-xqpzbab5.js} +106 -240
- package/{index-e4v6vhxq.js → index-xsjh6nzh.js} +178 -165
- package/{index-18zybgkc.js → index-ygn77a5w.js} +47 -99
- package/{index-9d6nvkz2.js → index-ztp3e73t.js} +79 -35
- package/index.js +23 -24
- package/{library.command-cqr175dy.js → library.command-1gx04jgn.js} +4 -5
- package/{localRegistry.command-49z55qqz.js → localRegistry.command-zndxj1q6.js} +21 -42
- package/{module.command-9p8mm3b0.js → module.command-3waddk95.js} +6 -7
- package/{package.command-wxyz909t.js → package.command-zrc7br1y.js} +5 -6
- package/package.json +2 -2
- package/{page.command-gsrsfqqs.js → page.command-vpjgardh.js} +4 -5
- package/{primitive.command-ns1mptje.js → primitive.command-sz84tk4t.js} +9 -20
- package/{prompter-1f8d9pcc.js → prompter-ptaa3nk0.js} +2 -2
- package/{quality.command-e76k2q9k.js → quality.command-g869hafs.js} +129 -363
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-pkrsm3cw.js → repair.command-chsnjvvv.js} +11 -35
- package/{scalar.command-0cpt3fc8.js → scalar.command-2v21newx.js} +5 -6
- package/skills/akan-code/SKILL.md +12 -4
- package/{subspace.command-fktpwp0g.js → subspace.command-ckcbwfp1.js} +39 -58
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +3 -3
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +3 -3
- package/templates/client.ts +7 -30
- package/templates/lib/__lib/lib.dictionary.ts +0 -2
- package/templates/lib/__lib/lib.document.ts +0 -2
- package/templates/lib/sig.ts +8 -30
- package/templates/server.ts +0 -2
- package/{tunnel.command-d5jy9gk8.js → tunnel.command-kd2yr4fx.js} +5 -6
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-44252cqv.js +79 -0
- package/{workspace.command-gv84eh1p.js → workspace.command-fqcztt5p.js} +72 -107
- package/TunnelShare-2j6s511d.js +0 -9
- package/cloud.script-fwx3vb34.js +0 -20
- package/context.command-dsnw0jby.js +0 -80
- package/context.runner-rs4rj15d.js +0 -22
- package/devTuiView-1q1mdgrv.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/index-6wwzs1bc.js +0 -7
- package/workflow.command-6tkcysmx.js +0 -105
|
@@ -3,34 +3,21 @@ import {
|
|
|
3
3
|
Workspace,
|
|
4
4
|
script,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
7
|
-
import"./index-
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-18zybgkc.js";
|
|
6
|
+
} from "./index-w2zdcw3k.js";
|
|
7
|
+
import"./index-5b6tavv3.js";
|
|
8
|
+
import"./index-9d9bgcx4.js";
|
|
9
|
+
import"./index-hj6w4ka1.js";
|
|
10
|
+
import"./index-myhc3c1j.js";
|
|
11
|
+
import"./index-ygn77a5w.js";
|
|
13
12
|
import {
|
|
14
13
|
RepairRunner
|
|
15
|
-
} from "./index-
|
|
14
|
+
} from "./index-31yr441d.js";
|
|
16
15
|
|
|
17
16
|
// pkgs/@akanjs/cli/repair/repair.script.ts
|
|
18
17
|
import { Logger } from "akanjs/common";
|
|
19
18
|
class RepairScript extends script("repair", [RepairRunner]) {
|
|
20
|
-
async repair(kind, {
|
|
21
|
-
|
|
22
|
-
app = null,
|
|
23
|
-
module = null,
|
|
24
|
-
target = null,
|
|
25
|
-
format = "markdown"
|
|
26
|
-
}) {
|
|
27
|
-
Logger.rawLog(await this.repairRunner.repair(kind, {
|
|
28
|
-
workspace,
|
|
29
|
-
app,
|
|
30
|
-
module,
|
|
31
|
-
target,
|
|
32
|
-
format
|
|
33
|
-
}));
|
|
19
|
+
async repair(kind, options) {
|
|
20
|
+
Logger.rawLog(await this.repairRunner.repair(kind, options));
|
|
34
21
|
}
|
|
35
22
|
}
|
|
36
23
|
|
|
@@ -39,12 +26,7 @@ class RepairCommand extends command("repair", [RepairScript], ({ public: target
|
|
|
39
26
|
repair: target({ desc: "Run a narrow Akan repair command and return a structured report" }).arg("kind", String, {
|
|
40
27
|
desc: "generated, format, imports, dictionary, or module-shape",
|
|
41
28
|
enum: ["generated", "format", "imports", "dictionary", "module-shape"]
|
|
42
|
-
}).with(Workspace).option("format", String, {
|
|
43
|
-
desc: "output format",
|
|
44
|
-
flag: "o",
|
|
45
|
-
default: "markdown",
|
|
46
|
-
enum: ["markdown", "json"]
|
|
47
|
-
}).option("app", String, {
|
|
29
|
+
}).with(Workspace).option("format", String, { desc: "output format", flag: "o", default: "markdown", enum: ["markdown", "json"] }).option("app", String, {
|
|
48
30
|
desc: "target app or library for generated/dictionary/module-shape repair",
|
|
49
31
|
nullable: true
|
|
50
32
|
}).option("module", String, { desc: "target module for dictionary/module-shape repair", nullable: true }).option("target", String, {
|
|
@@ -52,13 +34,7 @@ class RepairCommand extends command("repair", [RepairScript], ({ public: target
|
|
|
52
34
|
desc: "target app, library, or package for format/imports repair",
|
|
53
35
|
nullable: true
|
|
54
36
|
}).exec(async function(kind, workspace, format, app, module, targetName) {
|
|
55
|
-
await this.repairScript.repair(kind, {
|
|
56
|
-
workspace,
|
|
57
|
-
format,
|
|
58
|
-
app,
|
|
59
|
-
module,
|
|
60
|
-
target: targetName
|
|
61
|
-
});
|
|
37
|
+
await this.repairScript.repair(kind, { workspace, format, app, module, target: targetName });
|
|
62
38
|
})
|
|
63
39
|
})) {
|
|
64
40
|
}
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
Sys,
|
|
4
4
|
command
|
|
5
|
-
} from "./index-
|
|
6
|
-
import"./index-
|
|
7
|
-
import"./index-
|
|
8
|
-
import"./index-6wwzs1bc.js";
|
|
5
|
+
} from "./index-w2zdcw3k.js";
|
|
6
|
+
import"./index-5b6tavv3.js";
|
|
7
|
+
import"./index-9d9bgcx4.js";
|
|
9
8
|
import {
|
|
10
9
|
renderPrimitiveReport
|
|
11
|
-
} from "./index-
|
|
10
|
+
} from "./index-myhc3c1j.js";
|
|
12
11
|
import {
|
|
13
12
|
ScalarScript
|
|
14
|
-
} from "./index-
|
|
13
|
+
} from "./index-3sq321ak.js";
|
|
15
14
|
|
|
16
15
|
// pkgs/@akanjs/cli/scalar/scalar.command.ts
|
|
17
16
|
import { Logger, lowerlize } from "akanjs/common";
|
|
@@ -15,8 +15,9 @@ which command makes it take effect.
|
|
|
15
15
|
|
|
16
16
|
## MCP servers
|
|
17
17
|
|
|
18
|
-
Declared in
|
|
19
|
-
|
|
18
|
+
Declared in **`~/.akan/code/mcp.json`**, which every repo reads, or in this repo's **`.akan/code/mcp.json`**,
|
|
19
|
+
which wins a name both declare — in the same `mcpServers` shape Claude, Cursor and VS Code already write, so a
|
|
20
|
+
block can be pasted across rather than translated. VS Code's `servers` spelling is read too, and
|
|
20
21
|
whichever key the file already uses is the one a write goes back into.
|
|
21
22
|
|
|
22
23
|
```jsonc
|
|
@@ -41,7 +42,9 @@ From the prompt:
|
|
|
41
42
|
/mcp <name> the tools that one server published
|
|
42
43
|
/mcp add <name> <command> [args…]
|
|
43
44
|
/mcp add <name> <https://…>
|
|
44
|
-
/mcp
|
|
45
|
+
/mcp add --local <name> … this repo's file only, not ~/.akan/code/mcp.json
|
|
46
|
+
/mcp remove <name> this repo's file first, else ~/.akan/code/mcp.json
|
|
47
|
+
/mcp remove --local <name>
|
|
45
48
|
/mcp login <name> OAuth, in the browser
|
|
46
49
|
/mcp logout <name> forget the token, leaving the server declared
|
|
47
50
|
/mcp reload reopen this session so the file takes effect
|
|
@@ -52,11 +55,16 @@ session is created, so `add`, `remove`, `login` and `logout` all reload by thems
|
|
|
52
55
|
said nothing yet has nothing on disk to reopen, and says so. If you edit `mcp.json` yourself, tell the user to
|
|
53
56
|
run `/mcp reload`.
|
|
54
57
|
|
|
58
|
+
`/mcp remove` on a name both files declare takes this repo's entry and leaves the home file's in force; its
|
|
59
|
+
notice says so, and running it again removes that one too.
|
|
60
|
+
|
|
55
61
|
Sign-in is discovered, not configured: the server's `401` names its resource metadata, that names the
|
|
56
62
|
authorization server, and most hosted servers register a client on demand — so a url is usually the whole
|
|
57
63
|
entry. For a provider that issues client ids by hand, add `"oauth": { "clientId": "…", "scope": "…" }`.
|
|
58
64
|
Tokens are stored per server in `~/.akan/code/mcpAuth.json` at mode 0600, never in the repo, and refreshed
|
|
59
|
-
silently
|
|
65
|
+
silently — at connect when one has expired, and mid-session when a server refuses one, after which the call is
|
|
66
|
+
retried once. When a refresh cannot fix it, `/mcp` shows `sign-in needed` and that server's tools answer with
|
|
67
|
+
`/mcp login <name>` until the user signs in; the sign-in reloads the session, which brings the server back.
|
|
60
68
|
|
|
61
69
|
## Sessions
|
|
62
70
|
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./index-
|
|
3
|
+
FileSys2
|
|
4
|
+
} from "./index-5b6tavv3.js";
|
|
5
5
|
import {
|
|
6
6
|
GlobalConfig
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-22d57v4c.js";
|
|
8
8
|
import {
|
|
9
9
|
Workspace,
|
|
10
10
|
CommandContainer,
|
|
11
11
|
runner,
|
|
12
12
|
script,
|
|
13
13
|
command
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-w2zdcw3k.js";
|
|
15
15
|
import {
|
|
16
16
|
Executor,
|
|
17
17
|
WorkspaceExecutor,
|
|
18
18
|
AppExecutor
|
|
19
|
-
} from "./index-
|
|
20
|
-
import"./index-6wwzs1bc.js";
|
|
19
|
+
} from "./index-9d9bgcx4.js";
|
|
21
20
|
import {
|
|
22
21
|
SlicePlanner
|
|
23
|
-
} from "./index-
|
|
22
|
+
} from "./index-xqjwd384.js";
|
|
24
23
|
import {
|
|
25
24
|
LibSource
|
|
26
|
-
} from "./index-
|
|
25
|
+
} from "./index-bjwxs904.js";
|
|
27
26
|
|
|
28
27
|
// pkgs/@akanjs/devkit/subspace.ts
|
|
29
28
|
import { mkdir, readdir, rename, rm } from "fs/promises";
|
|
@@ -118,16 +117,16 @@ class Subspace {
|
|
|
118
117
|
return true;
|
|
119
118
|
const normalize = (content) => {
|
|
120
119
|
try {
|
|
121
|
-
|
|
122
|
-
delete manifest[LibSource.manifestKey];
|
|
123
|
-
return JSON.stringify(manifest);
|
|
120
|
+
return LibSource.unstamped(content);
|
|
124
121
|
} catch {
|
|
125
122
|
return content;
|
|
126
123
|
}
|
|
127
124
|
};
|
|
128
125
|
return normalize(theirs) !== normalize(ours);
|
|
129
126
|
}
|
|
130
|
-
async#
|
|
127
|
+
async#changedSliceFiles(ref, diffArgs) {
|
|
128
|
+
const files = (await this.#git(["diff", "--name-only", ...diffArgs])).split(`
|
|
129
|
+
`).filter((file) => !!file.trim() && !this.#isSubspaceOwned(file));
|
|
131
130
|
const kept = await Promise.all(files.map(async (file) => this.#isStamped(file) ? await this.#differsBeyondStamp(ref, file) : true));
|
|
132
131
|
return files.filter((_, index) => kept[index]);
|
|
133
132
|
}
|
|
@@ -140,14 +139,12 @@ class Subspace {
|
|
|
140
139
|
if (!hasBranch)
|
|
141
140
|
return { name: this.name, branch, hasBranch, anchor, behindPaths: [], driftedLibs: [] };
|
|
142
141
|
const ref = `${this.#remote}/${branch}`;
|
|
143
|
-
const
|
|
144
|
-
const behindPaths = await this.#meaningfulFiles(ref, diff.split(`
|
|
145
|
-
`).filter((file) => !!file.trim()).filter((file) => !this.#isSubspaceOwned(file)));
|
|
142
|
+
const behindPaths = await this.#changedSliceFiles(ref, ["HEAD", ref, "--", ...paths]);
|
|
146
143
|
const driftedLibs = libs.filter((lib) => behindPaths.some((file) => file.startsWith(`libs/${lib}/`)));
|
|
147
144
|
return { name: this.name, branch, hasBranch, anchor, behindPaths, driftedLibs };
|
|
148
145
|
}
|
|
149
146
|
async#ensureClone(branch) {
|
|
150
|
-
if (!await
|
|
147
|
+
if (!await FileSys2.dirExists(path.join(this.#clonePath, ".git"))) {
|
|
151
148
|
await rm(this.#clonePath, { recursive: true, force: true });
|
|
152
149
|
await mkdir(path.dirname(this.#clonePath), { recursive: true });
|
|
153
150
|
await this.#workspace.spawn("git", ["clone", "--quiet", this.#declaration.repo, this.#clonePath]);
|
|
@@ -164,12 +161,12 @@ class Subspace {
|
|
|
164
161
|
await rm(holdRoot, { recursive: true, force: true });
|
|
165
162
|
for (const member of Subspace.memberDirs) {
|
|
166
163
|
const memberRoot = path.join(this.#clonePath, member);
|
|
167
|
-
if (!await
|
|
164
|
+
if (!await FileSys2.dirExists(memberRoot))
|
|
168
165
|
continue;
|
|
169
166
|
for (const name of await readdir(memberRoot)) {
|
|
170
167
|
for (const owned of Subspace.subspaceOwnedDirs) {
|
|
171
168
|
const from = path.join(memberRoot, name, owned);
|
|
172
|
-
if (!await
|
|
169
|
+
if (!await FileSys2.dirExists(from))
|
|
173
170
|
continue;
|
|
174
171
|
const to = path.join(holdRoot, member, name, owned);
|
|
175
172
|
await mkdir(path.dirname(to), { recursive: true });
|
|
@@ -192,7 +189,7 @@ class Subspace {
|
|
|
192
189
|
const target = path.join(to, entry.name);
|
|
193
190
|
if (entry.isDirectory())
|
|
194
191
|
await Subspace.#copyMissing(source, target);
|
|
195
|
-
else if (!await
|
|
192
|
+
else if (!await FileSys2.entryExists(target))
|
|
196
193
|
await rename(source, target);
|
|
197
194
|
}
|
|
198
195
|
}
|
|
@@ -225,32 +222,32 @@ class Subspace {
|
|
|
225
222
|
}
|
|
226
223
|
async#writeLocalEnv() {
|
|
227
224
|
const excludePath = path.join(this.#clonePath, ".git/info/exclude");
|
|
228
|
-
const exclude = await
|
|
225
|
+
const exclude = await FileSys2.fileExists(excludePath) ? await FileSys2.readText(excludePath) : "";
|
|
229
226
|
if (!exclude.split(`
|
|
230
227
|
`).includes("/.env")) {
|
|
231
228
|
await mkdir(path.dirname(excludePath), { recursive: true });
|
|
232
|
-
await
|
|
229
|
+
await FileSys2.writeText(excludePath, exclude.trim() ? `${exclude.replace(/\n*$/, `
|
|
233
230
|
`)}/.env
|
|
234
231
|
` : `/.env
|
|
235
232
|
`);
|
|
236
233
|
}
|
|
237
234
|
const envPath = path.join(this.#clonePath, ".env");
|
|
238
|
-
if (await
|
|
235
|
+
if (await FileSys2.fileExists(envPath))
|
|
239
236
|
return;
|
|
240
237
|
const lines = Object.entries(this.#localEnv()).map(([key, value]) => `${key}=${value}`);
|
|
241
|
-
await
|
|
238
|
+
await FileSys2.writeText(envPath, `${lines.join(`
|
|
242
239
|
`)}
|
|
243
240
|
`);
|
|
244
241
|
}
|
|
245
242
|
async#rewriteManifest(plans) {
|
|
246
243
|
const manifestPath = path.join(this.#clonePath, "package.json");
|
|
247
|
-
if (!await
|
|
244
|
+
if (!await FileSys2.fileExists(manifestPath))
|
|
248
245
|
return [];
|
|
249
|
-
const rootPackageJson = await
|
|
246
|
+
const rootPackageJson = await FileSys2.readJson(manifestPath);
|
|
250
247
|
const { packageJson, pruned, warnings } = await SlicePlanner.pruneDependencies(this.#workspace, rootPackageJson, plans.flatMap((plan) => plan.requiredDependencies));
|
|
251
248
|
for (const warning of warnings)
|
|
252
249
|
this.#workspace.logger.warn(warning);
|
|
253
|
-
await
|
|
250
|
+
await FileSys2.writeJson(manifestPath, {
|
|
254
251
|
...packageJson,
|
|
255
252
|
name: this.name,
|
|
256
253
|
description: `${this.name} workspace`
|
|
@@ -277,10 +274,10 @@ class Subspace {
|
|
|
277
274
|
}
|
|
278
275
|
async#rewriteGitignore() {
|
|
279
276
|
const gitignorePath = path.join(this.#clonePath, ".gitignore");
|
|
280
|
-
if (!await
|
|
277
|
+
if (!await FileSys2.fileExists(gitignorePath))
|
|
281
278
|
return;
|
|
282
279
|
const [begin = "", end = ""] = Subspace.secretsMarkers;
|
|
283
|
-
const lines = (await
|
|
280
|
+
const lines = (await FileSys2.readText(gitignorePath)).split(/\r?\n/);
|
|
284
281
|
const beginIdx = lines.indexOf(begin);
|
|
285
282
|
const endIdx = lines.indexOf(end);
|
|
286
283
|
const filtered = beginIdx >= 0 && endIdx > beginIdx ? [
|
|
@@ -288,7 +285,7 @@ class Subspace {
|
|
|
288
285
|
...lines.slice(beginIdx + 1, endIdx).filter((line) => this.#declaration.apps.some((app) => line.startsWith(`apps/${app}/`))),
|
|
289
286
|
...lines.slice(endIdx)
|
|
290
287
|
] : lines;
|
|
291
|
-
await
|
|
288
|
+
await FileSys2.writeText(gitignorePath, filtered.filter((line) => line.trim() !== "**/bun.lock").join(`
|
|
292
289
|
`));
|
|
293
290
|
}
|
|
294
291
|
async#rewriteWorkspaceSection(libs) {
|
|
@@ -299,27 +296,27 @@ class Subspace {
|
|
|
299
296
|
];
|
|
300
297
|
for (const file of ["AGENTS.md", "CLAUDE.md"]) {
|
|
301
298
|
const filePath = path.join(this.#clonePath, file);
|
|
302
|
-
if (!await
|
|
299
|
+
if (!await FileSys2.fileExists(filePath))
|
|
303
300
|
continue;
|
|
304
|
-
const content = await
|
|
301
|
+
const content = await FileSys2.readText(filePath);
|
|
305
302
|
const rewritten = replacements.reduce((text, [pattern, value]) => text.replace(pattern, value), content);
|
|
306
303
|
if (rewritten !== content)
|
|
307
|
-
await
|
|
304
|
+
await FileSys2.writeText(filePath, rewritten);
|
|
308
305
|
}
|
|
309
306
|
}
|
|
310
307
|
async#stampLib(clone, lib, branch) {
|
|
311
308
|
const manifestPath = path.join(this.#clonePath, "libs", lib, "package.json");
|
|
312
|
-
if (!await
|
|
309
|
+
if (!await FileSys2.fileExists(manifestPath))
|
|
313
310
|
return;
|
|
314
311
|
const origin = `${this.#workspace.repoName}#${branch}`;
|
|
315
312
|
const sha = await this.headSha();
|
|
316
313
|
const [hash, previous] = await Promise.all([this.#hashLib(clone, lib), this.#committedStamp(clone, lib)]);
|
|
317
|
-
const manifest = await
|
|
314
|
+
const manifest = await FileSys2.readJson(manifestPath);
|
|
318
315
|
const akan = manifest[LibSource.manifestKey] ?? {};
|
|
319
316
|
const unchanged = previous?.origin === origin && previous.sha === sha && previous.hash === hash;
|
|
320
317
|
const syncedAt = unchanged ? previous.syncedAt : new Date().toISOString();
|
|
321
318
|
manifest[LibSource.manifestKey] = { ...akan, source: { origin, sha, hash, syncedAt } };
|
|
322
|
-
await
|
|
319
|
+
await FileSys2.writeJson(manifestPath, manifest);
|
|
323
320
|
}
|
|
324
321
|
async#committedStamp(clone, lib) {
|
|
325
322
|
try {
|
|
@@ -342,22 +339,9 @@ class Subspace {
|
|
|
342
339
|
`libs/${lib}`
|
|
343
340
|
]);
|
|
344
341
|
const candidates = listed.split("\x00").filter((file) => !!file && !this.#isSubspaceOwned(file)).sort();
|
|
345
|
-
const present = await Promise.all(candidates.map(async (file) => await
|
|
342
|
+
const present = await Promise.all(candidates.map(async (file) => await FileSys2.entryExists(path.join(this.#clonePath, file))));
|
|
346
343
|
const files = candidates.filter((_, index) => present[index]);
|
|
347
|
-
|
|
348
|
-
for (const file of files) {
|
|
349
|
-
const content = await FileSys.readText(path.join(this.#clonePath, file));
|
|
350
|
-
hasher.update(file);
|
|
351
|
-
hasher.update("\x00");
|
|
352
|
-
if (file === `libs/${lib}/package.json`) {
|
|
353
|
-
const manifest = JSON.parse(content);
|
|
354
|
-
delete manifest[LibSource.manifestKey];
|
|
355
|
-
hasher.update(JSON.stringify(manifest));
|
|
356
|
-
} else
|
|
357
|
-
hasher.update(content);
|
|
358
|
-
hasher.update("\x00");
|
|
359
|
-
}
|
|
360
|
-
return hasher.digest("hex").slice(0, 32);
|
|
344
|
+
return await LibSource.hashFiles(files, `libs/${lib}/package.json`, (file) => FileSys2.readText(path.join(this.#clonePath, file)));
|
|
361
345
|
}
|
|
362
346
|
async diff(branch, filter) {
|
|
363
347
|
if (!await this.fetch(branch))
|
|
@@ -376,10 +360,7 @@ class Subspace {
|
|
|
376
360
|
if (!scoped.length)
|
|
377
361
|
return { files: [], patch: "" };
|
|
378
362
|
const from = `${this.#remote}/${branch}`;
|
|
379
|
-
const
|
|
380
|
-
const names = await this.#git(["diff", "--name-only", from, "HEAD", "--", ...pathspec]);
|
|
381
|
-
const files = await this.#meaningfulFiles(from, names.split(`
|
|
382
|
-
`).filter((file) => !!file.trim()).filter((file) => !this.#isSubspaceOwned(file)));
|
|
363
|
+
const files = await this.#changedSliceFiles(from, [from, "HEAD", "--", ...filter ? [filter] : scoped]);
|
|
383
364
|
if (!files.length)
|
|
384
365
|
return { files: [], patch: "" };
|
|
385
366
|
return { files, patch: await this.#git(["diff", from, "HEAD", "--", ...files]) };
|
|
@@ -433,7 +414,7 @@ class Subspace {
|
|
|
433
414
|
};
|
|
434
415
|
}
|
|
435
416
|
async#writeAnchorFile(branch) {
|
|
436
|
-
await
|
|
417
|
+
await FileSys2.writeJson(path.join(this.#clonePath, Subspace.anchorFile), {
|
|
437
418
|
workspace: this.#workspace.repoName,
|
|
438
419
|
hubSha: await this.headSha(),
|
|
439
420
|
branch,
|
|
@@ -470,7 +451,7 @@ class Subspace {
|
|
|
470
451
|
async#savePatch(range, files, label) {
|
|
471
452
|
const patchPath = path.join(this.#workspace.workspaceRoot, ".akan/subspace", `${this.name}-${label}.patch`);
|
|
472
453
|
await mkdir(path.dirname(patchPath), { recursive: true });
|
|
473
|
-
await
|
|
454
|
+
await FileSys2.writeText(patchPath, await this.#git(["diff", range, "--", ...files]));
|
|
474
455
|
return { path: path.relative(this.#workspace.workspaceRoot, patchPath), absolute: patchPath, files };
|
|
475
456
|
}
|
|
476
457
|
}
|
|
@@ -592,7 +573,7 @@ class SubspaceConfig {
|
|
|
592
573
|
static defaultPushableBranches = ["main", "develop", "debug"];
|
|
593
574
|
static async from(workspace) {
|
|
594
575
|
const configPath = path2.join(workspace.workspaceRoot, SubspaceConfig.fileName);
|
|
595
|
-
if (!await
|
|
576
|
+
if (!await FileSys2.fileExists(configPath))
|
|
596
577
|
return null;
|
|
597
578
|
const input = await import(configPath).then((mod) => mod.default);
|
|
598
579
|
return new SubspaceConfig(input);
|
|
@@ -735,7 +716,7 @@ class SubspaceRunner extends runner("subspace") {
|
|
|
735
716
|
if (!asked)
|
|
736
717
|
return { name: subspace.name, workspaceId, host, apps, libs: [], outcome: "cancelled", files: [] };
|
|
737
718
|
const { libs } = await subspace.slice();
|
|
738
|
-
const { CloudScript } = await import("./cloud.script-
|
|
719
|
+
const { CloudScript } = await import("./cloud.script-bkbpcr96.js");
|
|
739
720
|
const { files } = await CommandContainer.get(CloudScript).uploadEnv(workspace, {
|
|
740
721
|
host,
|
|
741
722
|
workspaceId,
|
|
@@ -2,14 +2,14 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
|
-
filename: "
|
|
5
|
+
filename: "guards.ts",
|
|
6
6
|
content: `import type { Guard, GuardScope, SignalContext } from "akanjs/signal";
|
|
7
7
|
|
|
8
|
-
// =====
|
|
8
|
+
// ===== guards.ts =====
|
|
9
9
|
// Convention: srvkit/ folder — server-only helpers, cannot import from client code.
|
|
10
10
|
// Implements the Guard interface from akanjs/signal.
|
|
11
11
|
// Guards are applied at endpoint/slice declaration: { guards: { root: SignedIn } }.
|
|
12
|
-
// Naming:
|
|
12
|
+
// Naming: camelCase file, PascalCase classes; each static name matches its guard identifier.
|
|
13
13
|
// Scanned by akan sync into srvkit/index.ts barrel automatically.
|
|
14
14
|
|
|
15
15
|
export class SignedIn implements Guard {
|
|
@@ -2,15 +2,15 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
|
-
filename: "
|
|
5
|
+
filename: "internalArgs.ts",
|
|
6
6
|
content: `import type { InternalArg, SignalContext } from "akanjs/signal";
|
|
7
7
|
|
|
8
|
-
// =====
|
|
8
|
+
// ===== internalArgs.ts =====
|
|
9
9
|
// Convention: srvkit/ folder — server-only helpers.
|
|
10
10
|
// Implements the InternalArg interface from akanjs/signal.
|
|
11
11
|
// InternalArg is an auto-injected argument for resolveField/endpoint .with() chains.
|
|
12
12
|
// Appended to a query/mutation via: .with(CurrentUserId, { nullable: true }).exec(...)
|
|
13
|
-
// Naming:
|
|
13
|
+
// Naming: camelCase file, PascalCase classes; each class name is its arg identifier.
|
|
14
14
|
// Scanned by akan sync into srvkit/index.ts barrel automatically.
|
|
15
15
|
|
|
16
16
|
export class CurrentUserId implements InternalArg<string | null> {
|
package/templates/client.ts
CHANGED
|
@@ -4,36 +4,13 @@ const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
4
4
|
|
|
5
5
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
6
|
if (!scanInfo) return null;
|
|
7
|
-
const
|
|
8
|
-
.
|
|
9
|
-
([_, fileTypes]) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
fileTypes.has("zone"),
|
|
15
|
-
)
|
|
16
|
-
.map(([key]) => key);
|
|
17
|
-
const scalarModules = [...scanInfo.scalar.entries()]
|
|
18
|
-
.filter(
|
|
19
|
-
([_, fileTypes]) =>
|
|
20
|
-
fileTypes.has("template") ||
|
|
21
|
-
fileTypes.has("unit") ||
|
|
22
|
-
fileTypes.has("util") ||
|
|
23
|
-
fileTypes.has("view") ||
|
|
24
|
-
fileTypes.has("zone"),
|
|
25
|
-
)
|
|
26
|
-
.map(([key]) => key);
|
|
27
|
-
const serviceModules = [...scanInfo.service.entries()]
|
|
28
|
-
.filter(
|
|
29
|
-
([_, fileTypes]) =>
|
|
30
|
-
fileTypes.has("template") ||
|
|
31
|
-
fileTypes.has("unit") ||
|
|
32
|
-
fileTypes.has("util") ||
|
|
33
|
-
fileTypes.has("view") ||
|
|
34
|
-
fileTypes.has("zone"),
|
|
35
|
-
)
|
|
36
|
-
.map(([key]) => key);
|
|
7
|
+
const uiModules = (modules: Map<string, Set<string>>) =>
|
|
8
|
+
[...modules.entries()]
|
|
9
|
+
.filter(([_, fileTypes]) => ["template", "unit", "util", "view", "zone"].some((type) => fileTypes.has(type)))
|
|
10
|
+
.map(([key]) => key);
|
|
11
|
+
const databaseModules = uiModules(scanInfo.database);
|
|
12
|
+
const scalarModules = uiModules(scanInfo.scalar);
|
|
13
|
+
const serviceModules = uiModules(scanInfo.service);
|
|
37
14
|
return `
|
|
38
15
|
export * as cnst from "./lib/cnst";
|
|
39
16
|
export { msg, Err, usePage, fetch, sig } from "./lib/useClient";
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
|
-
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
|
|
5
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
4
|
if (!scanInfo) return null;
|
|
7
5
|
const libs = scanInfo.getLibs();
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
|
-
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
|
|
5
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
4
|
if (!scanInfo) return null;
|
|
7
5
|
const libs = scanInfo.getLibs();
|
package/templates/lib/sig.ts
CHANGED
|
@@ -13,6 +13,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [
|
|
|
13
13
|
const libs = scanInfo.getLibs();
|
|
14
14
|
|
|
15
15
|
const signalNames = [...(libs.length === 0 ? ["base"] : libs), ...databaseModules, ...serviceModules];
|
|
16
|
+
const serverSignalClass = (module: string) =>
|
|
17
|
+
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`;
|
|
16
18
|
|
|
17
19
|
return `
|
|
18
20
|
import { FetchClient, type FetchClientType } from "akanjs/fetch";
|
|
@@ -20,38 +22,14 @@ import { SignalRegistry, serverSignal${libs.length === 0 ? ", fetch as base" : "
|
|
|
20
22
|
import { Err } from "./dict";
|
|
21
23
|
${libs.map((lib) => `import { fetch as ${lib} } from "@libs/${lib}/lib/sig";`).join("\n")}
|
|
22
24
|
|
|
23
|
-
${
|
|
24
|
-
|
|
25
|
-
.map(([module]) => `import * as ${module}Sig from "./${module}/${module}.signal";`)
|
|
26
|
-
.join("\n")}
|
|
27
|
-
${[...scanInfo.service.entries()]
|
|
28
|
-
.filter(([_, files]) => files.has("signal"))
|
|
29
|
-
.map(([module]) => `import * as ${module}Sig from "./_${module}/${module}.signal";`)
|
|
30
|
-
.join("\n")}
|
|
25
|
+
${databaseModules.map((module) => `import * as ${module}Sig from "./${module}/${module}.signal";`).join("\n")}
|
|
26
|
+
${serviceModules.map((module) => `import * as ${module}Sig from "./_${module}/${module}.signal";`).join("\n")}
|
|
31
27
|
|
|
32
|
-
${
|
|
33
|
-
|
|
34
|
-
.map(([module]) => `export * from "./${module}/${module}.signal";`)
|
|
35
|
-
.join("\n")}
|
|
36
|
-
${[...scanInfo.service.entries()]
|
|
37
|
-
.filter(([_, files]) => files.has("signal"))
|
|
38
|
-
.map(([module]) => `export * from "./_${module}/${module}.signal";`)
|
|
39
|
-
.join("\n")}
|
|
28
|
+
${databaseModules.map((module) => `export * from "./${module}/${module}.signal";`).join("\n")}
|
|
29
|
+
${serviceModules.map((module) => `export * from "./_${module}/${module}.signal";`).join("\n")}
|
|
40
30
|
|
|
41
|
-
${
|
|
42
|
-
|
|
43
|
-
.map(
|
|
44
|
-
([module]) =>
|
|
45
|
-
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
|
|
46
|
-
)
|
|
47
|
-
.join("\n")}
|
|
48
|
-
${[...scanInfo.service.entries()]
|
|
49
|
-
.filter(([_, files]) => files.has("signal"))
|
|
50
|
-
.map(
|
|
51
|
-
([module]) =>
|
|
52
|
-
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
|
|
53
|
-
)
|
|
54
|
-
.join("\n")}
|
|
31
|
+
${databaseModules.map(serverSignalClass).join("\n")}
|
|
32
|
+
${serviceModules.map(serverSignalClass).join("\n")}
|
|
55
33
|
|
|
56
34
|
${databaseModules.map((module) => `export const ${module} = SignalRegistry.registerDatabase("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Slice, ${capitalize(module)});`).join("\n")}
|
|
57
35
|
${serviceModules.map((module) => `export const ${module} = SignalRegistry.registerService("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${capitalize(module)});`).join("\n")}
|
package/templates/server.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
|
-
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
|
|
5
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
4
|
if (!scanInfo) return null;
|
|
7
5
|
const libs = scanInfo.getLibs();
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./index-
|
|
2
|
+
import"./index-5b6tavv3.js";
|
|
3
3
|
import {
|
|
4
4
|
GlobalConfig,
|
|
5
5
|
CloudApi
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-22d57v4c.js";
|
|
7
7
|
import {
|
|
8
8
|
Workspace,
|
|
9
9
|
runner,
|
|
10
10
|
script,
|
|
11
11
|
command
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-w2zdcw3k.js";
|
|
13
13
|
import {
|
|
14
14
|
AppExecutor
|
|
15
|
-
} from "./index-
|
|
16
|
-
import"./index-6wwzs1bc.js";
|
|
15
|
+
} from "./index-9d9bgcx4.js";
|
|
17
16
|
import {
|
|
18
17
|
TunnelShare2
|
|
19
|
-
} from "./index-
|
|
18
|
+
} from "./index-smme4r47.js";
|
|
20
19
|
import {
|
|
21
20
|
writeClipboard
|
|
22
21
|
} from "./index-p6pbz9n5.js";
|