@akanjs/cli 3.0.0-beta.18 → 3.0.0-beta.19
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-0035exh3.js → CodeAgent-6cm97kay.js} +2 -2
- package/{CodeAgentRpcHost-qvwfv0n9.js → CodeAgentRpcHost-p7h6n2hp.js} +1 -1
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/{CodeTui-eweg1hep.js → CodeTui-za4jsm41.js} +1 -1
- package/{TunnelShare-r5tc2qk5.js → TunnelShare-2j6s511d.js} +2 -2
- package/{agent.command-65zqfkg0.js → agent.command-e0wpbbyg.js} +5 -5
- package/akanCode.js +4 -4
- package/{application.command-2wcj5da3.js → application.command-8wyxqc8q.js} +15 -9
- package/{applicationBuildRunner-m0hhgwsx.js → applicationBuildRunner-n9gzaxd0.js} +31 -7
- package/{applicationReleasePackager-vykfzgx3.js → applicationReleasePackager-vpggfqgq.js} +1 -1
- package/buildBatch.proc.js +3 -3
- package/{capacitorApp-2daqhb5h.js → capacitorApp-q3z0qht0.js} +2 -2
- package/{cloud.command-960bgbf4.js → cloud.command-4zwa5dsx.js} +34 -12
- package/cloud.script-fwx3vb34.js +20 -0
- package/{code.command-4feh3ef7.js → code.command-468c9d7s.js} +41 -19
- package/commandManifest.json +1 -1
- package/{context.command-kzehkx48.js → context.command-dsnw0jby.js} +13 -13
- package/context.runner-rs4rj15d.js +22 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-0z2h2tks.js} +1 -1
- package/{guideline.command-3w2g20x4.js → guideline.command-vhw13pqr.js} +2 -2
- package/guidelines/agentRule/agentRule.instruction.md +27 -10
- package/guidelines/conventions/conventions.instruction.md +16 -4
- package/guidelines/queryRule/queryRule.instruction.md +16 -6
- package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
- package/incrementalBuilder.proc.js +3 -2
- package/{index-dw943k93.js → index-10dkrrww.js} +4 -4
- package/{index-rpgxs245.js → index-18zybgkc.js} +2 -2
- package/{index-mt2154s2.js → index-22xtgmhn.js} +1 -1
- package/{index-yw6g3bbv.js → index-2446k7b4.js} +1 -1
- package/{index-cjw1sj1x.js → index-3jrp517k.js} +10 -10
- package/{index-q9c3c0hy.js → index-4m929vvn.js} +2 -2
- package/{index-ef228gzf.js → index-53176s7j.js} +3 -3
- package/{index-jwrpsrg3.js → index-667w0yah.js} +1 -1
- package/{index-6q589y9t.js → index-7ep8qtvp.js} +2 -2
- package/{index-w8kmx1b6.js → index-89hy31kf.js} +30 -7
- package/{index-jd01kj5r.js → index-9d6nvkz2.js} +1 -1
- package/{index-zq0mr3hh.js → index-a1w6934z.js} +3 -3
- package/{index-sbfk9daf.js → index-ab0c38ea.js} +4 -4
- package/index-bc88j1ry.js +1166 -0
- package/{index-h94faz96.js → index-bftkz6cp.js} +274 -60
- package/{index-kcxmv48c.js → index-bhtmj233.js} +4 -1
- package/{index-m41ptvat.js → index-bwf965h6.js} +3 -3
- package/{index-bwxpk2cj.js → index-crmeqnmf.js} +52 -26
- package/{index-8k16atqy.js → index-d2242ksy.js} +23 -6
- package/{index-jwexzh42.js → index-e4v6vhxq.js} +222 -56
- package/{index-pn8mhpps.js → index-esk82rvk.js} +4 -4
- package/{index-4r42ext5.js → index-kwaq3n9n.js} +1 -1
- package/{index-gm76f0qb.js → index-n3cv0tm4.js} +1 -1
- package/{index-ycy302an.js → index-qdgzsnhg.js} +1 -1
- package/{index-wcg582a8.js → index-sq2dzkzm.js} +35 -10
- package/{index-myj01w9r.js → index-srmay5jw.js} +15 -2
- package/{index-zmj143x7.js → index-txr7dj2g.js} +3 -3
- package/{index-erfc1x40.js → index-vqx8bdxz.js} +1 -1
- package/{index-d9fjz06h.js → index-zqgj2rt2.js} +4 -4
- package/index.js +21 -21
- package/{library.command-fp0nhr62.js → library.command-cqr175dy.js} +3 -3
- package/{localRegistry.command-8y0ecxb9.js → localRegistry.command-49z55qqz.js} +9 -9
- package/{module.command-kqkn48t2.js → module.command-9p8mm3b0.js} +5 -5
- package/{package.command-qverjh22.js → package.command-wxyz909t.js} +4 -4
- package/package.json +2 -2
- package/{page.command-94bwhd0g.js → page.command-gsrsfqqs.js} +3 -3
- package/{primitive.command-2ydvtah2.js → primitive.command-ns1mptje.js} +6 -6
- package/{quality.command-fa0gth4p.js → quality.command-e76k2q9k.js} +17 -15
- package/{repair.command-4qng2hpm.js → repair.command-pkrsm3cw.js} +5 -5
- package/{scalar.command-pb2y95sh.js → scalar.command-0cpt3fc8.js} +4 -4
- package/{subspace.command-vkxmwp74.js → subspace.command-fktpwp0g.js} +20 -10
- package/templates/appSample/lib/task/task.signal.test.ts +1 -1
- package/templates/localDev/docker-compose.yaml.template +3 -14
- package/{tunnel.command-02cvp9nf.js → tunnel.command-d5jy9gk8.js} +4 -4
- package/{workflow.command-132txnrh.js → workflow.command-6tkcysmx.js} +9 -9
- package/{workspace.command-d5wkswek.js → workspace.command-gv84eh1p.js} +24 -23
- package/cloud.script-qhcnqt1n.js +0 -20
- package/context.runner-z0rrcz7b.js +0 -22
- package/index-3hpxeys1.js +0 -462
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-qdgzsnhg.js";
|
|
6
6
|
import {
|
|
7
7
|
WorkspaceExecutor,
|
|
8
8
|
AppExecutor,
|
|
9
9
|
LibExecutor,
|
|
10
10
|
PkgExecutor
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-crmeqnmf.js";
|
|
12
12
|
import {
|
|
13
13
|
LibraryScript
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-7ep8qtvp.js";
|
|
15
15
|
import {
|
|
16
16
|
HmrWatcher,
|
|
17
17
|
WatchRootResolver
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import {
|
|
23
23
|
SlicePlanner,
|
|
24
24
|
formatSlicePlan
|
|
25
|
-
} from "./index-
|
|
25
|
+
} from "./index-kwaq3n9n.js";
|
|
26
26
|
import {
|
|
27
27
|
resolveMobileTargets
|
|
28
28
|
} from "./index-47pj3aee.js";
|
|
@@ -1344,16 +1344,18 @@ ${this.#backendStderrTail.join(`
|
|
|
1344
1344
|
this.#recycleBuilderForRss(settledBytes === null ? reason : `${reason}; still ${asMib(settledBytes)}MiB after settling`);
|
|
1345
1345
|
}
|
|
1346
1346
|
static async readProcessRssBytes(pid) {
|
|
1347
|
+
if (process.platform === "win32")
|
|
1348
|
+
return await AkanAppHost.#readRssKbVia(["tasklist", "/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], AkanAppHost.#tasklistRssKb);
|
|
1347
1349
|
const status = await Bun.file(`/proc/${pid}/status`).text().catch(() => null);
|
|
1348
1350
|
const vmRssKb = status === null ? null : /VmRSS:\s+(\d+) kB/.exec(status)?.[1];
|
|
1349
1351
|
if (vmRssKb)
|
|
1350
1352
|
return Number(vmRssKb) * 1024;
|
|
1351
|
-
return await AkanAppHost.#
|
|
1353
|
+
return await AkanAppHost.#readRssKbVia(["ps", "-o", "rss=", "-p", String(pid)], (output) => Number(output.trim()));
|
|
1352
1354
|
}
|
|
1353
|
-
static async#
|
|
1355
|
+
static async#readRssKbVia(command, parseKb, timeoutMs = PS_RSS_TIMEOUT_MS) {
|
|
1354
1356
|
let proc;
|
|
1355
1357
|
try {
|
|
1356
|
-
proc = Bun.spawn(
|
|
1358
|
+
proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"] });
|
|
1357
1359
|
} catch {
|
|
1358
1360
|
return null;
|
|
1359
1361
|
}
|
|
@@ -1361,7 +1363,7 @@ ${this.#backendStderrTail.join(`
|
|
|
1361
1363
|
try {
|
|
1362
1364
|
const output = await new Response(proc.stdout).text();
|
|
1363
1365
|
await proc.exited;
|
|
1364
|
-
const rssKb =
|
|
1366
|
+
const rssKb = parseKb(output);
|
|
1365
1367
|
return Number.isFinite(rssKb) && rssKb > 0 ? rssKb * 1024 : null;
|
|
1366
1368
|
} catch {
|
|
1367
1369
|
return null;
|
|
@@ -1369,6 +1371,10 @@ ${this.#backendStderrTail.join(`
|
|
|
1369
1371
|
clearTimeout(killer);
|
|
1370
1372
|
}
|
|
1371
1373
|
}
|
|
1374
|
+
static #tasklistRssKb(output) {
|
|
1375
|
+
const memUsage = /"([^"]*)"\s*$/m.exec(output)?.[1];
|
|
1376
|
+
return memUsage ? Number(memUsage.replace(/\D/g, "")) : Number.NaN;
|
|
1377
|
+
}
|
|
1372
1378
|
#cancelRssRecycle() {
|
|
1373
1379
|
this.#rssRecycleReason = null;
|
|
1374
1380
|
this.#rssRecycleOver = null;
|
|
@@ -1959,9 +1965,9 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
|
1959
1965
|
|
|
1960
1966
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
1961
1967
|
import { Logger as Logger4 } from "akanjs/common";
|
|
1962
|
-
var loadBuildRunner = async () => (await import("./applicationBuildRunner-
|
|
1963
|
-
var loadReleasePackager = async () => (await import("./applicationReleasePackager-
|
|
1964
|
-
var loadCapacitorApp = async () => (await import("./capacitorApp-
|
|
1968
|
+
var loadBuildRunner = async () => (await import("./applicationBuildRunner-n9gzaxd0.js")).ApplicationBuildRunner;
|
|
1969
|
+
var loadReleasePackager = async () => (await import("./applicationReleasePackager-vpggfqgq.js")).ApplicationReleasePackager;
|
|
1970
|
+
var loadCapacitorApp = async () => (await import("./capacitorApp-q3z0qht0.js")).CapacitorApp;
|
|
1965
1971
|
var loadPrompts = async () => await import("@inquirer/prompts");
|
|
1966
1972
|
|
|
1967
1973
|
class ApplicationRunner extends runner("application") {
|
|
@@ -2004,7 +2010,7 @@ class ApplicationRunner extends runner("application") {
|
|
|
2004
2010
|
if (!await app.exists(scriptPath))
|
|
2005
2011
|
throw new Error(`Script file not found: apps/${app.name}/${scriptPath}`);
|
|
2006
2012
|
await app.spawn("bun", [scriptPath], {
|
|
2007
|
-
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script" }),
|
|
2013
|
+
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script", ...await app.getDatabaseModeEnv() }),
|
|
2008
2014
|
stdio: "inherit"
|
|
2009
2015
|
});
|
|
2010
2016
|
}
|
|
@@ -2095,7 +2101,29 @@ try {
|
|
|
2095
2101
|
}
|
|
2096
2102
|
`;
|
|
2097
2103
|
await app.spawn("bun", ["-e", code], {
|
|
2098
|
-
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "console" }),
|
|
2104
|
+
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "console", ...await app.getDatabaseModeEnv() }),
|
|
2105
|
+
stdio: "inherit"
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
async transferDatabase(app, direction, dir) {
|
|
2109
|
+
const serverPath = `${app.cwdPath}/server.ts`;
|
|
2110
|
+
if (!await app.exists("server.ts"))
|
|
2111
|
+
throw new Error(`Server file not found: apps/${app.name}/server.ts`);
|
|
2112
|
+
const target = path5.resolve(app.workspace.workspaceRoot, dir);
|
|
2113
|
+
const code = `
|
|
2114
|
+
const { server } = await import(${JSON.stringify(serverPath)});
|
|
2115
|
+
const { DatabaseAdaptorRole, DocumentTransfer } = await import("akanjs/service");
|
|
2116
|
+
await server.start({ listen: false, web: false });
|
|
2117
|
+
try {
|
|
2118
|
+
const transfer = new DocumentTransfer(server.get(DatabaseAdaptorRole));
|
|
2119
|
+
const reports = await transfer.${direction === "export" ? "exportTo" : "importFrom"}(${JSON.stringify(target)});
|
|
2120
|
+
for (const { table, rows } of reports) console.info(\`${direction === "export" ? "exported" : "imported"} \${table}: \${rows} rows\`);
|
|
2121
|
+
} finally {
|
|
2122
|
+
await server.stop();
|
|
2123
|
+
}
|
|
2124
|
+
`;
|
|
2125
|
+
await app.spawn("bun", ["-e", code], {
|
|
2126
|
+
env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script", ...await app.getDatabaseModeEnv() }),
|
|
2099
2127
|
stdio: "inherit"
|
|
2100
2128
|
});
|
|
2101
2129
|
}
|
|
@@ -2255,9 +2283,15 @@ try {
|
|
|
2255
2283
|
if (mode === "single")
|
|
2256
2284
|
return [];
|
|
2257
2285
|
if (mode === "multiple")
|
|
2258
|
-
return ["redis"
|
|
2286
|
+
return ["redis"];
|
|
2259
2287
|
return ["redis", "postgres"];
|
|
2260
2288
|
}
|
|
2289
|
+
async#assertComposeHas(workspace, services) {
|
|
2290
|
+
const compose = Bun.YAML.parse(await Bun.file(`${workspace.workspaceRoot}/local/docker-compose.yaml`).text());
|
|
2291
|
+
const missing = services.filter((service) => !compose?.services?.[service]);
|
|
2292
|
+
if (missing.length)
|
|
2293
|
+
throw new Error(`local/docker-compose.yaml declares no ${missing.join(" or ")} service. Add it, or move the file aside so the next akan dbup writes the current template.`);
|
|
2294
|
+
}
|
|
2261
2295
|
async#isLocalDatabaseUp(workspace, mode) {
|
|
2262
2296
|
const requiredServices = this.#getLocalDatabaseServices(mode);
|
|
2263
2297
|
if (!requiredServices.length)
|
|
@@ -2271,16 +2305,18 @@ try {
|
|
|
2271
2305
|
async dbup(workspace, mode = "multiple") {
|
|
2272
2306
|
if (mode === "single")
|
|
2273
2307
|
return true;
|
|
2308
|
+
const services = this.#getLocalDatabaseServices(mode);
|
|
2309
|
+
await workspace.applyTemplate({
|
|
2310
|
+
basePath: "local",
|
|
2311
|
+
template: "localDev",
|
|
2312
|
+
dict: { repoName: workspace.repoName },
|
|
2313
|
+
overwrite: false
|
|
2314
|
+
});
|
|
2315
|
+
await this.#assertComposeHas(workspace, services);
|
|
2274
2316
|
try {
|
|
2275
|
-
await workspace.applyTemplate({
|
|
2276
|
-
basePath: "local",
|
|
2277
|
-
template: "localDev",
|
|
2278
|
-
dict: { repoName: workspace.repoName },
|
|
2279
|
-
overwrite: false
|
|
2280
|
-
});
|
|
2281
2317
|
const wasAlreadyUp = await this.#isLocalDatabaseUp(workspace, mode);
|
|
2282
2318
|
if (!wasAlreadyUp)
|
|
2283
|
-
await workspace.spawn(`docker`, ["compose", "up", "-d", ...
|
|
2319
|
+
await workspace.spawn(`docker`, ["compose", "up", "-d", ...services], {
|
|
2284
2320
|
cwd: `${workspace.workspaceRoot}/local`
|
|
2285
2321
|
});
|
|
2286
2322
|
return wasAlreadyUp;
|
|
@@ -2341,9 +2377,187 @@ ${detail}`
|
|
|
2341
2377
|
}
|
|
2342
2378
|
}
|
|
2343
2379
|
|
|
2380
|
+
// pkgs/@akanjs/cli/application/hostProcessProbe.ts
|
|
2381
|
+
import { readdirSync, readFileSync, readlinkSync } from "fs";
|
|
2382
|
+
|
|
2383
|
+
class HostProcessProbe {
|
|
2384
|
+
static timeoutMs = 3000;
|
|
2385
|
+
static win32TimeoutMs = 20000;
|
|
2386
|
+
static #procTcpListen = "0A";
|
|
2387
|
+
static #win32ProcessQuery = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress";
|
|
2388
|
+
platform;
|
|
2389
|
+
#win32Table = null;
|
|
2390
|
+
constructor(platform = process.platform) {
|
|
2391
|
+
this.platform = platform;
|
|
2392
|
+
}
|
|
2393
|
+
async listenersOn(port) {
|
|
2394
|
+
if (this.platform === "win32")
|
|
2395
|
+
return HostProcessProbe.parseNetstat(await HostProcessProbe.run(["netstat", "-ano"]), port);
|
|
2396
|
+
if (this.platform === "linux")
|
|
2397
|
+
return HostProcessProbe.#procListenersOn(port);
|
|
2398
|
+
const output = await HostProcessProbe.run(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
|
|
2399
|
+
return [
|
|
2400
|
+
...new Set(output.split(`
|
|
2401
|
+
`).map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0))
|
|
2402
|
+
];
|
|
2403
|
+
}
|
|
2404
|
+
async parentOf(pid) {
|
|
2405
|
+
if (this.platform === "win32") {
|
|
2406
|
+
const child = await this.#win32Process(pid);
|
|
2407
|
+
const parent = child ? await this.#win32Process(child.ppid) : null;
|
|
2408
|
+
return child && parent ? HostProcessProbe.parentPidOf(child, parent) : null;
|
|
2409
|
+
}
|
|
2410
|
+
if (this.platform === "linux") {
|
|
2411
|
+
const stat = HostProcessProbe.#readProc(pid, "stat");
|
|
2412
|
+
return stat === null ? null : HostProcessProbe.parseProcStatPpid(stat);
|
|
2413
|
+
}
|
|
2414
|
+
const parsed = Number((await HostProcessProbe.run(["ps", "-p", String(pid), "-o", "ppid="])).trim());
|
|
2415
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
2416
|
+
}
|
|
2417
|
+
async commandOf(pid) {
|
|
2418
|
+
if (this.platform === "win32")
|
|
2419
|
+
return (await this.#win32Process(pid))?.command ?? null;
|
|
2420
|
+
if (this.platform === "linux") {
|
|
2421
|
+
const cmdline = HostProcessProbe.#readProc(pid, "cmdline");
|
|
2422
|
+
return cmdline?.split("\x00").filter(Boolean).join(" ") || null;
|
|
2423
|
+
}
|
|
2424
|
+
return (await HostProcessProbe.run(["ps", "-ww", "-p", String(pid), "-o", "command="])).trim() || null;
|
|
2425
|
+
}
|
|
2426
|
+
static parentPidOf(child, parent) {
|
|
2427
|
+
if (child.ppid !== parent.pid)
|
|
2428
|
+
return null;
|
|
2429
|
+
if (parent.startedAt !== null && child.startedAt !== null && parent.startedAt > child.startedAt)
|
|
2430
|
+
return null;
|
|
2431
|
+
return parent.pid;
|
|
2432
|
+
}
|
|
2433
|
+
static parseNetstat(output, port) {
|
|
2434
|
+
const pids = new Set;
|
|
2435
|
+
for (const line of output.split(/\r?\n/)) {
|
|
2436
|
+
const fields = line.trim().split(/\s+/);
|
|
2437
|
+
if (fields[0] !== "TCP" || fields.length < 5)
|
|
2438
|
+
continue;
|
|
2439
|
+
const [, local, remote] = fields;
|
|
2440
|
+
if (!local?.endsWith(`:${port}`) || !remote?.endsWith(":0"))
|
|
2441
|
+
continue;
|
|
2442
|
+
const pid = Number(fields.at(-1));
|
|
2443
|
+
if (Number.isInteger(pid) && pid > 0)
|
|
2444
|
+
pids.add(pid);
|
|
2445
|
+
}
|
|
2446
|
+
return [...pids];
|
|
2447
|
+
}
|
|
2448
|
+
static parseProcNetTcp(text, port) {
|
|
2449
|
+
const inodes = [];
|
|
2450
|
+
for (const line of text.split(`
|
|
2451
|
+
`).slice(1)) {
|
|
2452
|
+
const fields = line.trim().split(/\s+/);
|
|
2453
|
+
const [, local, , state, , , , , , inode] = fields;
|
|
2454
|
+
if (!local || !inode || state !== HostProcessProbe.#procTcpListen || inode === "0")
|
|
2455
|
+
continue;
|
|
2456
|
+
if (Number.parseInt(local.slice(local.lastIndexOf(":") + 1), 16) === port)
|
|
2457
|
+
inodes.push(inode);
|
|
2458
|
+
}
|
|
2459
|
+
return inodes;
|
|
2460
|
+
}
|
|
2461
|
+
static parseProcStatPpid(stat) {
|
|
2462
|
+
const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
|
|
2463
|
+
return Number.isInteger(ppid) && ppid > 0 ? ppid : null;
|
|
2464
|
+
}
|
|
2465
|
+
static parseWin32Processes(json) {
|
|
2466
|
+
const table = new Map;
|
|
2467
|
+
let parsed;
|
|
2468
|
+
try {
|
|
2469
|
+
parsed = JSON.parse(json.trim() || "[]");
|
|
2470
|
+
} catch {
|
|
2471
|
+
return table;
|
|
2472
|
+
}
|
|
2473
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
2474
|
+
for (const row of rows) {
|
|
2475
|
+
if (typeof row?.ProcessId !== "number")
|
|
2476
|
+
continue;
|
|
2477
|
+
table.set(row.ProcessId, {
|
|
2478
|
+
pid: row.ProcessId,
|
|
2479
|
+
ppid: row.ParentProcessId ?? 0,
|
|
2480
|
+
command: row.CommandLine?.trim() || null,
|
|
2481
|
+
startedAt: HostProcessProbe.#parseCimDate(row.CreationDate)
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
return table;
|
|
2485
|
+
}
|
|
2486
|
+
static async run(command, timeoutMs = HostProcessProbe.timeoutMs) {
|
|
2487
|
+
let proc;
|
|
2488
|
+
try {
|
|
2489
|
+
proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
|
|
2490
|
+
} catch {
|
|
2491
|
+
return "";
|
|
2492
|
+
}
|
|
2493
|
+
const timer = setTimeout(() => proc.kill("SIGKILL"), timeoutMs);
|
|
2494
|
+
try {
|
|
2495
|
+
return await new Response(proc.stdout).text();
|
|
2496
|
+
} catch {
|
|
2497
|
+
return "";
|
|
2498
|
+
} finally {
|
|
2499
|
+
clearTimeout(timer);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
async#win32Process(pid) {
|
|
2503
|
+
this.#win32Table ??= await HostProcessProbe.#queryWin32Processes();
|
|
2504
|
+
if (!this.#win32Table.has(pid))
|
|
2505
|
+
this.#win32Table = await HostProcessProbe.#queryWin32Processes();
|
|
2506
|
+
return this.#win32Table.get(pid) ?? null;
|
|
2507
|
+
}
|
|
2508
|
+
static async#queryWin32Processes() {
|
|
2509
|
+
const output = await HostProcessProbe.run(["powershell", "-NoProfile", "-NonInteractive", "-Command", HostProcessProbe.#win32ProcessQuery], HostProcessProbe.win32TimeoutMs);
|
|
2510
|
+
return HostProcessProbe.parseWin32Processes(output);
|
|
2511
|
+
}
|
|
2512
|
+
static #parseCimDate(value) {
|
|
2513
|
+
if (!value)
|
|
2514
|
+
return null;
|
|
2515
|
+
const legacy = /\/Date\((\d+)/.exec(value)?.[1];
|
|
2516
|
+
const ms = legacy ? Number(legacy) : Date.parse(value);
|
|
2517
|
+
return Number.isFinite(ms) ? ms : null;
|
|
2518
|
+
}
|
|
2519
|
+
static #procListenersOn(port) {
|
|
2520
|
+
const inodes = new Set(["tcp", "tcp6"].flatMap((table) => HostProcessProbe.parseProcNetTcp(HostProcessProbe.#readProc("net", table) ?? "", port)));
|
|
2521
|
+
if (!inodes.size)
|
|
2522
|
+
return [];
|
|
2523
|
+
const pids = [];
|
|
2524
|
+
for (const entry of HostProcessProbe.#listDir("/proc")) {
|
|
2525
|
+
if (!/^\d+$/.test(entry))
|
|
2526
|
+
continue;
|
|
2527
|
+
const holds = HostProcessProbe.#listDir(`/proc/${entry}/fd`).some((fd) => {
|
|
2528
|
+
const inode = /^socket:\[(\d+)\]$/.exec(HostProcessProbe.#readLink(`/proc/${entry}/fd/${fd}`))?.[1];
|
|
2529
|
+
return !!inode && inodes.has(inode);
|
|
2530
|
+
});
|
|
2531
|
+
if (holds)
|
|
2532
|
+
pids.push(Number(entry));
|
|
2533
|
+
}
|
|
2534
|
+
return pids;
|
|
2535
|
+
}
|
|
2536
|
+
static #readProc(pid, file) {
|
|
2537
|
+
try {
|
|
2538
|
+
return readFileSync(`/proc/${pid}/${file}`, "utf8");
|
|
2539
|
+
} catch {
|
|
2540
|
+
return null;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
static #listDir(dir) {
|
|
2544
|
+
try {
|
|
2545
|
+
return readdirSync(dir);
|
|
2546
|
+
} catch {
|
|
2547
|
+
return [];
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
static #readLink(link) {
|
|
2551
|
+
try {
|
|
2552
|
+
return readlinkSync(link);
|
|
2553
|
+
} catch {
|
|
2554
|
+
return "";
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2344
2559
|
// pkgs/@akanjs/cli/application/devPortReclaimer.ts
|
|
2345
2560
|
class DevPortReclaimer {
|
|
2346
|
-
static lsofTimeoutMs = 3000;
|
|
2347
2561
|
static releaseTimeoutMs = 8000;
|
|
2348
2562
|
static maxAncestorDepth = 8;
|
|
2349
2563
|
static #releasePollMs = 100;
|
|
@@ -2352,7 +2566,12 @@ class DevPortReclaimer {
|
|
|
2352
2566
|
return [...new Set(ports.flatMap((port) => [port, port + DevPortReclaimer.wsPortOffset]))].sort((left, right) => left - right);
|
|
2353
2567
|
}
|
|
2354
2568
|
static isAkanCommand(command) {
|
|
2355
|
-
|
|
2569
|
+
const normalized = command.replaceAll("\\", "/");
|
|
2570
|
+
return /(^|\/)akan(\.exe)?"?(\s|$)/.test(normalized) || normalized.includes("@akanjs/cli") || normalized.includes("akanjs/server") || /\bapps\/[^/\s]+\/main\.ts\b/.test(normalized) || normalized.includes("incrementalBuilder.proc") || normalized.includes("rscWorker");
|
|
2571
|
+
}
|
|
2572
|
+
#probe;
|
|
2573
|
+
constructor(probe = new HostProcessProbe) {
|
|
2574
|
+
this.#probe = probe;
|
|
2356
2575
|
}
|
|
2357
2576
|
async reclaim(ports) {
|
|
2358
2577
|
const killed = [];
|
|
@@ -2377,10 +2596,10 @@ class DevPortReclaimer {
|
|
|
2377
2596
|
}
|
|
2378
2597
|
async holdersOf(port) {
|
|
2379
2598
|
const holders = [];
|
|
2380
|
-
for (const listenerPid of await this.#
|
|
2599
|
+
for (const listenerPid of await this.#probe.listenersOn(port)) {
|
|
2381
2600
|
if (listenerPid === process.pid || listenerPid === process.ppid)
|
|
2382
2601
|
continue;
|
|
2383
|
-
const command = await this.#commandOf(listenerPid);
|
|
2602
|
+
const command = await this.#probe.commandOf(listenerPid);
|
|
2384
2603
|
if (!command)
|
|
2385
2604
|
continue;
|
|
2386
2605
|
if (!DevPortReclaimer.isAkanCommand(command)) {
|
|
@@ -2395,44 +2614,37 @@ class DevPortReclaimer {
|
|
|
2395
2614
|
async#akanRootOf(pid, command) {
|
|
2396
2615
|
let root = { pid, command };
|
|
2397
2616
|
for (let depth = 0;depth < DevPortReclaimer.maxAncestorDepth; depth += 1) {
|
|
2398
|
-
const parentPid = await this.#
|
|
2617
|
+
const parentPid = await this.#probe.parentOf(root.pid);
|
|
2399
2618
|
if (parentPid === null || parentPid <= 1 || parentPid === process.pid || parentPid === process.ppid)
|
|
2400
2619
|
break;
|
|
2401
|
-
const parentCommand = await this.#commandOf(parentPid);
|
|
2620
|
+
const parentCommand = await this.#probe.commandOf(parentPid);
|
|
2402
2621
|
if (!parentCommand || !DevPortReclaimer.isAkanCommand(parentCommand))
|
|
2403
2622
|
break;
|
|
2404
2623
|
root = { pid: parentPid, command: parentCommand };
|
|
2405
2624
|
}
|
|
2406
2625
|
return root;
|
|
2407
2626
|
}
|
|
2408
|
-
async#ppidOf(pid) {
|
|
2409
|
-
const output = await this.#run(["ps", "-p", String(pid), "-o", "ppid="]);
|
|
2410
|
-
const parsed = Number(output.trim());
|
|
2411
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
2412
|
-
}
|
|
2413
|
-
async#pidsOn(port) {
|
|
2414
|
-
const output = await this.#run(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
|
|
2415
|
-
return [
|
|
2416
|
-
...new Set(output.split(`
|
|
2417
|
-
`).map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0))
|
|
2418
|
-
];
|
|
2419
|
-
}
|
|
2420
|
-
async#commandOf(pid) {
|
|
2421
|
-
const output = await this.#run(["ps", "-p", String(pid), "-o", "command="]);
|
|
2422
|
-
return output.trim() || null;
|
|
2423
|
-
}
|
|
2424
2627
|
async#terminate(pid) {
|
|
2628
|
+
if (this.#probe.platform === "win32") {
|
|
2629
|
+
await HostProcessProbe.run(["taskkill", "/PID", String(pid), "/T", "/F"]);
|
|
2630
|
+
return await this.#released(pid);
|
|
2631
|
+
}
|
|
2425
2632
|
if (!this.#signal(pid, "SIGTERM"))
|
|
2426
2633
|
return !this.#alive(pid);
|
|
2634
|
+
if (await this.#released(pid))
|
|
2635
|
+
return true;
|
|
2636
|
+
this.#signal(pid, "SIGKILL");
|
|
2637
|
+
await Bun.sleep(DevPortReclaimer.#releasePollMs);
|
|
2638
|
+
return !this.#alive(pid);
|
|
2639
|
+
}
|
|
2640
|
+
async#released(pid) {
|
|
2427
2641
|
const deadline = Date.now() + DevPortReclaimer.releaseTimeoutMs;
|
|
2428
2642
|
while (Date.now() < deadline) {
|
|
2429
2643
|
if (!this.#alive(pid))
|
|
2430
2644
|
return true;
|
|
2431
2645
|
await Bun.sleep(DevPortReclaimer.#releasePollMs);
|
|
2432
2646
|
}
|
|
2433
|
-
|
|
2434
|
-
await Bun.sleep(DevPortReclaimer.#releasePollMs);
|
|
2435
|
-
return !this.#alive(pid);
|
|
2647
|
+
return false;
|
|
2436
2648
|
}
|
|
2437
2649
|
#signal(pid, signal) {
|
|
2438
2650
|
try {
|
|
@@ -2450,17 +2662,6 @@ class DevPortReclaimer {
|
|
|
2450
2662
|
return error.code === "EPERM";
|
|
2451
2663
|
}
|
|
2452
2664
|
}
|
|
2453
|
-
async#run(command) {
|
|
2454
|
-
const proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"] });
|
|
2455
|
-
const timer = setTimeout(() => proc.kill("SIGKILL"), DevPortReclaimer.lsofTimeoutMs);
|
|
2456
|
-
try {
|
|
2457
|
-
return await new Response(proc.stdout).text();
|
|
2458
|
-
} catch {
|
|
2459
|
-
return "";
|
|
2460
|
-
} finally {
|
|
2461
|
-
clearTimeout(timer);
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
2665
|
}
|
|
2465
2666
|
|
|
2466
2667
|
// pkgs/@akanjs/cli/application/devStreamView.ts
|
|
@@ -3175,7 +3376,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3175
3376
|
async startOne(app, { open = false, dbup = true, stdio = "inherit", write = true, onDevEvent } = {}) {
|
|
3176
3377
|
await app.scanSync({ write });
|
|
3177
3378
|
const akanConfig = await app.getConfig();
|
|
3178
|
-
const databaseMode =
|
|
3379
|
+
const databaseMode = akanConfig.resolveDatabaseMode();
|
|
3179
3380
|
await this.syncDatabaseModeDependencies(app, akanConfig, databaseMode);
|
|
3180
3381
|
if (app.getEnv() === "local" && dbup && databaseMode !== "single") {
|
|
3181
3382
|
const wasDbAlreadyUp = await this.dbup(app.workspace, databaseMode);
|
|
@@ -3233,7 +3434,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3233
3434
|
if (app.getEnv() !== "local")
|
|
3234
3435
|
continue;
|
|
3235
3436
|
const akanConfig = await app.getConfig();
|
|
3236
|
-
const mode =
|
|
3437
|
+
const mode = akanConfig.resolveDatabaseMode();
|
|
3237
3438
|
await this.syncDatabaseModeDependencies(app, akanConfig, mode);
|
|
3238
3439
|
if (mode !== "single")
|
|
3239
3440
|
modes.add(mode);
|
|
@@ -3321,6 +3522,19 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3321
3522
|
async codepush(app, os) {
|
|
3322
3523
|
await this.applicationRunner.codepush(app, os);
|
|
3323
3524
|
}
|
|
3525
|
+
async transferDatabase(app, direction, dir) {
|
|
3526
|
+
await this.applicationRunner.transferDatabase(app, direction, dir);
|
|
3527
|
+
}
|
|
3528
|
+
async dbupDeclared(workspace, mode) {
|
|
3529
|
+
const declared = mode ? [mode] : await Promise.all((await workspace.getApps()).map(async (appName) => (await AppExecutor.from(workspace, appName).getConfig()).database.modes)).then((modes) => [...new Set(modes.flat())]);
|
|
3530
|
+
const needing = declared.filter((each) => each !== "single");
|
|
3531
|
+
if (!needing.length) {
|
|
3532
|
+
workspace.log("No app here declares a database mode that runs on local services; single needs none.");
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
for (const each of needing)
|
|
3536
|
+
await this.dbup(workspace, each);
|
|
3537
|
+
}
|
|
3324
3538
|
async dbup(workspace, mode = "multiple") {
|
|
3325
3539
|
const spinner = workspace.spinning(`Starting local database (${mode})...`);
|
|
3326
3540
|
const wasAlreadyUp = await this.applicationRunner.dbup(workspace, mode);
|
|
@@ -3344,7 +3558,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3344
3558
|
await Promise.all(shares.map(async (share) => await share.close()));
|
|
3345
3559
|
}, "Abandoning the tunnel release; the shares expire on their own.");
|
|
3346
3560
|
await Promise.all(apps.map(async (app) => {
|
|
3347
|
-
const { TunnelShare } = await import("./TunnelShare-
|
|
3561
|
+
const { TunnelShare } = await import("./TunnelShare-2j6s511d.js");
|
|
3348
3562
|
const share = await TunnelShare.open(app, { workspace: app.workspace });
|
|
3349
3563
|
shares.push(share);
|
|
3350
3564
|
urls.set(app.name, share.url);
|
|
@@ -10,7 +10,10 @@ import ignore from "ignore";
|
|
|
10
10
|
import ts from "typescript";
|
|
11
11
|
var testFileRegex = /\.(?:test|spec)\.[cm]?[tj]sx?$/;
|
|
12
12
|
var skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android", "__fixtures__"];
|
|
13
|
-
var isSkippedPath = (filePath) =>
|
|
13
|
+
var isSkippedPath = (filePath) => {
|
|
14
|
+
const posixPath = filePath.split(path.sep).join("/");
|
|
15
|
+
return skipDirs.some((dir) => posixPath.includes(`/${dir}/`) || posixPath.startsWith(`${dir}/`));
|
|
16
|
+
};
|
|
14
17
|
var builtinModuleSet = new Set([...builtinModules, ...builtinModules.map((mod) => `node:${mod}`)]);
|
|
15
18
|
var stripShebang = (source) => source.replace(/^#!.*(?:\r?\n|$)/, "");
|
|
16
19
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-qdgzsnhg.js";
|
|
6
6
|
import {
|
|
7
7
|
AGENT_BLOCK_START,
|
|
8
8
|
AGENT_BLOCK_END,
|
|
@@ -13,14 +13,14 @@ import {
|
|
|
13
13
|
CLAUDE_COMMENT_RULE,
|
|
14
14
|
AppExecutor,
|
|
15
15
|
LibExecutor
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-crmeqnmf.js";
|
|
17
17
|
import {
|
|
18
18
|
collectRecipeSources2,
|
|
19
19
|
scanRecipes2
|
|
20
20
|
} from "./index-by5gpp8x.js";
|
|
21
21
|
import {
|
|
22
22
|
AkanContextAnalyzer
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-18zybgkc.js";
|
|
24
24
|
import {
|
|
25
25
|
Prompter2
|
|
26
26
|
} from "./index-s5rhm04y.js";
|