@akanjs/cli 3.0.2-rc.0 → 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.
Files changed (86) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-szbjv4gv.js → CodeAgent-q7a4srt6.js} +2 -2
  3. package/{CodeTui-5nw86ab6.js → CodeTui-ak23dxc9.js} +1 -1
  4. package/{TunnelShare-cwh9ezsm.js → TunnelShare-21mm6dr5.js} +2 -2
  5. package/{agent.command-np1dffkb.js → agent.command-f3gsc1gd.js} +5 -5
  6. package/akanCode.js +2 -2
  7. package/{application.command-fyjy9ryc.js → application.command-3v2d53gd.js} +38 -16
  8. package/{applicationBuildRunner-etrzfwjj.js → applicationBuildRunner-1yaqsrdq.js} +115 -103
  9. package/buildBatch.proc.js +17 -6
  10. package/cloud.command-kk2rwkvw.js +187 -0
  11. package/cloud.script-r7eyfey4.js +20 -0
  12. package/{code.command-hmtx14b2.js → code.command-30sca09d.js} +6 -6
  13. package/commandManifest.json +1 -1
  14. package/{context.command-6aqvdx43.js → context.command-k7eqacq6.js} +13 -13
  15. package/context.runner-hqd1ppqe.js +21 -0
  16. package/{guideline.command-axvf68gc.js → guideline.command-dtczrqpf.js} +2 -2
  17. package/guidelines/agentRule/agentRule.instruction.md +10 -2
  18. package/guidelines/conventions/conventions.instruction.md +68 -25
  19. package/guidelines/cssRule/cssRule.instruction.md +19 -0
  20. package/guidelines/mcpRule/mcpRule.instruction.md +67 -12
  21. package/guidelines/queryRule/queryRule.instruction.md +11 -1
  22. package/guidelines/runtimeRule/runtimeRule.instruction.md +97 -16
  23. package/guidelines/ssrRule/ssrRule.instruction.md +10 -7
  24. package/guidelines/transportRule/transportRule.instruction.md +19 -0
  25. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +6 -6
  26. package/incrementalBuilder.proc.js +25 -4
  27. package/{index-h9ht6s60.js → index-05g3jayg.js} +1 -1
  28. package/{index-j38qkvkk.js → index-0bm04n5g.js} +12 -10
  29. package/{index-g38nhv87.js → index-2etcv0sc.js} +1 -1
  30. package/{index-zyw622y1.js → index-2mx692qq.js} +3 -3
  31. package/{index-jb0hmt3k.js → index-2t4tqd1c.js} +3 -3
  32. package/{index-50wb2a26.js → index-55mynnqs.js} +354 -129
  33. package/{index-q6ft9fkc.js → index-6jjtnhkw.js} +8 -3
  34. package/index-6w0rbr9d.js +68 -0
  35. package/{index-2wc41k5w.js → index-7bymavqk.js} +2 -2
  36. package/{index-krjcg4y6.js → index-aprt7pkz.js} +7 -10
  37. package/{index-1bjkfvm9.js → index-c1x0be5j.js} +2 -2
  38. package/{index-d95tfg3n.js → index-c2yrsxdh.js} +14 -8
  39. package/{index-cb6yc5mb.js → index-c76k723e.js} +2 -2
  40. package/{index-6keyf4sg.js → index-ctanya41.js} +4 -4
  41. package/{index-f4e08ptp.js → index-e0cvze1s.js} +4 -4
  42. package/{index-hp3stk1m.js → index-fm46xrf1.js} +3 -3
  43. package/{index-3xmzr1p1.js → index-gnyf1fqy.js} +2 -2
  44. package/{index-zwd84m0w.js → index-jyv387qw.js} +4 -4
  45. package/{index-senscydg.js → index-k9rrten6.js} +6 -1
  46. package/{index-jk9xnck6.js → index-kjvrq3nc.js} +231 -133
  47. package/{index-xwprn9nr.js → index-nz15k0b6.js} +1 -1
  48. package/{index-61mmsdjg.js → index-p9ystjrp.js} +174 -72
  49. package/index-q958tqqg.js +77 -0
  50. package/{index-50jjwg8y.js → index-qt22xstj.js} +1 -1
  51. package/{index-94s080qm.js → index-r2tpeb3n.js} +127 -1
  52. package/{index-bsv901fd.js → index-rwq3ekqc.js} +7 -7
  53. package/{index-gvpvxdm1.js → index-tn4rpqp1.js} +96 -12
  54. package/{index-1gs9g12n.js → index-v29746vb.js} +4 -4
  55. package/index-ww9bhp67.js +62 -0
  56. package/{index-hxnnfy57.js → index-y8q31011.js} +180 -8
  57. package/index.js +22 -21
  58. package/{library.command-9m2rdwwz.js → library.command-gaga5bmq.js} +3 -3
  59. package/{localRegistry.command-vacc2njh.js → localRegistry.command-9e84e32q.js} +10 -10
  60. package/{module.command-q63dffya.js → module.command-7vpf6db4.js} +5 -5
  61. package/{package.command-y2jh0m99.js → package.command-twmvvf69.js} +3 -3
  62. package/package.json +2 -2
  63. package/{page.command-f3e4cwhh.js → page.command-5asq7fdf.js} +3 -3
  64. package/pipeline.command-d0v38572.js +1334 -0
  65. package/{primitive.command-r4kq75qj.js → primitive.command-dyrs2fm8.js} +6 -6
  66. package/projectTypecheck-cvtkrzp2.js +7 -0
  67. package/{quality.command-f7gzh26z.js → quality.command-6emsqpbg.js} +5 -4
  68. package/{repair.command-0qmyr6qa.js → repair.command-8t6aegv5.js} +5 -5
  69. package/{scalar.command-kddn7av4.js → scalar.command-bnggy1x7.js} +4 -4
  70. package/{subspace.command-j7ayp382.js → subspace.command-f02j5tge.js} +158 -91
  71. package/templates/app/tsconfig.json.template +1 -6
  72. package/templates/appSample/page/task/[taskId]/_index.tsx +2 -2
  73. package/templates/appSample/page/task/[taskId]/edit.tsx +2 -2
  74. package/templates/appSample/page/task/_index.tsx +2 -2
  75. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -2
  76. package/templates/crudPages/[__model__Id]/page.tsx +3 -3
  77. package/templates/crudPages/page.tsx +2 -2
  78. package/templates/crudSinglePage/page.tsx +3 -3
  79. package/templates/lib/cnst.ts +2 -2
  80. package/templates/lib/sig.ts +3 -3
  81. package/{tunnel.command-b3ymdk4f.js → tunnel.command-9x8nfn75.js} +16 -13
  82. package/{workflow.command-z1srcdfw.js → workflow.command-jx0wag5r.js} +10 -10
  83. package/{workspace.command-17c46dbp.js → workspace.command-cmj6mqyk.js} +58 -28
  84. package/cloud.command-c0rnwy65.js +0 -95
  85. package/cloud.script-6ba8e9v8.js +0 -20
  86. package/context.runner-hnkvv3z3.js +0 -21
@@ -22,26 +22,26 @@ import {
22
22
  renderWorkflowApply,
23
23
  renderWorkflowValidation,
24
24
  renderWorkflowRunArtifact
25
- } from "./index-h9ht6s60.js";
25
+ } from "./index-05g3jayg.js";
26
26
  import {
27
27
  AkanContextAnalyzer
28
- } from "./index-zyw622y1.js";
28
+ } from "./index-2mx692qq.js";
29
29
  import {
30
30
  CommandContainer,
31
31
  runner
32
- } from "./index-q6ft9fkc.js";
32
+ } from "./index-6jjtnhkw.js";
33
33
  import {
34
34
  ModuleScript
35
- } from "./index-f4e08ptp.js";
35
+ } from "./index-e0cvze1s.js";
36
36
  import {
37
37
  PrimitiveScript
38
- } from "./index-6keyf4sg.js";
38
+ } from "./index-ctanya41.js";
39
39
  import {
40
40
  spawnShell
41
- } from "./index-hp3stk1m.js";
41
+ } from "./index-fm46xrf1.js";
42
42
  import {
43
43
  ScalarScript
44
- } from "./index-cb6yc5mb.js";
44
+ } from "./index-c76k723e.js";
45
45
 
46
46
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
47
47
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -2,34 +2,35 @@
2
2
  import {
3
3
  GlobalConfig,
4
4
  CloudApi
5
- } from "./index-94s080qm.js";
5
+ } from "./index-r2tpeb3n.js";
6
6
  import {
7
7
  script
8
- } from "./index-q6ft9fkc.js";
8
+ } from "./index-6jjtnhkw.js";
9
9
  import {
10
10
  PkgExecutor
11
- } from "./index-50wb2a26.js";
11
+ } from "./index-55mynnqs.js";
12
12
  import {
13
13
  ApplicationScript
14
- } from "./index-61mmsdjg.js";
14
+ } from "./index-p9ystjrp.js";
15
15
  import {
16
16
  PackageScript
17
- } from "./index-3xmzr1p1.js";
17
+ } from "./index-gnyf1fqy.js";
18
18
  import {
19
19
  CloudRunner
20
- } from "./index-hxnnfy57.js";
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 = GlobalConfig.akanCloudHost) {
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 = GlobalConfig.akanCloudHost) {
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 = GlobalConfig.akanCloudHost } = {}) {
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 = GlobalConfig.akanCloudHost,
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-q6ft9fkc.js";
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-50wb2a26.js";
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-zyw622y1.js";
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
- } from "./index-94s080qm.js";
5
+ CloudApi,
6
+ UpdatePackUpload
7
+ } from "./index-r2tpeb3n.js";
7
8
  import {
8
9
  runner
9
- } from "./index-q6ft9fkc.js";
10
+ } from "./index-6jjtnhkw.js";
10
11
  import {
11
12
  WorkspaceExecutor,
12
13
  AppExecutor
13
- } from "./index-50wb2a26.js";
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-q6ft9fkc.js";
7
+ } from "./index-6jjtnhkw.js";
8
8
  import"./index-52w0fvh8.js";
9
- import"./index-50wb2a26.js";
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-17c46dbp.js")).WorkspaceCommand,
17
- agent: async () => (await import("./agent.command-np1dffkb.js")).AgentCommand,
18
- code: async () => (await import("./code.command-hmtx14b2.js")).CodeCommand,
19
- application: async () => (await import("./application.command-fyjy9ryc.js")).ApplicationCommand,
20
- library: async () => (await import("./library.command-9m2rdwwz.js")).LibraryCommand,
21
- localRegistry: async () => (await import("./localRegistry.command-vacc2njh.js")).LocalRegistryCommand,
22
- package: async () => (await import("./package.command-y2jh0m99.js")).PackageCommand,
23
- module: async () => (await import("./module.command-q63dffya.js")).ModuleCommand,
24
- page: async () => (await import("./page.command-f3e4cwhh.js")).PageCommand,
25
- context: async () => (await import("./context.command-6aqvdx43.js")).ContextCommand,
26
- cloud: async () => (await import("./cloud.command-c0rnwy65.js")).CloudCommand,
27
- subspace: async () => (await import("./subspace.command-j7ayp382.js")).SubspaceCommand,
28
- guideline: async () => (await import("./guideline.command-axvf68gc.js")).GuidelineCommand,
29
- scalar: async () => (await import("./scalar.command-kddn7av4.js")).ScalarCommand,
30
- primitive: async () => (await import("./primitive.command-r4kq75qj.js")).PrimitiveCommand,
31
- quality: async () => (await import("./quality.command-f7gzh26z.js")).QualityCommand,
32
- repair: async () => (await import("./repair.command-0qmyr6qa.js")).RepairCommand,
33
- workflow: async () => (await import("./workflow.command-z1srcdfw.js")).WorkflowCommand,
34
- tunnel: async () => (await import("./tunnel.command-b3ymdk4f.js")).TunnelCommand
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-q6ft9fkc.js";
6
+ } from "./index-6jjtnhkw.js";
7
7
  import"./index-52w0fvh8.js";
8
- import"./index-50wb2a26.js";
8
+ import"./index-55mynnqs.js";
9
9
  import {
10
10
  LibraryScript
11
- } from "./index-1bjkfvm9.js";
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-q6ft9fkc.js";
7
+ } from "./index-6jjtnhkw.js";
8
8
  import"./index-52w0fvh8.js";
9
9
  import {
10
10
  PkgExecutor
11
- } from "./index-50wb2a26.js";
12
- import"./index-senscydg.js";
13
- import"./index-jk9xnck6.js";
14
- import"./index-1bjkfvm9.js";
11
+ } from "./index-55mynnqs.js";
12
+ import"./index-k9rrten6.js";
13
+ import"./index-kjvrq3nc.js";
14
+ import"./index-c1x0be5j.js";
15
15
  import {
16
16
  ApplicationScript
17
- } from "./index-61mmsdjg.js";
17
+ } from "./index-p9ystjrp.js";
18
18
  import"./index-7md2g9vw.js";
19
- import"./index-94s080qm.js";
19
+ import"./index-r2tpeb3n.js";
20
20
  import {
21
21
  getNpmRegistryUrl,
22
22
  CloudRunner
23
- } from "./index-hxnnfy57.js";
23
+ } from "./index-y8q31011.js";
24
24
  import"./index-2ahj896a.js";
25
25
  import {
26
26
  PackageScript
27
- } from "./index-3xmzr1p1.js";
28
- import"./index-50jjwg8y.js";
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-q6ft9fkc.js";
6
+ } from "./index-6jjtnhkw.js";
7
7
  import"./index-52w0fvh8.js";
8
- import"./index-50wb2a26.js";
8
+ import"./index-55mynnqs.js";
9
9
  import {
10
10
  renderPrimitiveReport
11
- } from "./index-h9ht6s60.js";
12
- import"./index-g38nhv87.js";
11
+ } from "./index-05g3jayg.js";
12
+ import"./index-2etcv0sc.js";
13
13
  import {
14
14
  ModuleScript
15
- } from "./index-f4e08ptp.js";
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-q6ft9fkc.js";
6
+ } from "./index-6jjtnhkw.js";
7
7
  import"./index-52w0fvh8.js";
8
- import"./index-50wb2a26.js";
8
+ import"./index-55mynnqs.js";
9
9
  import"./index-2ahj896a.js";
10
10
  import {
11
11
  PackageScript
12
- } from "./index-3xmzr1p1.js";
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 }) => ({