@akanjs/cli 2.3.11-rc.6 → 2.3.11-rc.8
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/incrementalBuilder.proc.js +239 -34
- package/index.js +285 -55
- package/package.json +2 -2
- package/templates/appSample/lib/task/task.service.ts +1 -1
- package/templates/module/__Model__.Template.tsx +4 -5
- package/templates/module/__Model__.Unit.tsx +1 -1
- package/templates/module/__Model__.View.tsx +1 -1
- package/templates/module/__Model__.Zone.tsx +5 -3
- package/templates/module/__model__.constant.ts +2 -1
- package/templates/module/__model__.dictionary.ts +3 -1
- package/templates/workspaceRoot/.gitignore.template +2 -0
- package/templates/workspaceRoot/AGENTS.md.template +55 -3
- package/templates/workspaceRoot/biome.json.template +4 -0
- package/templates/workspaceRoot/docs/GENERATED.md.template +0 -1
- package/templates/workspaceRoot/package.json.template +3 -3
package/index.js
CHANGED
|
@@ -664,6 +664,7 @@ import {
|
|
|
664
664
|
import { readFileSync as readFileSync3 } from "fs";
|
|
665
665
|
import { copyFile, mkdir as mkdir2, readdir as readDirEntries, stat as stat2 } from "fs/promises";
|
|
666
666
|
import path7 from "path";
|
|
667
|
+
import { pathToFileURL } from "url";
|
|
667
668
|
import {
|
|
668
669
|
capitalize,
|
|
669
670
|
isRouteSourceFile,
|
|
@@ -1105,6 +1106,63 @@ var decreaseBuildNum = async (app) => {
|
|
|
1105
1106
|
const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
|
|
1106
1107
|
fs.writeFileSync(akanConfigPath, akanConfigContent);
|
|
1107
1108
|
};
|
|
1109
|
+
// pkgs/@akanjs/devkit/firebaseMessagingSw.ts
|
|
1110
|
+
var FIREBASE_WEB_SDK_VERSION = "12.13.0";
|
|
1111
|
+
function normalizeFirebaseClientConfig(config) {
|
|
1112
|
+
if (!config || typeof config !== "object")
|
|
1113
|
+
return null;
|
|
1114
|
+
const value = config;
|
|
1115
|
+
if (typeof value.apiKey !== "string" || typeof value.projectId !== "string" || typeof value.messagingSenderId !== "string" || typeof value.appId !== "string") {
|
|
1116
|
+
return null;
|
|
1117
|
+
}
|
|
1118
|
+
return {
|
|
1119
|
+
apiKey: value.apiKey,
|
|
1120
|
+
...typeof value.authDomain === "string" ? { authDomain: value.authDomain } : {},
|
|
1121
|
+
projectId: value.projectId,
|
|
1122
|
+
...typeof value.storageBucket === "string" ? { storageBucket: value.storageBucket } : {},
|
|
1123
|
+
messagingSenderId: value.messagingSenderId,
|
|
1124
|
+
appId: value.appId
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function createFirebaseMessagingServiceWorker(config) {
|
|
1128
|
+
const configJson = JSON.stringify(config);
|
|
1129
|
+
return `/* Generated by Akan.js. Do not edit. */
|
|
1130
|
+
const firebaseConfig = ${configJson};
|
|
1131
|
+
|
|
1132
|
+
if (firebaseConfig) {
|
|
1133
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-app-compat.js");
|
|
1134
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-messaging-compat.js");
|
|
1135
|
+
|
|
1136
|
+
firebase.initializeApp(firebaseConfig);
|
|
1137
|
+
const messaging = firebase.messaging();
|
|
1138
|
+
|
|
1139
|
+
const notificationUrl = (payload) =>
|
|
1140
|
+
payload?.data?.url || payload?.fcmOptions?.link || payload?.notification?.click_action;
|
|
1141
|
+
|
|
1142
|
+
messaging.onBackgroundMessage((payload) => {
|
|
1143
|
+
const title = payload?.notification?.title || "";
|
|
1144
|
+
const options = {
|
|
1145
|
+
body: payload?.notification?.body,
|
|
1146
|
+
icon: payload?.notification?.icon,
|
|
1147
|
+
image: payload?.notification?.image,
|
|
1148
|
+
data: {
|
|
1149
|
+
url: notificationUrl(payload),
|
|
1150
|
+
FCM_MSG: payload,
|
|
1151
|
+
},
|
|
1152
|
+
};
|
|
1153
|
+
self.registration.showNotification(title, options);
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
self.addEventListener("notificationclick", (event) => {
|
|
1158
|
+
const url = event.notification?.data?.url || event.notification?.data?.FCM_MSG?.data?.url;
|
|
1159
|
+
event.notification?.close();
|
|
1160
|
+
if (!url) return;
|
|
1161
|
+
event.waitUntil(clients.openWindow(url));
|
|
1162
|
+
});
|
|
1163
|
+
`;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1108
1166
|
// pkgs/@akanjs/devkit/getDirname.ts
|
|
1109
1167
|
import path2 from "path";
|
|
1110
1168
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1390,6 +1448,7 @@ ${errorText}, ${warningText} found`];
|
|
|
1390
1448
|
|
|
1391
1449
|
// pkgs/@akanjs/devkit/scanInfo.ts
|
|
1392
1450
|
import path5 from "path";
|
|
1451
|
+
import { rm } from "fs/promises";
|
|
1393
1452
|
|
|
1394
1453
|
// pkgs/@akanjs/devkit/dependencyScanner.ts
|
|
1395
1454
|
import { builtinModules } from "module";
|
|
@@ -1711,6 +1770,7 @@ var appRootAllowedFiles = new Set([
|
|
|
1711
1770
|
"tsconfig.json",
|
|
1712
1771
|
"tsconfig.tsbuildinfo"
|
|
1713
1772
|
]);
|
|
1773
|
+
var generatedRootCapacitorConfigFiles = ["capacitor.config.js", "capacitor.config.json"];
|
|
1714
1774
|
var appRootAllowedDirs = new Set([
|
|
1715
1775
|
".akan",
|
|
1716
1776
|
"android",
|
|
@@ -1754,11 +1814,17 @@ var rootSignalTestFilePattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(
|
|
|
1754
1814
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1755
1815
|
var isAllowedLibRootFile = (filename) => libRootAllowedFiles.has(filename) || rootSignalTestFilePattern.test(filename);
|
|
1756
1816
|
var getScanPath = (exec, relativePath) => path5.posix.join(`${exec.type}s`, exec.name, relativePath.split(path5.sep).join("/"));
|
|
1817
|
+
async function clearGeneratedRootCapacitorConfigs(exec) {
|
|
1818
|
+
if (exec.type !== "app")
|
|
1819
|
+
return;
|
|
1820
|
+
await Promise.all(generatedRootCapacitorConfigFiles.map((filename) => rm(exec.getPath(filename), { force: true })));
|
|
1821
|
+
}
|
|
1757
1822
|
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1758
1823
|
const dirname = path5.basename(modulePath);
|
|
1759
1824
|
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1760
1825
|
};
|
|
1761
1826
|
async function assertScanConvention(exec, libRoot) {
|
|
1827
|
+
await clearGeneratedRootCapacitorConfigs(exec);
|
|
1762
1828
|
const violations = [];
|
|
1763
1829
|
const addViolation = (relativePath, reason) => {
|
|
1764
1830
|
violations.push(`${getScanPath(exec, relativePath)}: ${reason}`);
|
|
@@ -3575,6 +3641,8 @@ class AppExecutor extends SysExecutor {
|
|
|
3575
3641
|
...routeEnv,
|
|
3576
3642
|
...devPort ? { PORT: devPort, AKAN_PUBLIC_CLIENT_PORT: devPort, AKAN_PUBLIC_SERVER_PORT: devPort } : {}
|
|
3577
3643
|
});
|
|
3644
|
+
if (type === "build")
|
|
3645
|
+
Object.assign(process.env, env);
|
|
3578
3646
|
return { env };
|
|
3579
3647
|
}
|
|
3580
3648
|
#publicEnv = null;
|
|
@@ -3685,8 +3753,30 @@ class AppExecutor extends SysExecutor {
|
|
|
3685
3753
|
});
|
|
3686
3754
|
if (write)
|
|
3687
3755
|
await this.syncAssets(scanInfo.getScanResult().libDeps);
|
|
3756
|
+
if (write)
|
|
3757
|
+
await this.#syncFirebaseMessagingSw();
|
|
3688
3758
|
return scanInfo;
|
|
3689
3759
|
}
|
|
3760
|
+
async#syncFirebaseMessagingSw() {
|
|
3761
|
+
const swRelPath = "public/firebase-messaging-sw.js";
|
|
3762
|
+
if (await FileSys.fileExists(this.getPath(swRelPath)))
|
|
3763
|
+
return;
|
|
3764
|
+
const envClientPath = path7.join(this.cwdPath, "env", "env.client.ts");
|
|
3765
|
+
if (!await FileSys.fileExists(envClientPath))
|
|
3766
|
+
return;
|
|
3767
|
+
let firebaseConfig = null;
|
|
3768
|
+
try {
|
|
3769
|
+
const envUrl = pathToFileURL(envClientPath);
|
|
3770
|
+
envUrl.searchParams.set("t", String(Date.now()));
|
|
3771
|
+
const envModule = await import(envUrl.href);
|
|
3772
|
+
firebaseConfig = normalizeFirebaseClientConfig(envModule.env?.firebase);
|
|
3773
|
+
} catch {
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
if (!firebaseConfig)
|
|
3777
|
+
return;
|
|
3778
|
+
await this.writeFile(swRelPath, createFirebaseMessagingServiceWorker(firebaseConfig), { overwrite: false });
|
|
3779
|
+
}
|
|
3690
3780
|
async increaseBuildNum() {
|
|
3691
3781
|
await increaseBuildNum(this);
|
|
3692
3782
|
}
|
|
@@ -4994,7 +5084,6 @@ var workflowSyncStatePath = (target) => `${workflowSyncDir}/${syncStateSlug(targ
|
|
|
4994
5084
|
var generatedFilePathsForTarget = (targetRoot, reason = "Generated files were refreshed by sync.") => [
|
|
4995
5085
|
{ path: `${targetRoot}/lib/cnst.ts`, action: "sync", reason },
|
|
4996
5086
|
{ path: `${targetRoot}/lib/dict.ts`, action: "sync", reason },
|
|
4997
|
-
{ path: `${targetRoot}/lib/option.ts`, action: "sync", reason },
|
|
4998
5087
|
{ path: `${targetRoot}/lib/index.ts`, action: "sync", reason }
|
|
4999
5088
|
];
|
|
5000
5089
|
var writeGeneratedSyncState = async (workspace, state) => {
|
|
@@ -7648,13 +7737,59 @@ var resourceList = [
|
|
|
7648
7737
|
{ uri: "akan://workspace/modules", name: "Workspace modules", mimeType: "application/json" }
|
|
7649
7738
|
];
|
|
7650
7739
|
var cursorMcpConfigPath = ".cursor/mcp.json";
|
|
7740
|
+
var claudeMcpConfigPath = ".mcp.json";
|
|
7741
|
+
var codexMcpConfigPath = ".codex/config.toml";
|
|
7742
|
+
var akanMcpInstallTargets = ["cursor", "claude", "codex"];
|
|
7743
|
+
var akanMcpInstallConfigPaths = {
|
|
7744
|
+
cursor: cursorMcpConfigPath,
|
|
7745
|
+
claude: claudeMcpConfigPath,
|
|
7746
|
+
codex: codexMcpConfigPath
|
|
7747
|
+
};
|
|
7651
7748
|
var cursorWorkspaceFolder = "$" + "{workspaceFolder}";
|
|
7749
|
+
var claudeProjectDir = "$CLAUDE_PROJECT_DIR";
|
|
7750
|
+
var akanMcpCommand = (mode, { cd } = {}) => cd ? `cd "${cd}" && akan mcp --mode ${mode}` : `akan mcp --mode ${mode}`;
|
|
7652
7751
|
var createAkanCursorMcpServer = (mode = "readonly") => ({
|
|
7653
7752
|
type: "stdio",
|
|
7654
7753
|
command: "bash",
|
|
7655
|
-
args: ["-lc",
|
|
7754
|
+
args: ["-lc", akanMcpCommand(mode, { cd: cursorWorkspaceFolder })]
|
|
7755
|
+
});
|
|
7756
|
+
var createAkanClaudeMcpServer = (mode = "readonly") => ({
|
|
7757
|
+
type: "stdio",
|
|
7758
|
+
command: "bash",
|
|
7759
|
+
args: ["-lc", akanMcpCommand(mode, { cd: claudeProjectDir })]
|
|
7656
7760
|
});
|
|
7761
|
+
var createAkanMcpServer = (target, mode = "readonly") => target === "cursor" ? createAkanCursorMcpServer(mode) : createAkanClaudeMcpServer(mode);
|
|
7657
7762
|
var akanCursorMcpServer = createAkanCursorMcpServer();
|
|
7763
|
+
var codexMcpServerTableHeader = "[mcp_servers.akan]";
|
|
7764
|
+
var createAkanCodexMcpServerBlock = (mode = "readonly") => `${codexMcpServerTableHeader}
|
|
7765
|
+
command = "bash"
|
|
7766
|
+
args = ["-lc", "${akanMcpCommand(mode)}"]
|
|
7767
|
+
`;
|
|
7768
|
+
var codexAkanTablePattern = /^\[mcp_servers\.akan\][^\n]*\n(?:(?!\[)[^\n]*(?:\n|$))*/m;
|
|
7769
|
+
var upsertCodexMcpServerBlock = (existing, block, { force = false } = {}) => {
|
|
7770
|
+
const nextBlock = block.endsWith(`
|
|
7771
|
+
`) ? block : `${block}
|
|
7772
|
+
`;
|
|
7773
|
+
const match = existing.match(codexAkanTablePattern);
|
|
7774
|
+
if (!match) {
|
|
7775
|
+
if (!existing.trim())
|
|
7776
|
+
return nextBlock;
|
|
7777
|
+
return `${existing.replace(/\s*$/, "")}
|
|
7778
|
+
|
|
7779
|
+
${nextBlock}`;
|
|
7780
|
+
}
|
|
7781
|
+
if (match[0].trim() === nextBlock.trim())
|
|
7782
|
+
return existing;
|
|
7783
|
+
if (!force)
|
|
7784
|
+
throw new Error(`${codexMcpConfigPath} already has an "akan" MCP server. Re-run with --force to overwrite it.`);
|
|
7785
|
+
const start = match.index ?? 0;
|
|
7786
|
+
const before = existing.slice(0, start);
|
|
7787
|
+
const after = existing.slice(start + match[0].length);
|
|
7788
|
+
const separator = after && !after.startsWith(`
|
|
7789
|
+
`) ? `
|
|
7790
|
+
` : "";
|
|
7791
|
+
return `${before}${nextBlock}${separator}${after}`;
|
|
7792
|
+
};
|
|
7658
7793
|
var renderDoctorText = (result) => {
|
|
7659
7794
|
const lines = [`Akan doctor status: ${result.status}`];
|
|
7660
7795
|
if (result.diagnostics.length === 0) {
|
|
@@ -7677,7 +7812,6 @@ var generatedFiles = [
|
|
|
7677
7812
|
"*/lib/cnst.ts",
|
|
7678
7813
|
"*/lib/db.ts",
|
|
7679
7814
|
"*/lib/dict.ts",
|
|
7680
|
-
"*/lib/option.ts",
|
|
7681
7815
|
"*/lib/sig.ts",
|
|
7682
7816
|
"*/lib/srv.ts",
|
|
7683
7817
|
"*/lib/st.ts",
|
|
@@ -8671,7 +8805,7 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
8671
8805
|
}
|
|
8672
8806
|
}
|
|
8673
8807
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
8674
|
-
import { mkdir as mkdir8, rm as
|
|
8808
|
+
import { mkdir as mkdir8, rm as rm4 } from "fs/promises";
|
|
8675
8809
|
import path37 from "path";
|
|
8676
8810
|
|
|
8677
8811
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
@@ -10429,7 +10563,7 @@ class AllRoutesBuilder {
|
|
|
10429
10563
|
}
|
|
10430
10564
|
}
|
|
10431
10565
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
10432
|
-
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
10566
|
+
import { mkdir as mkdir5, rm as rm2, unlink } from "fs/promises";
|
|
10433
10567
|
import path24 from "path";
|
|
10434
10568
|
|
|
10435
10569
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
@@ -10559,7 +10693,7 @@ class CsrArtifactBuilder {
|
|
|
10559
10693
|
const artifact = await this.#loadCsrArtifact();
|
|
10560
10694
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
10561
10695
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
10562
|
-
await
|
|
10696
|
+
await rm2(this.#outputDir, { recursive: true, force: true });
|
|
10563
10697
|
await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
10564
10698
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
10565
10699
|
const result = await Bun.build({
|
|
@@ -11293,7 +11427,7 @@ class DevChangePlanner {
|
|
|
11293
11427
|
}
|
|
11294
11428
|
var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
|
|
11295
11429
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
11296
|
-
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as
|
|
11430
|
+
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm3, stat as stat3, writeFile } from "fs/promises";
|
|
11297
11431
|
import path28 from "path";
|
|
11298
11432
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
11299
11433
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
@@ -11376,7 +11510,7 @@ class DevGeneratedIndexSync {
|
|
|
11376
11510
|
if (content === null) {
|
|
11377
11511
|
if (!await exists(indexPath))
|
|
11378
11512
|
return false;
|
|
11379
|
-
await
|
|
11513
|
+
await rm3(indexPath, { force: true });
|
|
11380
11514
|
return true;
|
|
11381
11515
|
}
|
|
11382
11516
|
const current = await readFile(indexPath, "utf8").catch(() => null);
|
|
@@ -12523,7 +12657,7 @@ class ApplicationBuildRunner {
|
|
|
12523
12657
|
await this.#app.getPageKeys({ refresh: true });
|
|
12524
12658
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
12525
12659
|
if (clean)
|
|
12526
|
-
await
|
|
12660
|
+
await rm4(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
12527
12661
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
12528
12662
|
}
|
|
12529
12663
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -12723,7 +12857,7 @@ void run().catch((error) => {
|
|
|
12723
12857
|
}
|
|
12724
12858
|
}
|
|
12725
12859
|
// pkgs/@akanjs/devkit/applicationReleasePackager.ts
|
|
12726
|
-
import { cp, mkdir as mkdir9, rm as
|
|
12860
|
+
import { cp, mkdir as mkdir9, rm as rm5 } from "fs/promises";
|
|
12727
12861
|
import path38 from "path";
|
|
12728
12862
|
|
|
12729
12863
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
@@ -12830,7 +12964,7 @@ class ApplicationReleasePackager {
|
|
|
12830
12964
|
const platformVersion = akanConfig2.mobile.version;
|
|
12831
12965
|
const buildRoot = `${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}`;
|
|
12832
12966
|
if (await FileSys.dirExists(buildRoot))
|
|
12833
|
-
await
|
|
12967
|
+
await rm5(buildRoot, { recursive: true, force: true });
|
|
12834
12968
|
await mkdir9(buildRoot, { recursive: true });
|
|
12835
12969
|
if (rebuild || !await FileSys.dirExists(`${this.#app.dist.cwdPath}/backend`))
|
|
12836
12970
|
await this.#build();
|
|
@@ -12839,7 +12973,7 @@ class ApplicationReleasePackager {
|
|
|
12839
12973
|
await mkdir9(buildPath, { recursive: true });
|
|
12840
12974
|
await cp(`${this.#app.dist.cwdPath}/backend`, `${buildPath}/backend`, { recursive: true });
|
|
12841
12975
|
await cp(this.#app.dist.cwdPath, buildRoot, { recursive: true });
|
|
12842
|
-
await
|
|
12976
|
+
await rm5(`${buildRoot}/frontend/.next`, { recursive: true, force: true });
|
|
12843
12977
|
const releaseRoot = this.#app.workspace.workspaceRoot;
|
|
12844
12978
|
const releaseArchivePath = path38.relative(releaseRoot, `${releaseRoot}/releases/builds/${this.#app.name}-release.tar.gz`).split(path38.sep).join("/");
|
|
12845
12979
|
await this.#app.workspace.spawn("tar", ["-zcf", releaseArchivePath, "-C", buildRoot, "./"], { cwd: releaseRoot });
|
|
@@ -12855,7 +12989,7 @@ class ApplicationReleasePackager {
|
|
|
12855
12989
|
`${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}-appBuild.zip`,
|
|
12856
12990
|
"./csr"
|
|
12857
12991
|
]);
|
|
12858
|
-
await
|
|
12992
|
+
await rm5("./csr", { recursive: true, force: true });
|
|
12859
12993
|
}
|
|
12860
12994
|
async#writeSourceArchive({ readme }) {
|
|
12861
12995
|
const sourceRoot = `${this.#app.workspace.workspaceRoot}/releases/sources/${this.#app.name}`;
|
|
@@ -12866,7 +13000,7 @@ class ApplicationReleasePackager {
|
|
|
12866
13000
|
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path39) => {
|
|
12867
13001
|
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path39}`;
|
|
12868
13002
|
if (await FileSys.dirExists(targetPath))
|
|
12869
|
-
await
|
|
13003
|
+
await rm5(targetPath, { recursive: true, force: true });
|
|
12870
13004
|
}));
|
|
12871
13005
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
12872
13006
|
await Promise.all(syncPaths.map((path39) => cp(`${this.#app.workspace.cwdPath}/${path39}`, `${sourceRoot}/${path39}`, { recursive: true })));
|
|
@@ -12881,7 +13015,7 @@ class ApplicationReleasePackager {
|
|
|
12881
13015
|
const maxRetry = 3;
|
|
12882
13016
|
for (let i = 0;i < maxRetry; i++) {
|
|
12883
13017
|
try {
|
|
12884
|
-
await
|
|
13018
|
+
await rm5(sourceRoot, { recursive: true, force: true });
|
|
12885
13019
|
} catch {}
|
|
12886
13020
|
}
|
|
12887
13021
|
}
|
|
@@ -13114,7 +13248,7 @@ class Builder {
|
|
|
13114
13248
|
}
|
|
13115
13249
|
}
|
|
13116
13250
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
13117
|
-
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as
|
|
13251
|
+
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as rm6, writeFile as writeFile2 } from "fs/promises";
|
|
13118
13252
|
import os from "os";
|
|
13119
13253
|
import path41 from "path";
|
|
13120
13254
|
import { select as select2 } from "@inquirer/prompts";
|
|
@@ -13325,7 +13459,7 @@ var rootCapacitorConfigFilenames = [
|
|
|
13325
13459
|
];
|
|
13326
13460
|
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path41.join(appRoot, file));
|
|
13327
13461
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
13328
|
-
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) =>
|
|
13462
|
+
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm6(file, { force: true })));
|
|
13329
13463
|
}
|
|
13330
13464
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
13331
13465
|
await clearRootCapacitorConfigs(appRoot);
|
|
@@ -13346,6 +13480,7 @@ var getLocalIP = () => {
|
|
|
13346
13480
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13347
13481
|
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
13348
13482
|
var firstString = (...values) => values.find((value) => typeof value === "string");
|
|
13483
|
+
var resolveIosApnsEnvironment = ({ operation }) => operation === "release" ? "production" : "development";
|
|
13349
13484
|
var scoreIosDeviceTarget = (target) => {
|
|
13350
13485
|
const state = target.state?.toLowerCase() ?? "";
|
|
13351
13486
|
return (state.includes("available") ? 4 : 0) + (state.includes("wired") ? 2 : 0) + (state.includes("paired") ? 1 : 0);
|
|
@@ -13651,6 +13786,8 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13651
13786
|
const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
|
|
13652
13787
|
const pluginsConfig = isRecord2(plugins) ? plugins : {};
|
|
13653
13788
|
const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
|
|
13789
|
+
const pushNotificationsPluginConfig = isRecord2(pluginsConfig.PushNotifications) ? pluginsConfig.PushNotifications : {};
|
|
13790
|
+
const usesPushNotifications = target.permissions?.includes("push") ?? false;
|
|
13654
13791
|
const config = {
|
|
13655
13792
|
...capacitorConfig,
|
|
13656
13793
|
appId,
|
|
@@ -13659,6 +13796,12 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13659
13796
|
plugins: {
|
|
13660
13797
|
CapacitorCookies: { enabled: true },
|
|
13661
13798
|
...pluginsConfig,
|
|
13799
|
+
...usesPushNotifications || isRecord2(pluginsConfig.PushNotifications) ? {
|
|
13800
|
+
PushNotifications: {
|
|
13801
|
+
...usesPushNotifications ? { presentationOptions: ["badge", "sound", "alert"] } : {},
|
|
13802
|
+
...pushNotificationsPluginConfig
|
|
13803
|
+
}
|
|
13804
|
+
} : {},
|
|
13662
13805
|
Keyboard: {
|
|
13663
13806
|
resize: "none",
|
|
13664
13807
|
...keyboardPluginConfig
|
|
@@ -13730,9 +13873,9 @@ class CapacitorApp {
|
|
|
13730
13873
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
13731
13874
|
if (regenerate) {
|
|
13732
13875
|
if (!platform || platform === "ios")
|
|
13733
|
-
await
|
|
13876
|
+
await rm6(path41.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
13734
13877
|
if (!platform || platform === "android")
|
|
13735
|
-
await
|
|
13878
|
+
await rm6(path41.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
13736
13879
|
}
|
|
13737
13880
|
const project = this.project;
|
|
13738
13881
|
await this.project.load();
|
|
@@ -13754,7 +13897,7 @@ class CapacitorApp {
|
|
|
13754
13897
|
await this.#prepareTargetAssets();
|
|
13755
13898
|
await this.#prepareExternalFiles("ios");
|
|
13756
13899
|
await this.#applyIosMetadata();
|
|
13757
|
-
await this.#applyPermissions();
|
|
13900
|
+
await this.#applyPermissions({ operation, env });
|
|
13758
13901
|
await this.#applyDeepLinks("ios", { operation, env });
|
|
13759
13902
|
await this.project.commit();
|
|
13760
13903
|
await this.#generateAssets({ operation, env });
|
|
@@ -13897,7 +14040,7 @@ ${error.message}`;
|
|
|
13897
14040
|
await this.#prepareTargetAssets();
|
|
13898
14041
|
await this.#prepareExternalFiles("android");
|
|
13899
14042
|
await this.#applyAndroidMetadata();
|
|
13900
|
-
await this.#applyPermissions();
|
|
14043
|
+
await this.#applyPermissions({ operation, env });
|
|
13901
14044
|
await this.#applyDeepLinks("android", { operation, env });
|
|
13902
14045
|
await this.project.commit();
|
|
13903
14046
|
await this.#generateAssets({ operation, env });
|
|
@@ -14031,7 +14174,7 @@ ${error.message}`;
|
|
|
14031
14174
|
const htmlSource = path41.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
14032
14175
|
if (!await Bun.file(htmlSource).exists())
|
|
14033
14176
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
14034
|
-
await
|
|
14177
|
+
await rm6(this.targetWebRoot, { recursive: true, force: true });
|
|
14035
14178
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
14036
14179
|
await Bun.write(path41.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
14037
14180
|
}
|
|
@@ -14112,7 +14255,7 @@ ${error.message}`;
|
|
|
14112
14255
|
await this.project.android.setVersionCode(this.target.buildNum);
|
|
14113
14256
|
await this.project.android.setAppName(this.target.appName);
|
|
14114
14257
|
}
|
|
14115
|
-
async#applyPermissions() {
|
|
14258
|
+
async#applyPermissions({ operation, env }) {
|
|
14116
14259
|
for (const permission of this.target.permissions ?? []) {
|
|
14117
14260
|
if (permission === "camera")
|
|
14118
14261
|
await this.addCamera();
|
|
@@ -14121,7 +14264,7 @@ ${error.message}`;
|
|
|
14121
14264
|
else if (permission === "location")
|
|
14122
14265
|
await this.addLocation();
|
|
14123
14266
|
else if (permission === "push")
|
|
14124
|
-
await this.addPush();
|
|
14267
|
+
await this.addPush({ operation, env });
|
|
14125
14268
|
}
|
|
14126
14269
|
}
|
|
14127
14270
|
async#applyDeepLinks(platform, { operation, env }) {
|
|
@@ -14140,7 +14283,7 @@ ${error.message}`;
|
|
|
14140
14283
|
await this.#setUrlSchemesInIos(schemes);
|
|
14141
14284
|
}
|
|
14142
14285
|
if (domains.length > 0)
|
|
14143
|
-
await this.#setAssociatedDomainsInIos(domains);
|
|
14286
|
+
await this.#setAssociatedDomainsInIos(domains, { operation, env });
|
|
14144
14287
|
return;
|
|
14145
14288
|
}
|
|
14146
14289
|
if (platform === "android") {
|
|
@@ -14234,12 +14377,64 @@ ${error.message}`;
|
|
|
14234
14377
|
this.#setPermissionsInAndroid(["ACCESS_COARSE_LOCATION", "ACCESS_FINE_LOCATION"]);
|
|
14235
14378
|
this.#setFeaturesInAndroid(["android.hardware.location.gps"]);
|
|
14236
14379
|
}
|
|
14237
|
-
async addPush() {
|
|
14380
|
+
async addPush({ operation, env }) {
|
|
14238
14381
|
await this.#setPermissionInIos({
|
|
14239
14382
|
userNotificationsUsageDescription: "$(PRODUCT_NAME) uses notifications to keep you updated."
|
|
14240
14383
|
});
|
|
14384
|
+
await Promise.all([
|
|
14385
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", { UIBackgroundModes: ["remote-notification"] }),
|
|
14386
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { UIBackgroundModes: ["remote-notification"] }),
|
|
14387
|
+
this.#writeEntitlementsInIos(this.target.deepLinks?.domains ?? [], { operation, env }),
|
|
14388
|
+
this.#ensurePushAppDelegateInIos()
|
|
14389
|
+
]);
|
|
14241
14390
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
14242
14391
|
}
|
|
14392
|
+
async#ensurePushAppDelegateInIos() {
|
|
14393
|
+
const appDelegatePath = path41.join(this.app.cwdPath, this.iosProjectPath, "App/AppDelegate.swift");
|
|
14394
|
+
if (!await Bun.file(appDelegatePath).exists())
|
|
14395
|
+
return;
|
|
14396
|
+
const editor = await FileEditor.create(appDelegatePath);
|
|
14397
|
+
let content = editor.getContent();
|
|
14398
|
+
if (!content.includes("import FirebaseCore")) {
|
|
14399
|
+
content = content.replace("import Capacitor", `import Capacitor
|
|
14400
|
+
import FirebaseCore`);
|
|
14401
|
+
}
|
|
14402
|
+
if (!content.includes("import FirebaseMessaging")) {
|
|
14403
|
+
content = content.replace("import FirebaseCore", `import FirebaseCore
|
|
14404
|
+
import FirebaseMessaging`);
|
|
14405
|
+
}
|
|
14406
|
+
if (!content.includes("FirebaseApp.configure()")) {
|
|
14407
|
+
content = content.replace(/\n(\s*)return true/, `
|
|
14408
|
+
$1FirebaseApp.configure()
|
|
14409
|
+
|
|
14410
|
+
$1return true`);
|
|
14411
|
+
}
|
|
14412
|
+
if (!content.includes("didRegisterForRemoteNotificationsWithDeviceToken")) {
|
|
14413
|
+
const delegateMethods = `
|
|
14414
|
+
func application(_ application: UIApplication,
|
|
14415
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
14416
|
+
Messaging.messaging().apnsToken = deviceToken
|
|
14417
|
+
NotificationCenter.default.post(
|
|
14418
|
+
name: .capacitorDidRegisterForRemoteNotifications,
|
|
14419
|
+
object: deviceToken
|
|
14420
|
+
)
|
|
14421
|
+
}
|
|
14422
|
+
|
|
14423
|
+
func application(_ application: UIApplication,
|
|
14424
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
14425
|
+
NotificationCenter.default.post(
|
|
14426
|
+
name: .capacitorDidFailToRegisterForRemoteNotifications,
|
|
14427
|
+
object: error
|
|
14428
|
+
)
|
|
14429
|
+
}
|
|
14430
|
+
`;
|
|
14431
|
+
content = content.replace(`
|
|
14432
|
+
func applicationWillResignActive`, `${delegateMethods}
|
|
14433
|
+
func applicationWillResignActive`);
|
|
14434
|
+
}
|
|
14435
|
+
if (content !== editor.getContent())
|
|
14436
|
+
await editor.setContent(content).save();
|
|
14437
|
+
}
|
|
14243
14438
|
async#setPermissionInIos(permissions) {
|
|
14244
14439
|
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
|
|
14245
14440
|
await Promise.all([
|
|
@@ -14257,25 +14452,35 @@ ${error.message}`;
|
|
|
14257
14452
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { CFBundleURLTypes: urlTypes })
|
|
14258
14453
|
]);
|
|
14259
14454
|
}
|
|
14260
|
-
async#setAssociatedDomainsInIos(domains) {
|
|
14455
|
+
async#setAssociatedDomainsInIos(domains, { operation, env }) {
|
|
14456
|
+
await this.#writeEntitlementsInIos(domains, { operation, env });
|
|
14457
|
+
}
|
|
14458
|
+
async#writeEntitlementsInIos(domains, runConfig) {
|
|
14261
14459
|
const entitlementsRelPath = "App/App.entitlements";
|
|
14262
14460
|
const entitlementsPath = path41.join(this.app.cwdPath, this.iosProjectPath, entitlementsRelPath);
|
|
14263
14461
|
const values = domains.map((domain) => `applinks:${domain}`);
|
|
14462
|
+
const usesPush = this.target.permissions?.includes("push") ?? false;
|
|
14463
|
+
const apsEnvironment = resolveIosApnsEnvironment(runConfig);
|
|
14264
14464
|
const body = [
|
|
14265
14465
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
14266
14466
|
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
14267
14467
|
'<plist version="1.0">',
|
|
14268
14468
|
"<dict>",
|
|
14269
|
-
" <key>
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
|
|
14469
|
+
...usesPush ? [" <key>aps-environment</key>", ` <string>${apsEnvironment}</string>`] : [],
|
|
14470
|
+
...values.length > 0 ? [
|
|
14471
|
+
" <key>com.apple.developer.associated-domains</key>",
|
|
14472
|
+
" <array>",
|
|
14473
|
+
...values.map((value) => ` <string>${value}</string>`),
|
|
14474
|
+
" </array>"
|
|
14475
|
+
] : [],
|
|
14273
14476
|
"</dict>",
|
|
14274
14477
|
"</plist>",
|
|
14275
14478
|
""
|
|
14276
14479
|
].join(`
|
|
14277
14480
|
`);
|
|
14278
|
-
await
|
|
14481
|
+
const currentBody = await Bun.file(entitlementsPath).exists() ? await Bun.file(entitlementsPath).text() : undefined;
|
|
14482
|
+
if (currentBody !== body)
|
|
14483
|
+
await writeFile2(entitlementsPath, body);
|
|
14279
14484
|
await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
|
|
14280
14485
|
}
|
|
14281
14486
|
async#setCodeSignEntitlementsInIos(entitlementsRelPath) {
|
|
@@ -14379,7 +14584,7 @@ ${filter}$1`);
|
|
|
14379
14584
|
for (const permission of permissions) {
|
|
14380
14585
|
if (this.#hasPermissionInAndroid(permission)) {
|
|
14381
14586
|
this.app.logger.info(`${permission} already exists in android`);
|
|
14382
|
-
|
|
14587
|
+
continue;
|
|
14383
14588
|
}
|
|
14384
14589
|
this.app.logger.info(`Adding ${permission} to android`);
|
|
14385
14590
|
this.project.android.getAndroidManifest().injectFragment("manifest", `<uses-permission android:name="android.permission.${permission}" />`);
|
|
@@ -14395,7 +14600,7 @@ ${filter}$1`);
|
|
|
14395
14600
|
return Array.from(usesPermission).map((permission) => permission.getAttribute("android:name"));
|
|
14396
14601
|
}
|
|
14397
14602
|
#hasPermissionInAndroid(permission) {
|
|
14398
|
-
return this.#getPermissionsInAndroid().includes(permission);
|
|
14603
|
+
return this.#getPermissionsInAndroid().includes(`android.permission.${permission}`);
|
|
14399
14604
|
}
|
|
14400
14605
|
}
|
|
14401
14606
|
// pkgs/@akanjs/devkit/commandDecorators/targetMeta.ts
|
|
@@ -18092,8 +18297,7 @@ var addEnumFieldWorkflowSpec = {
|
|
|
18092
18297
|
predictedChanges: [
|
|
18093
18298
|
{ target: "*/lib/<module>/<module>.constant.ts", action: "modify", reason: "Enum field shape is added." },
|
|
18094
18299
|
{ target: "*/lib/<module>/<module>.dictionary.ts", action: "modify", reason: "Enum labels are added." },
|
|
18095
|
-
{ target: "*/lib/<module>/<module>.option.ts", action: "modify", reason: "Enum options may be added." }
|
|
18096
|
-
{ target: "*/lib/option.ts", action: "sync", reason: "Generated option barrel may change after sync." }
|
|
18300
|
+
{ target: "*/lib/<module>/<module>.option.ts", action: "modify", reason: "Enum options may be added." }
|
|
18097
18301
|
],
|
|
18098
18302
|
validation: [
|
|
18099
18303
|
...baseValidation,
|
|
@@ -18498,8 +18702,7 @@ var createScalarWorkflowSpec = {
|
|
|
18498
18702
|
}
|
|
18499
18703
|
],
|
|
18500
18704
|
predictedChanges: [
|
|
18501
|
-
{ target: "*/lib/__scalar/<scalar>/*", action: "create", reason: "New scalar source files are scaffolded." }
|
|
18502
|
-
{ target: "*/lib/option.ts", action: "sync", reason: "Generated option barrel may include scalar options." }
|
|
18705
|
+
{ target: "*/lib/__scalar/<scalar>/*", action: "create", reason: "New scalar source files are scaffolded." }
|
|
18503
18706
|
],
|
|
18504
18707
|
validation: baseValidation,
|
|
18505
18708
|
completionCriteria: ["Scalar files exist under __scalar.", "Generated files are refreshed.", "Lint passes."]
|
|
@@ -20370,14 +20573,18 @@ class ContextRunner extends runner("context") {
|
|
|
20370
20573
|
return await Prompter.getInstruction(name);
|
|
20371
20574
|
}
|
|
20372
20575
|
async installMcp(workspace, target, { force = false, mode = "readonly" } = {}) {
|
|
20373
|
-
if (target
|
|
20374
|
-
|
|
20375
|
-
|
|
20576
|
+
if (target === "codex")
|
|
20577
|
+
return await this.#installCodexMcp(workspace, { force, mode });
|
|
20578
|
+
return await this.#installJsonMcp(workspace, target, { force, mode });
|
|
20579
|
+
}
|
|
20580
|
+
async#installJsonMcp(workspace, target, { force, mode }) {
|
|
20581
|
+
const configPath2 = akanMcpInstallConfigPaths[target];
|
|
20582
|
+
const existing = await workspace.exists(configPath2) ? await workspace.readJson(configPath2) : {};
|
|
20376
20583
|
const mcpServers = existing.mcpServers ?? {};
|
|
20377
20584
|
const currentAkanServer = mcpServers.akan;
|
|
20378
|
-
const nextAkanServer =
|
|
20585
|
+
const nextAkanServer = createAkanMcpServer(target, mode);
|
|
20379
20586
|
if (currentAkanServer && !force && JSON.stringify(currentAkanServer) !== JSON.stringify(nextAkanServer)) {
|
|
20380
|
-
throw new Error(`${
|
|
20587
|
+
throw new Error(`${configPath2} already has an "akan" MCP server. Re-run with --force to overwrite it.`);
|
|
20381
20588
|
}
|
|
20382
20589
|
const nextConfig = {
|
|
20383
20590
|
...existing,
|
|
@@ -20386,9 +20593,15 @@ class ContextRunner extends runner("context") {
|
|
|
20386
20593
|
akan: nextAkanServer
|
|
20387
20594
|
}
|
|
20388
20595
|
};
|
|
20389
|
-
await workspace.writeFile(
|
|
20596
|
+
await workspace.writeFile(configPath2, `${JSON.stringify(nextConfig, null, 2)}
|
|
20390
20597
|
`);
|
|
20391
|
-
return
|
|
20598
|
+
return configPath2;
|
|
20599
|
+
}
|
|
20600
|
+
async#installCodexMcp(workspace, { force, mode }) {
|
|
20601
|
+
const existing = await workspace.exists(codexMcpConfigPath) ? await workspace.readFile(codexMcpConfigPath) : "";
|
|
20602
|
+
const merged = upsertCodexMcpServerBlock(existing, createAkanCodexMcpServerBlock(mode), { force });
|
|
20603
|
+
await workspace.writeFile(codexMcpConfigPath, merged);
|
|
20604
|
+
return codexMcpConfigPath;
|
|
20392
20605
|
}
|
|
20393
20606
|
listMcpTools(mode = "readonly") {
|
|
20394
20607
|
return listAkanMcpTools(mode);
|
|
@@ -20680,13 +20893,26 @@ ${payload}`);
|
|
|
20680
20893
|
agent: "`akan agent install <target>` writes editor-specific agent rules with overwrite protection.",
|
|
20681
20894
|
mcp: "`akan mcp --mode readonly|plan|apply` starts the Akan MCP server over stdio with an explicit permission mode.",
|
|
20682
20895
|
"mcp-call": '`akan mcp-call <tool> --mode plan --args \'{"workflow":"add-field","inputs":{"app":"demo"}}\'` calls one MCP tool through the same runner path for debugging.',
|
|
20683
|
-
"mcp-install": "`akan mcp-install cursor --mode readonly|plan|apply` installs the Akan MCP server config for Cursor."
|
|
20896
|
+
"mcp-install": "`akan mcp-install [cursor|claude|codex|all] --mode readonly|plan|apply` installs the Akan MCP server config for Cursor (.cursor/mcp.json), Claude Code (.mcp.json), and Codex (.codex/config.toml). Defaults to all targets."
|
|
20684
20897
|
};
|
|
20685
20898
|
return explanations[command3] ?? `No detailed explanation is available for ${command3}. Run \`akan --help\` for command help.`;
|
|
20686
20899
|
}
|
|
20687
20900
|
}
|
|
20688
20901
|
|
|
20689
20902
|
// pkgs/@akanjs/cli/context/context.script.ts
|
|
20903
|
+
var resolveMcpInstallTargets = (target) => {
|
|
20904
|
+
if (!target || target === "all")
|
|
20905
|
+
return [...akanMcpInstallTargets];
|
|
20906
|
+
if (akanMcpInstallTargets.includes(target))
|
|
20907
|
+
return [target];
|
|
20908
|
+
throw new Error(`Unknown MCP install target: ${target}. Use cursor, claude, codex, or all.`);
|
|
20909
|
+
};
|
|
20910
|
+
var mcpTargetLabels = {
|
|
20911
|
+
cursor: "Cursor",
|
|
20912
|
+
claude: "Claude Code",
|
|
20913
|
+
codex: "Codex"
|
|
20914
|
+
};
|
|
20915
|
+
|
|
20690
20916
|
class ContextScript extends script("context", [ContextRunner]) {
|
|
20691
20917
|
async context(workspace, options = {}) {
|
|
20692
20918
|
Logger17.rawLog(await this.contextRunner.getContext(workspace, options));
|
|
@@ -20695,11 +20921,15 @@ class ContextScript extends script("context", [ContextRunner]) {
|
|
|
20695
20921
|
Logger17.rawLog(await this.contextRunner.doctor(workspace, options));
|
|
20696
20922
|
}
|
|
20697
20923
|
async mcpInstall(workspace, target, { force = false, mode = "readonly" } = {}) {
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
const
|
|
20701
|
-
|
|
20702
|
-
|
|
20924
|
+
const targets = resolveMcpInstallTargets(target);
|
|
20925
|
+
const written = [];
|
|
20926
|
+
for (const t of targets) {
|
|
20927
|
+
const configPath2 = await this.contextRunner.installMcp(workspace, t, { force, mode });
|
|
20928
|
+
written.push(`${mcpTargetLabels[t]}: ${configPath2}`);
|
|
20929
|
+
}
|
|
20930
|
+
Logger17.rawLog(`Akan MCP server installed (${mode} mode):
|
|
20931
|
+
${written.map((line) => `- ${line}`).join(`
|
|
20932
|
+
`)}`);
|
|
20703
20933
|
}
|
|
20704
20934
|
async mcp(workspace, { mode = "readonly" } = {}) {
|
|
20705
20935
|
await this.contextRunner.runMcp(workspace, { mode });
|
|
@@ -20738,7 +20968,7 @@ class ContextCommand extends command("context", [ContextScript], ({ public: targ
|
|
|
20738
20968
|
}).option("strict", Boolean, { desc: "treat recommended conventions as errors", default: false }).with(Workspace).exec(async function(format, strict, workspace) {
|
|
20739
20969
|
await this.contextScript.doctor(workspace, { format, strict });
|
|
20740
20970
|
}),
|
|
20741
|
-
mcpInstall: target({ desc: "Install the Akan MCP server config for Cursor" }).arg("target", String, { desc: "cursor", nullable: true }).option("force", Boolean, { desc: "overwrite an existing Akan MCP server entry", default: false }).option("mode", String, {
|
|
20971
|
+
mcpInstall: target({ desc: "Install the Akan MCP server config for Cursor, Claude Code, and Codex" }).arg("target", String, { desc: "cursor, claude, codex, or all", nullable: true }).option("force", Boolean, { desc: "overwrite an existing Akan MCP server entry", default: false }).option("mode", String, {
|
|
20742
20972
|
desc: "MCP permission mode",
|
|
20743
20973
|
default: "readonly",
|
|
20744
20974
|
enum: ["readonly", "plan", "apply"]
|
|
@@ -21123,7 +21353,7 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
|
|
|
21123
21353
|
}
|
|
21124
21354
|
|
|
21125
21355
|
// pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
|
|
21126
|
-
import { mkdir as mkdir13, rm as
|
|
21356
|
+
import { mkdir as mkdir13, rm as rm7 } from "fs/promises";
|
|
21127
21357
|
import path47 from "path";
|
|
21128
21358
|
import { Logger as Logger19 } from "akanjs/common";
|
|
21129
21359
|
var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
|
|
@@ -21166,13 +21396,13 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
21166
21396
|
try {
|
|
21167
21397
|
await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
|
|
21168
21398
|
} catch {}
|
|
21169
|
-
await
|
|
21399
|
+
await rm7(path47.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
|
|
21170
21400
|
Logger19.info("Local registry storage has been reset");
|
|
21171
21401
|
}
|
|
21172
21402
|
async smoke(workspace, { registryUrl } = {}) {
|
|
21173
21403
|
const registry = this.getRegistryUrl(registryUrl);
|
|
21174
21404
|
const smokeRoot = path47.join(workspace.workspaceRoot, ".akan/e2e");
|
|
21175
|
-
await
|
|
21405
|
+
await rm7(path47.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
|
|
21176
21406
|
await workspace.spawn(process.execPath, [
|
|
21177
21407
|
"dist/pkgs/create-akan-workspace/index.js",
|
|
21178
21408
|
smokeRepoName,
|