@akanjs/cli 3.0.0-beta.17 → 3.0.0-beta.18
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-0035exh3.js} +2 -2
- package/{CodeTui-nd9hqvrw.js → CodeTui-eweg1hep.js} +205 -34
- package/{agent.command-n664dtcv.js → agent.command-65zqfkg0.js} +6 -6
- package/akanCode.js +5 -3
- package/{application.command-t5542jte.js → application.command-2wcj5da3.js} +18 -11
- package/{applicationBuildRunner-x4gbfn7y.js → applicationBuildRunner-m0hhgwsx.js} +6 -5
- package/{applicationReleasePackager-z61ep017.js → applicationReleasePackager-vykfzgx3.js} +1 -1
- package/buildBatch.proc.js +2 -2
- package/{capacitorApp-shv3ajh5.js → capacitorApp-2daqhb5h.js} +2 -2
- package/{cloud.command-dk5tj39k.js → cloud.command-960bgbf4.js} +8 -8
- package/{cloud.script-ch3xrw3s.js → cloud.script-qhcnqt1n.js} +8 -8
- package/{code.command-88sebgnn.js → code.command-4feh3ef7.js} +6 -6
- package/{context.command-pqsm5jrk.js → context.command-kzehkx48.js} +14 -14
- package/context.runner-z0rrcz7b.js +22 -0
- 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-3w2g20x4.js} +8 -13
- package/guidelines/conventions/conventions.instruction.md +37 -22
- package/guidelines/queryRule/queryRule.instruction.md +1 -1
- 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 +1 -1
- package/{index-bzakk0c2.js → index-14zrtgfa.js} +5 -3
- package/{index-57p9p179.js → index-3hpxeys1.js} +6 -5
- package/{index-sn7dnzq4.js → index-4r42ext5.js} +1 -1
- package/{index-3mg4h788.js → index-6q589y9t.js} +2 -2
- package/index-9dp031by.js +12 -0
- package/{index-p4p9t45x.js → index-bwxpk2cj.js} +4 -18
- package/{index-g9zghs4h.js → index-cjw1sj1x.js} +12 -12
- package/{index-te0y1c0m.js → index-d9fjz06h.js} +12 -7
- package/{index-4n4821gp.js → index-dw943k93.js} +4 -4
- package/{index-4cvpzkq6.js → index-ef228gzf.js} +3 -3
- package/{index-3cymrzsb.js → index-erfc1x40.js} +17 -3
- package/{index-ns128c4q.js → index-h94faz96.js} +13 -20
- package/index-jd01kj5r.js +656 -0
- package/{index-2sq06vv0.js → index-jwexzh42.js} +200 -54
- package/{index-kvzjda3v.js → index-m41ptvat.js} +5 -5
- package/{index-qh7brn20.js → index-mt2154s2.js} +6 -2
- package/{index-xjc7gg65.js → index-pn8mhpps.js} +23 -33
- package/{index-vpx68e4x.js → index-q9c3c0hy.js} +2 -2
- package/{index-v17gj504.js → index-rpgxs245.js} +2 -2
- package/{index-twq9p2sp.js → index-s5rhm04y.js} +0 -6
- package/{index-p0tew3fq.js → index-sbfk9daf.js} +8 -3
- package/{index-n8kt2wh6.js → index-wcg582a8.js} +5 -5
- package/{index-6na0sd2b.js → index-ycy302an.js} +5 -2
- package/{index-qhtj9y6j.js → index-yw6g3bbv.js} +74 -21
- package/{index-2pm1j01n.js → index-zmj143x7.js} +4 -4
- package/{index-zn8qgeqx.js → index-zq0mr3hh.js} +1 -1
- package/index.js +21 -21
- package/{library.command-m8p2r1dh.js → library.command-fp0nhr62.js} +3 -3
- package/{localRegistry.command-yppdqrxv.js → localRegistry.command-8y0ecxb9.js} +7 -7
- package/{module.command-mfzvqt0n.js → module.command-kqkn48t2.js} +5 -5
- package/{package.command-cgp2p2v5.js → package.command-qverjh22.js} +4 -4
- package/package.json +2 -2
- package/{page.command-taenb02b.js → page.command-94bwhd0g.js} +3 -3
- package/{primitive.command-7kpncmkk.js → primitive.command-2ydvtah2.js} +6 -6
- package/{prompter-9mn3kp36.js → prompter-1f8d9pcc.js} +1 -1
- package/{quality.command-1ar94hrw.js → quality.command-fa0gth4p.js} +3 -4
- package/{repair.command-n08t6j8p.js → repair.command-4qng2hpm.js} +5 -5
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-mq8qfp4t.js → scalar.command-pb2y95sh.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-vkxmwp74.js} +4 -4
- 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 +14 -0
- 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/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-02cvp9nf.js} +2 -2
- package/{workflow.command-tvz4nm9n.js → workflow.command-132txnrh.js} +9 -9
- package/{workspace.command-txv1yv5e.js → workspace.command-d5wkswek.js} +21 -21
- 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-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,8 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SubagentPool2,
|
|
4
4
|
akanCodePaths2,
|
|
5
|
-
McpServerConfig
|
|
6
|
-
|
|
5
|
+
McpServerConfig,
|
|
6
|
+
McpSignIn
|
|
7
|
+
} from "./index-jd01kj5r.js";
|
|
7
8
|
import {
|
|
8
9
|
stripAnsi
|
|
9
10
|
} from "./index-7md2g9vw.js";
|
|
@@ -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-z0rrcz7b.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-z0rrcz7b.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
|
|
@@ -1281,6 +1399,7 @@ var akanSystemPrompt2 = (profile) => {
|
|
|
1281
1399
|
"- 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
1400
|
"- Read context with `inspect_akan_context` before reading source bodies; it answers most structural questions without spending the file.",
|
|
1283
1401
|
"- Fetch the guideline for an area before a deep pass on it: `get_guideline`.",
|
|
1402
|
+
"- 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
1403
|
"- 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
1404
|
];
|
|
1286
1405
|
if (profile.tools.builtin.includes("write"))
|
|
@@ -1289,6 +1408,8 @@ var akanSystemPrompt2 = (profile) => {
|
|
|
1289
1408
|
lines.push("- This session is read-only: there is no write, edit or bash tool. Report what should change instead of changing it.");
|
|
1290
1409
|
if (profile.tools.subagent)
|
|
1291
1410
|
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.');
|
|
1411
|
+
if (profile.ui.canPrompt)
|
|
1412
|
+
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
1413
|
if (profile.approval !== "never")
|
|
1293
1414
|
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
1415
|
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.");
|
|
@@ -1403,8 +1524,12 @@ class AkanCodeServices2 {
|
|
|
1403
1524
|
static #skillPaths(profile, workspaceRoot) {
|
|
1404
1525
|
if (!profile.context.skills)
|
|
1405
1526
|
return [];
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1527
|
+
const dirs = [
|
|
1528
|
+
akanCodePaths2.builtinSkillsDir(),
|
|
1529
|
+
akanCodePaths2.globalSkillsDir(),
|
|
1530
|
+
akanCodePaths2.skillsDir(workspaceRoot)
|
|
1531
|
+
];
|
|
1532
|
+
return dirs.filter((dir) => !!dir && existsSync7(dir));
|
|
1408
1533
|
}
|
|
1409
1534
|
static resourceOptions(options) {
|
|
1410
1535
|
const present = (dir) => existsSync7(dir) ? [dir] : [];
|
|
@@ -2041,7 +2166,8 @@ class CodeAgent2 {
|
|
|
2041
2166
|
currentSessionId: () => agent.sessionId,
|
|
2042
2167
|
mailbox: () => agent.#mailbox,
|
|
2043
2168
|
onNotice: (message) => agent.#emit({ type: "notice", level: "warning", message }),
|
|
2044
|
-
onAgents: (agents) => agent.#emit({ type: "subagent", agents })
|
|
2169
|
+
onAgents: (agents) => agent.#emit({ type: "subagent", agents }),
|
|
2170
|
+
onAsk: (question) => agent.ask(question)
|
|
2045
2171
|
});
|
|
2046
2172
|
const resourceLoader = new DefaultResourceLoader({
|
|
2047
2173
|
cwd,
|
|
@@ -2160,6 +2286,7 @@ ${mail.text}`).catch((error) => this.#emit({ type: "notice", level: "error", mes
|
|
|
2160
2286
|
if (text)
|
|
2161
2287
|
this.#emit({ type: "message", turnId, role: message.role, text });
|
|
2162
2288
|
}
|
|
2289
|
+
this.#emitContextNow();
|
|
2163
2290
|
}
|
|
2164
2291
|
static #textOf(content) {
|
|
2165
2292
|
if (typeof content === "string")
|
|
@@ -2249,6 +2376,23 @@ Continue the task.`);
|
|
|
2249
2376
|
session.setThinkingLevel(effort);
|
|
2250
2377
|
this.#emit({ type: "session", info: this.info });
|
|
2251
2378
|
}
|
|
2379
|
+
catalogue() {
|
|
2380
|
+
const runtime = this.#session?.modelRuntime;
|
|
2381
|
+
if (!runtime)
|
|
2382
|
+
return [];
|
|
2383
|
+
const current = this.#session?.model;
|
|
2384
|
+
return runtime.getProviders().map((provider) => ({
|
|
2385
|
+
id: provider.id,
|
|
2386
|
+
name: provider.name ?? provider.id,
|
|
2387
|
+
authorized: runtime.hasConfiguredAuth(provider.id),
|
|
2388
|
+
models: (runtime.getModels(provider.id) ?? []).map((model) => ({
|
|
2389
|
+
id: model.id,
|
|
2390
|
+
name: model.name,
|
|
2391
|
+
...model.contextWindow ? { contextWindow: model.contextWindow } : {},
|
|
2392
|
+
current: model.provider === current?.provider && model.id === current?.id
|
|
2393
|
+
}))
|
|
2394
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
2395
|
+
}
|
|
2252
2396
|
async setModel(ref) {
|
|
2253
2397
|
const session = this.#require();
|
|
2254
2398
|
const model = await akanCodeModel2(session.modelRuntime, ref);
|
|
@@ -2301,6 +2445,9 @@ Continue the task.`);
|
|
|
2301
2445
|
#emitContextUsage(eventType) {
|
|
2302
2446
|
if (eventType !== "agent_end" && eventType !== "compaction_end")
|
|
2303
2447
|
return;
|
|
2448
|
+
this.#emitContextNow();
|
|
2449
|
+
}
|
|
2450
|
+
#emitContextNow() {
|
|
2304
2451
|
const usage = this.#session?.getContextUsage();
|
|
2305
2452
|
if (usage?.tokens == null)
|
|
2306
2453
|
return;
|
|
@@ -2376,29 +2523,28 @@ Continue the task.`);
|
|
|
2376
2523
|
}
|
|
2377
2524
|
return await this.#asks.openApproval(approvalId);
|
|
2378
2525
|
}
|
|
2526
|
+
async ask(spec) {
|
|
2527
|
+
if (!this.#profile.ui.canPrompt)
|
|
2528
|
+
return;
|
|
2529
|
+
const question = { questionId: this.#asks.nextId("q"), ...spec };
|
|
2530
|
+
this.#emit({ type: "question", question });
|
|
2531
|
+
if (this.#profile.interaction.question === "suspend") {
|
|
2532
|
+
this.#mapper.noteOutcome("awaiting");
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
return await this.#asks.openQuestion(question) || undefined;
|
|
2536
|
+
}
|
|
2379
2537
|
#ui() {
|
|
2380
2538
|
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
|
-
},
|
|
2539
|
+
ask: async (prompt, kind, choices) => await this.ask({
|
|
2540
|
+
prompt,
|
|
2541
|
+
kind,
|
|
2542
|
+
...choices ? { options: choices.map((label) => ({ key: label, label })) } : {},
|
|
2543
|
+
freeText: kind === "text"
|
|
2544
|
+
}),
|
|
2399
2545
|
notify: (level, message) => this.#emit({ type: "notice", level, message })
|
|
2400
2546
|
});
|
|
2401
2547
|
}
|
|
2402
2548
|
}
|
|
2403
2549
|
|
|
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 };
|
|
2550
|
+
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 };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ycy302an.js";
|
|
6
6
|
import {
|
|
7
7
|
AGENT_BLOCK_START,
|
|
8
8
|
AGENT_BLOCK_END,
|
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
CLAUDE_COMMENT_RULE,
|
|
14
14
|
AppExecutor,
|
|
15
15
|
LibExecutor
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-bwxpk2cj.js";
|
|
17
17
|
import {
|
|
18
18
|
collectRecipeSources2,
|
|
19
19
|
scanRecipes2
|
|
20
20
|
} from "./index-by5gpp8x.js";
|
|
21
21
|
import {
|
|
22
22
|
AkanContextAnalyzer
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-rpgxs245.js";
|
|
24
24
|
import {
|
|
25
25
|
Prompter2
|
|
26
|
-
} from "./index-
|
|
26
|
+
} from "./index-s5rhm04y.js";
|
|
27
27
|
|
|
28
28
|
// pkgs/@akanjs/cli/agent/agent.script.ts
|
|
29
29
|
import { Logger as Logger2 } from "akanjs/common";
|
|
@@ -148,7 +148,7 @@ If generated output is stale or broken, update the owning source file and run \`
|
|
|
148
148
|
${recipeIndex}## MCP Workflow Policy
|
|
149
149
|
|
|
150
150
|
- **Prefer an Akan workflow to a direct source edit.** A direct edit is denied when an allowlisted workflow or repair tool can make the change.
|
|
151
|
-
- Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and the repair tools.
|
|
151
|
+
- Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and three of the five repair tools \u2014 \`repair_generated\`, \`repair_imports\` and \`repair_module_shape\`. \`akan repair format\` and \`akan repair dictionary\` are CLI-only.
|
|
152
152
|
- If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source. Then run \`run_validation\` with \`validationTarget\` when present, otherwise \`applyReportPath\`.
|
|
153
153
|
- Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
|
|
154
154
|
- When no workflow exists, or apply reports unsupported/no-op/failed diagnostics needing manual action, keep edits scoped to owning source files and never patch generated files directly.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ycy302an.js";
|
|
6
6
|
|
|
7
7
|
// pkgs/@akanjs/cli/page/page.runner.ts
|
|
8
8
|
class PageRunner extends runner("page") {
|
|
@@ -10,7 +10,11 @@ class PageRunner extends runner("page") {
|
|
|
10
10
|
await app.applyTemplate({
|
|
11
11
|
basePath: basePath ?? `page/(${app.name})/(public)/${module.name}`,
|
|
12
12
|
template: single ? "crudSinglePage" : "crudPages",
|
|
13
|
-
dict: {
|
|
13
|
+
dict: {
|
|
14
|
+
model: module.name,
|
|
15
|
+
appName: module.sys.name,
|
|
16
|
+
clientPath: `@${module.sys.type}s/${module.sys.name}/client`
|
|
17
|
+
}
|
|
14
18
|
});
|
|
15
19
|
}
|
|
16
20
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ycy302an.js";
|
|
6
6
|
import {
|
|
7
7
|
ModuleExecutor
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-bwxpk2cj.js";
|
|
9
9
|
import {
|
|
10
10
|
sourceFile,
|
|
11
11
|
moduleSourcePaths,
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
createPassedPrimitiveReport,
|
|
14
14
|
bilingualLabelForField,
|
|
15
15
|
bilingualDescriptionForField
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-yw6g3bbv.js";
|
|
17
17
|
import {
|
|
18
18
|
PageScript
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-mt2154s2.js";
|
|
20
20
|
import {
|
|
21
21
|
pluralizeName
|
|
22
22
|
} from "./index-nz8prx9g.js";
|
|
@@ -31,37 +31,17 @@ var purposeByModule = {
|
|
|
31
31
|
project: "Project represents a project workspace or business initiative managed by the app.",
|
|
32
32
|
task: "Task represents work items that move through the app workflow."
|
|
33
33
|
};
|
|
34
|
-
var moduleAbstractContent = (moduleName) => {
|
|
34
|
+
var moduleAbstractContent = (moduleName, sharedGuards) => {
|
|
35
35
|
const title = capitalize(moduleName);
|
|
36
|
-
const
|
|
37
|
-
const purpose = purposeByModule[moduleName] ?? `${title} represents ${
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## Purpose
|
|
41
|
-
|
|
36
|
+
const noun = bilingualLabelForField(moduleName).en.toLowerCase();
|
|
37
|
+
const purpose = purposeByModule[moduleName] ?? `${title} represents ${noun} records managed by the app.`;
|
|
38
|
+
const writeRule = sharedGuards ? `Anyone may read a ${noun}; only an admin creates, updates or removes one.` : `Anyone may read a ${noun}; nobody creates, updates or removes one until the slice names a guard.`;
|
|
39
|
+
return `# ${moduleName} Abstract
|
|
42
40
|
${purpose}
|
|
43
41
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
## Data Meaning
|
|
49
|
-
|
|
50
|
-
${label.en} (${label.ko}) is the primary business concept for this module.
|
|
51
|
-
|
|
52
|
-
## Workflows
|
|
53
|
-
|
|
54
|
-
No lifecycle workflow yet.
|
|
55
|
-
|
|
56
|
-
## Agent Notes
|
|
57
|
-
|
|
58
|
-
- Read this abstract before changing the module.
|
|
59
|
-
- Update this file when business invariants, workflows, or public behavior change.
|
|
60
|
-
- Do not update this file for formatting-only, import-only, or style-only changes.
|
|
61
|
-
|
|
62
|
-
## Related Modules
|
|
63
|
-
|
|
64
|
-
- None yet.
|
|
42
|
+
## Rules
|
|
43
|
+
- ${writeRule}
|
|
44
|
+
- Removal is soft: a removed ${noun} keeps its row with \`removedAt\` set.
|
|
65
45
|
`;
|
|
66
46
|
};
|
|
67
47
|
var localModuleFilename = (moduleName, pathKey) => moduleSourcePaths(moduleName)[pathKey].replace(`lib/${moduleName}/`, "");
|
|
@@ -92,6 +72,14 @@ class ModuleRunner extends runner("module") {
|
|
|
92
72
|
async removeModule(module) {
|
|
93
73
|
await module.sys.removeDir(`lib/${module.name}`);
|
|
94
74
|
}
|
|
75
|
+
async#hasSharedGuards(module) {
|
|
76
|
+
const { sys } = module;
|
|
77
|
+
if (sys.type === "lib" && sys.name === "shared")
|
|
78
|
+
return true;
|
|
79
|
+
if (!await sys.exists("lib/srv.ts"))
|
|
80
|
+
return false;
|
|
81
|
+
return (await sys.readFile("lib/srv.ts")).includes('"@libs/shared/lib/srv"');
|
|
82
|
+
}
|
|
95
83
|
async createComponentTemplate(module, type) {
|
|
96
84
|
await module.sys.applyTemplate({
|
|
97
85
|
basePath: `./lib/${module.name}`,
|
|
@@ -122,9 +110,11 @@ class ModuleRunner extends runner("module") {
|
|
|
122
110
|
zone: localModuleFilename(module.name, "zone"),
|
|
123
111
|
util: localModuleFilename(module.name, "util")
|
|
124
112
|
};
|
|
113
|
+
const sharedGuards = await this.#hasSharedGuards(module);
|
|
125
114
|
await module.applyTemplate({
|
|
126
115
|
basePath: `.`,
|
|
127
116
|
template: "module",
|
|
117
|
+
options: { sharedGuards },
|
|
128
118
|
dict: {
|
|
129
119
|
model: module.name,
|
|
130
120
|
models: names,
|
|
@@ -136,7 +126,7 @@ class ModuleRunner extends runner("module") {
|
|
|
136
126
|
modelDescKo: modelDescription.ko
|
|
137
127
|
}
|
|
138
128
|
});
|
|
139
|
-
await module.writeFile(filenames.abstract, moduleAbstractContent(module.name));
|
|
129
|
+
await module.writeFile(filenames.abstract, moduleAbstractContent(module.name, sharedGuards));
|
|
140
130
|
const [
|
|
141
131
|
abstractContent,
|
|
142
132
|
constantContent,
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ycy302an.js";
|
|
6
6
|
import {
|
|
7
7
|
generatedFilesForSync,
|
|
8
8
|
createPassedPrimitiveReport,
|
|
9
9
|
scalarChangedFiles
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-yw6g3bbv.js";
|
|
11
11
|
import {
|
|
12
12
|
pluralizeName
|
|
13
13
|
} from "./index-nz8prx9g.js";
|