@akanjs/cli 3.0.2 → 3.1.0-rc.0
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-szbjv4gv.js → CodeAgent-q7a4srt6.js} +2 -2
- package/{CodeTui-5nw86ab6.js → CodeTui-ak23dxc9.js} +1 -1
- package/{TunnelShare-cwh9ezsm.js → TunnelShare-21mm6dr5.js} +2 -2
- package/{agent.command-np1dffkb.js → agent.command-f3gsc1gd.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-gk69v1xs.js → application.command-3v2d53gd.js} +37 -15
- package/{applicationBuildRunner-wx09n9g6.js → applicationBuildRunner-1yaqsrdq.js} +115 -103
- package/buildBatch.proc.js +16 -5
- package/cloud.command-kk2rwkvw.js +187 -0
- package/cloud.script-r7eyfey4.js +20 -0
- package/{code.command-hmtx14b2.js → code.command-30sca09d.js} +6 -6
- package/commandManifest.json +1 -1
- package/{context.command-6aqvdx43.js → context.command-k7eqacq6.js} +13 -13
- package/context.runner-hqd1ppqe.js +21 -0
- package/{guideline.command-axvf68gc.js → guideline.command-dtczrqpf.js} +2 -2
- package/guidelines/agentRule/agentRule.instruction.md +10 -2
- package/guidelines/conventions/conventions.instruction.md +68 -25
- package/guidelines/cssRule/cssRule.instruction.md +19 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +67 -12
- package/guidelines/queryRule/queryRule.instruction.md +11 -1
- package/guidelines/runtimeRule/runtimeRule.instruction.md +97 -16
- package/guidelines/ssrRule/ssrRule.instruction.md +10 -7
- package/guidelines/transportRule/transportRule.instruction.md +19 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +6 -6
- package/incrementalBuilder.proc.js +24 -3
- package/{index-h9ht6s60.js → index-05g3jayg.js} +1 -1
- package/{index-j38qkvkk.js → index-0bm04n5g.js} +12 -10
- package/{index-g38nhv87.js → index-2etcv0sc.js} +1 -1
- package/{index-zyw622y1.js → index-2mx692qq.js} +3 -3
- package/{index-jb0hmt3k.js → index-2t4tqd1c.js} +3 -3
- package/{index-50wb2a26.js → index-55mynnqs.js} +354 -129
- package/{index-q6ft9fkc.js → index-6jjtnhkw.js} +8 -3
- package/index-6w0rbr9d.js +68 -0
- package/{index-2wc41k5w.js → index-7bymavqk.js} +2 -2
- package/{index-gtjgnv36.js → index-aprt7pkz.js} +6 -9
- package/{index-1bjkfvm9.js → index-c1x0be5j.js} +2 -2
- package/{index-z750gk1j.js → index-c2yrsxdh.js} +13 -7
- package/{index-cb6yc5mb.js → index-c76k723e.js} +2 -2
- package/{index-6keyf4sg.js → index-ctanya41.js} +4 -4
- package/{index-f4e08ptp.js → index-e0cvze1s.js} +4 -4
- package/{index-hp3stk1m.js → index-fm46xrf1.js} +3 -3
- package/{index-3xmzr1p1.js → index-gnyf1fqy.js} +2 -2
- package/{index-zwd84m0w.js → index-jyv387qw.js} +4 -4
- package/{index-jk9xnck6.js → index-kjvrq3nc.js} +231 -133
- package/{index-xwprn9nr.js → index-nz15k0b6.js} +1 -1
- package/{index-nwd6qzvv.js → index-p9ystjrp.js} +138 -55
- package/index-q958tqqg.js +77 -0
- package/{index-50jjwg8y.js → index-qt22xstj.js} +1 -1
- package/{index-94s080qm.js → index-r2tpeb3n.js} +127 -1
- package/{index-bsv901fd.js → index-rwq3ekqc.js} +7 -7
- package/{index-t91a7339.js → index-tn4rpqp1.js} +96 -12
- package/{index-1gs9g12n.js → index-v29746vb.js} +4 -4
- package/index-ww9bhp67.js +62 -0
- package/{index-hxnnfy57.js → index-y8q31011.js} +180 -8
- package/index.js +22 -21
- package/{library.command-9m2rdwwz.js → library.command-gaga5bmq.js} +3 -3
- package/{localRegistry.command-kda81jyk.js → localRegistry.command-9e84e32q.js} +9 -9
- package/{module.command-q63dffya.js → module.command-7vpf6db4.js} +5 -5
- package/{package.command-y2jh0m99.js → package.command-twmvvf69.js} +3 -3
- package/package.json +2 -2
- package/{page.command-f3e4cwhh.js → page.command-5asq7fdf.js} +3 -3
- package/pipeline.command-d0v38572.js +1334 -0
- package/{primitive.command-r4kq75qj.js → primitive.command-dyrs2fm8.js} +6 -6
- package/projectTypecheck-cvtkrzp2.js +7 -0
- package/{quality.command-f7gzh26z.js → quality.command-6emsqpbg.js} +5 -4
- package/{repair.command-0qmyr6qa.js → repair.command-8t6aegv5.js} +5 -5
- package/{scalar.command-kddn7av4.js → scalar.command-bnggy1x7.js} +4 -4
- package/{subspace.command-ft65qvc4.js → subspace.command-f02j5tge.js} +158 -91
- package/templates/appSample/page/task/[taskId]/_index.tsx +2 -2
- package/templates/appSample/page/task/[taskId]/edit.tsx +2 -2
- package/templates/appSample/page/task/_index.tsx +2 -2
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -2
- package/templates/crudPages/[__model__Id]/page.tsx +3 -3
- package/templates/crudPages/page.tsx +2 -2
- package/templates/crudSinglePage/page.tsx +3 -3
- package/templates/lib/cnst.ts +2 -2
- package/templates/lib/sig.ts +3 -3
- package/{tunnel.command-b3ymdk4f.js → tunnel.command-9x8nfn75.js} +16 -13
- package/{workflow.command-z1srcdfw.js → workflow.command-jx0wag5r.js} +10 -10
- package/{workspace.command-vp6vmx3z.js → workspace.command-cmj6mqyk.js} +57 -27
- package/cloud.command-tw06613r.js +0 -95
- package/cloud.script-64gzba8r.js +0 -20
- package/context.runner-hnkvv3z3.js +0 -21
|
@@ -2,34 +2,35 @@
|
|
|
2
2
|
import {
|
|
3
3
|
GlobalConfig,
|
|
4
4
|
CloudApi
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-r2tpeb3n.js";
|
|
6
6
|
import {
|
|
7
7
|
script
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-6jjtnhkw.js";
|
|
9
9
|
import {
|
|
10
10
|
PkgExecutor
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-55mynnqs.js";
|
|
12
12
|
import {
|
|
13
13
|
ApplicationScript
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-p9ystjrp.js";
|
|
15
15
|
import {
|
|
16
16
|
PackageScript
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-gnyf1fqy.js";
|
|
18
18
|
import {
|
|
19
19
|
CloudRunner
|
|
20
|
-
} from "./index-
|
|
20
|
+
} from "./index-y8q31011.js";
|
|
21
21
|
|
|
22
22
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
23
23
|
import { Logger } from "akanjs/common";
|
|
24
24
|
class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
|
|
25
|
-
async login(workspace, host
|
|
26
|
-
await this.cloudRunner.login(host, workspace);
|
|
25
|
+
async login(workspace, host) {
|
|
26
|
+
await this.cloudRunner.login(await GlobalConfig.hostFor(workspace, host), workspace);
|
|
27
27
|
}
|
|
28
|
-
async logout(workspace, host
|
|
29
|
-
await this.cloudRunner.logout(host);
|
|
28
|
+
async logout(workspace, host) {
|
|
29
|
+
await this.cloudRunner.logout(await GlobalConfig.hostFor(workspace, host));
|
|
30
30
|
}
|
|
31
|
-
async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host
|
|
31
|
+
async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host: given } = {}) {
|
|
32
32
|
if (workspaceId) {
|
|
33
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
33
34
|
await this.login(workspace, host);
|
|
34
35
|
const cloudApi = await CloudApi.fromHost(workspace, host);
|
|
35
36
|
await this.cloudRunner.downloadEnv(cloudApi, workspace, workspaceId);
|
|
@@ -38,7 +39,7 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
|
|
|
38
39
|
await this.cloudRunner.downloadEnvByScp(workspace);
|
|
39
40
|
}
|
|
40
41
|
async uploadEnv(workspace, {
|
|
41
|
-
host
|
|
42
|
+
host: given,
|
|
42
43
|
workspaceId = workspace.getWorkspaceId({ allowEmpty: true }),
|
|
43
44
|
scope,
|
|
44
45
|
archivePath
|
|
@@ -47,6 +48,7 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
|
|
|
47
48
|
throw new Error("A scoped env upload needs a cloud workspace id \u2014 the scp target is workspace-wide.");
|
|
48
49
|
const { files, path } = await this.cloudRunner.gatherEnvFiles(workspace, { scope, archivePath });
|
|
49
50
|
if (workspaceId) {
|
|
51
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
50
52
|
await this.login(workspace, host);
|
|
51
53
|
const cloudApi = await CloudApi.fromHost(workspace, host);
|
|
52
54
|
await this.cloudRunner.uploadEnv(cloudApi, workspaceId, path);
|
|
@@ -55,6 +57,88 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
|
|
|
55
57
|
await this.cloudRunner.uploadEnvByScp(workspace, path);
|
|
56
58
|
return { workspaceId: null, files };
|
|
57
59
|
}
|
|
60
|
+
async uploadSecret(workspace, {
|
|
61
|
+
name,
|
|
62
|
+
branch,
|
|
63
|
+
file,
|
|
64
|
+
subspace,
|
|
65
|
+
host: given
|
|
66
|
+
}) {
|
|
67
|
+
const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
|
|
68
|
+
const value = await this.cloudRunner.readSecretValue(name, file);
|
|
69
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
70
|
+
await this.login(workspace, host);
|
|
71
|
+
const cloudApi = await CloudApi.fromHost(workspace, host);
|
|
72
|
+
await this.cloudRunner.uploadSecret(cloudApi, devProjectId, { name, branch, value });
|
|
73
|
+
}
|
|
74
|
+
async listSecrets(workspace, { branch, subspace, host: given }) {
|
|
75
|
+
const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
|
|
76
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
77
|
+
await this.login(workspace, host);
|
|
78
|
+
const cloudApi = await CloudApi.fromHost(workspace, host);
|
|
79
|
+
await this.cloudRunner.listSecrets(cloudApi, devProjectId, branch);
|
|
80
|
+
}
|
|
81
|
+
async removeSecret(workspace, {
|
|
82
|
+
name,
|
|
83
|
+
branch,
|
|
84
|
+
subspace,
|
|
85
|
+
host: given
|
|
86
|
+
}) {
|
|
87
|
+
const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
|
|
88
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
89
|
+
await this.login(workspace, host);
|
|
90
|
+
const cloudApi = await CloudApi.fromHost(workspace, host);
|
|
91
|
+
await this.cloudRunner.removeSecret(cloudApi, devProjectId, { name, branch });
|
|
92
|
+
}
|
|
93
|
+
async pushUpdate(workspace, app, {
|
|
94
|
+
platform,
|
|
95
|
+
target,
|
|
96
|
+
env,
|
|
97
|
+
channel,
|
|
98
|
+
notes,
|
|
99
|
+
subspace,
|
|
100
|
+
host: given,
|
|
101
|
+
write,
|
|
102
|
+
allowLocalRelease
|
|
103
|
+
}) {
|
|
104
|
+
const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
|
|
105
|
+
const pack = await this.applicationScript.packUpdate(app, platform, {
|
|
106
|
+
target,
|
|
107
|
+
env,
|
|
108
|
+
write,
|
|
109
|
+
allowLocalRelease
|
|
110
|
+
});
|
|
111
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
112
|
+
await this.login(workspace, host);
|
|
113
|
+
return await this.cloudRunner.pushUpdate(await CloudApi.fromHost(workspace, host), devProjectId, pack, {
|
|
114
|
+
channel,
|
|
115
|
+
notes
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async registerBinary(workspace, app, {
|
|
119
|
+
platform,
|
|
120
|
+
distribution,
|
|
121
|
+
target,
|
|
122
|
+
env,
|
|
123
|
+
subspace,
|
|
124
|
+
host: given,
|
|
125
|
+
write,
|
|
126
|
+
allowLocalRelease
|
|
127
|
+
}) {
|
|
128
|
+
const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
|
|
129
|
+
const pack = await this.applicationScript.packUpdate(app, platform, {
|
|
130
|
+
target,
|
|
131
|
+
env,
|
|
132
|
+
write,
|
|
133
|
+
allowLocalRelease
|
|
134
|
+
});
|
|
135
|
+
const host = await GlobalConfig.hostFor(workspace, given);
|
|
136
|
+
await this.login(workspace, host);
|
|
137
|
+
return await this.cloudRunner.registerBinary(await CloudApi.fromHost(workspace, host), devProjectId, app, pack, {
|
|
138
|
+
distribution,
|
|
139
|
+
env
|
|
140
|
+
});
|
|
141
|
+
}
|
|
58
142
|
async deployAkan(workspace, {
|
|
59
143
|
test = true,
|
|
60
144
|
registryUrl,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-6jjtnhkw.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-55mynnqs.js";
|
|
17
17
|
import {
|
|
18
18
|
collectRecipeSources2,
|
|
19
19
|
scanRecipes2
|
|
20
20
|
} from "./index-hj6w4ka1.js";
|
|
21
21
|
import {
|
|
22
22
|
AkanContextAnalyzer
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-2mx692qq.js";
|
|
24
24
|
import {
|
|
25
25
|
Prompter2
|
|
26
26
|
} from "./index-zzvvc845.js";
|
|
@@ -166,7 +166,7 @@ ${frameworkGuide.trim()}
|
|
|
166
166
|
## Before You Finish
|
|
167
167
|
|
|
168
168
|
1. \`bun run akan lint <appName>\` \u2014 Tailwind class order, \`Err\`, \`console\`, \`#private\` scope, unused imports.
|
|
169
|
-
2. \`bun run akan typecheck <appName>\` \u2014 server/client boundary violations.
|
|
169
|
+
2. \`bun run akan typecheck <appName>\` \u2014 server/client boundary violations, and the tests and specs nothing imports.
|
|
170
170
|
3. \`bun run akan sync <appName>\` if you added, renamed, or deleted any file.
|
|
171
171
|
4. Did you write or change a \`.tsx\` file? \`bun run akan quality ssr\` \u2014 did the server share hold, and did you add
|
|
172
172
|
a \`"use client"\` you cannot justify?
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// pkgs/@akanjs/devkit/subspaceConfig.ts
|
|
3
|
+
class SubspaceConfig {
|
|
4
|
+
static source = "subspace in the workspace root akan.config.ts";
|
|
5
|
+
static defaultPushableBranches = ["main", "develop", "debug"];
|
|
6
|
+
static async from(workspace) {
|
|
7
|
+
const { subspace } = await workspace.getConfig();
|
|
8
|
+
return subspace ? new SubspaceConfig(subspace) : null;
|
|
9
|
+
}
|
|
10
|
+
pushableBranches;
|
|
11
|
+
exclude;
|
|
12
|
+
subspaces;
|
|
13
|
+
constructor(input) {
|
|
14
|
+
this.pushableBranches = input.pushableBranches ?? SubspaceConfig.defaultPushableBranches;
|
|
15
|
+
this.exclude = input.exclude ?? [];
|
|
16
|
+
this.subspaces = input.subspaces ?? [];
|
|
17
|
+
this.#assertValid();
|
|
18
|
+
}
|
|
19
|
+
#assertValid() {
|
|
20
|
+
const seenNames = new Set;
|
|
21
|
+
const appOwners = new Map;
|
|
22
|
+
const idOwners = new Map;
|
|
23
|
+
for (const subspace of this.subspaces) {
|
|
24
|
+
if (!subspace.name || !subspace.repo)
|
|
25
|
+
throw new Error(`${SubspaceConfig.source}: every subspace needs a name and a repo`);
|
|
26
|
+
if (seenNames.has(subspace.name))
|
|
27
|
+
throw new Error(`${SubspaceConfig.source}: duplicate subspace "${subspace.name}"`);
|
|
28
|
+
seenNames.add(subspace.name);
|
|
29
|
+
if (!subspace.apps?.length)
|
|
30
|
+
throw new Error(`${SubspaceConfig.source}: subspace "${subspace.name}" declares no apps`);
|
|
31
|
+
for (const app of subspace.apps) {
|
|
32
|
+
const owner = appOwners.get(app);
|
|
33
|
+
if (owner)
|
|
34
|
+
throw new Error(`${SubspaceConfig.source}: app "${app}" is claimed by both "${owner}" and "${subspace.name}"`);
|
|
35
|
+
appOwners.set(app, subspace.name);
|
|
36
|
+
}
|
|
37
|
+
if (!subspace.workspaceId)
|
|
38
|
+
continue;
|
|
39
|
+
const idOwner = idOwners.get(subspace.workspaceId);
|
|
40
|
+
if (idOwner)
|
|
41
|
+
throw new Error(`${SubspaceConfig.source}: subspaces "${idOwner}" and "${subspace.name}" declare the same workspaceId`);
|
|
42
|
+
idOwners.set(subspace.workspaceId, subspace.name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
select(names) {
|
|
46
|
+
if (!names.length)
|
|
47
|
+
return this.subspaces;
|
|
48
|
+
return names.map((name) => {
|
|
49
|
+
const subspace = this.subspaces.find((candidate) => candidate.name === name);
|
|
50
|
+
if (!subspace)
|
|
51
|
+
throw new Error(`${SubspaceConfig.source}: unknown subspace "${name}"`);
|
|
52
|
+
return subspace;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
assertPushable(branch) {
|
|
56
|
+
if (this.pushableBranches.includes(branch))
|
|
57
|
+
return;
|
|
58
|
+
throw new Error(`Branch "${branch}" is not pushable. ${SubspaceConfig.source} allows: ${this.pushableBranches.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { SubspaceConfig };
|
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getDefaultHostConfig,
|
|
4
4
|
GlobalConfig,
|
|
5
|
-
CloudApi
|
|
6
|
-
|
|
5
|
+
CloudApi,
|
|
6
|
+
UpdatePackUpload
|
|
7
|
+
} from "./index-r2tpeb3n.js";
|
|
7
8
|
import {
|
|
8
9
|
runner
|
|
9
|
-
} from "./index-
|
|
10
|
+
} from "./index-6jjtnhkw.js";
|
|
10
11
|
import {
|
|
11
12
|
WorkspaceExecutor,
|
|
12
13
|
AppExecutor
|
|
13
|
-
} from "./index-
|
|
14
|
+
} from "./index-55mynnqs.js";
|
|
15
|
+
import {
|
|
16
|
+
NativeApp
|
|
17
|
+
} from "./index-kjvrq3nc.js";
|
|
18
|
+
import {
|
|
19
|
+
SubspaceConfig
|
|
20
|
+
} from "./index-ww9bhp67.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveMobileTargets
|
|
23
|
+
} from "./index-q958tqqg.js";
|
|
14
24
|
import {
|
|
15
25
|
openBrowser
|
|
16
26
|
} from "./index-9dp031by.js";
|
|
@@ -647,9 +657,11 @@ class PlatformTestRun {
|
|
|
647
657
|
}
|
|
648
658
|
|
|
649
659
|
// pkgs/@akanjs/cli/cloud/cloud.runner.ts
|
|
660
|
+
import { rm } from "fs/promises";
|
|
661
|
+
import os3 from "os";
|
|
650
662
|
import path7 from "path";
|
|
651
|
-
import { confirm, input, select } from "@inquirer/prompts";
|
|
652
|
-
import { Logger, sleep } from "akanjs/common";
|
|
663
|
+
import { confirm, input, password, select } from "@inquirer/prompts";
|
|
664
|
+
import { Logger, PipelineNames, sleep } from "akanjs/common";
|
|
653
665
|
import chalk2 from "chalk";
|
|
654
666
|
import * as QRcode from "qrcode";
|
|
655
667
|
|
|
@@ -1001,14 +1013,18 @@ ${run.format(results)}
|
|
|
1001
1013
|
}
|
|
1002
1014
|
async downloadEnv(cloudApi, workspace, workspaceId) {
|
|
1003
1015
|
await workspace.mkdir("local");
|
|
1004
|
-
const localPath = await cloudApi.downloadEnv(workspaceId)
|
|
1016
|
+
const localPath = await cloudApi.downloadEnv(workspaceId).catch((error) => {
|
|
1017
|
+
throw CloudRunner.#refusal(error, "downloading its env archive takes the project owner's own `akan login`");
|
|
1018
|
+
});
|
|
1005
1019
|
const relativePath = path7.relative(workspace.workspaceRoot, localPath).split(path7.sep).join("/");
|
|
1006
1020
|
await workspace.spawn("tar", ["-xf", relativePath], { cwd: workspace.workspaceRoot });
|
|
1007
1021
|
await workspace.remove(localPath);
|
|
1008
1022
|
}
|
|
1009
1023
|
async uploadEnv(cloudApi, workspaceId, filePath) {
|
|
1010
1024
|
const file = new File([Bun.file(filePath)], path7.basename(filePath));
|
|
1011
|
-
await cloudApi.uploadEnv(workspaceId, file)
|
|
1025
|
+
await cloudApi.uploadEnv(workspaceId, file).catch((error) => {
|
|
1026
|
+
throw CloudRunner.#refusal(error, "an env archive is uploaded by a project member signed in with `akan login`");
|
|
1027
|
+
});
|
|
1012
1028
|
}
|
|
1013
1029
|
async downloadEnvByScp(workspace) {
|
|
1014
1030
|
const envArchivePath = "local/env.tar";
|
|
@@ -1080,6 +1096,162 @@ ${run.format(results)}
|
|
|
1080
1096
|
}));
|
|
1081
1097
|
return secretPaths.flat();
|
|
1082
1098
|
}
|
|
1099
|
+
async secretProject(workspace, subspace) {
|
|
1100
|
+
if (!subspace) {
|
|
1101
|
+
const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
|
|
1102
|
+
if (!workspaceId)
|
|
1103
|
+
throw new Error("AKAN_WORKSPACE_ID is not set in the workspace .env, so there is no project to address.");
|
|
1104
|
+
return workspaceId;
|
|
1105
|
+
}
|
|
1106
|
+
const config = await SubspaceConfig.from(workspace);
|
|
1107
|
+
if (!config)
|
|
1108
|
+
throw new Error("The workspace root akan.config.ts declares no `subspace`.");
|
|
1109
|
+
const [declaration] = config.select([subspace]);
|
|
1110
|
+
if (!declaration?.workspaceId)
|
|
1111
|
+
throw new Error(`Subspace "${subspace}" declares no workspaceId in ${SubspaceConfig.source}.`);
|
|
1112
|
+
return declaration.workspaceId;
|
|
1113
|
+
}
|
|
1114
|
+
async readSecretValue(name, file) {
|
|
1115
|
+
const raw = file ? await Bun.file(file).text() : process.stdin.isTTY ? await password({ message: `Value of ${name} (hidden; it can never be read back)`, mask: "*" }) : await Bun.stdin.text();
|
|
1116
|
+
const value = raw.replace(/\r?\n$/, "");
|
|
1117
|
+
if (!value)
|
|
1118
|
+
throw new Error(`The value of ${name} is empty.`);
|
|
1119
|
+
const bytes = new TextEncoder().encode(value).length;
|
|
1120
|
+
if (bytes > CloudRunner.#secretBytes)
|
|
1121
|
+
throw new Error(`The value of ${name} is ${bytes} bytes, over ${CloudRunner.#secretBytes}.`);
|
|
1122
|
+
return value;
|
|
1123
|
+
}
|
|
1124
|
+
async uploadSecret(cloudApi, devProjectId, { name, branch, value }) {
|
|
1125
|
+
CloudRunner.#assertSecretName(name);
|
|
1126
|
+
CloudRunner.#assertSecretBranch(branch);
|
|
1127
|
+
const saved = await cloudApi.uploadSecret(devProjectId, { scope: branch ?? "*", name, value }).catch((error) => {
|
|
1128
|
+
throw CloudRunner.#refusal(error, "a secret is written by a project member signed in with `akan login`", {
|
|
1129
|
+
unavailable: CloudRunner.#secretsUnavailable
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
Logger.rawLog(`Saved ${saved.name} for ${saved.scope === "*" ? "every branch" : `branch ${saved.scope}`}. Builds that start from now on use it.`);
|
|
1133
|
+
}
|
|
1134
|
+
async listSecrets(cloudApi, devProjectId, branch) {
|
|
1135
|
+
CloudRunner.#assertSecretBranch(branch);
|
|
1136
|
+
const listed = await cloudApi.listSecrets(devProjectId).catch((error) => {
|
|
1137
|
+
throw CloudRunner.#refusal(error, "the secrets are listed for a project member", {
|
|
1138
|
+
unavailable: CloudRunner.#secretsUnavailable
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
1141
|
+
const secrets = listed.filter((secret) => !branch || secret.scope === "*" || secret.scope === branch);
|
|
1142
|
+
Logger.rawLog(CloudRunner.formatSecrets(secrets));
|
|
1143
|
+
}
|
|
1144
|
+
async removeSecret(cloudApi, devProjectId, { name, branch }) {
|
|
1145
|
+
CloudRunner.#assertSecretName(name);
|
|
1146
|
+
CloudRunner.#assertSecretBranch(branch);
|
|
1147
|
+
const removed = await cloudApi.removeSecret(devProjectId, { scope: branch ?? "*", name }).catch((error) => {
|
|
1148
|
+
throw CloudRunner.#refusal(error, "a secret is removed by a project member signed in with `akan login`", {
|
|
1149
|
+
unavailable: CloudRunner.#secretsUnavailable
|
|
1150
|
+
});
|
|
1151
|
+
});
|
|
1152
|
+
Logger.rawLog(removed ? `Removed ${name} for ${branch ? `branch ${branch}` : "every branch"}.` : `No ${name} for ${branch ? `branch ${branch}` : "every branch"} to remove.`);
|
|
1153
|
+
}
|
|
1154
|
+
static async#tarPack(pack) {
|
|
1155
|
+
const archive = path7.join(os3.tmpdir(), `akan-pack-${pack.app}-${pack.target}-${pack.platform}-${process.pid}.tgz`);
|
|
1156
|
+
const tar = Bun.spawn(["tar", "-czf", archive, "-C", pack.out, "."], { stdout: "ignore", stderr: "pipe" });
|
|
1157
|
+
if (await tar.exited !== 0)
|
|
1158
|
+
throw new Error(`tar of ${pack.out} failed: ${(await new Response(tar.stderr).text()).trim()}`);
|
|
1159
|
+
return archive;
|
|
1160
|
+
}
|
|
1161
|
+
async pushUpdate(cloudApi, devProjectId, pack, { channel, notes }) {
|
|
1162
|
+
const archive = await CloudRunner.#tarPack(pack);
|
|
1163
|
+
const target = channel ?? pack.channel;
|
|
1164
|
+
try {
|
|
1165
|
+
const release = await new UpdatePackUpload(cloudApi, devProjectId).send(archive, { appName: pack.app, target: pack.target, platform: pack.platform, channel: target, notes }).catch((error) => {
|
|
1166
|
+
throw CloudRunner.#refusal(error, "a pack is uploaded by a project member signed in with `akan login`");
|
|
1167
|
+
});
|
|
1168
|
+
const label = `${pack.app} ${pack.target} ${pack.platform} on channel ${target}: release ${release.id}`;
|
|
1169
|
+
if (release.status === "rejected") {
|
|
1170
|
+
process.exitCode = 2;
|
|
1171
|
+
Logger.error(`The project rejected ${label}:
|
|
1172
|
+
${(release.problems ?? []).map((problem) => ` - ${problem}`).join(`
|
|
1173
|
+
`)}`);
|
|
1174
|
+
} else if (release.status === "published")
|
|
1175
|
+
Logger.rawLog(`Published ${label} (${pack.files} files, native API ${pack.nativeApi}).`);
|
|
1176
|
+
else
|
|
1177
|
+
Logger.rawLog(`Staged ${label} (${pack.files} files, native API ${pack.nativeApi}). Publish it from the project's release screen.`);
|
|
1178
|
+
return release;
|
|
1179
|
+
} finally {
|
|
1180
|
+
await rm(archive, { force: true });
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
async registerBinary(cloudApi, devProjectId, app, pack, { distribution, env }) {
|
|
1184
|
+
const [mobileTarget] = await resolveMobileTargets(app, pack.target);
|
|
1185
|
+
if (!mobileTarget)
|
|
1186
|
+
throw new Error(`Native target '${pack.target}' was not found.`);
|
|
1187
|
+
const bundlePath = path7.join(new NativeApp(app, mobileTarget).outDir(pack.platform), "bundle.json");
|
|
1188
|
+
const bundleFile = Bun.file(bundlePath);
|
|
1189
|
+
if (!await bundleFile.exists())
|
|
1190
|
+
throw new Error(`No store build at ${bundlePath}: run \`akan release-${pack.platform} ${app.name} --target ${pack.target} --env ${env}\` first.`);
|
|
1191
|
+
const bundle = await bundleFile.json();
|
|
1192
|
+
if (!bundle.updates)
|
|
1193
|
+
throw new Error(`The store build at ${bundlePath} takes no updates: give the target native.updates.`);
|
|
1194
|
+
if (bundle.nativeApi?.hash !== pack.nativeApi)
|
|
1195
|
+
throw new Error(`The store build at ${bundlePath} provides native API ${bundle.nativeApi?.hash}, and this commit's pack needs ${pack.nativeApi}: build the store binary from this commit.`);
|
|
1196
|
+
const archive = await CloudRunner.#tarPack(pack);
|
|
1197
|
+
try {
|
|
1198
|
+
const binary = await cloudApi.registerAppBinary(devProjectId, {
|
|
1199
|
+
appName: pack.app,
|
|
1200
|
+
target: pack.target,
|
|
1201
|
+
distribution,
|
|
1202
|
+
bundle: bundleFile,
|
|
1203
|
+
pack: Bun.file(archive),
|
|
1204
|
+
...bundle.updates.channel ? { channel: bundle.updates.channel } : {}
|
|
1205
|
+
}).catch((error) => {
|
|
1206
|
+
throw CloudRunner.#refusal(error, "a binary is registered by a project member signed in with `akan login`");
|
|
1207
|
+
});
|
|
1208
|
+
Logger.rawLog(`Registered ${pack.app} ${pack.target} ${pack.platform} (${distribution}): binary ${binary.id}, native API ${pack.nativeApi}.`);
|
|
1209
|
+
return binary;
|
|
1210
|
+
} finally {
|
|
1211
|
+
await rm(archive, { force: true });
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
static formatSecrets(secrets) {
|
|
1215
|
+
if (!secrets.length)
|
|
1216
|
+
return "No pipeline secrets.";
|
|
1217
|
+
const rows = [...secrets].sort((a, b) => a.name.localeCompare(b.name) || a.scope.localeCompare(b.scope)).map((secret) => [
|
|
1218
|
+
secret.name,
|
|
1219
|
+
secret.scope === "*" ? "every branch" : secret.scope,
|
|
1220
|
+
secret.updatedAt,
|
|
1221
|
+
secret.updatedBy
|
|
1222
|
+
]);
|
|
1223
|
+
const header = ["NAME", "SCOPE", "UPDATED", "BY"];
|
|
1224
|
+
const widths = header.map((title, column) => Math.max(title.length, ...rows.map((row) => row[column]?.length ?? 0)));
|
|
1225
|
+
return [header, ...rows].map((row) => row.map((cell, column) => cell.padEnd(widths[column] ?? 0)).join(" ").trimEnd()).join(`
|
|
1226
|
+
`);
|
|
1227
|
+
}
|
|
1228
|
+
static #secretBytes = 64 * 1024;
|
|
1229
|
+
static #secretBranches = ["debug", "develop", "main"];
|
|
1230
|
+
static #secretsUnavailable = "The server is not configured for pipeline secrets yet.";
|
|
1231
|
+
static #assertSecretName(name) {
|
|
1232
|
+
const problem = PipelineNames.secretNameError(name);
|
|
1233
|
+
if (problem)
|
|
1234
|
+
throw new Error(problem);
|
|
1235
|
+
}
|
|
1236
|
+
static #assertSecretBranch(branch) {
|
|
1237
|
+
if (branch !== null && !CloudRunner.#secretBranches.includes(branch))
|
|
1238
|
+
throw new Error(`--branch ${branch} is not a deployed branch: ${CloudRunner.#secretBranches.join(", ")}.`);
|
|
1239
|
+
}
|
|
1240
|
+
static #refusal(error, who, { unavailable } = {}) {
|
|
1241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1242
|
+
const status = CloudApi.statusOf(error);
|
|
1243
|
+
if (status === 401)
|
|
1244
|
+
return new Error("The server did not accept your sign-in: run `akan login`, then try again.");
|
|
1245
|
+
if (status === 403)
|
|
1246
|
+
return new Error(`The project refused: ${who}.`);
|
|
1247
|
+
if (status === 400) {
|
|
1248
|
+
const key = /"error"\s*:\s*"([^"]+)"/.exec(message)?.[1];
|
|
1249
|
+
return new Error(`The project refused the request${key ? `: ${key}` : ""}.`);
|
|
1250
|
+
}
|
|
1251
|
+
if (status === 503 && unavailable)
|
|
1252
|
+
return new Error(unavailable);
|
|
1253
|
+
return error;
|
|
1254
|
+
}
|
|
1083
1255
|
async#syncSecretGitignore(workspace, appNames) {
|
|
1084
1256
|
const patterns = (await Promise.all(appNames.map(async (appName) => {
|
|
1085
1257
|
const config = await AppExecutor.from(workspace, appName).getConfig();
|
package/index.js
CHANGED
|
@@ -4,34 +4,35 @@ import {
|
|
|
4
4
|
getTargetMetas,
|
|
5
5
|
getTargetCommandNames,
|
|
6
6
|
runCommands
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-6jjtnhkw.js";
|
|
8
8
|
import"./index-52w0fvh8.js";
|
|
9
|
-
import"./index-
|
|
9
|
+
import"./index-55mynnqs.js";
|
|
10
10
|
|
|
11
11
|
// pkgs/@akanjs/cli/commandManifest.ts
|
|
12
12
|
import path from "path";
|
|
13
13
|
|
|
14
14
|
// pkgs/@akanjs/cli/commandModules.ts
|
|
15
15
|
var commandModules = {
|
|
16
|
-
workspace: async () => (await import("./workspace.command-
|
|
17
|
-
agent: async () => (await import("./agent.command-
|
|
18
|
-
code: async () => (await import("./code.command-
|
|
19
|
-
application: async () => (await import("./application.command-
|
|
20
|
-
library: async () => (await import("./library.command-
|
|
21
|
-
localRegistry: async () => (await import("./localRegistry.command-
|
|
22
|
-
package: async () => (await import("./package.command-
|
|
23
|
-
module: async () => (await import("./module.command-
|
|
24
|
-
page: async () => (await import("./page.command-
|
|
25
|
-
context: async () => (await import("./context.command-
|
|
26
|
-
cloud: async () => (await import("./cloud.command-
|
|
27
|
-
subspace: async () => (await import("./subspace.command-
|
|
28
|
-
guideline: async () => (await import("./guideline.command-
|
|
29
|
-
scalar: async () => (await import("./scalar.command-
|
|
30
|
-
primitive: async () => (await import("./primitive.command-
|
|
31
|
-
quality: async () => (await import("./quality.command-
|
|
32
|
-
repair: async () => (await import("./repair.command-
|
|
33
|
-
workflow: async () => (await import("./workflow.command-
|
|
34
|
-
|
|
16
|
+
workspace: async () => (await import("./workspace.command-cmj6mqyk.js")).WorkspaceCommand,
|
|
17
|
+
agent: async () => (await import("./agent.command-f3gsc1gd.js")).AgentCommand,
|
|
18
|
+
code: async () => (await import("./code.command-30sca09d.js")).CodeCommand,
|
|
19
|
+
application: async () => (await import("./application.command-3v2d53gd.js")).ApplicationCommand,
|
|
20
|
+
library: async () => (await import("./library.command-gaga5bmq.js")).LibraryCommand,
|
|
21
|
+
localRegistry: async () => (await import("./localRegistry.command-9e84e32q.js")).LocalRegistryCommand,
|
|
22
|
+
package: async () => (await import("./package.command-twmvvf69.js")).PackageCommand,
|
|
23
|
+
module: async () => (await import("./module.command-7vpf6db4.js")).ModuleCommand,
|
|
24
|
+
page: async () => (await import("./page.command-5asq7fdf.js")).PageCommand,
|
|
25
|
+
context: async () => (await import("./context.command-k7eqacq6.js")).ContextCommand,
|
|
26
|
+
cloud: async () => (await import("./cloud.command-kk2rwkvw.js")).CloudCommand,
|
|
27
|
+
subspace: async () => (await import("./subspace.command-f02j5tge.js")).SubspaceCommand,
|
|
28
|
+
guideline: async () => (await import("./guideline.command-dtczrqpf.js")).GuidelineCommand,
|
|
29
|
+
scalar: async () => (await import("./scalar.command-bnggy1x7.js")).ScalarCommand,
|
|
30
|
+
primitive: async () => (await import("./primitive.command-dyrs2fm8.js")).PrimitiveCommand,
|
|
31
|
+
quality: async () => (await import("./quality.command-6emsqpbg.js")).QualityCommand,
|
|
32
|
+
repair: async () => (await import("./repair.command-8t6aegv5.js")).RepairCommand,
|
|
33
|
+
workflow: async () => (await import("./workflow.command-jx0wag5r.js")).WorkflowCommand,
|
|
34
|
+
pipeline: async () => (await import("./pipeline.command-d0v38572.js")).PipelineCommand,
|
|
35
|
+
tunnel: async () => (await import("./tunnel.command-9x8nfn75.js")).TunnelCommand
|
|
35
36
|
};
|
|
36
37
|
var commandModuleIds = Object.keys(commandModules);
|
|
37
38
|
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
Lib,
|
|
4
4
|
Workspace,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-6jjtnhkw.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
8
|
+
import"./index-55mynnqs.js";
|
|
9
9
|
import {
|
|
10
10
|
LibraryScript
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-c1x0be5j.js";
|
|
12
12
|
|
|
13
13
|
// pkgs/@akanjs/cli/library/library.command.ts
|
|
14
14
|
class LibraryCommand extends command("library", [LibraryScript], ({ public: target }) => ({
|
|
@@ -4,28 +4,28 @@ import {
|
|
|
4
4
|
runner,
|
|
5
5
|
script,
|
|
6
6
|
command
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-6jjtnhkw.js";
|
|
8
8
|
import"./index-52w0fvh8.js";
|
|
9
9
|
import {
|
|
10
10
|
PkgExecutor
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-55mynnqs.js";
|
|
12
12
|
import"./index-k9rrten6.js";
|
|
13
|
-
import"./index-
|
|
14
|
-
import"./index-
|
|
13
|
+
import"./index-kjvrq3nc.js";
|
|
14
|
+
import"./index-c1x0be5j.js";
|
|
15
15
|
import {
|
|
16
16
|
ApplicationScript
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-p9ystjrp.js";
|
|
18
18
|
import"./index-7md2g9vw.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-r2tpeb3n.js";
|
|
20
20
|
import {
|
|
21
21
|
getNpmRegistryUrl,
|
|
22
22
|
CloudRunner
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-y8q31011.js";
|
|
24
24
|
import"./index-2ahj896a.js";
|
|
25
25
|
import {
|
|
26
26
|
PackageScript
|
|
27
|
-
} from "./index-
|
|
28
|
-
import"./index-
|
|
27
|
+
} from "./index-gnyf1fqy.js";
|
|
28
|
+
import"./index-qt22xstj.js";
|
|
29
29
|
|
|
30
30
|
// pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
|
|
31
31
|
import { mkdir, rm } from "fs/promises";
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
Sys,
|
|
4
4
|
Module,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-6jjtnhkw.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
8
|
+
import"./index-55mynnqs.js";
|
|
9
9
|
import {
|
|
10
10
|
renderPrimitiveReport
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
} from "./index-05g3jayg.js";
|
|
12
|
+
import"./index-2etcv0sc.js";
|
|
13
13
|
import {
|
|
14
14
|
ModuleScript
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-e0cvze1s.js";
|
|
16
16
|
|
|
17
17
|
// pkgs/@akanjs/cli/module/module.command.ts
|
|
18
18
|
import { Logger, lowerlize } from "akanjs/common";
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
Pkg,
|
|
4
4
|
Workspace,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-6jjtnhkw.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
8
|
+
import"./index-55mynnqs.js";
|
|
9
9
|
import"./index-2ahj896a.js";
|
|
10
10
|
import {
|
|
11
11
|
PackageScript
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-gnyf1fqy.js";
|
|
13
13
|
|
|
14
14
|
// pkgs/@akanjs/cli/package/package.command.ts
|
|
15
15
|
class PackageCommand extends command("package", [PackageScript], ({ public: target }) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.1.0-rc.0",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@earendil-works/pi-tui": "0.86.1",
|
|
40
40
|
"@inquirer/prompts": "^8.4.3",
|
|
41
41
|
"@tailwindcss/node": "^4.3.0",
|
|
42
|
-
"akanjs": "3.0.
|
|
42
|
+
"akanjs": "3.1.0-rc.0",
|
|
43
43
|
"chalk": "^5.6.2",
|
|
44
44
|
"commander": "^14.0.3",
|
|
45
45
|
"dayjs": "^1.11.20",
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
App,
|
|
4
4
|
Module,
|
|
5
5
|
command
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-6jjtnhkw.js";
|
|
7
7
|
import"./index-52w0fvh8.js";
|
|
8
|
-
import"./index-
|
|
8
|
+
import"./index-55mynnqs.js";
|
|
9
9
|
import {
|
|
10
10
|
PageScript
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-2etcv0sc.js";
|
|
12
12
|
|
|
13
13
|
// pkgs/@akanjs/cli/page/page.command.ts
|
|
14
14
|
class PageCommand extends command("page", [PageScript], ({ public: target }) => ({
|