@akanjs/cli 3.0.0-beta.7 → 3.0.0-beta.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.
Files changed (41) hide show
  1. package/.build-stamp +1 -1
  2. package/{abstractCompactor-mjh5ppsq.js → abstractCompactor-gmkc0z8j.js} +2 -1
  3. package/{agent.command-d2gfxfck.js → agent.command-0q17pnrs.js} +2 -2
  4. package/{application.command-pj2m7584.js → application.command-18y0s485.js} +3 -3
  5. package/{cloud.command-jshwdq22.js → cloud.command-av97ndh6.js} +10 -9
  6. package/cloud.script-cm11xjdz.js +20 -0
  7. package/{context.command-ez8a0zyz.js → context.command-5v37ef3n.js} +10 -9
  8. package/{devTui-40ggmd99.js → devTui-m1atgkc9.js} +1 -1
  9. package/{devTuiView-c08ccbat.js → devTuiView-0hc2emhe.js} +1 -1
  10. package/{guideline.command-xmqwx8zm.js → guideline.command-4pz9g1rt.js} +3 -2
  11. package/guidelines/agentRule/agentRule.instruction.md +37 -0
  12. package/{index-fz5q3gd7.js → index-04bk599g.js} +1 -1
  13. package/{index-zry5nz81.js → index-2xp0kfkt.js} +22 -13
  14. package/{index-8pm30m73.js → index-5ystnsd5.js} +5 -5
  15. package/{index-ws5e0j51.js → index-9077wzd2.js} +1 -1
  16. package/{index-rwg2aa4f.js → index-a17x49vg.js} +2 -2
  17. package/{index-4edzf1gr.js → index-d43r08tf.js} +2 -2
  18. package/{index-7737gxcp.js → index-ffvk10zz.js} +1 -1
  19. package/{index-ne2qy0nk.js → index-k2j1hc4r.js} +1 -1
  20. package/index-m0xccmmm.js +228 -0
  21. package/{index-2hq52jq3.js → index-rtxxan88.js} +24 -18
  22. package/{index-v0qh106m.js → index-sj5vxr8f.js} +4 -4
  23. package/{index-kn1h7p1x.js → index-te54x9zm.js} +3 -225
  24. package/{index-259dsnz3.js → index-vxtad5bd.js} +1 -1
  25. package/{index-pnqbkf5p.js → index-vyvre9en.js} +1 -1
  26. package/{index-600zhnve.js → index-y6n8nmny.js} +6 -6
  27. package/index.js +18 -18
  28. package/{library.command-nbsky672.js → library.command-qzzbj6d8.js} +2 -2
  29. package/{localRegistry.command-yeq57wjr.js → localRegistry.command-vyrgg4xw.js} +7 -6
  30. package/{module.command-29vqzrh8.js → module.command-rq5hq3ax.js} +5 -4
  31. package/{package.command-axv0abmn.js → package.command-d9hd6v9n.js} +2 -2
  32. package/package.json +2 -2
  33. package/{page.command-vs9s3zrh.js → page.command-126d56te.js} +2 -2
  34. package/{primitive.command-cbxmqbtc.js → primitive.command-taxd1538.js} +6 -5
  35. package/{quality.command-gmbs7nws.js → quality.command-6gsna0a3.js} +1 -1
  36. package/{repair.command-bqsjptsj.js → repair.command-tq2dgy72.js} +2 -2
  37. package/{scalar.command-6k1vhe9s.js → scalar.command-3bcmrrkv.js} +4 -3
  38. package/{subspace.command-fwjfcts7.js → subspace.command-eddzqpx3.js} +90 -10
  39. package/{workflow.command-nwpcdc8p.js → workflow.command-gtdnzvbz.js} +8 -7
  40. package/{workspace.command-8s050m0h.js → workspace.command-06wvstgr.js} +18 -17
  41. package/{index-mak3cd28.js → index-0g7r8xz3.js} +24 -24
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- 9e33ade766cacd9904efc83145b59bdfd1e58d8e47a794657e6c0f1aa7349292
1
+ 12db5271f628dad0e03d37da2235d3eb2f1d6e5e39d63e6c1962eb73baaddfae
@@ -1,8 +1,9 @@
1
1
  // @bun
2
2
  import"./index-q0y2jq9j.js";
3
+ import"./index-m0xccmmm.js";
3
4
  import {
4
5
  AiSession
5
- } from "./index-kn1h7p1x.js";
6
+ } from "./index-te54x9zm.js";
6
7
  import {
7
8
  AbstractDoc
8
9
  } from "./index-meh558jy.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  Workspace,
4
4
  command
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-0g7r8xz3.js";
6
6
  import"./index-q0y2jq9j.js";
7
7
  import"./index-2tv3fdx4.js";
8
8
  import"./index-6wwzs1bc.js";
@@ -12,7 +12,7 @@ import"./index-ktb5njgy.js";
12
12
  import"./index-h7yw2z9n.js";
13
13
  import {
14
14
  AgentScript
15
- } from "./index-ne2qy0nk.js";
15
+ } from "./index-k2j1hc4r.js";
16
16
 
17
17
  // pkgs/@akanjs/cli/agent/agent.command.ts
18
18
  class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({
@@ -6,14 +6,14 @@ import {
6
6
  Exec,
7
7
  Workspace,
8
8
  command
9
- } from "./index-mak3cd28.js";
9
+ } from "./index-0g7r8xz3.js";
10
10
  import"./index-q0y2jq9j.js";
11
11
  import"./index-2tv3fdx4.js";
12
12
  import"./index-6wwzs1bc.js";
13
13
  import {
14
14
  ApplicationScript
15
- } from "./index-v0qh106m.js";
16
- import"./index-259dsnz3.js";
15
+ } from "./index-sj5vxr8f.js";
16
+ import"./index-vxtad5bd.js";
17
17
  import"./index-hwkygn9s.js";
18
18
  import {
19
19
  AbstractDoc
@@ -2,29 +2,30 @@
2
2
  import"./index-q0y2jq9j.js";
3
3
  import {
4
4
  GlobalConfig
5
- } from "./index-kn1h7p1x.js";
5
+ } from "./index-m0xccmmm.js";
6
6
  import {
7
7
  Workspace,
8
8
  command
9
- } from "./index-mak3cd28.js";
9
+ } from "./index-0g7r8xz3.js";
10
10
  import"./index-2tv3fdx4.js";
11
11
  import"./index-6wwzs1bc.js";
12
- import"./index-v0qh106m.js";
13
- import"./index-259dsnz3.js";
12
+ import"./index-te54x9zm.js";
13
+ import"./index-sj5vxr8f.js";
14
+ import"./index-vxtad5bd.js";
14
15
  import"./index-hwkygn9s.js";
15
16
  import"./index-kcxmv48c.js";
16
- import"./index-ws5e0j51.js";
17
- import"./index-2hq52jq3.js";
17
+ import"./index-9077wzd2.js";
18
+ import"./index-rtxxan88.js";
18
19
  import {
19
- CloudScript
20
- } from "./index-zry5nz81.js";
20
+ CloudScript2
21
+ } from "./index-2xp0kfkt.js";
21
22
  import"./index-j9yhg404.js";
22
23
 
23
24
  // pkgs/@akanjs/cli/cloud/cloud.command.ts
24
25
  var localRegistryUrl = () => process.env.AKAN_NPM_REGISTRY ?? "http://127.0.0.1:4873";
25
26
  var resolveRegistryUrl = (registry) => registry === "local" ? localRegistryUrl() : undefined;
26
27
 
27
- class CloudCommand extends command("cloud", [CloudScript], ({ public: target }) => ({
28
+ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target }) => ({
28
29
  login: target({ desc: "Login to Akan Cloud services" }).option("host", String, { desc: "host of the cloud", default: GlobalConfig.akanCloudHost }).with(Workspace).exec(async function(host, workspace) {
29
30
  await this.cloudScript.login(workspace, host);
30
31
  }),
@@ -0,0 +1,20 @@
1
+ // @bun
2
+ import {
3
+ CloudScript2
4
+ } from "./index-2xp0kfkt.js";
5
+ import"./index-rtxxan88.js";
6
+ import"./index-sj5vxr8f.js";
7
+ import"./index-j9yhg404.js";
8
+ import"./index-vxtad5bd.js";
9
+ import"./index-9077wzd2.js";
10
+ import"./index-te54x9zm.js";
11
+ import"./index-m0xccmmm.js";
12
+ import"./index-0g7r8xz3.js";
13
+ import"./index-hwkygn9s.js";
14
+ import"./index-2tv3fdx4.js";
15
+ import"./index-6wwzs1bc.js";
16
+ import"./index-kcxmv48c.js";
17
+ import"./index-q0y2jq9j.js";
18
+ export {
19
+ CloudScript2 as CloudScript
20
+ };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  Workspace,
4
4
  command
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-0g7r8xz3.js";
6
6
  import"./index-q0y2jq9j.js";
7
7
  import"./index-2tv3fdx4.js";
8
8
  import"./index-6wwzs1bc.js";
@@ -11,16 +11,17 @@ import"./index-gyd220p2.js";
11
11
  import"./index-ktb5njgy.js";
12
12
  import {
13
13
  ContextScript
14
- } from "./index-600zhnve.js";
14
+ } from "./index-y6n8nmny.js";
15
15
  import"./index-wt7qrtd4.js";
16
16
  import"./index-h7yw2z9n.js";
17
- import"./index-fz5q3gd7.js";
18
- import"./index-7737gxcp.js";
19
- import"./index-kn1h7p1x.js";
20
- import"./index-8pm30m73.js";
21
- import"./index-pnqbkf5p.js";
22
- import"./index-4edzf1gr.js";
23
- import"./index-rwg2aa4f.js";
17
+ import"./index-04bk599g.js";
18
+ import"./index-ffvk10zz.js";
19
+ import"./index-m0xccmmm.js";
20
+ import"./index-te54x9zm.js";
21
+ import"./index-5ystnsd5.js";
22
+ import"./index-vyvre9en.js";
23
+ import"./index-d43r08tf.js";
24
+ import"./index-a17x49vg.js";
24
25
 
25
26
  // pkgs/@akanjs/cli/context/context.command.ts
26
27
  class ContextCommand extends command("context", [ContextScript], ({ public: target }) => ({
@@ -4,7 +4,7 @@ import {
4
4
  plainTextOf,
5
5
  HOST_SOURCE,
6
6
  DevLogBuffer
7
- } from "./index-v0qh106m.js";
7
+ } from "./index-sj5vxr8f.js";
8
8
 
9
9
  // pkgs/@akanjs/cli/application/devTui.tsx
10
10
  import { render } from "ink";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // pkgs/@akanjs/cli/application/devTuiView.ts
3
3
  var createDevTuiView = async (supervisor) => {
4
- const { DevTui } = await import("./devTui-40ggmd99.js");
4
+ const { DevTui } = await import("./devTui-m1atgkc9.js");
5
5
  return new DevTui(supervisor);
6
6
  };
7
7
  export {
@@ -4,7 +4,7 @@ import {
4
4
  runner,
5
5
  script,
6
6
  command
7
- } from "./index-mak3cd28.js";
7
+ } from "./index-0g7r8xz3.js";
8
8
  import {
9
9
  FileSys
10
10
  } from "./index-q0y2jq9j.js";
@@ -15,9 +15,10 @@ import {
15
15
  import {
16
16
  Prompter
17
17
  } from "./index-h7yw2z9n.js";
18
+ import"./index-m0xccmmm.js";
18
19
  import {
19
20
  AiSession
20
- } from "./index-kn1h7p1x.js";
21
+ } from "./index-te54x9zm.js";
21
22
 
22
23
  // pkgs/@akanjs/cli/guideline/guideline.script.ts
23
24
  import { Logger } from "akanjs/common";
@@ -164,6 +164,43 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
164
164
  WebView, **which has neither on Android or iOS**, so a `speech.plugin.ts` declares the permission and
165
165
  the packages the native build needs. An engine answering `available()` false renders no microphone at all,
166
166
  the same rule as publishing no tool for a control the screen does not draw.
167
+ - **Data the user points at rides the message too, as `references` — and its value is a snapshot.** A file is
168
+ something they handed over; a reference is something they pointed at while asking, so it belongs in the same
169
+ place and for the same reason. Screen context does not do this job: `ContextBlock`s are rebuilt from the screen
170
+ every turn, so what was named three turns ago is simply not in the conversation any more. A `MessageReference`
171
+ carries the host's own `refName`, the id, a label, an optional dotted `path` into the document, and the `value`
172
+ those resolved to. **The value is never re-read on a later turn**, which is the point: re-reading rewrites what
173
+ the person was looking at when they spoke, and the usual next thing the agent does is edit the very field it was
174
+ pointed at — leaving a live reference showing the result with no record of what it was changed from.
175
+ `refName`/`refId`/`path` travel so a tool can read the current value when the answer needs it, and
176
+ `AgentService.referenced` folds the whole lot into the message text in one place, so every provider carries a
177
+ reference without either adaptor knowing the word. **The value is masked on the way in and nowhere else**: masking
178
+ needs the model class, which no wire carries, so the model a host names when it stages the reference is the whole
179
+ of the decision about what leaves the browser — name the class that actually holds the field, because a `Light`
180
+ one usually does not. **The ceiling is 20,000 characters per reference**, applied as it is staged and again on
181
+ the server; a reference is bulkier than a tool result and outlives one, riding every later turn and being the last
182
+ thing compaction folds. Persisting keeps the pointer and drops the value with a note saying so, which is a better
183
+ restored state than an attachment can offer — the pointer is still live, so the answer is to read it again.
184
+ Staging lives on the **session** (`stage` / `staged` / `unstage(key)` / `clearStaged()`), not on the composer where
185
+ staged files live, because a reference comes from whichever component drew the data rather than from the paperclip;
186
+ `unstage` is keyed on `refName/refId#path` because what orders a message's references is its text, not that list.
187
+ - **Two ways to point at data, and which one depends on who knows the value.** `<Agent.Chat reference={[…]} />`
188
+ takes one `ReferenceSource` per kind of document — `refName`, a `type`, the app's own `search`, and a `resolve` —
189
+ and the composer's `@` menu offers whole documents from them; the token is written the moment a row is picked and
190
+ the value is staged when `resolve` lands, so a slow fetch never freezes the menu and one that fails leaves a
191
+ pointer that reads as *go and read it*. For a field *inside* a document, the component drawing it calls
192
+ `useAgentReference()` — it already holds the value, so there is no round trip, and it is the only thing that
193
+ knows a rich-text field stored as `field(Any)` reads as a paragraph rather than as the editor document it is. The
194
+ hook no-ops with a warning outside a session, the same call `AgentValue.publishable` makes: a card carrying a
195
+ reference button must not cost a route its render.
196
+ - **The token in the draft is what carries a reference, and the chip only draws it.** Deleting
197
+ `@[label](mention:refName/id#path)` by hand drops the reference exactly as removing the chip does — removing the
198
+ chip removes the token — so the two can never disagree, and nothing re-derives a value from text somebody edited.
199
+ A token pasted out of an earlier message travels as a pointer with a note, which is the same shape a restored
200
+ conversation produces. Staged references are the **session's**, not the composer's, because `useAgentReference`
201
+ is called from components the composer cannot see; writing the token is the composer's half, and `refer` warns
202
+ rather than staging silently when no chat is mounted on that session — the case where a card sits outside the
203
+ `<Agent.Zone>` its chat is inside.
167
204
  - **`attach` and `voice` both carry functions, so a server layout cannot pass either.** A closure does not cross
168
205
  the RSC boundary — `non-scalar-props-restricted` says so on `page/**` — so an app that wants either mounts the
169
206
  chat from a small client component in the app's own `ui/` that calls the hook.
@@ -11,7 +11,7 @@ import {
11
11
  } from "./index-ktb5njgy.js";
12
12
  import {
13
13
  runner
14
- } from "./index-mak3cd28.js";
14
+ } from "./index-0g7r8xz3.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/repair/repair.runner.ts
17
17
  var commandForShell = (command) => command.startsWith("akan ") ? `bun run ${command}` : command;
@@ -1,28 +1,30 @@
1
1
  // @bun
2
2
  import {
3
3
  GlobalConfig,
4
- CloudApi,
5
- AiSession
6
- } from "./index-kn1h7p1x.js";
4
+ CloudApi
5
+ } from "./index-m0xccmmm.js";
7
6
  import {
8
7
  PkgExecutor
9
8
  } from "./index-2tv3fdx4.js";
9
+ import {
10
+ AiSession
11
+ } from "./index-te54x9zm.js";
10
12
  import {
11
13
  script
12
- } from "./index-mak3cd28.js";
14
+ } from "./index-0g7r8xz3.js";
13
15
  import {
14
16
  ApplicationScript
15
- } from "./index-v0qh106m.js";
17
+ } from "./index-sj5vxr8f.js";
16
18
  import {
17
19
  PackageScript
18
- } from "./index-ws5e0j51.js";
20
+ } from "./index-9077wzd2.js";
19
21
  import {
20
22
  CloudRunner
21
- } from "./index-2hq52jq3.js";
23
+ } from "./index-rtxxan88.js";
22
24
 
23
25
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
24
26
  import { Logger } from "akanjs/common";
25
- class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
27
+ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
26
28
  async login(workspace, host = GlobalConfig.akanCloudHost) {
27
29
  await this.cloudRunner.login(host, workspace);
28
30
  }
@@ -48,16 +50,23 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
48
50
  }
49
51
  await this.cloudRunner.downloadEnvByScp(workspace);
50
52
  }
51
- async uploadEnv(workspace, { host = GlobalConfig.akanCloudHost } = {}) {
52
- const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
53
- const { path } = await this.cloudRunner.gatherEnvFiles(workspace);
53
+ async uploadEnv(workspace, {
54
+ host = GlobalConfig.akanCloudHost,
55
+ workspaceId = workspace.getWorkspaceId({ allowEmpty: true }),
56
+ scope,
57
+ archivePath
58
+ } = {}) {
59
+ if (scope && !workspaceId)
60
+ throw new Error("A scoped env upload needs a cloud workspace id \u2014 the scp target is workspace-wide.");
61
+ const { files, path } = await this.cloudRunner.gatherEnvFiles(workspace, { scope, archivePath });
54
62
  if (workspaceId) {
55
63
  await this.login(workspace, host);
56
64
  const cloudApi = await CloudApi.fromHost(workspace, host);
57
65
  await this.cloudRunner.uploadEnv(cloudApi, workspaceId, path);
58
- return;
66
+ return { workspaceId, files };
59
67
  }
60
68
  await this.cloudRunner.uploadEnvByScp(workspace, path);
69
+ return { workspaceId: null, files };
61
70
  }
62
71
  async deployAkan(workspace, { test = true, registryUrl } = {}) {
63
72
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
@@ -80,4 +89,4 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
80
89
  }
81
90
  }
82
91
 
83
- export { CloudScript };
92
+ export { CloudScript2 };
@@ -2,16 +2,16 @@
2
2
  import {
3
3
  FileSys
4
4
  } from "./index-q0y2jq9j.js";
5
- import {
6
- AiSession
7
- } from "./index-kn1h7p1x.js";
8
5
  import {
9
6
  ModuleExecutor
10
7
  } from "./index-2tv3fdx4.js";
8
+ import {
9
+ AiSession
10
+ } from "./index-te54x9zm.js";
11
11
  import {
12
12
  runner,
13
13
  script
14
- } from "./index-mak3cd28.js";
14
+ } from "./index-0g7r8xz3.js";
15
15
  import {
16
16
  sourceFile,
17
17
  moduleSourcePaths,
@@ -22,7 +22,7 @@ import {
22
22
  } from "./index-gyd220p2.js";
23
23
  import {
24
24
  PageScript
25
- } from "./index-pnqbkf5p.js";
25
+ } from "./index-vyvre9en.js";
26
26
  import {
27
27
  Prompter
28
28
  } from "./index-h7yw2z9n.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-0g7r8xz3.js";
6
6
  import {
7
7
  FileSys
8
8
  } from "./index-q0y2jq9j.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-0g7r8xz3.js";
6
6
  import {
7
7
  generatedFilesForSync,
8
8
  createPassedPrimitiveReport,
@@ -10,7 +10,7 @@ import {
10
10
  } from "./index-gyd220p2.js";
11
11
  import {
12
12
  AiSession
13
- } from "./index-kn1h7p1x.js";
13
+ } from "./index-te54x9zm.js";
14
14
  import {
15
15
  Prompter
16
16
  } from "./index-h7yw2z9n.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  script
4
- } from "./index-mak3cd28.js";
4
+ } from "./index-0g7r8xz3.js";
5
5
  import {
6
6
  AppExecutor,
7
7
  LibExecutor,
@@ -42,7 +42,7 @@ import {
42
42
  } from "./index-gyd220p2.js";
43
43
  import {
44
44
  ModuleScript
45
- } from "./index-8pm30m73.js";
45
+ } from "./index-5ystnsd5.js";
46
46
 
47
47
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
48
48
  import { capitalize } from "akanjs/common";
@@ -26,7 +26,7 @@ import {
26
26
  } from "./index-ktb5njgy.js";
27
27
  import {
28
28
  runner
29
- } from "./index-mak3cd28.js";
29
+ } from "./index-0g7r8xz3.js";
30
30
 
31
31
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
32
32
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-mak3cd28.js";
5
+ } from "./index-0g7r8xz3.js";
6
6
  import {
7
7
  AGENT_BLOCK_START,
8
8
  AGENT_BLOCK_END,
@@ -0,0 +1,228 @@
1
+ // @bun
2
+ import {
3
+ FileSys
4
+ } from "./index-q0y2jq9j.js";
5
+
6
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
7
+ import { chmod, mkdir } from "fs/promises";
8
+ import dayjs from "dayjs";
9
+
10
+ // pkgs/@akanjs/devkit/cloud/constants.ts
11
+ var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
12
+ var configPath = `${basePath}/config.json`;
13
+ var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
14
+ var defaultAkanGlobalConfig = {
15
+ cloudHost: {},
16
+ remoteEnvServers: {},
17
+ llm: null
18
+ };
19
+
20
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
21
+ class GlobalConfig {
22
+ static akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? `http://localhost:${process.env.CLOUD_HOST_PORT ?? 8283}` : "https://cloud.akanjs.com";
23
+ static async#getAkanGlobalConfig() {
24
+ const exists = await FileSys.fileExists(configPath);
25
+ const akanConfig = exists ? await FileSys.readJson(configPath) : {};
26
+ return {
27
+ ...defaultAkanGlobalConfig,
28
+ ...akanConfig,
29
+ cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
30
+ remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers
31
+ };
32
+ }
33
+ static async#setAkanGlobalConfig(akanConfig) {
34
+ await mkdir(basePath, { recursive: true, mode: 448 });
35
+ await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
36
+ await chmod(configPath, 384);
37
+ }
38
+ static async getHostConfig(host = GlobalConfig.akanCloudHost) {
39
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
40
+ return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
41
+ }
42
+ static async setHostConfig(config = getDefaultHostConfig()) {
43
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
44
+ akanConfig.cloudHost[config.host] = GlobalConfig.toHostConfigDto(config);
45
+ await GlobalConfig.#setAkanGlobalConfig(akanConfig);
46
+ }
47
+ static async getLlmConfig() {
48
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
49
+ return akanConfig.llm ?? null;
50
+ }
51
+ static async setLlmConfig(llmConfig) {
52
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
53
+ await GlobalConfig.#setAkanGlobalConfig({ ...akanConfig, llm: llmConfig });
54
+ }
55
+ static async getRemoteEnvServers() {
56
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
57
+ return akanConfig.remoteEnvServers;
58
+ }
59
+ static async setRemoteEnvServer(name, config) {
60
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
61
+ await GlobalConfig.#setAkanGlobalConfig({
62
+ ...akanConfig,
63
+ remoteEnvServers: {
64
+ ...akanConfig.remoteEnvServers,
65
+ [name]: config
66
+ }
67
+ });
68
+ }
69
+ static async removeRemoteEnvServer(name) {
70
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
71
+ const { [name]: _, ...remoteEnvServers } = akanConfig.remoteEnvServers;
72
+ await GlobalConfig.#setAkanGlobalConfig({
73
+ ...akanConfig,
74
+ remoteEnvServers
75
+ });
76
+ }
77
+ static needRefreshToken(accessToken) {
78
+ return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
79
+ }
80
+ static toAccessToken(accessToken) {
81
+ return {
82
+ jwt: accessToken.jwt,
83
+ refreshToken: accessToken.refreshToken ?? null,
84
+ expiresAt: accessToken.expiresAt ? dayjs(accessToken.expiresAt) : null
85
+ };
86
+ }
87
+ static toAccessTokenDto(accessToken) {
88
+ return {
89
+ jwt: accessToken.jwt,
90
+ refreshToken: accessToken.refreshToken ?? null,
91
+ expiresAt: accessToken.expiresAt?.toString() ?? null
92
+ };
93
+ }
94
+ static toHostConfigDto(hostConfig) {
95
+ return {
96
+ host: hostConfig.host,
97
+ auth: {
98
+ accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
99
+ self: hostConfig.auth?.self
100
+ }
101
+ };
102
+ }
103
+ static toHostConfig(hostConfigDto) {
104
+ return {
105
+ host: hostConfigDto.host,
106
+ auth: {
107
+ accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
108
+ self: hostConfigDto.auth?.self
109
+ }
110
+ };
111
+ }
112
+ }
113
+
114
+ // pkgs/@akanjs/devkit/cloud/cloudApi.ts
115
+ class HttpClient {
116
+ baseUrl;
117
+ headers = {};
118
+ constructor(baseUrl, headers = {}) {
119
+ this.baseUrl = baseUrl;
120
+ this.headers = headers;
121
+ }
122
+ async get(url, { headers } = {}) {
123
+ const response = await fetch(`${this.baseUrl}${url}`, {
124
+ headers: {
125
+ "Content-Type": "application/json",
126
+ ...this.headers,
127
+ ...headers
128
+ }
129
+ });
130
+ return await response.json();
131
+ }
132
+ async getFile(url, localPath, headers) {
133
+ const response = await fetch(`${this.baseUrl}${url}`, {
134
+ headers: { ...this.headers, ...headers }
135
+ });
136
+ if (!response.ok)
137
+ throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
138
+ await Bun.write(localPath, response);
139
+ }
140
+ async post(url, data, { headers } = {}) {
141
+ const isFormData = data instanceof FormData;
142
+ const response = await fetch(`${this.baseUrl}${url}`, {
143
+ method: "POST",
144
+ body: isFormData ? data : JSON.stringify(data),
145
+ headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
146
+ });
147
+ return await response.json();
148
+ }
149
+ setHeaders(headers) {
150
+ Object.assign(this.headers, headers);
151
+ return this;
152
+ }
153
+ }
154
+
155
+ class CloudApi {
156
+ #api;
157
+ #accessToken = null;
158
+ #workspace;
159
+ host;
160
+ url;
161
+ static async fromHost(workspace, host) {
162
+ const hostConfig = await GlobalConfig.getHostConfig(host);
163
+ return new CloudApi(workspace, hostConfig);
164
+ }
165
+ constructor(workspace, hostConfig) {
166
+ this.#workspace = workspace;
167
+ this.#accessToken = hostConfig.auth?.accessToken ?? null;
168
+ this.host = hostConfig.host;
169
+ this.url = `${this.host}/api`;
170
+ this.#api = new HttpClient(this.url);
171
+ if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
172
+ this.#api.setHeaders({
173
+ Authorization: `Bearer ${this.#accessToken.jwt}`
174
+ });
175
+ }
176
+ async uploadEnv(devProjectId, file) {
177
+ const formData = new FormData;
178
+ formData.append("devProjectId", devProjectId);
179
+ formData.append("file", file);
180
+ const data = await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
181
+ return data;
182
+ }
183
+ async downloadEnv(devProjectId) {
184
+ const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
185
+ await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
186
+ return localPath;
187
+ }
188
+ async getRemoteAuthToken(remoteId) {
189
+ try {
190
+ const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
191
+ this.#accessToken = GlobalConfig.toAccessToken(accessToken);
192
+ this.#api.setHeaders({
193
+ Authorization: `Bearer ${this.#accessToken.jwt}`
194
+ });
195
+ return this.#accessToken;
196
+ } catch (_) {
197
+ return null;
198
+ }
199
+ }
200
+ async#ensureAccessTokenLive({
201
+ allowUnauthorized = false
202
+ } = {}) {
203
+ if (!this.#accessToken)
204
+ throw new Error("No access token");
205
+ const needRefresh = GlobalConfig.needRefreshToken(this.#accessToken);
206
+ if (!needRefresh)
207
+ return this.#accessToken;
208
+ const refreshToken = this.#accessToken?.refreshToken;
209
+ if (!refreshToken)
210
+ throw new Error("No refresh token");
211
+ return await this.refreshAuthToken(refreshToken);
212
+ }
213
+ async refreshAuthToken(refreshToken) {
214
+ const response = await this.#api.post(`/refreshAuthToken`, { refreshToken });
215
+ this.#accessToken = GlobalConfig.toAccessToken(response);
216
+ this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
217
+ return this.#accessToken;
218
+ }
219
+ async getRemoteSelf() {
220
+ try {
221
+ const data = await this.#api.get(`/getRemoteSelf`);
222
+ return data;
223
+ } catch {
224
+ return null;
225
+ }
226
+ }
227
+ }
228
+ export { getDefaultHostConfig, GlobalConfig, CloudApi };