@akanjs/cli 3.0.0-beta.17 → 3.0.0-beta.19
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-gjqnc2mg.js → CodeAgent-6cm97kay.js} +2 -2
- package/{CodeAgentRpcHost-qvwfv0n9.js → CodeAgentRpcHost-p7h6n2hp.js} +1 -1
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/{CodeTui-nd9hqvrw.js → CodeTui-za4jsm41.js} +205 -34
- package/{TunnelShare-r5tc2qk5.js → TunnelShare-2j6s511d.js} +2 -2
- package/{agent.command-n664dtcv.js → agent.command-e0wpbbyg.js} +6 -6
- package/akanCode.js +7 -5
- package/{application.command-t5542jte.js → application.command-8wyxqc8q.js} +28 -15
- package/{applicationBuildRunner-x4gbfn7y.js → applicationBuildRunner-n9gzaxd0.js} +35 -10
- package/{applicationReleasePackager-z61ep017.js → applicationReleasePackager-vpggfqgq.js} +1 -1
- package/buildBatch.proc.js +3 -3
- package/{capacitorApp-shv3ajh5.js → capacitorApp-q3z0qht0.js} +2 -2
- package/{cloud.command-dk5tj39k.js → cloud.command-4zwa5dsx.js} +34 -12
- package/cloud.script-fwx3vb34.js +20 -0
- package/{code.command-88sebgnn.js → code.command-468c9d7s.js} +41 -19
- package/commandManifest.json +1 -1
- package/{context.command-pqsm5jrk.js → context.command-dsnw0jby.js} +14 -14
- package/context.runner-rs4rj15d.js +22 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-0z2h2tks.js} +1 -1
- package/{devTui-gy6mendg.js → devTui-ffjsarqa.js} +3 -3
- package/{devTuiView-y1548wy6.js → devTuiView-1q1mdgrv.js} +1 -1
- package/{guideline.command-rpc2emw8.js → guideline.command-vhw13pqr.js} +8 -13
- package/guidelines/agentRule/agentRule.instruction.md +27 -10
- package/guidelines/conventions/conventions.instruction.md +53 -26
- package/guidelines/queryRule/queryRule.instruction.md +17 -7
- package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
- package/guidelines/transportRule/transportRule.instruction.md +10 -8
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +4 -3
- package/incrementalBuilder.proc.js +3 -2
- package/{index-4n4821gp.js → index-10dkrrww.js} +4 -4
- package/{index-bzakk0c2.js → index-14zrtgfa.js} +5 -3
- package/{index-v17gj504.js → index-18zybgkc.js} +2 -2
- package/{index-qh7brn20.js → index-22xtgmhn.js} +6 -2
- package/{index-qhtj9y6j.js → index-2446k7b4.js} +74 -21
- package/{index-g9zghs4h.js → index-3jrp517k.js} +12 -12
- package/{index-vpx68e4x.js → index-4m929vvn.js} +2 -2
- package/{index-4cvpzkq6.js → index-53176s7j.js} +3 -3
- package/{index-jwrpsrg3.js → index-667w0yah.js} +1 -1
- package/{index-3mg4h788.js → index-7ep8qtvp.js} +2 -2
- package/{index-w8kmx1b6.js → index-89hy31kf.js} +30 -7
- package/index-9d6nvkz2.js +656 -0
- package/index-9dp031by.js +12 -0
- package/{index-zn8qgeqx.js → index-a1w6934z.js} +3 -3
- package/{index-p0tew3fq.js → index-ab0c38ea.js} +10 -5
- package/index-bc88j1ry.js +1166 -0
- package/{index-ns128c4q.js → index-bftkz6cp.js} +280 -73
- package/{index-kcxmv48c.js → index-bhtmj233.js} +4 -1
- package/{index-kvzjda3v.js → index-bwf965h6.js} +5 -5
- package/{index-p4p9t45x.js → index-crmeqnmf.js} +56 -44
- package/{index-8k16atqy.js → index-d2242ksy.js} +23 -6
- package/{index-2sq06vv0.js → index-e4v6vhxq.js} +417 -105
- package/{index-xjc7gg65.js → index-esk82rvk.js} +23 -33
- package/{index-sn7dnzq4.js → index-kwaq3n9n.js} +1 -1
- package/{index-gm76f0qb.js → index-n3cv0tm4.js} +1 -1
- package/{index-6na0sd2b.js → index-qdgzsnhg.js} +5 -2
- package/{index-twq9p2sp.js → index-s5rhm04y.js} +0 -6
- package/{index-n8kt2wh6.js → index-sq2dzkzm.js} +35 -10
- package/{index-myj01w9r.js → index-srmay5jw.js} +15 -2
- package/{index-2pm1j01n.js → index-txr7dj2g.js} +4 -4
- package/{index-3cymrzsb.js → index-vqx8bdxz.js} +17 -3
- package/{index-te0y1c0m.js → index-zqgj2rt2.js} +12 -7
- package/index.js +21 -21
- package/{library.command-m8p2r1dh.js → library.command-cqr175dy.js} +3 -3
- package/{localRegistry.command-yppdqrxv.js → localRegistry.command-49z55qqz.js} +9 -9
- package/{module.command-mfzvqt0n.js → module.command-9p8mm3b0.js} +5 -5
- package/{package.command-cgp2p2v5.js → package.command-wxyz909t.js} +5 -5
- package/package.json +2 -2
- package/{page.command-taenb02b.js → page.command-gsrsfqqs.js} +3 -3
- package/{primitive.command-7kpncmkk.js → primitive.command-ns1mptje.js} +6 -6
- package/{prompter-9mn3kp36.js → prompter-1f8d9pcc.js} +1 -1
- package/{quality.command-1ar94hrw.js → quality.command-e76k2q9k.js} +18 -17
- package/{repair.command-n08t6j8p.js → repair.command-pkrsm3cw.js} +5 -5
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-mq8qfp4t.js → scalar.command-0cpt3fc8.js} +4 -4
- package/skills/akan-code/SKILL.md +122 -0
- package/skills/akan-module/SKILL.md +2 -2
- package/skills/akan-store/SKILL.md +6 -2
- package/{subspace.command-jqv5n79w.js → subspace.command-fktpwp0g.js} +20 -10
- package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
- package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
- package/templates/appSample/lib/task/task.abstract.ts +12 -32
- package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
- package/templates/appSample/lib/task/task.signal.test.ts +15 -1
- package/templates/appSample/lib/task/task.signal.ts +1 -1
- package/templates/appSample/srvkit/AuthGuard.ts +4 -1
- package/templates/appSample/srvkit/SessionInternalArg.ts +3 -1
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
- package/templates/crudPages/[__model__Id]/page.tsx +2 -1
- package/templates/crudPages/new/page.tsx +2 -1
- package/templates/crudPages/page.tsx +2 -1
- package/templates/crudSinglePage/page.tsx +2 -1
- package/templates/localDev/docker-compose.yaml.template +3 -14
- package/templates/module/__model__.signal.ts +12 -4
- package/templates/pkgRoot/tsconfig.json.template +2 -7
- package/templates/service/__model__.abstract.md.template +8 -0
- package/{tunnel.command-ht2es78c.js → tunnel.command-d5jy9gk8.js} +4 -4
- package/{workflow.command-tvz4nm9n.js → workflow.command-6tkcysmx.js} +9 -9
- package/{workspace.command-txv1yv5e.js → workspace.command-gv84eh1p.js} +25 -24
- package/cloud.script-ch3xrw3s.js +0 -20
- package/context.runner-bys6ykcp.js +0 -22
- package/guidelines/agentRule/agentRule.generate.json +0 -31
- package/guidelines/componentRule/componentRule.generate.json +0 -31
- package/guidelines/conventions/conventions.generate.json +0 -25
- package/guidelines/cssRule/cssRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
- package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
- package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
- package/guidelines/enumConstant/enumConstant.generate.json +0 -31
- package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
- package/guidelines/fieldRule/fieldRule.generate.json +0 -31
- package/guidelines/framework/framework.generate.json +0 -32
- package/guidelines/mcpRule/mcpRule.generate.json +0 -35
- package/guidelines/modelConstant/modelConstant.generate.json +0 -32
- package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
- package/guidelines/modelDocument/modelDocument.generate.json +0 -31
- package/guidelines/modelService/modelService.generate.json +0 -31
- package/guidelines/modelSignal/modelSignal.generate.json +0 -31
- package/guidelines/modelStore/modelStore.generate.json +0 -31
- package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
- package/guidelines/modelUnit/modelUnit.generate.json +0 -31
- package/guidelines/modelUtil/modelUtil.generate.json +0 -31
- package/guidelines/modelView/modelView.generate.json +0 -31
- package/guidelines/modelZone/modelZone.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
- package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
- package/guidelines/queryRule/queryRule.generate.json +0 -31
- package/guidelines/recipeRule/recipeRule.generate.json +0 -31
- package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
- package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
- package/guidelines/scalarModule/scalarModule.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
- package/guidelines/ssrRule/ssrRule.generate.json +0 -31
- package/guidelines/transportRule/transportRule.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -34
- package/index-57p9p179.js +0 -461
- package/index-qt8dqgnf.js +0 -250
- package/templates/__scalar/__model__/__model__.abstract.md +0 -28
- package/templates/module/__model__.abstract.md +0 -28
- package/templates/service/__model__.abstract.md +0 -28
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SubagentPool2,
|
|
4
4
|
akanCodePaths2,
|
|
5
|
-
McpServerConfig
|
|
6
|
-
|
|
5
|
+
McpServerConfig,
|
|
6
|
+
McpSignIn
|
|
7
|
+
} from "./index-9d6nvkz2.js";
|
|
7
8
|
import {
|
|
8
9
|
stripAnsi
|
|
9
10
|
} from "./index-7md2g9vw.js";
|
|
10
11
|
import {
|
|
12
|
+
akanCodeDefaultModel2,
|
|
11
13
|
akanCodeModel2,
|
|
12
14
|
akanCodeModelSupportsImages2,
|
|
13
15
|
akanCodeModelWarnings2
|
|
14
|
-
} from "./index-
|
|
16
|
+
} from "./index-667w0yah.js";
|
|
15
17
|
|
|
16
18
|
// pkgs/@akanjs/devkit/codeAgent/agent/CodeAgent.ts
|
|
17
19
|
import {
|
|
18
20
|
createAgentSession,
|
|
19
|
-
DEFAULT_COMPACTION_SETTINGS,
|
|
20
21
|
DefaultResourceLoader
|
|
21
22
|
} from "@earendil-works/pi-coding-agent";
|
|
22
23
|
import {
|
|
@@ -513,7 +514,7 @@ class AkanToolPack2 {
|
|
|
513
514
|
return { name: "akan-tools", factory: async (pi) => await this.#register(pi) };
|
|
514
515
|
}
|
|
515
516
|
async names() {
|
|
516
|
-
const { ContextRunner } = await import("./context.runner-
|
|
517
|
+
const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
|
|
517
518
|
return [
|
|
518
519
|
...new ContextRunner().listMcpTools(this.#options.mode).map((tool) => tool.name),
|
|
519
520
|
AkanToolPack2.verifyToolName
|
|
@@ -521,7 +522,7 @@ class AkanToolPack2 {
|
|
|
521
522
|
}
|
|
522
523
|
static verifyToolName = "akan_verify";
|
|
523
524
|
async#register(pi) {
|
|
524
|
-
const { ContextRunner } = await import("./context.runner-
|
|
525
|
+
const { ContextRunner } = await import("./context.runner-rs4rj15d.js");
|
|
525
526
|
const runner = new ContextRunner;
|
|
526
527
|
const guidelineNames = await AkanToolPack2.#guidelineNames();
|
|
527
528
|
for (const tool of runner.listMcpTools(this.#options.mode, { guidelineNames })) {
|
|
@@ -563,7 +564,7 @@ class AkanToolPack2 {
|
|
|
563
564
|
}
|
|
564
565
|
static async#guidelineNames() {
|
|
565
566
|
try {
|
|
566
|
-
const { Prompter } = await import("./prompter-
|
|
567
|
+
const { Prompter } = await import("./prompter-1f8d9pcc.js");
|
|
567
568
|
return await Prompter.listGuidelines();
|
|
568
569
|
} catch {
|
|
569
570
|
return [];
|
|
@@ -576,9 +577,78 @@ class AkanToolPack2 {
|
|
|
576
577
|
}
|
|
577
578
|
}
|
|
578
579
|
|
|
579
|
-
// pkgs/@akanjs/devkit/codeAgent/tools/
|
|
580
|
+
// pkgs/@akanjs/devkit/codeAgent/tools/AskToolPack.ts
|
|
580
581
|
import { Type as Type2 } from "typebox";
|
|
581
582
|
|
|
583
|
+
class AskToolPack {
|
|
584
|
+
static toolName = "ask_user";
|
|
585
|
+
static maxQuestions = 4;
|
|
586
|
+
#options;
|
|
587
|
+
constructor(options) {
|
|
588
|
+
this.#options = options;
|
|
589
|
+
}
|
|
590
|
+
names() {
|
|
591
|
+
return this.#options.profile.ui.canPrompt ? [AskToolPack.toolName] : [];
|
|
592
|
+
}
|
|
593
|
+
extension() {
|
|
594
|
+
if (!this.#options.profile.ui.canPrompt)
|
|
595
|
+
return;
|
|
596
|
+
return { name: "akan-ask", factory: (pi) => this.#register(pi) };
|
|
597
|
+
}
|
|
598
|
+
#register(pi) {
|
|
599
|
+
pi.registerTool({
|
|
600
|
+
name: AskToolPack.toolName,
|
|
601
|
+
label: "Ask",
|
|
602
|
+
description: "Ask the user to decide something you cannot decide from the code or the request. Use it when two readings of the task would lead to materially different work, not for choices with an obvious default \u2014 and never to ask permission for work you were already asked to do. Offer concrete options whenever you can name them; mark one recommended when you have a view.",
|
|
603
|
+
promptSnippet: "ask_user: put a decision the user owns back to them, with options",
|
|
604
|
+
parameters: Type2.Object({
|
|
605
|
+
questions: Type2.Array(Type2.Object({
|
|
606
|
+
question: Type2.String({ description: "The whole question, as one sentence ending in a question mark." }),
|
|
607
|
+
header: Type2.Optional(Type2.String({ description: "Two or three words naming what is being chosen, e.g. 'Auth method'." })),
|
|
608
|
+
options: Type2.Optional(Type2.Array(Type2.Object({
|
|
609
|
+
label: Type2.String({ description: "The choice, in one to five words." }),
|
|
610
|
+
detail: Type2.Optional(Type2.String({ description: "What picking it means, or the trade-off it carries." })),
|
|
611
|
+
recommended: Type2.Optional(Type2.Boolean({ description: "Mark at most one. It is offered first and labelled as such." }))
|
|
612
|
+
}), { description: "Two to four distinct choices. Leave it out to ask for an answer in prose." })),
|
|
613
|
+
multiSelect: Type2.Optional(Type2.Boolean({ description: "Several options may be chosen together, rather than exactly one." })),
|
|
614
|
+
freeText: Type2.Optional(Type2.Boolean({
|
|
615
|
+
description: "Offer a further choice that lets the user type an answer of their own. Default true."
|
|
616
|
+
}))
|
|
617
|
+
}), { description: `One to ${AskToolPack.maxQuestions} questions, asked in order.` })
|
|
618
|
+
}),
|
|
619
|
+
execute: async (_id, params) => {
|
|
620
|
+
const questions = (params.questions ?? []).slice(0, AskToolPack.maxQuestions);
|
|
621
|
+
if (!questions.length)
|
|
622
|
+
return { content: [{ type: "text", text: "No question was asked." }], details: undefined, isError: true };
|
|
623
|
+
const answers = [];
|
|
624
|
+
for (const entry of questions) {
|
|
625
|
+
const options = (entry.options ?? []).map((option, at) => ({
|
|
626
|
+
key: `${at}`,
|
|
627
|
+
label: option.label,
|
|
628
|
+
...option.detail ? { detail: option.detail } : {},
|
|
629
|
+
...option.recommended ? { recommended: true } : {}
|
|
630
|
+
}));
|
|
631
|
+
const answer = await this.#options.ask({
|
|
632
|
+
prompt: entry.header ? `${entry.header} \u2014 ${entry.question}` : entry.question,
|
|
633
|
+
kind: options.length ? "select" : "text",
|
|
634
|
+
...options.length ? { options } : {},
|
|
635
|
+
...entry.multiSelect ? { multiSelect: true } : {},
|
|
636
|
+
freeText: entry.freeText ?? true
|
|
637
|
+
});
|
|
638
|
+
answers.push(`${entry.question}
|
|
639
|
+
\u2192 ${answer ?? "(skipped \u2014 decide this yourself and say what you chose)"}`);
|
|
640
|
+
}
|
|
641
|
+
return { content: [{ type: "text", text: answers.join(`
|
|
642
|
+
|
|
643
|
+
`) }], details: undefined };
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// pkgs/@akanjs/devkit/codeAgent/tools/MailToolPack.ts
|
|
650
|
+
import { Type as Type3 } from "typebox";
|
|
651
|
+
|
|
582
652
|
class MailToolPack2 {
|
|
583
653
|
static toolNames = ["list_peers", "send_peer_message"];
|
|
584
654
|
#options;
|
|
@@ -599,7 +669,7 @@ class MailToolPack2 {
|
|
|
599
669
|
label: "List peer sessions",
|
|
600
670
|
description: "List the other akan code sessions running in this workspace right now, with their name and working directory. Call it before send_peer_message so you name a session that is actually there.",
|
|
601
671
|
promptSnippet: "list_peers: the other akan code sessions running here",
|
|
602
|
-
parameters:
|
|
672
|
+
parameters: Type3.Object({}),
|
|
603
673
|
execute: async () => ({
|
|
604
674
|
content: [{ type: "text", text: MailToolPack2.#render(this.#options.mailbox()?.peers() ?? []) }],
|
|
605
675
|
details: undefined
|
|
@@ -610,9 +680,9 @@ class MailToolPack2 {
|
|
|
610
680
|
label: "Message a peer session",
|
|
611
681
|
description: "Hand a message to another akan code session in this workspace. It arrives there as a prompt, so it costs that session a turn \u2014 use it to hand over a piece of work or to warn it about a change you made, not to chat. Say what you want done and what you already did.",
|
|
612
682
|
promptSnippet: "send_peer_message: hand work to another akan code session",
|
|
613
|
-
parameters:
|
|
614
|
-
to:
|
|
615
|
-
message:
|
|
683
|
+
parameters: Type3.Object({
|
|
684
|
+
to: Type3.String({ description: "The peer's name, or the front of its id, from list_peers." }),
|
|
685
|
+
message: Type3.String({ description: "What that session should know or do." })
|
|
616
686
|
}),
|
|
617
687
|
execute: async (_id, params) => {
|
|
618
688
|
const mailbox = this.#options.mailbox();
|
|
@@ -645,20 +715,32 @@ import {
|
|
|
645
715
|
codeAgentClip,
|
|
646
716
|
codeAgentOutputChars
|
|
647
717
|
} from "akanjs/common";
|
|
648
|
-
import { Type as
|
|
718
|
+
import { Type as Type4 } from "typebox";
|
|
649
719
|
|
|
650
720
|
// pkgs/@akanjs/devkit/codeAgent/tools/McpClient.ts
|
|
651
721
|
var protocolVersion = "2025-06-18";
|
|
652
722
|
|
|
723
|
+
class McpUnauthorized2 extends Error {
|
|
724
|
+
challenge;
|
|
725
|
+
constructor(name, challenge) {
|
|
726
|
+
super(`MCP server "${name}" requires authentication`);
|
|
727
|
+
this.name = "McpUnauthorized";
|
|
728
|
+
this.challenge = challenge;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
653
732
|
class McpClient2 {
|
|
733
|
+
static maxToolPages = 50;
|
|
654
734
|
ref;
|
|
655
735
|
#proc;
|
|
656
736
|
#nextId = 0;
|
|
657
737
|
#buffer = "";
|
|
658
738
|
#pending = new Map;
|
|
659
739
|
#sessionId;
|
|
660
|
-
|
|
740
|
+
#token;
|
|
741
|
+
constructor(ref, token) {
|
|
661
742
|
this.ref = ref;
|
|
743
|
+
this.#token = token;
|
|
662
744
|
}
|
|
663
745
|
async connect() {
|
|
664
746
|
if (this.ref.transport === "stdio")
|
|
@@ -674,10 +756,19 @@ class McpClient2 {
|
|
|
674
756
|
return this;
|
|
675
757
|
}
|
|
676
758
|
async listTools() {
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
759
|
+
const tools = [];
|
|
760
|
+
let cursor;
|
|
761
|
+
for (let page = 0;page < McpClient2.maxToolPages; page += 1) {
|
|
762
|
+
const response = await this.#call("tools/list", cursor ? { cursor } : {});
|
|
763
|
+
if (response.error)
|
|
764
|
+
throw new Error(response.error.message);
|
|
765
|
+
tools.push(...response.result?.tools ?? []);
|
|
766
|
+
const next = response.result?.nextCursor;
|
|
767
|
+
if (!next || next === cursor)
|
|
768
|
+
return tools;
|
|
769
|
+
cursor = next;
|
|
770
|
+
}
|
|
771
|
+
return tools;
|
|
681
772
|
}
|
|
682
773
|
async callTool(name, args) {
|
|
683
774
|
const response = await this.#call("tools/call", { name, arguments: args });
|
|
@@ -761,11 +852,16 @@ class McpClient2 {
|
|
|
761
852
|
headers: {
|
|
762
853
|
"content-type": "application/json",
|
|
763
854
|
accept: "application/json, text/event-stream",
|
|
855
|
+
"mcp-protocol-version": protocolVersion,
|
|
856
|
+
...this.ref.headers,
|
|
857
|
+
...this.#token ? { authorization: `Bearer ${this.#token}` } : {},
|
|
764
858
|
...this.#sessionId ? { "mcp-session-id": this.#sessionId } : {}
|
|
765
859
|
},
|
|
766
860
|
body: JSON.stringify(body),
|
|
767
861
|
signal: AbortSignal.timeout(30000)
|
|
768
862
|
});
|
|
863
|
+
if (response.status === 401)
|
|
864
|
+
throw new McpUnauthorized2(this.ref.name, response.headers.get("www-authenticate") ?? "");
|
|
769
865
|
this.#sessionId = response.headers.get("mcp-session-id") ?? this.#sessionId;
|
|
770
866
|
const text = await response.text();
|
|
771
867
|
if (!text.trim())
|
|
@@ -797,12 +893,22 @@ class McpToolPack2 {
|
|
|
797
893
|
const pack = new McpToolPack2;
|
|
798
894
|
for (const ref of refs) {
|
|
799
895
|
const base = { name: ref.name, transport: ref.transport, target: McpServerConfig.targetOf(ref) };
|
|
896
|
+
const token = ref.transport === "http" ? await McpSignIn.token(ref, options.onNotice) : undefined;
|
|
800
897
|
try {
|
|
801
|
-
const client = await new McpClient2(ref).connect();
|
|
898
|
+
const client = await new McpClient2(ref, token).connect();
|
|
802
899
|
const tools = await client.listTools();
|
|
803
900
|
pack.#clients.push({ client, tools });
|
|
804
|
-
pack.#status.push({
|
|
901
|
+
pack.#status.push({
|
|
902
|
+
...base,
|
|
903
|
+
tools: tools.map((tool) => McpToolPack2.#nameOf(ref.name, tool.name)),
|
|
904
|
+
auth: token ? "authorized" : "none"
|
|
905
|
+
});
|
|
805
906
|
} catch (error) {
|
|
907
|
+
if (error instanceof McpUnauthorized2) {
|
|
908
|
+
options.onNotice?.(`MCP server "${ref.name}" needs signing in \u2014 /mcp login ${ref.name}`);
|
|
909
|
+
pack.#status.push({ ...base, tools: [], auth: "required" });
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
806
912
|
options.onNotice?.(`MCP server "${ref.name}" is unavailable: ${String(error)}`);
|
|
807
913
|
pack.#status.push({ ...base, tools: [], error: String(error) });
|
|
808
914
|
}
|
|
@@ -832,7 +938,7 @@ class McpToolPack2 {
|
|
|
832
938
|
label: `${client.ref.name}: ${tool.name}`,
|
|
833
939
|
description,
|
|
834
940
|
promptSnippet: `${name}: ${description.split(".")[0] ?? description}`,
|
|
835
|
-
parameters:
|
|
941
|
+
parameters: Type4.Unsafe(tool.inputSchema),
|
|
836
942
|
execute: async (_id, params) => {
|
|
837
943
|
const result = await client.callTool(tool.name, params ?? {});
|
|
838
944
|
return {
|
|
@@ -858,7 +964,7 @@ class McpToolPack2 {
|
|
|
858
964
|
// pkgs/@akanjs/devkit/codeAgent/tools/SessionToolPack.ts
|
|
859
965
|
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
860
966
|
import { codeAgentClip as codeAgentClip2, codeAgentOutputChars as codeAgentOutputChars2 } from "akanjs/common";
|
|
861
|
-
import { Type as
|
|
967
|
+
import { Type as Type5 } from "typebox";
|
|
862
968
|
var snippetChars = 240;
|
|
863
969
|
|
|
864
970
|
class SessionToolPack2 {
|
|
@@ -881,9 +987,9 @@ class SessionToolPack2 {
|
|
|
881
987
|
label: "Search sessions",
|
|
882
988
|
description: "Search earlier coding-agent conversations in this workspace for a phrase, and get back the matching sessions with a snippet. Use it when the user refers to something decided before, or when you suspect this problem has been solved here already.",
|
|
883
989
|
promptSnippet: "session_search: find earlier conversations in this workspace by phrase",
|
|
884
|
-
parameters:
|
|
885
|
-
query:
|
|
886
|
-
limit:
|
|
990
|
+
parameters: Type5.Object({
|
|
991
|
+
query: Type5.String({ description: "A phrase to look for, matched case-insensitively." }),
|
|
992
|
+
limit: Type5.Optional(Type5.Number({ description: "How many sessions to return, default 5." }))
|
|
887
993
|
}),
|
|
888
994
|
execute: async (_id, params) => {
|
|
889
995
|
const matches = await this.#search(params.query, params.limit ?? 5);
|
|
@@ -895,7 +1001,7 @@ class SessionToolPack2 {
|
|
|
895
1001
|
label: "Read session",
|
|
896
1002
|
description: "Read one earlier conversation, found with session_search, as plain text.",
|
|
897
1003
|
promptSnippet: "session_read: read one earlier conversation by id",
|
|
898
|
-
parameters:
|
|
1004
|
+
parameters: Type5.Object({ sessionId: Type5.String() }),
|
|
899
1005
|
execute: async (_id, params) => {
|
|
900
1006
|
const text = await this.#read(params.sessionId);
|
|
901
1007
|
return { content: [{ type: "text", text }], details: undefined, isError: text.startsWith("No session") };
|
|
@@ -928,7 +1034,7 @@ class SessionToolPack2 {
|
|
|
928
1034
|
|
|
929
1035
|
// pkgs/@akanjs/devkit/codeAgent/tools/WebToolPack.ts
|
|
930
1036
|
import { codeAgentClip as codeAgentClip3, codeAgentOutputChars as codeAgentOutputChars3 } from "akanjs/common";
|
|
931
|
-
import { Type as
|
|
1037
|
+
import { Type as Type6 } from "typebox";
|
|
932
1038
|
|
|
933
1039
|
class WebToolPack2 {
|
|
934
1040
|
#options;
|
|
@@ -993,7 +1099,7 @@ class WebToolPack2 {
|
|
|
993
1099
|
label: "Fetch",
|
|
994
1100
|
description: "Fetch a URL and return its readable text. HTML is stripped to text; the result is truncated.",
|
|
995
1101
|
promptSnippet: "web_fetch: fetch a URL and return its readable text",
|
|
996
|
-
parameters:
|
|
1102
|
+
parameters: Type6.Object({ url: Type6.String({ description: "Absolute http(s) URL." }) }),
|
|
997
1103
|
execute: async (_id, params) => {
|
|
998
1104
|
const refusal = WebToolPack2.#refuseHost(params.url, allowHosts);
|
|
999
1105
|
if (refusal)
|
|
@@ -1018,9 +1124,9 @@ ${codeAgentClip3(text, codeAgentOutputChars3)}` }
|
|
|
1018
1124
|
label: "Search",
|
|
1019
1125
|
description: `Search the web (${provider.name}) and return the top results as title, url and snippet.`,
|
|
1020
1126
|
promptSnippet: "web_search: search the web and return titles, urls and snippets",
|
|
1021
|
-
parameters:
|
|
1022
|
-
query:
|
|
1023
|
-
count:
|
|
1127
|
+
parameters: Type6.Object({
|
|
1128
|
+
query: Type6.String(),
|
|
1129
|
+
count: Type6.Optional(Type6.Number({ description: "How many results, default 5." }))
|
|
1024
1130
|
}),
|
|
1025
1131
|
execute: async (_id, params) => {
|
|
1026
1132
|
const key = process.env[provider.envKey] ?? "";
|
|
@@ -1076,10 +1182,19 @@ class AkanCodePlugins2 {
|
|
|
1076
1182
|
const sessionExtension = sessions.extension();
|
|
1077
1183
|
const mail = new MailToolPack2({ profile: options.profile, mailbox: options.mailbox });
|
|
1078
1184
|
const mailExtension = mail.extension();
|
|
1185
|
+
const onAsk = options.onAsk;
|
|
1186
|
+
const ask = onAsk ? new AskToolPack({ profile: options.profile, ask: onAsk }) : undefined;
|
|
1187
|
+
const askExtension = ask?.extension();
|
|
1079
1188
|
if (!options.profile.tools.akan)
|
|
1080
1189
|
return {
|
|
1081
|
-
extensions: [mcp?.extension(), webExtension, sessionExtension, mailExtension].filter((entry) => !!entry),
|
|
1082
|
-
toolNames: [
|
|
1190
|
+
extensions: [mcp?.extension(), webExtension, sessionExtension, mailExtension, askExtension].filter((entry) => !!entry),
|
|
1191
|
+
toolNames: [
|
|
1192
|
+
...mcp?.toolNames ?? [],
|
|
1193
|
+
...web.names(),
|
|
1194
|
+
...sessions.names(),
|
|
1195
|
+
...mail.names(),
|
|
1196
|
+
...ask?.names() ?? []
|
|
1197
|
+
],
|
|
1083
1198
|
mcp: mcpStatus,
|
|
1084
1199
|
dispose
|
|
1085
1200
|
};
|
|
@@ -1114,6 +1229,8 @@ class AkanCodePlugins2 {
|
|
|
1114
1229
|
extensions.push(sessionExtension);
|
|
1115
1230
|
if (mailExtension)
|
|
1116
1231
|
extensions.push(mailExtension);
|
|
1232
|
+
if (askExtension)
|
|
1233
|
+
extensions.push(askExtension);
|
|
1117
1234
|
return {
|
|
1118
1235
|
extensions,
|
|
1119
1236
|
toolNames: [
|
|
@@ -1122,7 +1239,8 @@ class AkanCodePlugins2 {
|
|
|
1122
1239
|
...mcp?.toolNames ?? [],
|
|
1123
1240
|
...web.names(),
|
|
1124
1241
|
...sessions.names(),
|
|
1125
|
-
...mail.names()
|
|
1242
|
+
...mail.names(),
|
|
1243
|
+
...ask?.names() ?? []
|
|
1126
1244
|
],
|
|
1127
1245
|
mcp: mcpStatus,
|
|
1128
1246
|
dispose
|
|
@@ -1154,7 +1272,9 @@ class AkanCodePlugins2 {
|
|
|
1154
1272
|
}
|
|
1155
1273
|
|
|
1156
1274
|
// pkgs/@akanjs/devkit/codeAgent/agent/AkanCodeServices.ts
|
|
1157
|
-
import { existsSync as existsSync7, mkdirSync } from "fs";
|
|
1275
|
+
import { existsSync as existsSync7, mkdirSync, mkdtempSync } from "fs";
|
|
1276
|
+
import { tmpdir } from "os";
|
|
1277
|
+
import path7 from "path";
|
|
1158
1278
|
import { ModelRuntime, SessionManager as SessionManager2, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
1159
1279
|
|
|
1160
1280
|
// pkgs/@akanjs/devkit/codeAgent/tools/AkanEnvKeys.ts
|
|
@@ -1281,6 +1401,7 @@ var akanSystemPrompt2 = (profile) => {
|
|
|
1281
1401
|
"- Prefer an akan workflow to a direct source edit. `list_workflows` / `explain_workflow` / `plan_workflow`, then `apply_workflow({ planPath })`. Editing source by hand is the fallback, not the default.",
|
|
1282
1402
|
"- Read context with `inspect_akan_context` before reading source bodies; it answers most structural questions without spending the file.",
|
|
1283
1403
|
"- Fetch the guideline for an area before a deep pass on it: `get_guideline`.",
|
|
1404
|
+
"- A question about `akan code` itself \u2014 its slash commands, MCP servers, sessions, models, keys, or where its files live \u2014 is answered by the `akan-code` skill. Read it rather than describing the tool from memory.",
|
|
1284
1405
|
"- Never hand-edit a generated file (`lib/cnst.ts`, `db.ts`, `st.ts`, any `*/index.ts` barrel). Fix the owning source and run `repair_generated` or `akan sync`."
|
|
1285
1406
|
];
|
|
1286
1407
|
if (profile.tools.builtin.includes("write"))
|
|
@@ -1289,6 +1410,8 @@ var akanSystemPrompt2 = (profile) => {
|
|
|
1289
1410
|
lines.push("- This session is read-only: there is no write, edit or bash tool. Report what should change instead of changing it.");
|
|
1290
1411
|
if (profile.tools.subagent)
|
|
1291
1412
|
lines.push('- Hand a self-contained search or read to `task` \u2014 `type: "explore"` reads and reports, `type: "code"` makes the change. Only its answer comes back, so give it everything it needs and ask for exactly what you want returned. Do it yourself when the reading is short or when you need the files in front of you.');
|
|
1413
|
+
if (profile.ui.canPrompt)
|
|
1414
|
+
lines.push("- Ask with `ask_user` when two readings of the request would lead to materially different work, and offer the options you can name. Do not ask for a choice that has an obvious default, and do not ask permission for work you were already asked to do \u2014 make the call, say the assumption, and carry on.");
|
|
1292
1415
|
if (profile.approval !== "never")
|
|
1293
1416
|
lines.push(`- Some tool calls need the user's approval (policy: ${profile.approval}). A refusal is an answer; do not retry it a different way.`);
|
|
1294
1417
|
lines.push("- Secrets are refused at the tool boundary. If you need a value from `.env`, ask the user for it rather than looking for another way to read the file.", "", "## How to answer", "", "- Answer in as few words as carry the answer. A short question gets one sentence with no heading.", "- Do not open with what you are about to do, and do not close with a summary of what you did. The tool calls are already on the user's screen.", "- Skip headings, bold labels and bullet lists unless the answer is genuinely a list. Prose is shorter.", "- State a file as `path:line`. Do not paste a file back that the user can open.", "- Say what you could not do, and why, in one line. Do not offer alternatives nobody asked for.");
|
|
@@ -1374,11 +1497,20 @@ class AkanCodeServices2 {
|
|
|
1374
1497
|
return SettingsManager.inMemory({
|
|
1375
1498
|
enableInstallTelemetry: false,
|
|
1376
1499
|
enableAnalytics: false,
|
|
1377
|
-
quietStartup: true
|
|
1500
|
+
quietStartup: true,
|
|
1501
|
+
compaction: { reserveTokens: 32768 }
|
|
1378
1502
|
});
|
|
1379
1503
|
}
|
|
1380
|
-
static async runtime(workspaceRoot) {
|
|
1504
|
+
static async runtime(workspaceRoot, proxy = null) {
|
|
1381
1505
|
mkdirSync(akanCodePaths2.globalDir(), { recursive: true, mode: 448 });
|
|
1506
|
+
if (proxy) {
|
|
1507
|
+
const runtime = await ModelRuntime.create({
|
|
1508
|
+
authPath: path7.join(mkdtempSync(path7.join(tmpdir(), "akan-code-proxy-")), "auth.json"),
|
|
1509
|
+
modelsPath: akanCodePaths2.modelsFile()
|
|
1510
|
+
});
|
|
1511
|
+
await proxy.apply(runtime);
|
|
1512
|
+
return runtime;
|
|
1513
|
+
}
|
|
1382
1514
|
const runtime = await ModelRuntime.create({
|
|
1383
1515
|
authPath: akanCodePaths2.authFile(),
|
|
1384
1516
|
modelsPath: akanCodePaths2.modelsFile()
|
|
@@ -1387,7 +1519,7 @@ class AkanCodeServices2 {
|
|
|
1387
1519
|
return runtime;
|
|
1388
1520
|
}
|
|
1389
1521
|
static sessions(workspaceRoot, cwd, profile, resume) {
|
|
1390
|
-
if (profile.session.store
|
|
1522
|
+
if (profile.session.store === "memory")
|
|
1391
1523
|
return SessionManager2.inMemory(cwd);
|
|
1392
1524
|
const dir = akanCodePaths2.sessionsDir(workspaceRoot);
|
|
1393
1525
|
mkdirSync(dir, { recursive: true });
|
|
@@ -1403,8 +1535,12 @@ class AkanCodeServices2 {
|
|
|
1403
1535
|
static #skillPaths(profile, workspaceRoot) {
|
|
1404
1536
|
if (!profile.context.skills)
|
|
1405
1537
|
return [];
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1538
|
+
const dirs = [
|
|
1539
|
+
akanCodePaths2.builtinSkillsDir(),
|
|
1540
|
+
akanCodePaths2.globalSkillsDir(),
|
|
1541
|
+
akanCodePaths2.skillsDir(workspaceRoot)
|
|
1542
|
+
];
|
|
1543
|
+
return dirs.filter((dir) => !!dir && existsSync7(dir));
|
|
1408
1544
|
}
|
|
1409
1545
|
static resourceOptions(options) {
|
|
1410
1546
|
const present = (dir) => existsSync7(dir) ? [dir] : [];
|
|
@@ -1430,6 +1566,7 @@ class CodeAgentAsks2 {
|
|
|
1430
1566
|
#question;
|
|
1431
1567
|
#approvals = new Map;
|
|
1432
1568
|
#nextId = 0;
|
|
1569
|
+
#epoch = Date.now().toString(36);
|
|
1433
1570
|
get pendingQuestionId() {
|
|
1434
1571
|
return this.#question?.question.questionId;
|
|
1435
1572
|
}
|
|
@@ -1441,7 +1578,7 @@ class CodeAgentAsks2 {
|
|
|
1441
1578
|
}
|
|
1442
1579
|
nextId(prefix) {
|
|
1443
1580
|
this.#nextId += 1;
|
|
1444
|
-
return `${prefix}${this.#nextId}`;
|
|
1581
|
+
return `${prefix}${this.#epoch}.${this.#nextId}`;
|
|
1445
1582
|
}
|
|
1446
1583
|
openQuestion(question) {
|
|
1447
1584
|
this.#question?.deferred.resolve("");
|
|
@@ -1550,7 +1687,15 @@ class CodeAgentEventMapper2 {
|
|
|
1550
1687
|
case "compaction_start":
|
|
1551
1688
|
return [{ type: "compaction", phase: "start", reason: event.reason }];
|
|
1552
1689
|
case "compaction_end":
|
|
1553
|
-
return [
|
|
1690
|
+
return [
|
|
1691
|
+
{
|
|
1692
|
+
type: "compaction",
|
|
1693
|
+
phase: "end",
|
|
1694
|
+
reason: event.reason,
|
|
1695
|
+
...event.errorMessage ? { error: event.errorMessage } : {},
|
|
1696
|
+
...event.aborted ? { aborted: true } : {}
|
|
1697
|
+
}
|
|
1698
|
+
];
|
|
1554
1699
|
case "auto_retry_start":
|
|
1555
1700
|
return [
|
|
1556
1701
|
{
|
|
@@ -1694,7 +1839,7 @@ class CodeAgentEventMapper2 {
|
|
|
1694
1839
|
}
|
|
1695
1840
|
|
|
1696
1841
|
// pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentGate.ts
|
|
1697
|
-
import
|
|
1842
|
+
import path8 from "path";
|
|
1698
1843
|
var writeTools = new Set(["write", "edit"]);
|
|
1699
1844
|
var commandTools = new Set(["bash"]);
|
|
1700
1845
|
|
|
@@ -1733,9 +1878,9 @@ class CodeAgentGate2 {
|
|
|
1733
1878
|
return `The command names "${hit}", which the profile's deny list covers. Ask the user for the value instead of reading the file.`;
|
|
1734
1879
|
}
|
|
1735
1880
|
#deniedReason(target) {
|
|
1736
|
-
const absolute =
|
|
1737
|
-
const relative =
|
|
1738
|
-
if (relative.startsWith("..") ||
|
|
1881
|
+
const absolute = path8.isAbsolute(target) ? target : path8.resolve(this.#profile.paths.root, target);
|
|
1882
|
+
const relative = path8.relative(this.#profile.paths.root, absolute);
|
|
1883
|
+
if (relative.startsWith("..") || path8.isAbsolute(relative))
|
|
1739
1884
|
return `Path is outside the agent root (${this.#profile.paths.root}).`;
|
|
1740
1885
|
if (this.#deny.some((glob) => glob.match(absolute) || glob.match(relative)))
|
|
1741
1886
|
return "Path is on the profile's deny list (secrets and environment files are never readable).";
|
|
@@ -1782,6 +1927,137 @@ class CodeAgentGate2 {
|
|
|
1782
1927
|
}
|
|
1783
1928
|
}
|
|
1784
1929
|
|
|
1930
|
+
// pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentProxy.ts
|
|
1931
|
+
import { readFile } from "fs/promises";
|
|
1932
|
+
class CodeAgentProxy {
|
|
1933
|
+
static placeholderKey = "akan-code-proxy";
|
|
1934
|
+
baseUrl;
|
|
1935
|
+
providers;
|
|
1936
|
+
#tokenFile;
|
|
1937
|
+
#token;
|
|
1938
|
+
constructor({ baseUrl, providers, tokenFile, token }) {
|
|
1939
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
1940
|
+
this.providers = providers;
|
|
1941
|
+
this.#tokenFile = tokenFile;
|
|
1942
|
+
this.#token = token;
|
|
1943
|
+
if (!tokenFile && !token)
|
|
1944
|
+
throw new Error("AKAN_CODE_PROXY_URL needs AKAN_CODE_PROXY_TOKEN_FILE or AKAN_CODE_PROXY_TOKEN");
|
|
1945
|
+
}
|
|
1946
|
+
static fromEnv(profile) {
|
|
1947
|
+
const baseUrl = process.env.AKAN_CODE_PROXY_URL?.trim() || profile?.network.proxyBaseUrl;
|
|
1948
|
+
if (!baseUrl)
|
|
1949
|
+
return null;
|
|
1950
|
+
const providers = (process.env.AKAN_CODE_PROXY_PROVIDERS ?? akanCodeDefaultModel2.provider).split(",").map((provider) => provider.trim()).filter(Boolean);
|
|
1951
|
+
return new CodeAgentProxy({
|
|
1952
|
+
baseUrl,
|
|
1953
|
+
providers,
|
|
1954
|
+
tokenFile: process.env.AKAN_CODE_PROXY_TOKEN_FILE?.trim() || undefined,
|
|
1955
|
+
token: process.env.AKAN_CODE_PROXY_TOKEN?.trim() || undefined
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
baseUrlFor(provider) {
|
|
1959
|
+
return this.baseUrl.replaceAll("{provider}", provider);
|
|
1960
|
+
}
|
|
1961
|
+
async token() {
|
|
1962
|
+
if (!this.#tokenFile)
|
|
1963
|
+
return this.#token ?? "";
|
|
1964
|
+
const token = (await readFile(this.#tokenFile, "utf8")).trim();
|
|
1965
|
+
if (!token)
|
|
1966
|
+
throw new Error(`${this.#tokenFile} is empty`);
|
|
1967
|
+
return token;
|
|
1968
|
+
}
|
|
1969
|
+
async apply(runtime) {
|
|
1970
|
+
const target = runtime;
|
|
1971
|
+
const original = target.prepareRequest?.bind(runtime);
|
|
1972
|
+
if (!original)
|
|
1973
|
+
throw new Error("The model runtime no longer exposes prepareRequest; update CodeAgentProxy");
|
|
1974
|
+
for (const provider of this.providers)
|
|
1975
|
+
await runtime.setRuntimeApiKey(provider, CodeAgentProxy.placeholderKey);
|
|
1976
|
+
target.prepareRequest = async (model, options = {}) => {
|
|
1977
|
+
const apiKey = await this.token();
|
|
1978
|
+
const prepared = await original(model, { ...options, apiKey });
|
|
1979
|
+
return {
|
|
1980
|
+
...prepared,
|
|
1981
|
+
model: { ...prepared.model, baseUrl: this.baseUrlFor(prepared.model.provider) },
|
|
1982
|
+
options: { ...prepared.options, apiKey }
|
|
1983
|
+
};
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
// pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentSuspended.ts
|
|
1989
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync, writeFileSync } from "fs";
|
|
1990
|
+
import path9 from "path";
|
|
1991
|
+
|
|
1992
|
+
class CodeAgentSuspended {
|
|
1993
|
+
#file;
|
|
1994
|
+
#state;
|
|
1995
|
+
constructor(file) {
|
|
1996
|
+
this.#file = file;
|
|
1997
|
+
this.#state = CodeAgentSuspended.#read(file);
|
|
1998
|
+
}
|
|
1999
|
+
static fileOf(sessionDir, sessionId) {
|
|
2000
|
+
return sessionDir ? path9.join(sessionDir, `${sessionId}.suspended.json`) : null;
|
|
2001
|
+
}
|
|
2002
|
+
get question() {
|
|
2003
|
+
return this.#state.question;
|
|
2004
|
+
}
|
|
2005
|
+
get approvals() {
|
|
2006
|
+
return this.#state.approvals;
|
|
2007
|
+
}
|
|
2008
|
+
setQuestion(question) {
|
|
2009
|
+
this.#state = { ...this.#state, question };
|
|
2010
|
+
this.#save();
|
|
2011
|
+
}
|
|
2012
|
+
addApproval(request) {
|
|
2013
|
+
this.#state = { ...this.#state, approvals: [...this.#state.approvals, request] };
|
|
2014
|
+
this.#save();
|
|
2015
|
+
}
|
|
2016
|
+
takeQuestion(questionId) {
|
|
2017
|
+
const question = this.#state.question;
|
|
2018
|
+
if (question?.questionId !== questionId)
|
|
2019
|
+
return;
|
|
2020
|
+
this.#state = { approvals: this.#state.approvals };
|
|
2021
|
+
this.#save();
|
|
2022
|
+
return question;
|
|
2023
|
+
}
|
|
2024
|
+
takeApproval(approvalId) {
|
|
2025
|
+
const request = this.#state.approvals.find((approval) => approval.approvalId === approvalId);
|
|
2026
|
+
if (!request)
|
|
2027
|
+
return;
|
|
2028
|
+
this.#state = { ...this.#state, approvals: this.#state.approvals.filter((approval) => approval !== request) };
|
|
2029
|
+
this.#save();
|
|
2030
|
+
return request;
|
|
2031
|
+
}
|
|
2032
|
+
clear() {
|
|
2033
|
+
if (!this.#state.question && !this.#state.approvals.length)
|
|
2034
|
+
return;
|
|
2035
|
+
this.#state = { approvals: [] };
|
|
2036
|
+
this.#save();
|
|
2037
|
+
}
|
|
2038
|
+
#save() {
|
|
2039
|
+
if (!this.#file)
|
|
2040
|
+
return;
|
|
2041
|
+
if (!this.#state.question && !this.#state.approvals.length) {
|
|
2042
|
+
rmSync(this.#file, { force: true });
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
mkdirSync2(path9.dirname(this.#file), { recursive: true });
|
|
2046
|
+
writeFileSync(this.#file, `${JSON.stringify(this.#state)}
|
|
2047
|
+
`);
|
|
2048
|
+
}
|
|
2049
|
+
static #read(file) {
|
|
2050
|
+
if (!file || !existsSync8(file))
|
|
2051
|
+
return { approvals: [] };
|
|
2052
|
+
try {
|
|
2053
|
+
const parsed = JSON.parse(readFileSync4(file, "utf8"));
|
|
2054
|
+
return { ...parsed.question ? { question: parsed.question } : {}, approvals: parsed.approvals ?? [] };
|
|
2055
|
+
} catch {
|
|
2056
|
+
return { approvals: [] };
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
|
|
1785
2061
|
// pkgs/@akanjs/devkit/codeAgent/agent/CodeAgentUi.ts
|
|
1786
2062
|
class CodeAgentUi2 {
|
|
1787
2063
|
#handlers;
|
|
@@ -1825,15 +2101,15 @@ class CodeAgentUi2 {
|
|
|
1825
2101
|
// pkgs/@akanjs/devkit/codeAgent/agent/CodeMailbox.ts
|
|
1826
2102
|
import {
|
|
1827
2103
|
appendFileSync,
|
|
1828
|
-
existsSync as
|
|
1829
|
-
mkdirSync as
|
|
2104
|
+
existsSync as existsSync9,
|
|
2105
|
+
mkdirSync as mkdirSync3,
|
|
1830
2106
|
readdirSync as readdirSync3,
|
|
1831
|
-
readFileSync as
|
|
1832
|
-
rmSync,
|
|
2107
|
+
readFileSync as readFileSync5,
|
|
2108
|
+
rmSync as rmSync2,
|
|
1833
2109
|
statSync as statSync4,
|
|
1834
|
-
writeFileSync
|
|
2110
|
+
writeFileSync as writeFileSync2
|
|
1835
2111
|
} from "fs";
|
|
1836
|
-
import
|
|
2112
|
+
import path10 from "path";
|
|
1837
2113
|
|
|
1838
2114
|
class CodeMailbox2 {
|
|
1839
2115
|
static staleMs = 20000;
|
|
@@ -1853,11 +2129,11 @@ class CodeMailbox2 {
|
|
|
1853
2129
|
this.#name = name;
|
|
1854
2130
|
}
|
|
1855
2131
|
get inbox() {
|
|
1856
|
-
return
|
|
2132
|
+
return path10.join(this.#dir, "inbox", `${this.#id}.jsonl`);
|
|
1857
2133
|
}
|
|
1858
2134
|
open(cwd, onMail) {
|
|
1859
|
-
|
|
1860
|
-
|
|
2135
|
+
mkdirSync3(path10.join(this.#dir, "live"), { recursive: true });
|
|
2136
|
+
mkdirSync3(path10.join(this.#dir, "inbox"), { recursive: true });
|
|
1861
2137
|
this.#read = CodeMailbox2.#lines(this.inbox).length;
|
|
1862
2138
|
this.beat(cwd);
|
|
1863
2139
|
this.#beat = setInterval(() => this.beat(cwd), CodeMailbox2.beatMs);
|
|
@@ -1874,7 +2150,7 @@ class CodeMailbox2 {
|
|
|
1874
2150
|
this.#beat = null;
|
|
1875
2151
|
this.#poll = null;
|
|
1876
2152
|
try {
|
|
1877
|
-
|
|
2153
|
+
rmSync2(path10.join(this.#dir, "live", `${this.#id}.json`), { force: true });
|
|
1878
2154
|
} catch {}
|
|
1879
2155
|
}
|
|
1880
2156
|
rename(name, cwd) {
|
|
@@ -1884,15 +2160,15 @@ class CodeMailbox2 {
|
|
|
1884
2160
|
beat(cwd) {
|
|
1885
2161
|
const peer = { id: this.#id, name: this.#name, cwd, pid: process.pid, at: Date.now() };
|
|
1886
2162
|
try {
|
|
1887
|
-
|
|
2163
|
+
writeFileSync2(path10.join(this.#dir, "live", `${this.#id}.json`), JSON.stringify(peer));
|
|
1888
2164
|
} catch {}
|
|
1889
2165
|
}
|
|
1890
2166
|
peers() {
|
|
1891
|
-
const dir =
|
|
1892
|
-
if (!
|
|
2167
|
+
const dir = path10.join(this.#dir, "live");
|
|
2168
|
+
if (!existsSync9(dir))
|
|
1893
2169
|
return [];
|
|
1894
2170
|
const now = Date.now();
|
|
1895
|
-
return readdirSync3(dir).filter((entry) => entry.endsWith(".json")).map((entry) => CodeMailbox2.#peer(
|
|
2171
|
+
return readdirSync3(dir).filter((entry) => entry.endsWith(".json")).map((entry) => CodeMailbox2.#peer(path10.join(dir, entry))).filter((peer) => !!peer && peer.id !== this.#id && now - peer.at < CodeMailbox2.staleMs).sort((left, right) => right.at - left.at);
|
|
1896
2172
|
}
|
|
1897
2173
|
find(target) {
|
|
1898
2174
|
const needle = target.trim().toLowerCase();
|
|
@@ -1910,8 +2186,8 @@ class CodeMailbox2 {
|
|
|
1910
2186
|
throw new Error(`Too many messages: ${CodeMailbox2.sendsPerMinute} a minute is the ceiling.`);
|
|
1911
2187
|
this.#sent.push(now);
|
|
1912
2188
|
const mail = { at: now, from: this.#id, fromName: this.#name, text };
|
|
1913
|
-
|
|
1914
|
-
appendFileSync(
|
|
2189
|
+
mkdirSync3(path10.join(this.#dir, "inbox"), { recursive: true });
|
|
2190
|
+
appendFileSync(path10.join(this.#dir, "inbox", `${to}.jsonl`), `${JSON.stringify(mail)}
|
|
1915
2191
|
`);
|
|
1916
2192
|
}
|
|
1917
2193
|
#drain() {
|
|
@@ -1924,7 +2200,7 @@ class CodeMailbox2 {
|
|
|
1924
2200
|
}
|
|
1925
2201
|
static #peer(file) {
|
|
1926
2202
|
try {
|
|
1927
|
-
const peer = JSON.parse(
|
|
2203
|
+
const peer = JSON.parse(readFileSync5(file, "utf8"));
|
|
1928
2204
|
return typeof peer.id === "string" ? { ...peer, at: peer.at || statSync4(file).mtimeMs } : undefined;
|
|
1929
2205
|
} catch {
|
|
1930
2206
|
return;
|
|
@@ -1932,7 +2208,7 @@ class CodeMailbox2 {
|
|
|
1932
2208
|
}
|
|
1933
2209
|
static #lines(file) {
|
|
1934
2210
|
try {
|
|
1935
|
-
return
|
|
2211
|
+
return readFileSync5(file, "utf8").split(`
|
|
1936
2212
|
`).filter((line) => !!line.trim());
|
|
1937
2213
|
} catch {
|
|
1938
2214
|
return [];
|
|
@@ -1949,15 +2225,15 @@ class CodeMailbox2 {
|
|
|
1949
2225
|
|
|
1950
2226
|
// pkgs/@akanjs/devkit/codeAgent/agent/CodeSessionFork.ts
|
|
1951
2227
|
import { randomBytes } from "crypto";
|
|
1952
|
-
import { readFileSync as
|
|
1953
|
-
import
|
|
2228
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
2229
|
+
import path11 from "path";
|
|
1954
2230
|
import { codeAgentSessionName } from "akanjs/common";
|
|
1955
2231
|
class CodeSessionFork2 {
|
|
1956
2232
|
static fork(dir, id, name) {
|
|
1957
2233
|
const source = CodeSessionIndex2.fileOf(dir, id);
|
|
1958
2234
|
if (!source)
|
|
1959
2235
|
throw new Error(`No stored session ${id} in ${dir}`);
|
|
1960
|
-
const lines =
|
|
2236
|
+
const lines = readFileSync6(source, "utf8").split(`
|
|
1961
2237
|
`).filter((line) => !!line.trim());
|
|
1962
2238
|
if (!lines.length)
|
|
1963
2239
|
throw new Error(`Session ${id} has nothing in it to fork`);
|
|
@@ -1970,8 +2246,8 @@ class CodeSessionFork2 {
|
|
|
1970
2246
|
first.id = forked;
|
|
1971
2247
|
first.timestamp = at.toISOString();
|
|
1972
2248
|
records.push(CodeSessionFork2.#named(records, name ?? CodeSessionFork2.#nameOf(records), at));
|
|
1973
|
-
const file =
|
|
1974
|
-
|
|
2249
|
+
const file = path11.join(dir, `${at.toISOString().replace(/[:.]/g, "-")}_${forked}.jsonl`);
|
|
2250
|
+
writeFileSync3(file, `${records.map((record) => JSON.stringify(record)).join(`
|
|
1975
2251
|
`)}
|
|
1976
2252
|
`);
|
|
1977
2253
|
return { id: forked, file };
|
|
@@ -2006,6 +2282,7 @@ class CodeAgent2 {
|
|
|
2006
2282
|
#gate;
|
|
2007
2283
|
#mapper = new CodeAgentEventMapper2;
|
|
2008
2284
|
#asks = new CodeAgentAsks2;
|
|
2285
|
+
#suspended = new CodeAgentSuspended(null);
|
|
2009
2286
|
#listeners = new Set;
|
|
2010
2287
|
#session;
|
|
2011
2288
|
#disposePlugins;
|
|
@@ -2027,9 +2304,9 @@ class CodeAgent2 {
|
|
|
2027
2304
|
const cwd = options.cwd ?? workspaceRoot;
|
|
2028
2305
|
const agent = new CodeAgent2(options.profile);
|
|
2029
2306
|
const settingsManager = AkanCodeServices2.settings();
|
|
2030
|
-
const modelRuntime = await AkanCodeServices2.runtime(workspaceRoot);
|
|
2307
|
+
const modelRuntime = await AkanCodeServices2.runtime(workspaceRoot, CodeAgentProxy.fromEnv(options.profile));
|
|
2031
2308
|
const model = await akanCodeModel2(modelRuntime, options.model);
|
|
2032
|
-
const compaction =
|
|
2309
|
+
const compaction = settingsManager.getCompactionSettings(model);
|
|
2033
2310
|
const modelWarnings = akanCodeModelWarnings2(model, compaction.reserveTokens + compaction.keepRecentTokens);
|
|
2034
2311
|
const akan = await AkanCodePlugins2.build({
|
|
2035
2312
|
workspace: options.workspace,
|
|
@@ -2041,7 +2318,8 @@ class CodeAgent2 {
|
|
|
2041
2318
|
currentSessionId: () => agent.sessionId,
|
|
2042
2319
|
mailbox: () => agent.#mailbox,
|
|
2043
2320
|
onNotice: (message) => agent.#emit({ type: "notice", level: "warning", message }),
|
|
2044
|
-
onAgents: (agents) => agent.#emit({ type: "subagent", agents })
|
|
2321
|
+
onAgents: (agents) => agent.#emit({ type: "subagent", agents }),
|
|
2322
|
+
onAsk: (question) => agent.ask(question)
|
|
2045
2323
|
});
|
|
2046
2324
|
const resourceLoader = new DefaultResourceLoader({
|
|
2047
2325
|
cwd,
|
|
@@ -2070,10 +2348,11 @@ class CodeAgent2 {
|
|
|
2070
2348
|
agent.#disposePlugins = akan.dispose;
|
|
2071
2349
|
agent.#mcp = akan.mcp;
|
|
2072
2350
|
agent.#workspaceRoot = workspaceRoot;
|
|
2073
|
-
if (options.profile.session.store
|
|
2351
|
+
if (options.profile.session.store !== "memory")
|
|
2074
2352
|
agent.#sessionDir = akanCodePaths2.sessionsDir(workspaceRoot);
|
|
2075
2353
|
await agent.#attach(session, options.mode ?? "print");
|
|
2076
|
-
|
|
2354
|
+
agent.#suspended = new CodeAgentSuspended(CodeAgentSuspended.fileOf(agent.#sessionDir, agent.sessionId));
|
|
2355
|
+
if (agent.#sessionDir && options.profile.session.store === "file")
|
|
2077
2356
|
agent.#openMail(akanCodePaths2.mailDir(workspaceRoot), cwd);
|
|
2078
2357
|
for (const message of modelWarnings)
|
|
2079
2358
|
agent.#emit({ type: "notice", level: "warning", message });
|
|
@@ -2147,6 +2426,11 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
|
|
|
2147
2426
|
announce() {
|
|
2148
2427
|
this.#emit({ type: "session", info: this.info });
|
|
2149
2428
|
this.#restore();
|
|
2429
|
+
const { question, approvals } = this.#suspended;
|
|
2430
|
+
if (question)
|
|
2431
|
+
this.#emit({ type: "question", question });
|
|
2432
|
+
for (const request of approvals)
|
|
2433
|
+
this.#emit({ type: "approval", request });
|
|
2150
2434
|
}
|
|
2151
2435
|
#restore() {
|
|
2152
2436
|
const session = this.#session;
|
|
@@ -2160,6 +2444,7 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
|
|
|
2160
2444
|
if (text)
|
|
2161
2445
|
this.#emit({ type: "message", turnId, role: message.role, text });
|
|
2162
2446
|
}
|
|
2447
|
+
this.#emitContextNow();
|
|
2163
2448
|
}
|
|
2164
2449
|
static #textOf(content) {
|
|
2165
2450
|
if (typeof content === "string")
|
|
@@ -2203,8 +2488,12 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
|
|
|
2203
2488
|
}
|
|
2204
2489
|
if (this.#profile.interaction.question !== "suspend")
|
|
2205
2490
|
return false;
|
|
2206
|
-
this.#
|
|
2207
|
-
|
|
2491
|
+
const suspended = this.#suspended.takeQuestion(questionId);
|
|
2492
|
+
if (!suspended)
|
|
2493
|
+
return false;
|
|
2494
|
+
const suspendedRendered = codeAgentRenderAnswer(suspended, answer);
|
|
2495
|
+
this.#emit({ type: "question_resolved", questionId, answer, rendered: suspendedRendered });
|
|
2496
|
+
await this.prompt(`The user answered: ${suspendedRendered}
|
|
2208
2497
|
Continue the task.`);
|
|
2209
2498
|
return true;
|
|
2210
2499
|
}
|
|
@@ -2215,6 +2504,8 @@ Continue the task.`);
|
|
|
2215
2504
|
}
|
|
2216
2505
|
if (this.#profile.interaction.approval !== "suspend")
|
|
2217
2506
|
return false;
|
|
2507
|
+
if (!this.#suspended.takeApproval(approvalId))
|
|
2508
|
+
return false;
|
|
2218
2509
|
this.#emit({ type: "approval_resolved", approvalId, approved });
|
|
2219
2510
|
if (approved)
|
|
2220
2511
|
await this.prompt("The user approved the pending action. Retry it and continue.");
|
|
@@ -2249,6 +2540,23 @@ Continue the task.`);
|
|
|
2249
2540
|
session.setThinkingLevel(effort);
|
|
2250
2541
|
this.#emit({ type: "session", info: this.info });
|
|
2251
2542
|
}
|
|
2543
|
+
catalogue() {
|
|
2544
|
+
const runtime = this.#session?.modelRuntime;
|
|
2545
|
+
if (!runtime)
|
|
2546
|
+
return [];
|
|
2547
|
+
const current = this.#session?.model;
|
|
2548
|
+
return runtime.getProviders().map((provider) => ({
|
|
2549
|
+
id: provider.id,
|
|
2550
|
+
name: provider.name ?? provider.id,
|
|
2551
|
+
authorized: runtime.hasConfiguredAuth(provider.id),
|
|
2552
|
+
models: (runtime.getModels(provider.id) ?? []).map((model) => ({
|
|
2553
|
+
id: model.id,
|
|
2554
|
+
name: model.name,
|
|
2555
|
+
...model.contextWindow ? { contextWindow: model.contextWindow } : {},
|
|
2556
|
+
current: model.provider === current?.provider && model.id === current?.id
|
|
2557
|
+
}))
|
|
2558
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
2559
|
+
}
|
|
2252
2560
|
async setModel(ref) {
|
|
2253
2561
|
const session = this.#require();
|
|
2254
2562
|
const model = await akanCodeModel2(session.modelRuntime, ref);
|
|
@@ -2301,6 +2609,9 @@ Continue the task.`);
|
|
|
2301
2609
|
#emitContextUsage(eventType) {
|
|
2302
2610
|
if (eventType !== "agent_end" && eventType !== "compaction_end")
|
|
2303
2611
|
return;
|
|
2612
|
+
this.#emitContextNow();
|
|
2613
|
+
}
|
|
2614
|
+
#emitContextNow() {
|
|
2304
2615
|
const usage = this.#session?.getContextUsage();
|
|
2305
2616
|
if (usage?.tokens == null)
|
|
2306
2617
|
return;
|
|
@@ -2360,45 +2671,46 @@ Continue the task.`);
|
|
|
2360
2671
|
if (!this.#profile.ui.canPrompt)
|
|
2361
2672
|
return true;
|
|
2362
2673
|
const approvalId = this.#asks.nextId("a");
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
}
|
|
2372
|
-
});
|
|
2674
|
+
const request = {
|
|
2675
|
+
approvalId,
|
|
2676
|
+
toolCallId,
|
|
2677
|
+
name,
|
|
2678
|
+
summary: codeAgentClip5(summary, codeAgentLabelChars2),
|
|
2679
|
+
policy: this.#profile.approval
|
|
2680
|
+
};
|
|
2681
|
+
this.#emit({ type: "approval", request });
|
|
2373
2682
|
if (this.#profile.interaction.approval === "suspend") {
|
|
2683
|
+
this.#suspended.addApproval(request);
|
|
2374
2684
|
this.#mapper.noteOutcome("awaiting");
|
|
2375
2685
|
return false;
|
|
2376
2686
|
}
|
|
2377
2687
|
return await this.#asks.openApproval(approvalId);
|
|
2378
2688
|
}
|
|
2689
|
+
async ask(spec) {
|
|
2690
|
+
const question = { questionId: this.#asks.nextId("q"), ...spec };
|
|
2691
|
+
if (!this.#profile.ui.canPrompt) {
|
|
2692
|
+
this.#emit({ type: "question_skipped", question, reason: "no-host" });
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
this.#emit({ type: "question", question });
|
|
2696
|
+
if (this.#profile.interaction.question === "suspend") {
|
|
2697
|
+
this.#suspended.setQuestion(question);
|
|
2698
|
+
this.#mapper.noteOutcome("awaiting");
|
|
2699
|
+
return;
|
|
2700
|
+
}
|
|
2701
|
+
return await this.#asks.openQuestion(question) || undefined;
|
|
2702
|
+
}
|
|
2379
2703
|
#ui() {
|
|
2380
2704
|
return new CodeAgentUi2({
|
|
2381
|
-
ask: async (prompt, kind, choices) => {
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
prompt,
|
|
2388
|
-
kind,
|
|
2389
|
-
...choices ? { options: choices.map((label) => ({ key: label, label })) } : {},
|
|
2390
|
-
freeText: kind === "text"
|
|
2391
|
-
};
|
|
2392
|
-
this.#emit({ type: "question", question });
|
|
2393
|
-
if (this.#profile.interaction.question === "suspend") {
|
|
2394
|
-
this.#mapper.noteOutcome("awaiting");
|
|
2395
|
-
return;
|
|
2396
|
-
}
|
|
2397
|
-
return await this.#asks.openQuestion(question) || undefined;
|
|
2398
|
-
},
|
|
2705
|
+
ask: async (prompt, kind, choices) => await this.ask({
|
|
2706
|
+
prompt,
|
|
2707
|
+
kind,
|
|
2708
|
+
...choices ? { options: choices.map((label) => ({ key: label, label })) } : {},
|
|
2709
|
+
freeText: kind === "text"
|
|
2710
|
+
}),
|
|
2399
2711
|
notify: (level, message) => this.#emit({ type: "notice", level, message })
|
|
2400
2712
|
});
|
|
2401
2713
|
}
|
|
2402
2714
|
}
|
|
2403
2715
|
|
|
2404
|
-
export { AkanEditScope2, DevLogFeedback2, PreviewChrome2, PreviewView2, PreviewFeedback2, TurnFeedback2, AkanCli2, AkanVerifier2, VerifyFeedback2, AkanToolPack2, MailToolPack2, McpClient2, McpToolPack2, SessionToolPack2, WebToolPack2, AkanCodePlugins2, AkanEnvKeys2, akanSystemPrompt2, CodeSessionIndex2, AkanCodeServices2, CodeAgentAsks2, CodeAgentEventMapper2, CodeAgentGate2, CodeAgentUi2, CodeMailbox2, CodeSessionFork2, CodeAgent2 };
|
|
2716
|
+
export { AkanEditScope2, DevLogFeedback2, PreviewChrome2, PreviewView2, PreviewFeedback2, TurnFeedback2, AkanCli2, AkanVerifier2, VerifyFeedback2, AkanToolPack2, MailToolPack2, McpUnauthorized2, McpClient2, McpToolPack2, SessionToolPack2, WebToolPack2, AkanCodePlugins2, AkanEnvKeys2, akanSystemPrompt2, CodeSessionIndex2, AkanCodeServices2, CodeAgentAsks2, CodeAgentEventMapper2, CodeAgentGate2, CodeAgentUi2, CodeMailbox2, CodeSessionFork2, CodeAgent2 };
|