@akanjs/cli 3.0.0-beta.13 → 3.0.0-beta.14
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/{TunnelShare-2kwqb1j6.js → TunnelShare-r5tc2qk5.js} +2 -2
- package/{agent.command-7357vxd8.js → agent.command-bhwsc2aj.js} +1 -1
- package/{application.command-8s8ns95d.js → application.command-436y543n.js} +1 -11
- package/{cloud.command-p5dnhft9.js → cloud.command-3xn0xpz8.js} +4 -17
- package/{cloud.script-gxpbhras.js → cloud.script-0a76c2g8.js} +4 -5
- package/commandManifest.json +1 -1
- package/{context.command-wsjt98c1.js → context.command-hxh96cc3.js} +4 -6
- package/{devTui-myg3pqeg.js → devTui-4ted58a6.js} +1 -1
- package/{devTuiView-gz2fbf4v.js → devTuiView-1dj2yq7t.js} +1 -1
- package/guideline.command-cyw8c0m0.js +48 -0
- package/guidelines/agentRule/agentRule.instruction.md +24 -13
- package/guidelines/conventions/conventions.instruction.md +6 -3
- package/guidelines/moduleCodegen/moduleCodegen.instruction.md +1 -1
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +1 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +62 -0
- package/index-1mrmve4s.js +61 -0
- package/{index-s3fvrydw.js → index-31hmq4ys.js} +1 -1
- package/{index-t3c045et.js → index-8tcj5wk8.js} +6 -19
- package/index-9fbk3dbh.js +234 -0
- package/{index-j7rwsd23.js → index-fad0hhty.js} +3 -3
- package/{index-wmb05v4q.js → index-gm76f0qb.js} +1 -1
- package/{index-649svkyt.js → index-myj01w9r.js} +8 -15
- package/{index-h3g1152j.js → index-r73ha1rf.js} +1 -1
- package/{index-cnzm1wn5.js → index-sg1bgdhe.js} +65 -68
- package/{index-bz10w9t2.js → index-tt6kzwj5.js} +5 -15
- package/index.js +14 -14
- package/{localRegistry.command-w6w35j4r.js → localRegistry.command-4cbgz63s.js} +3 -4
- package/{module.command-8zkq0q9q.js → module.command-ew0484va.js} +4 -7
- package/package.json +2 -5
- package/{primitive.command-qm7tybpn.js → primitive.command-50ecfzg4.js} +2 -5
- package/{quality.command-5evdd263.js → quality.command-a2jytczs.js} +63 -3
- package/{scalar.command-a1ewkmab.js → scalar.command-bptz6aj6.js} +3 -6
- package/{subspace.command-3w5x13a1.js → subspace.command-kmemx1vm.js} +2 -2
- package/{tunnel.command-09n8h4s1.js → tunnel.command-67q8vsg5.js} +2 -2
- package/{workflow.command-y3fct1rq.js → workflow.command-2ze5y2xp.js} +4 -7
- package/{workspace.command-p6td4qad.js → workspace.command-2n385jkt.js} +9 -10
- package/abstractCompactor-g04vqcff.js +0 -102
- package/guideline.command-snqzfyt0.js +0 -360
- package/index-5tw8t1ts.js +0 -338
- package/index-j1tajctp.js +0 -229
- package/index-kpnp2e10.js +0 -841
- package/index-meh558jy.js +0 -65
package/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
f06399ed7f38f0f1001501ebf36203c43473554fc56177ed5d3be66e6b399252
|
|
@@ -12,7 +12,7 @@ import"./index-15r9a10e.js";
|
|
|
12
12
|
import"./index-h7yw2z9n.js";
|
|
13
13
|
import {
|
|
14
14
|
AgentScript
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-31hmq4ys.js";
|
|
16
16
|
|
|
17
17
|
// pkgs/@akanjs/cli/agent/agent.command.ts
|
|
18
18
|
class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({
|
|
@@ -12,16 +12,13 @@ import"./index-5nyznra1.js";
|
|
|
12
12
|
import"./index-6wwzs1bc.js";
|
|
13
13
|
import {
|
|
14
14
|
ApplicationScript
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-sg1bgdhe.js";
|
|
16
16
|
import"./index-1nwxbr2y.js";
|
|
17
17
|
import"./index-hwkygn9s.js";
|
|
18
18
|
import"./index-ys7dvdb3.js";
|
|
19
19
|
import {
|
|
20
20
|
getMobileTargetChoices
|
|
21
21
|
} from "./index-47pj3aee.js";
|
|
22
|
-
import {
|
|
23
|
-
AbstractDoc
|
|
24
|
-
} from "./index-meh558jy.js";
|
|
25
22
|
|
|
26
23
|
// pkgs/@akanjs/cli/application/application.command.ts
|
|
27
24
|
import { select } from "@inquirer/prompts";
|
|
@@ -44,13 +41,6 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
|
|
|
44
41
|
sync: target({ desc: "Sync dependencies and configuration for an app or library" }).with(Sys).exec(async function(sys) {
|
|
45
42
|
await this.applicationScript.sync(sys);
|
|
46
43
|
}),
|
|
47
|
-
compact: target({ desc: "Compact the *.abstract.md files of an app or library with the AI editor" }).with(Sys).option("module", String, { desc: "single module to compact", nullable: true }).option("minLines", Number, {
|
|
48
|
-
flag: "n",
|
|
49
|
-
desc: "only compact abstracts longer than this",
|
|
50
|
-
default: AbstractDoc.compactMinLines
|
|
51
|
-
}).option("interactive", Boolean, { desc: "confirm or refine each rewrite", default: false }).exec(async function(sys, module, minLines, interactive) {
|
|
52
|
-
await this.applicationScript.compact(sys, { module, minLines, interactive });
|
|
53
|
-
}),
|
|
54
44
|
script: target({ desc: "Run a custom script in the application" }).with(App).arg("filename", String, { desc: "name of script", nullable: true }).exec(async function(app, filename) {
|
|
55
45
|
await this.applicationScript.script(app, filename);
|
|
56
46
|
}),
|
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
import"./index-q0y2jq9j.js";
|
|
3
3
|
import {
|
|
4
4
|
GlobalConfig
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-myj01w9r.js";
|
|
6
6
|
import {
|
|
7
7
|
Workspace,
|
|
8
8
|
command
|
|
9
9
|
} from "./index-b3ae16mg.js";
|
|
10
10
|
import"./index-5nyznra1.js";
|
|
11
11
|
import"./index-6wwzs1bc.js";
|
|
12
|
-
import"./index-
|
|
13
|
-
import"./index-cnzm1wn5.js";
|
|
12
|
+
import"./index-sg1bgdhe.js";
|
|
14
13
|
import"./index-1nwxbr2y.js";
|
|
15
14
|
import"./index-hwkygn9s.js";
|
|
16
15
|
import"./index-kcxmv48c.js";
|
|
17
16
|
import"./index-t8gvwcrx.js";
|
|
18
|
-
import"./index-
|
|
17
|
+
import"./index-tt6kzwj5.js";
|
|
19
18
|
import {
|
|
20
19
|
CloudScript2
|
|
21
|
-
} from "./index-
|
|
20
|
+
} from "./index-8tcj5wk8.js";
|
|
22
21
|
import"./index-ys7dvdb3.js";
|
|
23
22
|
|
|
24
23
|
// pkgs/@akanjs/cli/cloud/cloud.command.ts
|
|
@@ -32,18 +31,6 @@ class CloudCommand extends command("cloud", [CloudScript2], ({ public: target })
|
|
|
32
31
|
logout: target({ desc: "Logout from Akan Cloud services" }).option("host", String, { desc: "host of the cloud", default: GlobalConfig.akanCloudHost }).with(Workspace).exec(async function(host, workspace) {
|
|
33
32
|
await this.cloudScript.logout(workspace, host);
|
|
34
33
|
}),
|
|
35
|
-
setLlm: target({ desc: "Configure LLM (Large Language Model) API key" }).with(Workspace).exec(async function(workspace) {
|
|
36
|
-
await this.cloudScript.setLlm(workspace);
|
|
37
|
-
}),
|
|
38
|
-
resetLlm: target({ desc: "Reset LLM configuration to default" }).with(Workspace).exec(function(workspace) {
|
|
39
|
-
this.cloudScript.resetLlm(workspace);
|
|
40
|
-
}),
|
|
41
|
-
ask: target({
|
|
42
|
-
devOnly: true,
|
|
43
|
-
desc: "Ask AI assistant a question about your project"
|
|
44
|
-
}).option("question", String, { ask: "question to ask" }).with(Workspace).exec(async function(question, workspace) {
|
|
45
|
-
await this.cloudScript.ask(question, workspace);
|
|
46
|
-
}),
|
|
47
34
|
deployAkan: target({
|
|
48
35
|
devOnly: true,
|
|
49
36
|
desc: "Deploy Akan.js framework to cloud (internal use)"
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudScript2
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
4
|
+
} from "./index-8tcj5wk8.js";
|
|
5
|
+
import"./index-tt6kzwj5.js";
|
|
6
|
+
import"./index-sg1bgdhe.js";
|
|
7
7
|
import"./index-ys7dvdb3.js";
|
|
8
8
|
import"./index-1nwxbr2y.js";
|
|
9
9
|
import"./index-t8gvwcrx.js";
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-649svkyt.js";
|
|
10
|
+
import"./index-myj01w9r.js";
|
|
12
11
|
import"./index-b3ae16mg.js";
|
|
13
12
|
import"./index-hwkygn9s.js";
|
|
14
13
|
import"./index-5nyznra1.js";
|
package/commandManifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"byCommand":{"create-workspace":"workspace","generate-agent-rules":"workspace","lint":"workspace","lint-all":"workspace","sync-all":"workspace","init":"workspace","agent":"agent","create-application":"application","remove-application":"application","plan-slice":"application","sync":"application","
|
|
1
|
+
{"byCommand":{"create-workspace":"workspace","generate-agent-rules":"workspace","lint":"workspace","lint-all":"workspace","sync-all":"workspace","init":"workspace","agent":"agent","create-application":"application","remove-application":"application","plan-slice":"application","sync":"application","script":"application","console":"application","logs":"application","build":"application","b":"application","typecheck":"application","t":"application","test":"application","build-ios":"application","bi":"application","build-android":"application","ba":"application","start":"application","s":"application","start-ios":"application","si":"application","start-android":"application","sa":"application","release-ios":"application","release-android":"application","release-source":"application","codepush":"application","dbup":"application","dbdown":"application","configure-app":"application","create-library":"library","remove-library":"library","sync-library":"library","library-status":"library","install-library":"library","start-registry":"localRegistry","reset-registry":"localRegistry","smoke-registry":"localRegistry","version":"package","create-package":"package","remove-package":"package","sync-package":"package","build-package":"package","verify-dist-package":"package","verify-akan-publish-packages":"package","create-module":"module","remove-module":"module","create-service":"module","create-view":"module","create-unit":"module","create-template":"module","create-crud-page":"page","context":"context","doctor":"context","mcp-install":"context","mcp":"context","mcp-call":"context","login":"cloud","logout":"cloud","deploy-akan":"cloud","update":"cloud","download-env":"cloud","upload-env":"cloud","subspace":"subspace","guideline":"guideline","create-scalar":"scalar","remove-scalar":"scalar","create-ui":"primitive","add-field":"primitive","add-enum-field":"primitive","quality":"quality","repair":"repair","workflow":"workflow","tunnel":"tunnel"}}
|
|
@@ -11,17 +11,15 @@ import"./index-jwjaf9fy.js";
|
|
|
11
11
|
import"./index-15r9a10e.js";
|
|
12
12
|
import {
|
|
13
13
|
ContextScript
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-fad0hhty.js";
|
|
15
15
|
import"./index-7f4dsf9v.js";
|
|
16
16
|
import"./index-h7yw2z9n.js";
|
|
17
17
|
import"./index-em4swemt.js";
|
|
18
18
|
import"./index-8pkvrcv1.js";
|
|
19
|
-
import"./index-649svkyt.js";
|
|
20
|
-
import"./index-5tw8t1ts.js";
|
|
21
|
-
import"./index-kpnp2e10.js";
|
|
22
19
|
import"./index-sh88vtye.js";
|
|
23
|
-
import"./index-
|
|
24
|
-
import"./index-
|
|
20
|
+
import"./index-9fbk3dbh.js";
|
|
21
|
+
import"./index-r73ha1rf.js";
|
|
22
|
+
import"./index-1mrmve4s.js";
|
|
25
23
|
|
|
26
24
|
// pkgs/@akanjs/cli/context/context.command.ts
|
|
27
25
|
class ContextCommand extends command("context", [ContextScript], ({ public: target }) => ({
|
|
@@ -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-
|
|
4
|
+
const { DevTui } = await import("./devTui-4ted58a6.js");
|
|
5
5
|
return new DevTui(supervisor);
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
script,
|
|
4
|
+
command
|
|
5
|
+
} from "./index-b3ae16mg.js";
|
|
6
|
+
import"./index-q0y2jq9j.js";
|
|
7
|
+
import"./index-5nyznra1.js";
|
|
8
|
+
import"./index-6wwzs1bc.js";
|
|
9
|
+
import {
|
|
10
|
+
Prompter
|
|
11
|
+
} from "./index-h7yw2z9n.js";
|
|
12
|
+
|
|
13
|
+
// pkgs/@akanjs/cli/guideline/guideline.script.ts
|
|
14
|
+
import { Logger } from "akanjs/common";
|
|
15
|
+
|
|
16
|
+
class GuidelineScript extends script("guideline") {
|
|
17
|
+
async guideline(action, name = null, format = "markdown") {
|
|
18
|
+
if (action === "list") {
|
|
19
|
+
const guidelines = await Prompter.listGuidelines();
|
|
20
|
+
Logger.rawLog(format === "json" ? JSON.stringify({ guidelines }, null, 2) : guidelines.join(`
|
|
21
|
+
`));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (action === "show") {
|
|
25
|
+
if (!name)
|
|
26
|
+
throw new Error("Guideline name is required. Example: akan guideline show framework");
|
|
27
|
+
const [instruction, guideJson] = await Promise.all([Prompter.getInstruction(name), Prompter.getGuideJson(name)]);
|
|
28
|
+
Logger.rawLog(format === "json" ? JSON.stringify({ name, instruction, guideJson }, null, 2) : instruction);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`Unknown guideline action: ${action}. Use "list" or "show".`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// pkgs/@akanjs/cli/guideline/guideline.command.ts
|
|
36
|
+
class GuidelineCommand extends command("guideline", [GuidelineScript], ({ public: target }) => ({
|
|
37
|
+
guideline: target({ desc: "List or show Akan AI guideline instructions" }).arg("action", String, { desc: "list or show" }).arg("name", String, { desc: "guideline name for show", nullable: true }).option("format", String, {
|
|
38
|
+
desc: "output format",
|
|
39
|
+
default: "markdown",
|
|
40
|
+
enum: ["markdown", "json"]
|
|
41
|
+
}).exec(async function(action, name, format) {
|
|
42
|
+
await this.guidelineScript.guideline(action, name, format);
|
|
43
|
+
})
|
|
44
|
+
})) {
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
GuidelineCommand
|
|
48
|
+
};
|
|
@@ -76,19 +76,30 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
|
|
|
76
76
|
- **The LLM is configured in `option.ts`, never through the environment.** `option.setLlm({ apiKey, model, host })`
|
|
77
77
|
— or `setLlm((options) => …)` to read the key out of the app's own env object, which is where a secret belongs —
|
|
78
78
|
fills whichever adaptor holds `LlmAdaptorRole`, reaching it as the `llmOption` use. The settings are the role's
|
|
79
|
-
rather than one provider's, so they survive a swap.
|
|
80
|
-
`https://api.
|
|
81
|
-
providers the way middleware is applied:
|
|
82
|
-
write its own — an `adapt()` class in a
|
|
83
|
-
ignoring `onDelta` still answers whole —
|
|
84
|
-
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
79
|
+
rather than one provider's, so they survive a swap. **`OpenaiLlm` is the built-in default**, pointed at
|
|
80
|
+
`https://api.openai.com/v1`; with no `apiKey` or no `model` the app still boots and the chat answers
|
|
81
|
+
`llmUnavailable`. Swap providers the way middleware is applied:
|
|
82
|
+
`option.applyAdaptor(LlmAdaptorRole, AnthropicLlm)`. An app may still write its own — an `adapt()` class in a
|
|
83
|
+
`srvkit/` implementing `LlmAdaptor.chat(request, onDelta?)`, where ignoring `onDelta` still answers whole — and
|
|
84
|
+
whatever settings it needs beyond `LlmOption` travel through the same `setLlm`, read back with
|
|
85
|
+
`use<MyLlmOption>()` from an interface extending it.
|
|
86
|
+
- **Two adaptors ship, one per wire — a vendor is a host and a model name, not a protocol.** `OpenaiLlm` is the
|
|
87
|
+
chat-completions dialect (`OpenaiDialect`) pointed at whatever `host` names, so OpenAI, DeepSeek, Groq,
|
|
88
|
+
Together, OpenRouter, Ollama and a self-hosted vLLM are all one class and one `option.setLlm({ host, model })`.
|
|
89
|
+
`AnthropicLlm` is the Messages API and declares `{ image: true, document: true }`; it is its own file rather
|
|
90
|
+
than a branch, because the system prompt is a field and not a message, tool calls and results are content
|
|
91
|
+
blocks, the results ride in a *user* turn, roles must alternate — so two wire turns that map to one role are
|
|
92
|
+
merged — and `max_tokens` is required. **Both require `model`**: a default would age into a 404, and worse, it
|
|
93
|
+
would decide the vision claim for the app.
|
|
94
|
+
- **`OpenaiLlm` claims vision for its default host and for nothing else.** OpenAI's own endpoint takes image
|
|
95
|
+
parts, so that is what it answers with no `host` set. A `host` the app named is a gateway the class knows
|
|
96
|
+
nothing about, and it stays text-only until `option.setLlm({ accepts })` says otherwise — handing bytes to a
|
|
97
|
+
model that cannot decode them kills the whole turn on a 400, where text-only degrades them to a note the model
|
|
98
|
+
can repeat back.
|
|
99
|
+
- **A refusal is one key, `agent.error.llmRequestFailed`, and it names the host.** The provider's own sentence
|
|
100
|
+
rides in `reason` and the hostname in `provider`, so an adaptor an app wrote reports through the same
|
|
101
|
+
translated channel the shipped ones do rather than needing a key in the framework's dictionary it cannot
|
|
102
|
+
add.
|
|
92
103
|
- **`accepts` is answered per model, through `option.setLlm({ accepts })`.** An adaptor answers for an API and one
|
|
93
104
|
API serves models that differ, so the override rides beside the `model` it is a fact about. It is not a table
|
|
94
105
|
the framework keeps: a table is a claim about models that ship after it, and getting this wrong is the worst
|
|
@@ -714,9 +714,12 @@ what every developer must know even when not building one.
|
|
|
714
714
|
every tool runs in the caller's own browser session, gated by guards and the approval card. Its guard is
|
|
715
715
|
`AgentRelayAccess`, which refuses every call until the app names a guard of its own —
|
|
716
716
|
`option.setAgentAccess(SignedIn)`. **The LLM is configured in `option.ts`, never through the environment**
|
|
717
|
-
(`option.setLlm({ apiKey, model, host })`).
|
|
718
|
-
|
|
719
|
-
`
|
|
717
|
+
(`option.setLlm({ apiKey, model, host })`). Two adaptors ship, one per wire: `OpenaiLlm` is the default and
|
|
718
|
+
speaks the chat-completions dialect to whatever `host` names — OpenAI, DeepSeek, Groq, OpenRouter, Ollama — and
|
|
719
|
+
`AnthropicLlm` speaks the Messages API and reads a PDF as well as a picture. Both require `model`. A provider
|
|
720
|
+
neither covers is an `adapt()` class in `srvkit/` implementing `LlmAdaptor`, applied with
|
|
721
|
+
`option.applyAdaptor(LlmAdaptorRole, TheClass)`; whatever settings it needs beyond `LlmOption` ride `setLlm`
|
|
722
|
+
too, read back with `use<MyLlmOption>()`.
|
|
720
723
|
- **Declare the tool beside the control that already does it**, never as a separate surface:
|
|
721
724
|
`st.tool("x").desc("…").arg("id", ID).exec(fn)` returns the callable to hand to `onClick` — one handler for the
|
|
722
725
|
person and the agent. Publish it only where the screen already renders the control; a falsy name declares the
|
|
@@ -6,7 +6,7 @@ Use this to orchestrate AI-assisted module creation. The model should emit small
|
|
|
6
6
|
## Ownership
|
|
7
7
|
- Input description explains the business object, lifecycle, actions, queries, UI needs, and relations.
|
|
8
8
|
- The first output pass should prioritize data shape and persistence over decorative UI.
|
|
9
|
-
- Each returned code block must start with `// File: <relative path>` so
|
|
9
|
+
- Each returned code block must start with `// File: <relative path>` so the caller can tell which file it writes.
|
|
10
10
|
- Generated files must target `lib/<model>/...` or `lib/__scalar/<scalar>/...` only unless explicitly requested.
|
|
11
11
|
|
|
12
12
|
## Current Akan Patterns
|
|
@@ -393,6 +393,68 @@ Rules the loader and `akan sync` enforce: a chain module has no other export; `p
|
|
|
393
393
|
`_overrides.tsx` is untouched. MCP: `prompts/get` now runs the page's body under the caller's token and hands the
|
|
394
394
|
model the description, what the page fetched, and the tools of those modules — see `mcpRule`.
|
|
395
395
|
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Recipe 8: Migrating the LLM Adaptor and the Removed `--ai` Commands
|
|
399
|
+
|
|
400
|
+
Two changes land together. The runtime LLM seam now names a wire rather than a vendor, and the CLI's AI editor is
|
|
401
|
+
gone. They touch different files and neither one is optional — the first breaks a build or, worse, degrades
|
|
402
|
+
silently; the second breaks a script that calls a command that no longer exists.
|
|
403
|
+
|
|
404
|
+
#### The adaptor, in `lib/option.ts` and `env/env.server.*.ts`
|
|
405
|
+
|
|
406
|
+
`DeepseekLlm` is deleted. `OpenaiLlm` is the default and speaks the chat-completions dialect to whatever `host`
|
|
407
|
+
names, so DeepSeek, Groq, Together, OpenRouter, Ollama and a self-hosted vLLM are the same class with a different
|
|
408
|
+
`host` and `model`. `AnthropicLlm` is unchanged.
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
// before — env/env.server.local.ts
|
|
412
|
+
export const env: ModulesOptions = {
|
|
413
|
+
...libEnv,
|
|
414
|
+
llm: { apiKey: process.env.DEEPSEEK_KEY },
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// after — the default model and host are gone, so name both
|
|
418
|
+
export const env: ModulesOptions = {
|
|
419
|
+
...libEnv,
|
|
420
|
+
llm: { apiKey: process.env.DEEPSEEK_KEY, model: "deepseek-v4-flash", host: "https://api.deepseek.com" },
|
|
421
|
+
};
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
| Before | After | What happens if you skip it |
|
|
425
|
+
|---|---|---|
|
|
426
|
+
| `setLlm({ apiKey })`, relying on the DeepSeek default | `setLlm({ apiKey, model, host })` | The app boots, the log warns once, and the chat answers `llmUnavailable` to every turn |
|
|
427
|
+
| `applyAdaptor(LlmAdaptorRole, DeepseekLlm)` | `OpenaiLlm` + `host: "https://api.deepseek.com"` | Build error — the class is gone |
|
|
428
|
+
| `OpenaiLlm` pointed at a **named** `host`, reading images | add `accepts: { image: true }` to `setLlm` | **Silent**: images reach the model as a note saying they could not be read |
|
|
429
|
+
| An adaptor of your own throwing `agent.error.<vendor>RequestFailed` | `new Err("agent.error.llmRequestFailed", { provider, status, reason })` | The chat prints the raw key instead of a sentence |
|
|
430
|
+
| Provider settings in a second `option.use({ myLlmOption })` | put them in `setLlm` and read `use<MyLlmOption>()` | Nothing breaks; the second channel is no longer needed |
|
|
431
|
+
|
|
432
|
+
`OpenaiLlm` claims vision for its default host (`https://api.openai.com/v1`) and for nothing else, because a host
|
|
433
|
+
you named is a gateway it knows nothing about — and bytes handed to a model that cannot decode them kill the whole
|
|
434
|
+
turn on a 400, where text-only degrades them to a note. Declare `accepts` whenever you set `host`.
|
|
435
|
+
|
|
436
|
+
`LlmOption` is now a floor rather than the whole shape: `setLlm` carries whatever else it is handed to the role, so
|
|
437
|
+
an adaptor of your own declares `interface MyLlmOption extends LlmOption { region: string }`, reads it with
|
|
438
|
+
`use<MyLlmOption>()`, and stops needing a config channel beside `setLlm`.
|
|
439
|
+
|
|
440
|
+
#### The CLI, in scripts and CI
|
|
441
|
+
|
|
442
|
+
`AiSession` and every command that drove it are removed. There is no replacement command — the workspace's agent
|
|
443
|
+
surface (`akan context`, the MCP tools, `akan guideline show`) is what feeds a coding agent now.
|
|
444
|
+
|
|
445
|
+
| Removed | What to do instead |
|
|
446
|
+
|---|---|
|
|
447
|
+
| `akan create-module <name> --ai`, `akan create-scalar <name> --ai` | Drop the flag. The command scaffolds the same files it always did; write the constant and dictionary yourself or let a coding agent do it against `get_guideline modelConstant` / `modelDictionary` |
|
|
448
|
+
| `akan compact <app-or-lib>` | Edit the `*.abstract.md` by hand. `akan quality scan` still warns past 300 lines |
|
|
449
|
+
| `akan set-llm`, `akan reset-llm`, `akan ask` | Nothing. The runtime LLM is `option.setLlm(...)` and has never been this config |
|
|
450
|
+
| `akan generate-instruction`, `akan update-instruction`, `akan generate-document`, `akan reapply-instruction` | Nothing. `akan guideline list` / `show` still read the bundled guidelines |
|
|
451
|
+
| `import { AiSession } from "@akanjs/devkit/aiEditor"` | Nothing — the module is gone |
|
|
452
|
+
|
|
453
|
+
`~/.akan/config.json` keeps an `llm` entry if it had one. It is ignored; delete it, because it holds an API key.
|
|
454
|
+
|
|
455
|
+
Then: `bun run akan typecheck <app>`, `bun run akan lint <app>`, and one agent turn in the browser to confirm the
|
|
456
|
+
provider answers.
|
|
457
|
+
|
|
396
458
|
### Data Flow Summary
|
|
397
459
|
|
|
398
460
|
For each business question, follow this chain:
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
runner,
|
|
4
|
+
script
|
|
5
|
+
} from "./index-b3ae16mg.js";
|
|
6
|
+
import {
|
|
7
|
+
generatedFilesForSync,
|
|
8
|
+
createPassedPrimitiveReport,
|
|
9
|
+
scalarChangedFiles
|
|
10
|
+
} from "./index-jwjaf9fy.js";
|
|
11
|
+
import {
|
|
12
|
+
pluralizeName
|
|
13
|
+
} from "./index-nz8prx9g.js";
|
|
14
|
+
|
|
15
|
+
// pkgs/@akanjs/cli/scalar/scalar.runner.ts
|
|
16
|
+
class ScalarRunner extends runner("scalar") {
|
|
17
|
+
async applyScalarTemplate(sys, scalarName) {
|
|
18
|
+
await sys.applyTemplate({
|
|
19
|
+
basePath: "./lib/__scalar",
|
|
20
|
+
template: "__scalar",
|
|
21
|
+
dict: { model: scalarName, models: pluralizeName(scalarName), sysName: sys.name },
|
|
22
|
+
overwrite: false
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
abstract: {
|
|
26
|
+
filename: `${scalarName}.abstract.md`,
|
|
27
|
+
content: await sys.readFile(`lib/__scalar/${scalarName}/${scalarName}.abstract.md`)
|
|
28
|
+
},
|
|
29
|
+
constant: {
|
|
30
|
+
filename: `${scalarName}.constant.ts`,
|
|
31
|
+
content: await sys.readFile(`lib/__scalar/${scalarName}/${scalarName}.constant.ts`)
|
|
32
|
+
},
|
|
33
|
+
dictionary: {
|
|
34
|
+
filename: `${scalarName}.dictionary.ts`,
|
|
35
|
+
content: await sys.readFile(`lib/__scalar/${scalarName}/${scalarName}.dictionary.ts`)
|
|
36
|
+
},
|
|
37
|
+
document: {
|
|
38
|
+
filename: `${scalarName}.document.ts`,
|
|
39
|
+
content: await sys.readFile(`lib/__scalar/${scalarName}/${scalarName}.document.ts`)
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// pkgs/@akanjs/cli/scalar/scalar.script.ts
|
|
46
|
+
class ScalarScript extends script("scalar", [ScalarRunner]) {
|
|
47
|
+
async createScalar(sys, scalarName) {
|
|
48
|
+
const files = await this.scalarRunner.applyScalarTemplate(sys, scalarName);
|
|
49
|
+
return createPassedPrimitiveReport({
|
|
50
|
+
command: "create-scalar",
|
|
51
|
+
changedFiles: scalarChangedFiles(sys, scalarName, files),
|
|
52
|
+
generatedFiles: generatedFilesForSync(sys),
|
|
53
|
+
target: sys.name
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async removeScalar(sys, scalarName) {
|
|
57
|
+
await sys.removeDir(`lib/__scalar/${scalarName}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { ScalarScript };
|
|
@@ -138,7 +138,7 @@ ${sampleCleanup}## Akan Module Abstracts
|
|
|
138
138
|
- Update the abstract when business invariants, workflows, or public behavior change.
|
|
139
139
|
- Do not update the abstract for formatting-only, import-only, or style-only changes.
|
|
140
140
|
- Service modules live in \`lib/_<service>\`, but their abstract file is \`<service>.abstract.md\`.
|
|
141
|
-
- Keep an abstract short
|
|
141
|
+
- Keep an abstract short \u2014 the invariants the code cannot show, and nothing it already states. \`akan quality scan\` warns past 300 lines.
|
|
142
142
|
|
|
143
143
|
## Generated Files
|
|
144
144
|
|
|
@@ -2,25 +2,22 @@
|
|
|
2
2
|
import {
|
|
3
3
|
GlobalConfig,
|
|
4
4
|
CloudApi
|
|
5
|
-
} from "./index-
|
|
6
|
-
import {
|
|
7
|
-
PkgExecutor
|
|
8
|
-
} from "./index-5nyznra1.js";
|
|
9
|
-
import {
|
|
10
|
-
AiSession
|
|
11
|
-
} from "./index-5tw8t1ts.js";
|
|
5
|
+
} from "./index-myj01w9r.js";
|
|
12
6
|
import {
|
|
13
7
|
script
|
|
14
8
|
} from "./index-b3ae16mg.js";
|
|
9
|
+
import {
|
|
10
|
+
PkgExecutor
|
|
11
|
+
} from "./index-5nyznra1.js";
|
|
15
12
|
import {
|
|
16
13
|
ApplicationScript
|
|
17
|
-
} from "./index-
|
|
14
|
+
} from "./index-sg1bgdhe.js";
|
|
18
15
|
import {
|
|
19
16
|
PackageScript
|
|
20
17
|
} from "./index-t8gvwcrx.js";
|
|
21
18
|
import {
|
|
22
19
|
CloudRunner
|
|
23
|
-
} from "./index-
|
|
20
|
+
} from "./index-tt6kzwj5.js";
|
|
24
21
|
|
|
25
22
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
26
23
|
import { Logger } from "akanjs/common";
|
|
@@ -31,16 +28,6 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
|
|
|
31
28
|
async logout(workspace, host = GlobalConfig.akanCloudHost) {
|
|
32
29
|
await this.cloudRunner.logout(host);
|
|
33
30
|
}
|
|
34
|
-
async setLlm(workspace) {
|
|
35
|
-
await this.cloudRunner.setLlm();
|
|
36
|
-
}
|
|
37
|
-
resetLlm(workspace) {
|
|
38
|
-
this.cloudRunner.resetLlm();
|
|
39
|
-
}
|
|
40
|
-
async ask(question, workspace) {
|
|
41
|
-
const session = new AiSession("general", { workspace, isContinued: true });
|
|
42
|
-
await session.ask(question);
|
|
43
|
-
}
|
|
44
31
|
async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host = GlobalConfig.akanCloudHost } = {}) {
|
|
45
32
|
if (workspaceId) {
|
|
46
33
|
await this.login(workspace, host);
|