agent-devkit 0.5.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -8,7 +8,7 @@ import React from "react";
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "agent-devkit",
11
- version: "0.5.7",
11
+ version: "0.6.0",
12
12
  description: "Agent DevKit CLI and TUI runtime for specialist AI agents, capabilities and provider-aware workflows.",
13
13
  license: "MIT",
14
14
  type: "module",
@@ -4295,6 +4295,9 @@ function createEnvironmentSurface() {
4295
4295
  // src/app/cli/toolRuntime.ts
4296
4296
  import { homedir as homedir12 } from "os";
4297
4297
 
4298
+ // src/infra/brain/claude_cli_provider.ts
4299
+ import { execFile } from "child_process";
4300
+
4298
4301
  // src/infra/helpers/tool_schema_summary.ts
4299
4302
  var MAX_VARIANTS = 12;
4300
4303
  var MAX_PROPS = 10;
@@ -4506,9 +4509,9 @@ var ModelStore = class {
4506
4509
  await once(writeStream, "drain");
4507
4510
  }
4508
4511
  }
4509
- await new Promise((resolve9, reject) => {
4512
+ await new Promise((resolve11, reject) => {
4510
4513
  writeStream.on("error", reject);
4511
- writeStream.end(() => resolve9());
4514
+ writeStream.end(() => resolve11());
4512
4515
  });
4513
4516
  } finally {
4514
4517
  reader.releaseLock();
@@ -4756,6 +4759,16 @@ var LocalLlamaBrainProvider = class {
4756
4759
  constructor(options = {}) {
4757
4760
  this.#store = options.store ?? new ModelStore({ stateDirectory: options.stateDirectory });
4758
4761
  }
4762
+ describe() {
4763
+ return {
4764
+ id: "local",
4765
+ kind: "local",
4766
+ supports: { embeddings: false, stream: true, structured: true }
4767
+ };
4768
+ }
4769
+ async isAvailable() {
4770
+ return (await this.#ensureNodeLlama()).isOk();
4771
+ }
4759
4772
  generate(request) {
4760
4773
  return this.#run(request);
4761
4774
  }
@@ -4875,6 +4888,96 @@ var LocalLlamaBrainProvider = class {
4875
4888
  }
4876
4889
  };
4877
4890
 
4891
+ // src/infra/brain/claude_cli_provider.ts
4892
+ var defaultCommand = "claude";
4893
+ var defaultTimeoutMs = 12e4;
4894
+ var maxOutputBufferBytes = 16 * 1024 * 1024;
4895
+ function defaultExecutor(command, args, options) {
4896
+ return new Promise((resolve11) => {
4897
+ execFile(
4898
+ command,
4899
+ args,
4900
+ { maxBuffer: maxOutputBufferBytes, timeout: options.timeoutMs },
4901
+ (error, stdout, stderr) => {
4902
+ if (error !== null) {
4903
+ resolve11(Result.fail(ErrorCodes.BrainProviderUnavailable));
4904
+ return;
4905
+ }
4906
+ resolve11(Result.ok({ stderr, stdout }));
4907
+ }
4908
+ );
4909
+ });
4910
+ }
4911
+ function parsePayload(stdout) {
4912
+ try {
4913
+ const payload = JSON.parse(stdout);
4914
+ if (typeof payload === "object" && payload !== null && typeof payload.result === "string") {
4915
+ const inputTokens = typeof payload.usage?.input_tokens === "number" ? payload.usage.input_tokens : void 0;
4916
+ const outputTokens2 = typeof payload.usage?.output_tokens === "number" ? payload.usage.output_tokens : void 0;
4917
+ const usage = inputTokens === void 0 && outputTokens2 === void 0 ? void 0 : { inputTokens, outputTokens: outputTokens2 };
4918
+ return { text: payload.result, usage };
4919
+ }
4920
+ } catch {
4921
+ }
4922
+ return { text: stdout.trim() };
4923
+ }
4924
+ var ClaudeCliBrainProvider = class {
4925
+ #command;
4926
+ #executor;
4927
+ #timeoutMs;
4928
+ #availability;
4929
+ constructor(options = {}) {
4930
+ this.#command = options.command ?? defaultCommand;
4931
+ this.#executor = options.executor ?? defaultExecutor;
4932
+ this.#timeoutMs = options.timeoutMs ?? defaultTimeoutMs;
4933
+ }
4934
+ describe() {
4935
+ return {
4936
+ id: "claude-cli",
4937
+ kind: "cli",
4938
+ supports: { embeddings: false, stream: false, structured: false }
4939
+ };
4940
+ }
4941
+ async isAvailable() {
4942
+ if (this.#availability !== void 0) {
4943
+ return this.#availability;
4944
+ }
4945
+ const probed = await this.#executor(this.#command, ["--version"], { timeoutMs: 1e4 });
4946
+ this.#availability = probed.isOk();
4947
+ return this.#availability;
4948
+ }
4949
+ async generate(request) {
4950
+ if (!await this.isAvailable()) {
4951
+ return Result.fail(ErrorCodes.BrainProviderUnavailable);
4952
+ }
4953
+ const promptText = [
4954
+ systemPromptFrom(request.prompt),
4955
+ "",
4956
+ `User: ${request.prompt.task.userMessage}`
4957
+ ].join("\n");
4958
+ const args = ["-p", promptText, "--output-format", "json"];
4959
+ if (request.options.model !== void 0) {
4960
+ args.push("--model", request.options.model);
4961
+ }
4962
+ const executed = await this.#executor(this.#command, args, { timeoutMs: this.#timeoutMs });
4963
+ if (executed.isErr()) {
4964
+ return Result.fail(executed.unwrapError());
4965
+ }
4966
+ const { text: text2, usage } = parsePayload(executed.unwrap().stdout);
4967
+ if (text2.length === 0) {
4968
+ return Result.fail(ErrorCodes.BrainProviderUnavailable);
4969
+ }
4970
+ return Result.ok({
4971
+ finishReason: "stop",
4972
+ model: request.options.model,
4973
+ provider: "claude-cli",
4974
+ schema: "agent-devkit.brain-response/v1",
4975
+ text: text2,
4976
+ usage
4977
+ });
4978
+ }
4979
+ };
4980
+
4878
4981
  // src/infra/brain/mock_provider.ts
4879
4982
  function reply(request) {
4880
4983
  const text2 = `Entendi. Vou responder no contexto da sess\xE3o atual: "${request.prompt.task.userMessage}".`;
@@ -4894,6 +4997,16 @@ function reply(request) {
4894
4997
  };
4895
4998
  }
4896
4999
  var MockBrainProvider = class {
5000
+ describe() {
5001
+ return {
5002
+ id: "mock",
5003
+ kind: "local",
5004
+ supports: { embeddings: false, stream: true, structured: true }
5005
+ };
5006
+ }
5007
+ async isAvailable() {
5008
+ return true;
5009
+ }
4897
5010
  async generate(request) {
4898
5011
  return Result.ok(reply(request));
4899
5012
  }
@@ -4911,83 +5024,183 @@ var MockBrainProvider = class {
4911
5024
  }
4912
5025
  };
4913
5026
 
5027
+ // src/infra/brain/structured_text_fallback.ts
5028
+ function extractJsonObject(text2) {
5029
+ const start = text2.indexOf("{");
5030
+ const end = text2.lastIndexOf("}");
5031
+ if (start === -1 || end === -1 || end <= start) {
5032
+ return void 0;
5033
+ }
5034
+ try {
5035
+ return JSON.parse(text2.slice(start, end + 1));
5036
+ } catch {
5037
+ return void 0;
5038
+ }
5039
+ }
5040
+ function withJsonInstruction(request, jsonSchema) {
5041
+ const instruction = [
5042
+ request.prompt.task.userMessage,
5043
+ "",
5044
+ "Responda SOMENTE com um objeto JSON v\xE1lido que satisfa\xE7a este JSON Schema:",
5045
+ JSON.stringify(jsonSchema),
5046
+ "Sem markdown, sem cercas de c\xF3digo, sem texto antes ou depois do JSON."
5047
+ ].join("\n");
5048
+ return {
5049
+ ...request,
5050
+ prompt: {
5051
+ ...request.prompt,
5052
+ output: { ...request.prompt.output, format: "json" },
5053
+ task: { ...request.prompt.task, userMessage: instruction }
5054
+ }
5055
+ };
5056
+ }
5057
+ function withRepairInstruction(request, previousRaw) {
5058
+ const instruction = [
5059
+ request.prompt.task.userMessage,
5060
+ "",
5061
+ "A resposta anterior n\xE3o era um JSON v\xE1lido:",
5062
+ previousRaw.slice(0, 800),
5063
+ "Corrija e responda apenas com o objeto JSON v\xE1lido."
5064
+ ].join("\n");
5065
+ return {
5066
+ ...request,
5067
+ prompt: { ...request.prompt, task: { ...request.prompt.task, userMessage: instruction } }
5068
+ };
5069
+ }
5070
+ async function generateStructuredViaText(provider, request, jsonSchema) {
5071
+ const constrained = withJsonInstruction(request, jsonSchema);
5072
+ const first = await provider.generate(constrained);
5073
+ if (first.isErr()) {
5074
+ return Result.fail(first.unwrapError());
5075
+ }
5076
+ const firstRaw = first.unwrap().text;
5077
+ const firstJson = extractJsonObject(firstRaw);
5078
+ if (firstJson !== void 0) {
5079
+ return Result.ok({ json: firstJson, raw: firstRaw });
5080
+ }
5081
+ const repaired = await provider.generate(withRepairInstruction(constrained, firstRaw));
5082
+ if (repaired.isErr()) {
5083
+ return Result.fail(repaired.unwrapError());
5084
+ }
5085
+ const repairedRaw = repaired.unwrap().text;
5086
+ const repairedJson = extractJsonObject(repairedRaw);
5087
+ if (repairedJson === void 0) {
5088
+ return Result.fail(ErrorCodes.InvalidInput);
5089
+ }
5090
+ return Result.ok({ json: repairedJson, raw: repairedRaw });
5091
+ }
5092
+
4914
5093
  // src/infra/brain/brain_dock.ts
4915
- var defaultProvider = "local";
5094
+ var defaultRouting = {
5095
+ agent: ["claude-cli", "local", "mock"],
5096
+ chat: ["claude-cli", "local", "mock"],
5097
+ embed: ["local"]
5098
+ };
4916
5099
  var fallbackProvider = "mock";
5100
+ var defaultRole = "chat";
4917
5101
  function shouldFallback(error) {
4918
5102
  return error === ErrorCodes.BrainProviderUnavailable || error === ErrorCodes.ModelNotFound;
4919
5103
  }
5104
+ function chainFromEnv(role) {
5105
+ const raw = process.env[`AGENT_DEVKIT_BRAIN_${role.toUpperCase()}`];
5106
+ if (raw === void 0) {
5107
+ return void 0;
5108
+ }
5109
+ const chain = raw.split(",").map((id) => id.trim()).filter((id) => id.length > 0);
5110
+ return chain.length > 0 ? chain : void 0;
5111
+ }
5112
+ function resolveRouting(overrides = {}) {
5113
+ const roles = ["agent", "chat", "embed"];
5114
+ const routing = { ...defaultRouting };
5115
+ for (const role of roles) {
5116
+ routing[role] = overrides[role] ?? chainFromEnv(role) ?? routing[role];
5117
+ }
5118
+ return routing;
5119
+ }
4920
5120
  var BrainDockProvider = class {
4921
5121
  #factories;
4922
5122
  #instances = /* @__PURE__ */ new Map();
5123
+ #routing;
4923
5124
  constructor(options = {}) {
5125
+ this.#routing = resolveRouting(options.routing);
4924
5126
  this.#factories = /* @__PURE__ */ new Map([
5127
+ ["claude-cli", () => new ClaudeCliBrainProvider()],
4925
5128
  ["local", () => new LocalLlamaBrainProvider({ stateDirectory: options.stateDirectory })],
4926
5129
  ["mock", () => new MockBrainProvider()]
4927
5130
  ]);
5131
+ for (const [id, factory] of Object.entries(options.providers ?? {})) {
5132
+ this.#factories.set(id, factory);
5133
+ }
5134
+ }
5135
+ async describeProviders() {
5136
+ const statuses = [];
5137
+ for (const id of this.#factories.keys()) {
5138
+ const provider = this.#resolveById(id);
5139
+ const descriptor = provider.describe?.() ?? {
5140
+ id,
5141
+ kind: "local",
5142
+ supports: { embeddings: false, stream: false, structured: false }
5143
+ };
5144
+ const available = await provider.isAvailable?.() ?? true;
5145
+ statuses.push({ ...descriptor, available });
5146
+ }
5147
+ return statuses;
5148
+ }
5149
+ routingPolicy() {
5150
+ return { ...this.#routing };
4928
5151
  }
4929
5152
  async generate(request) {
4930
- const provider = this.#resolve(request);
4931
- const response = await provider.generate(request);
4932
- if (response.isOk() || request.options.provider === fallbackProvider || !shouldFallback(response.unwrapError())) {
5153
+ return this.#withChain(request, (provider, chained) => provider.generate(chained));
5154
+ }
5155
+ async generateStream(request, onToken) {
5156
+ return this.#withChain(request, async (provider, chained) => {
5157
+ if (provider.generateStream !== void 0) {
5158
+ return provider.generateStream(chained, onToken);
5159
+ }
5160
+ const response = await provider.generate(chained);
5161
+ if (response.isOk()) {
5162
+ onToken(response.unwrap().text);
5163
+ }
4933
5164
  return response;
4934
- }
4935
- return this.#resolveById(fallbackProvider).generate({
4936
- ...request,
4937
- options: { ...request.options, provider: fallbackProvider }
4938
5165
  });
4939
5166
  }
4940
- async generateStream(request, onToken) {
4941
- const provider = this.#resolve(request);
4942
- if (provider.generateStream !== void 0) {
4943
- const response2 = await provider.generateStream(request, onToken);
4944
- if (response2.isOk() || request.options.provider === fallbackProvider || !shouldFallback(response2.unwrapError())) {
4945
- return response2;
5167
+ async generateStructured(request, jsonSchema) {
5168
+ return this.#withChain(request, (provider, chained) => {
5169
+ if (provider.generateStructured !== void 0) {
5170
+ return provider.generateStructured(chained, jsonSchema);
4946
5171
  }
4947
- return this.#resolveById(fallbackProvider).generateStream?.(
4948
- {
4949
- ...request,
4950
- options: { ...request.options, provider: fallbackProvider }
4951
- },
4952
- onToken
4953
- ) ?? this.#resolveById(fallbackProvider).generate({
4954
- ...request,
4955
- options: { ...request.options, provider: fallbackProvider }
4956
- });
4957
- }
4958
- const response = await provider.generate(request);
4959
- if (response.isOk()) {
4960
- onToken(response.unwrap().text);
5172
+ return generateStructuredViaText(provider, chained, jsonSchema);
5173
+ });
5174
+ }
5175
+ #chainFor(request) {
5176
+ if (request.options.provider !== void 0) {
5177
+ return request.options.provider === fallbackProvider ? [fallbackProvider] : [request.options.provider, fallbackProvider];
4961
5178
  }
4962
- return response;
5179
+ return this.#routing[request.options.role ?? defaultRole];
4963
5180
  }
4964
- async generateStructured(request, jsonSchema) {
4965
- const provider = this.#resolve(request);
4966
- if (provider.generateStructured !== void 0) {
4967
- const response = await provider.generateStructured(request, jsonSchema);
4968
- if (response.isOk() || request.options.provider === fallbackProvider || !shouldFallback(response.unwrapError())) {
5181
+ async #withChain(request, operation) {
5182
+ const chain = this.#chainFor(request);
5183
+ let lastError = ErrorCodes.BrainProviderUnavailable;
5184
+ for (const id of chain) {
5185
+ const provider = this.#resolveById(id);
5186
+ const chained = {
5187
+ ...request,
5188
+ options: { ...request.options, provider: id }
5189
+ };
5190
+ const response = await operation(provider, chained);
5191
+ if (response.isOk() || !shouldFallback(response.unwrapError())) {
4969
5192
  return response;
4970
5193
  }
4971
- return this.#resolveById(fallbackProvider).generateStructured?.(
4972
- {
4973
- ...request,
4974
- options: { ...request.options, provider: fallbackProvider }
4975
- },
4976
- jsonSchema
4977
- ) ?? Result.fail(ErrorCodes.BrainProviderUnavailable);
5194
+ lastError = response.unwrapError();
4978
5195
  }
4979
- return Result.fail(ErrorCodes.BrainProviderUnavailable);
4980
- }
4981
- #resolve(request) {
4982
- const id = request.options.provider ?? defaultProvider;
4983
- return this.#resolveById(id);
5196
+ return Result.fail(lastError);
4984
5197
  }
4985
5198
  #resolveById(id) {
4986
5199
  const cached = this.#instances.get(id);
4987
5200
  if (cached !== void 0) {
4988
5201
  return cached;
4989
5202
  }
4990
- const factory = this.#factories.get(id) ?? this.#factories.get(defaultProvider);
5203
+ const factory = this.#factories.get(id);
4991
5204
  const provider = factory === void 0 ? new MockBrainProvider() : factory();
4992
5205
  this.#instances.set(id, provider);
4993
5206
  return provider;
@@ -8787,12 +9000,13 @@ import { z as z27 } from "zod";
8787
9000
 
8788
9001
  // src/infra/bases/brain.ts
8789
9002
  import { z as z26 } from "zod";
9003
+ var BrainRoleSchema = z26.enum(["agent", "chat", "embed"]);
8790
9004
  var BrainGenerationOptionsSchema = z26.object({
8791
9005
  maxInputTokens: z26.number().int().positive().optional(),
8792
9006
  maxOutputTokens: z26.number().int().positive().optional(),
8793
9007
  model: z26.string().min(1).optional(),
8794
- provider: z26.enum(["local", "mock"]).default("local"),
8795
- role: z26.enum(["agent", "chat"]).optional(),
9008
+ provider: z26.string().min(1).optional(),
9009
+ role: BrainRoleSchema.optional(),
8796
9010
  seed: z26.number().int().optional(),
8797
9011
  stop: z26.array(z26.string().min(1)).optional(),
8798
9012
  stream: z26.boolean().optional(),
@@ -8801,7 +9015,7 @@ var BrainGenerationOptionsSchema = z26.object({
8801
9015
  topP: z26.number().min(0).max(1).optional()
8802
9016
  }).strict();
8803
9017
  var BrainRequestSchema = z26.object({
8804
- options: BrainGenerationOptionsSchema.default({ provider: "local" }),
9018
+ options: BrainGenerationOptionsSchema.default({}),
8805
9019
  prompt: AgentPromptSchema,
8806
9020
  schema: z26.literal("agent-devkit.brain-request/v1")
8807
9021
  }).strict();
@@ -8912,7 +9126,7 @@ var ConversationChatService = class extends BaseCapabilityService {
8912
9126
  return Result.fail(prepared.unwrapError());
8913
9127
  }
8914
9128
  const request = {
8915
- options: { provider: "local", ...parsed.data.brain, role: "chat" },
9129
+ options: { ...parsed.data.brain, role: "chat" },
8916
9130
  prompt: prepared.unwrap().prompt,
8917
9131
  schema: "agent-devkit.brain-request/v1"
8918
9132
  };
@@ -11481,9 +11695,9 @@ function createSecretsSurface() {
11481
11695
  }
11482
11696
 
11483
11697
  // src/modules/self/capabilities/update/update.repository.ts
11484
- import { execFile } from "child_process";
11698
+ import { execFile as execFile2 } from "child_process";
11485
11699
  import { promisify } from "util";
11486
- var execFileAsync = promisify(execFile);
11700
+ var execFileAsync = promisify(execFile2);
11487
11701
  var UpdateRepository = class {
11488
11702
  repositoryId = "self.update.repository";
11489
11703
  async getPackageVersions(packageName) {
@@ -12369,6 +12583,19 @@ var agentRouteJsonSchema = {
12369
12583
  },
12370
12584
  required: ["action"]
12371
12585
  };
12586
+ var AgentDomainRouteSchema = z41.discriminatedUnion("action", [
12587
+ z41.object({ action: z41.literal("domains"), domains: z41.array(z41.string().min(1)).min(1) }),
12588
+ z41.object({ action: z41.literal("final"), reply: z41.string() })
12589
+ ]);
12590
+ var agentDomainRouteJsonSchema = {
12591
+ type: "object",
12592
+ properties: {
12593
+ action: { type: "string", enum: ["domains", "final"] },
12594
+ domains: { type: "array", items: { type: "string" } },
12595
+ reply: { type: "string" }
12596
+ },
12597
+ required: ["action"]
12598
+ };
12372
12599
  var AgentPlanStepSchema = z41.object({
12373
12600
  dependsOn: z41.array(z41.string().min(1)).default([]),
12374
12601
  id: z41.string().min(1),
@@ -12515,6 +12742,24 @@ async function buildToolDecisionPrompt(input) {
12515
12742
  }
12516
12743
  });
12517
12744
  }
12745
+ async function buildDomainDecisionPrompt(input) {
12746
+ return promptComposer.compose("core/domain-decision", {
12747
+ agent: input.agent ?? agentPersona,
12748
+ context: {
12749
+ knowledge: recoveredKnowledge({
12750
+ contextSnapshot: input.contextSnapshot,
12751
+ memories: input.memories
12752
+ }),
12753
+ project: input.contextSnapshot?.project,
12754
+ session: input.contextSnapshot?.session
12755
+ },
12756
+ messages: input.transcript,
12757
+ variables: {
12758
+ domains: input.domains.map((domain) => `- ${domain.id} (${domain.toolCount} tools): ${domain.summary}`).join("\n"),
12759
+ task: input.task
12760
+ }
12761
+ });
12762
+ }
12518
12763
  async function buildTaskPlanPrompt(input) {
12519
12764
  return promptComposer.compose("core/task-plan", {
12520
12765
  agent: input.agent ?? agentPersona,
@@ -12623,6 +12868,178 @@ function approvalGrantForTool(tool, input) {
12623
12868
  });
12624
12869
  }
12625
12870
 
12871
+ // src/agent/agent.router.ts
12872
+ var defaultMaxToolsPerDecision = 20;
12873
+ var maxDomainSummaryLength = 200;
12874
+ function truncate(text2, length) {
12875
+ const compact3 = text2.replaceAll(/\s+/g, " ").trim();
12876
+ return compact3.length > length ? `${compact3.slice(0, length)}...` : compact3;
12877
+ }
12878
+ function approximatePromptTokens(prompt) {
12879
+ return Math.ceil(JSON.stringify(prompt).length / 4);
12880
+ }
12881
+ function domainsFor(tools, knowledge) {
12882
+ const byModule = /* @__PURE__ */ new Map();
12883
+ for (const tool of tools) {
12884
+ const grouped = byModule.get(tool.moduleId) ?? [];
12885
+ grouped.push(tool);
12886
+ byModule.set(tool.moduleId, grouped);
12887
+ }
12888
+ const knowledgeById = new Map(knowledge.map((module) => [module.moduleId, module]));
12889
+ return [...byModule.entries()].map(([moduleId, moduleTools]) => {
12890
+ const surface = knowledgeById.get(moduleId);
12891
+ const parts = [];
12892
+ if (surface !== void 0 && surface.summary.length > 0) {
12893
+ parts.push(surface.summary);
12894
+ }
12895
+ if (surface !== void 0 && surface.whenToUse.length > 0) {
12896
+ parts.push(`Use when: ${surface.whenToUse.join(" ")}`);
12897
+ }
12898
+ if (parts.length === 0) {
12899
+ parts.push(
12900
+ moduleTools.slice(0, 3).map((tool) => tool.description).join(" ")
12901
+ );
12902
+ }
12903
+ return {
12904
+ id: moduleId,
12905
+ summary: truncate(parts.join(" "), maxDomainSummaryLength),
12906
+ toolCount: moduleTools.length
12907
+ };
12908
+ });
12909
+ }
12910
+ var AgentToolRouter = class {
12911
+ #maxToolsPerDecision;
12912
+ constructor(options = {}) {
12913
+ this.#maxToolsPerDecision = options.maxToolsPerDecision ?? defaultMaxToolsPerDecision;
12914
+ }
12915
+ async route(input) {
12916
+ const scoped = await this.#scopeTools(input);
12917
+ if (scoped.isErr()) {
12918
+ return Result.fail(scoped.unwrapError());
12919
+ }
12920
+ const scopedValue = scoped.unwrap();
12921
+ if ("reply" in scopedValue) {
12922
+ return Result.ok(scopedValue);
12923
+ }
12924
+ return this.#decideTool(input, scopedValue.tools);
12925
+ }
12926
+ async #scopeTools(input) {
12927
+ if (input.tools.length <= this.#maxToolsPerDecision) {
12928
+ return Result.ok({ tools: input.tools });
12929
+ }
12930
+ const domains = domainsFor(input.tools, input.knowledge);
12931
+ const prompt = await buildDomainDecisionPrompt({
12932
+ agent: input.agent,
12933
+ contextSnapshot: input.contextSnapshot,
12934
+ domains,
12935
+ memories: input.memories,
12936
+ task: input.task,
12937
+ transcript: input.transcript
12938
+ });
12939
+ if (prompt.isErr()) {
12940
+ await input.onEvent?.({
12941
+ payload: { code: prompt.unwrapError(), phase: "route-domains-prompt" },
12942
+ type: "error"
12943
+ });
12944
+ return Result.fail(prompt.unwrapError());
12945
+ }
12946
+ const routed = await input.generateStructured(
12947
+ {
12948
+ options: { role: "agent" },
12949
+ prompt: prompt.unwrap(),
12950
+ schema: "agent-devkit.brain-request/v1"
12951
+ },
12952
+ agentDomainRouteJsonSchema
12953
+ );
12954
+ if (routed.isErr()) {
12955
+ await input.onEvent?.({
12956
+ payload: { code: routed.unwrapError(), phase: "route-domains" },
12957
+ type: "error"
12958
+ });
12959
+ return Result.fail(routed.unwrapError());
12960
+ }
12961
+ const route = AgentDomainRouteSchema.safeParse(routed.unwrap().json);
12962
+ if (!route.success) {
12963
+ await input.onEvent?.({
12964
+ payload: { phase: "route-domains", raw: routed.unwrap().raw },
12965
+ type: "error"
12966
+ });
12967
+ return Result.fail(ErrorCodes.InvalidInput);
12968
+ }
12969
+ if (route.data.action === "final") {
12970
+ return Result.ok({ reply: route.data.reply });
12971
+ }
12972
+ const selected = new Set(route.data.domains.slice(0, 2));
12973
+ const known = new Set(domains.map((domain) => domain.id));
12974
+ const validSelection = [...selected].filter((domain) => known.has(domain));
12975
+ const scoped = validSelection.length === 0 ? input.tools : input.tools.filter((tool) => selected.has(tool.moduleId));
12976
+ await input.onEvent?.({
12977
+ payload: {
12978
+ approximatePromptTokens: approximatePromptTokens(prompt.unwrap()),
12979
+ domainCount: domains.length,
12980
+ domains: validSelection,
12981
+ phase: "route-domains",
12982
+ scopedToolCount: Math.min(scoped.length, this.#maxToolsPerDecision),
12983
+ totalToolCount: input.tools.length
12984
+ },
12985
+ type: "thought"
12986
+ });
12987
+ return Result.ok({ tools: scoped.slice(0, this.#maxToolsPerDecision) });
12988
+ }
12989
+ async #decideTool(input, tools) {
12990
+ const prompt = await buildToolDecisionPrompt({
12991
+ agent: input.agent,
12992
+ contextSnapshot: input.contextSnapshot,
12993
+ knowledge: input.knowledge.filter(
12994
+ (module) => tools.some((tool) => tool.moduleId === module.moduleId)
12995
+ ),
12996
+ memories: input.memories,
12997
+ task: input.task,
12998
+ tools,
12999
+ transcript: input.transcript
13000
+ });
13001
+ if (prompt.isErr()) {
13002
+ await input.onEvent?.({
13003
+ payload: { code: prompt.unwrapError(), phase: "route-prompt" },
13004
+ type: "error"
13005
+ });
13006
+ return Result.fail(prompt.unwrapError());
13007
+ }
13008
+ const routed = await input.generateStructured(
13009
+ {
13010
+ options: { role: "agent" },
13011
+ prompt: prompt.unwrap(),
13012
+ schema: "agent-devkit.brain-request/v1"
13013
+ },
13014
+ agentRouteJsonSchema
13015
+ );
13016
+ if (routed.isErr()) {
13017
+ await input.onEvent?.({
13018
+ payload: { code: routed.unwrapError(), phase: "route" },
13019
+ type: "error"
13020
+ });
13021
+ return Result.fail(routed.unwrapError());
13022
+ }
13023
+ const route = AgentRouteSchema.safeParse(routed.unwrap().json);
13024
+ if (!route.success) {
13025
+ await input.onEvent?.({
13026
+ payload: { phase: "route", raw: routed.unwrap().raw },
13027
+ type: "error"
13028
+ });
13029
+ return Result.fail(ErrorCodes.InvalidInput);
13030
+ }
13031
+ await input.onEvent?.({
13032
+ payload: {
13033
+ approximatePromptTokens: approximatePromptTokens(prompt.unwrap()),
13034
+ phase: "route-tool",
13035
+ toolCount: tools.length
13036
+ },
13037
+ type: "thought"
13038
+ });
13039
+ return route.data.action === "final" ? Result.ok({ reply: route.data.reply }) : Result.ok({ tool: route.data.tool });
13040
+ }
13041
+ };
13042
+
12626
13043
  // src/agent/agent.loop.ts
12627
13044
  function summarize(value) {
12628
13045
  const text2 = typeof value === "string" ? value : JSON.stringify(value ?? "");
@@ -12648,6 +13065,7 @@ var AgentToolLoop = class {
12648
13065
  #contextAssembler;
12649
13066
  #knowledge;
12650
13067
  #memoryRetriever;
13068
+ #router;
12651
13069
  #tools;
12652
13070
  constructor(options) {
12653
13071
  this.#agent = options.agent;
@@ -12655,6 +13073,7 @@ var AgentToolLoop = class {
12655
13073
  this.#contextAssembler = options.contextAssembler;
12656
13074
  this.#knowledge = options.knowledge;
12657
13075
  this.#memoryRetriever = options.memoryRetriever;
13076
+ this.#router = options.router ?? new AgentToolRouter();
12658
13077
  this.#tools = options.toolRuntime;
12659
13078
  }
12660
13079
  async run(input, context) {
@@ -12976,7 +13395,7 @@ var AgentToolLoop = class {
12976
13395
  });
12977
13396
  const planned = prompt.isErr() ? void 0 : await input.generateStructured(
12978
13397
  {
12979
- options: { provider: "local", role: "agent" },
13398
+ options: { role: "agent" },
12980
13399
  prompt: prompt.unwrap(),
12981
13400
  schema: "agent-devkit.brain-request/v1"
12982
13401
  },
@@ -13065,7 +13484,7 @@ var AgentToolLoop = class {
13065
13484
  return Result.fail(prompt.unwrapError());
13066
13485
  }
13067
13486
  const request = {
13068
- options: { provider: "local", role: "agent" },
13487
+ options: { role: "agent" },
13069
13488
  prompt: prompt.unwrap(),
13070
13489
  schema: "agent-devkit.brain-request/v1"
13071
13490
  };
@@ -13075,47 +13494,29 @@ var AgentToolLoop = class {
13075
13494
  }
13076
13495
  return Result.ok(produced.unwrap().json ?? {});
13077
13496
  }
13497
+ /**
13498
+ * Decision phase adapter: hierarchical routing lives in `AgentToolRouter`
13499
+ * (domain stage + tool stage); the loop only forwards context and events.
13500
+ */
13078
13501
  async #routeToolOrFinal(input) {
13079
- const routePrompt = await buildToolDecisionPrompt({
13502
+ const routed = await this.#router.route({
13080
13503
  agent: input.agent,
13081
13504
  contextSnapshot: input.contextSnapshot,
13505
+ generateStructured: input.generateStructured,
13082
13506
  knowledge: input.knowledge,
13083
13507
  memories: input.memories,
13508
+ onEvent: async (event) => {
13509
+ await input.context?.eventSink?.appendEvent(event);
13510
+ },
13084
13511
  task: input.input.task,
13085
13512
  tools: input.tools,
13086
13513
  transcript: input.transcript
13087
13514
  });
13088
- if (routePrompt.isErr()) {
13089
- await input.context?.eventSink?.appendEvent({
13090
- payload: { code: routePrompt.unwrapError(), phase: "route-prompt" },
13091
- type: "error"
13092
- });
13093
- return Result.fail(routePrompt.unwrapError());
13094
- }
13095
- const routed = await input.generateStructured(
13096
- {
13097
- options: { provider: "local", role: "agent" },
13098
- prompt: routePrompt.unwrap(),
13099
- schema: "agent-devkit.brain-request/v1"
13100
- },
13101
- agentRouteJsonSchema
13102
- );
13103
13515
  if (routed.isErr()) {
13104
- await input.context?.eventSink?.appendEvent({
13105
- payload: { code: routed.unwrapError(), phase: "route" },
13106
- type: "error"
13107
- });
13108
13516
  return Result.fail(routed.unwrapError());
13109
13517
  }
13110
- const route = AgentRouteSchema.safeParse(routed.unwrap().json);
13111
- if (!route.success) {
13112
- await input.context?.eventSink?.appendEvent({
13113
- payload: { phase: "route", raw: routed.unwrap().raw },
13114
- type: "error"
13115
- });
13116
- return Result.fail(ErrorCodes.InvalidInput);
13117
- }
13118
- return route.data.action === "final" ? Result.ok({ reply: route.data.reply }) : Result.ok(route.data.tool);
13518
+ const decision = routed.unwrap();
13519
+ return "reply" in decision ? Result.ok(decision) : Result.ok(decision.tool);
13119
13520
  }
13120
13521
  async #reflect(input) {
13121
13522
  const prompt = await buildReflectionPrompt(input);
@@ -13124,7 +13525,7 @@ var AgentToolLoop = class {
13124
13525
  }
13125
13526
  const reflected = await input.generateStructured(
13126
13527
  {
13127
- options: { provider: "local", role: "agent" },
13528
+ options: { role: "agent" },
13128
13529
  prompt: prompt.unwrap(),
13129
13530
  schema: "agent-devkit.brain-request/v1"
13130
13531
  },
@@ -13151,7 +13552,7 @@ var AgentToolLoop = class {
13151
13552
  }
13152
13553
  const summarized = await input.generateStructured(
13153
13554
  {
13154
- options: { provider: "local", role: "agent" },
13555
+ options: { role: "agent" },
13155
13556
  prompt: prompt.unwrap(),
13156
13557
  schema: "agent-devkit.brain-request/v1"
13157
13558
  },
@@ -13828,8 +14229,8 @@ async function startMcpHttpServer(options) {
13828
14229
  }
13829
14230
  }
13830
14231
  });
13831
- await new Promise((resolve9) => {
13832
- httpServer.listen(options.port, options.host, resolve9);
14232
+ await new Promise((resolve11) => {
14233
+ httpServer.listen(options.port, options.host, resolve11);
13833
14234
  });
13834
14235
  return httpServer;
13835
14236
  }
@@ -14371,6 +14772,36 @@ function registerModelsCommand(program2, options) {
14371
14772
  }
14372
14773
  )
14373
14774
  );
14775
+ const providersCommand = modelsCommand.command("providers").description(options.translator.t("cli.models.providers.description")).option("--json", options.translator.t("cli.models.providers.option.json"));
14776
+ providersCommand.action(
14777
+ options.usageLogging.track(
14778
+ {
14779
+ area: "system",
14780
+ command: "models.providers",
14781
+ createStateIfMissing: false,
14782
+ options: () => providersCommand.opts()
14783
+ },
14784
+ async (commandOptions) => {
14785
+ const dock = createBrainDockProvider({ stateDirectory: `${homedir16()}/.agent-devkit` });
14786
+ const providers = await dock.describeProviders();
14787
+ const routing = dock.routingPolicy();
14788
+ if (wantsJson(commandOptions) === true) {
14789
+ console.log(JSON.stringify({ providers, routing }, null, 2));
14790
+ return;
14791
+ }
14792
+ for (const provider of providers) {
14793
+ const supports = Object.entries(provider.supports).filter(([, enabled]) => enabled).map(([name]) => name).join(", ");
14794
+ console.log(
14795
+ `${provider.available ? "\u25CF" : "\u25CB"} ${provider.id} (${provider.kind})${supports.length > 0 ? ` \u2014 ${supports}` : ""}`
14796
+ );
14797
+ }
14798
+ console.log("");
14799
+ for (const [role, chain] of Object.entries(routing)) {
14800
+ console.log(`${role}: ${chain.join(" \u2192 ")}`);
14801
+ }
14802
+ }
14803
+ )
14804
+ );
14374
14805
  const useCommand = modelsCommand.command("use").argument("<id>", options.translator.t("cli.models.argument.id")).description(options.translator.t("cli.models.use.description")).option("--agent", options.translator.t("cli.models.use.option.agent")).option("--chat", options.translator.t("cli.models.use.option.chat")).option("--json", options.translator.t("cli.models.option.json"));
14375
14806
  useCommand.action(
14376
14807
  options.usageLogging.track(
@@ -15841,11 +16272,20 @@ function cliConversationStatePathForScope(scope) {
15841
16272
  segments: [`cli-state-${sanitizeCliScope(scope)}.json`]
15842
16273
  };
15843
16274
  }
16275
+ function conversationStatePathForScope(invocationInterface, scope) {
16276
+ if (invocationInterface === "cli") {
16277
+ return cliConversationStatePathForScope(scope);
16278
+ }
16279
+ return {
16280
+ namespace: "conversation",
16281
+ segments: [`${invocationInterface}-state-${sanitizeCliScope(scope)}.json`]
16282
+ };
16283
+ }
15844
16284
  function isCliConversationState(value) {
15845
16285
  const record = value;
15846
16286
  return typeof value === "object" && value !== null && "activeSessionId" in value && "schema" in value && typeof record.activeSessionId === "string" && record.activeSessionId.length > 0 && record.schema === "agent-devkit.cli-conversation-state/v1";
15847
16287
  }
15848
- async function loadActiveCliSessionId(dataStore, sessions, statePath) {
16288
+ async function loadActiveCliSessionId(dataStore, sessions, statePath, expectedOrigin) {
15849
16289
  const state = await dataStore.readJson(statePath);
15850
16290
  if (state.isErr()) {
15851
16291
  return void 0;
@@ -15863,7 +16303,7 @@ async function loadActiveCliSessionId(dataStore, sessions, statePath) {
15863
16303
  return void 0;
15864
16304
  }
15865
16305
  const result = current.unwrap();
15866
- if (result.action !== "show" || result.session.origin !== "cli" || result.session.status !== "active") {
16306
+ if (result.action !== "show" || result.session.origin !== expectedOrigin || result.session.status !== "active") {
15867
16307
  return void 0;
15868
16308
  }
15869
16309
  return result.session.id;
@@ -15903,8 +16343,9 @@ function createConversationPort(chat) {
15903
16343
  }
15904
16344
  };
15905
16345
  }
15906
- async function runRootConversation(message, options) {
16346
+ function createCliAgentEnvironment(options) {
15907
16347
  const homeDirectory = homedir25();
16348
+ const invocationInterface = options.interface ?? "cli";
15908
16349
  const dataStore = new LocalAgentDataStore({
15909
16350
  rootDirectory: `${homeDirectory}/.agent-devkit/data`
15910
16351
  });
@@ -15935,12 +16376,8 @@ async function runRootConversation(message, options) {
15935
16376
  if (contextBindings.isErr()) {
15936
16377
  throw new Error(contextBindings.unwrapError());
15937
16378
  }
15938
- const cliStatePath = cliConversationStatePathForScope(currentCliSessionScope());
15939
- const activeSessionId = await loadActiveCliSessionId(
15940
- dataStore,
15941
- contextBindings.unwrap().capabilities.sessions,
15942
- cliStatePath
15943
- );
16379
+ const sessions = contextBindings.unwrap().capabilities.sessions;
16380
+ const cliStatePath = conversationStatePathForScope(invocationInterface, currentCliSessionScope());
15944
16381
  const agent = new AgentRuntime({
15945
16382
  brainProvider: createBrainDockProvider({ stateDirectory: `${homeDirectory}/.agent-devkit` }),
15946
16383
  conversation: createConversationPort(bindings.unwrap().capabilities.chat),
@@ -15952,7 +16389,17 @@ async function runRootConversation(message, options) {
15952
16389
  packageName: options.packageName
15953
16390
  })
15954
16391
  });
15955
- const result = await agent.run({
16392
+ return {
16393
+ agent,
16394
+ loadActiveSessionId: () => loadActiveCliSessionId(dataStore, sessions, cliStatePath, invocationInterface),
16395
+ saveActiveSessionId: (sessionId) => saveActiveCliSessionId(dataStore, sessionId, cliStatePath),
16396
+ sessions
16397
+ };
16398
+ }
16399
+ async function runRootConversation(message, options) {
16400
+ const environment = createCliAgentEnvironment(options);
16401
+ const activeSessionId = await environment.loadActiveSessionId();
16402
+ const result = await environment.agent.run({
15956
16403
  interface: "cli",
15957
16404
  message,
15958
16405
  mode: "chat",
@@ -15966,7 +16413,7 @@ async function runRootConversation(message, options) {
15966
16413
  if (payload.conversation === void 0 || !isConversationChatResult(rawConversation)) {
15967
16414
  throw new Error("Agent did not return a conversation result.");
15968
16415
  }
15969
- await saveActiveCliSessionId(dataStore, payload.conversation.sessionId, cliStatePath);
16416
+ await environment.saveActiveSessionId(payload.conversation.sessionId);
15970
16417
  console.log(formatConversationChatText(rawConversation));
15971
16418
  }
15972
16419
  function isConversationChatResult(value) {
@@ -16050,21 +16497,748 @@ var CliUsageLoggingMiddleware = class {
16050
16497
  };
16051
16498
 
16052
16499
  // src/app/tui/App.tsx
16500
+ import { Box as Box12, Text as Text14 } from "ink";
16501
+ import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState5 } from "react";
16502
+
16503
+ // src/app/tui/commands.ts
16504
+ function parseTuiCommand(value, pendingApproval) {
16505
+ const trimmed = value.trim();
16506
+ if (trimmed.length === 0) {
16507
+ return { type: "empty" };
16508
+ }
16509
+ if (pendingApproval) {
16510
+ const answer = trimmed.toLowerCase();
16511
+ if (answer === "s" || answer === "sim" || answer === "y" || answer === "yes") {
16512
+ return { type: "approve-yes" };
16513
+ }
16514
+ if (answer === "n" || answer === "nao" || answer === "n\xE3o" || answer === "no") {
16515
+ return { type: "approve-no" };
16516
+ }
16517
+ }
16518
+ if (trimmed === "/sessions" || trimmed === "/sessoes" || trimmed === "/sess\xF5es") {
16519
+ return { type: "sessions" };
16520
+ }
16521
+ if (trimmed === "/task") {
16522
+ return { type: "empty" };
16523
+ }
16524
+ if (trimmed.startsWith("/task ")) {
16525
+ const task = trimmed.slice("/task ".length).trim();
16526
+ return task.length === 0 ? { type: "empty" } : { type: "task", task };
16527
+ }
16528
+ return { type: "chat", message: trimmed };
16529
+ }
16530
+ function approvalRequiredTool(steps) {
16531
+ const waiting = [...steps].reverse().find((step) => !step.ok && step.summary.startsWith("approval_required"));
16532
+ return waiting?.tool;
16533
+ }
16534
+ function moodForEvent(event) {
16535
+ if (event.type === "tool") {
16536
+ return "working";
16537
+ }
16538
+ if (event.type === "observation") {
16539
+ return event.ok === false ? "concerned" : "working";
16540
+ }
16541
+ if (event.type === "final") {
16542
+ return "happy";
16543
+ }
16544
+ return "thinking";
16545
+ }
16546
+
16547
+ // src/app/tui/design/components/KbdBar.tsx
16053
16548
  import { Box, Text } from "ink";
16054
- import { jsx, jsxs } from "react/jsx-runtime";
16055
- function App({ initialPrompt, translator: translator2 }) {
16056
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
16057
- /* @__PURE__ */ jsx(Text, { bold: true, children: translator2.t("tui.title") }),
16058
- /* @__PURE__ */ jsx(Text, { children: translator2.t("tui.foundation") }),
16059
- initialPrompt ? /* @__PURE__ */ jsx(Text, { children: translator2.t("tui.prompt", { prompt: initialPrompt }) }) : /* @__PURE__ */ jsx(Text, { children: translator2.t("tui.helpHint") })
16549
+
16550
+ // src/app/tui/design/TokensContext.tsx
16551
+ import { createContext, useContext, useMemo } from "react";
16552
+
16553
+ // src/app/tui/design/tokens.ts
16554
+ function resolveTokens(theme, semantics) {
16555
+ const colors2 = theme.colors;
16556
+ const toColor = (tokenName) => colors2[tokenName] ?? theme.colors.textMuted;
16557
+ return {
16558
+ theme,
16559
+ semantics,
16560
+ glyphs: semantics.glyphs,
16561
+ color: (name) => theme.colors[name],
16562
+ statusColor: (status) => toColor(semantics.status[status]),
16563
+ riskColor: (risk) => toColor(semantics.risk[risk])
16564
+ };
16565
+ }
16566
+
16567
+ // src/app/tui/design/TokensContext.tsx
16568
+ import { jsx } from "react/jsx-runtime";
16569
+ var TokensContext = createContext(null);
16570
+ function TokensProvider({ theme, semantics, kit, children }) {
16571
+ const value = useMemo(
16572
+ () => ({ ...resolveTokens(theme, semantics), kit }),
16573
+ [theme, semantics, kit]
16574
+ );
16575
+ return /* @__PURE__ */ jsx(TokensContext.Provider, { value, children });
16576
+ }
16577
+ function useTokens() {
16578
+ const value = useContext(TokensContext);
16579
+ if (value === null) {
16580
+ throw new Error("useTokens must be used within a TokensProvider.");
16581
+ }
16582
+ return value;
16583
+ }
16584
+
16585
+ // src/app/tui/design/components/KbdBar.tsx
16586
+ import { jsx as jsx2 } from "react/jsx-runtime";
16587
+ function KbdBar({ keys }) {
16588
+ const tokens2 = useTokens();
16589
+ return /* @__PURE__ */ jsx2(Box, { gap: 2, children: keys.map((key) => /* @__PURE__ */ jsx2(Text, { color: tokens2.color("textDim"), children: key }, key)) });
16590
+ }
16591
+
16592
+ // src/app/tui/design/components/Kit.tsx
16593
+ import { Box as Box2, Text as Text2 } from "ink";
16594
+ import { useState as useState2 } from "react";
16595
+
16596
+ // src/app/tui/design/kit_cells.ts
16597
+ function applyOverrides(grid, overrides) {
16598
+ for (const [row, col, char] of overrides) {
16599
+ const line2 = grid[row];
16600
+ if (line2 !== void 0 && col >= 0 && col < line2.length) {
16601
+ line2[col] = char;
16602
+ }
16603
+ }
16604
+ }
16605
+ function kitCells(kit, mood, blink, background) {
16606
+ const grid = kit.base.map((line2) => line2.split(""));
16607
+ const moodDefinition = kit.moods[mood] ?? kit.moods.idle;
16608
+ if (moodDefinition !== void 0) {
16609
+ applyOverrides(grid, moodDefinition.overrides);
16610
+ }
16611
+ if (blink) {
16612
+ applyOverrides(grid, kit.blink.overrides);
16613
+ }
16614
+ const palette = { ...kit.palette };
16615
+ if (moodDefinition?.body !== void 0) {
16616
+ palette.B = moodDefinition.body;
16617
+ }
16618
+ if (moodDefinition?.dark !== void 0) {
16619
+ palette.D = moodDefinition.dark;
16620
+ }
16621
+ const colorFor = (char) => {
16622
+ const value = palette[char];
16623
+ return value === void 0 || value === "transparent" ? background : value;
16624
+ };
16625
+ const cellAt = (row, col) => grid[row]?.[col] ?? ".";
16626
+ const rows = [];
16627
+ for (let row = 0; row + 1 < kit.base.length; row += 2) {
16628
+ const cells = [];
16629
+ for (let col = 0; col < kit.size.cols; col += 1) {
16630
+ cells.push({ top: colorFor(cellAt(row, col)), bottom: colorFor(cellAt(row + 1, col)) });
16631
+ }
16632
+ rows.push(cells);
16633
+ }
16634
+ return rows;
16635
+ }
16636
+
16637
+ // src/app/tui/design/useTimers.ts
16638
+ import { useEffect, useRef, useState } from "react";
16639
+ function useInterval(callback, delayMs) {
16640
+ const saved = useRef(callback);
16641
+ saved.current = callback;
16642
+ useEffect(() => {
16643
+ if (delayMs === null) {
16644
+ return;
16645
+ }
16646
+ const id = setInterval(() => saved.current(), delayMs);
16647
+ return () => clearInterval(id);
16648
+ }, [delayMs]);
16649
+ }
16650
+ function useBlink(periodMs = 3600, durationMs3 = 150) {
16651
+ const [blinking, setBlinking] = useState(false);
16652
+ useInterval(() => {
16653
+ setBlinking(true);
16654
+ setTimeout(() => setBlinking(false), durationMs3);
16655
+ }, periodMs);
16656
+ return blinking;
16657
+ }
16658
+
16659
+ // src/app/tui/design/components/Kit.tsx
16660
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
16661
+ var spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
16662
+ function Kit({ mood = "idle", animate = true }) {
16663
+ const tokens2 = useTokens();
16664
+ const blink = useBlink();
16665
+ const [frame, setFrame] = useState2(0);
16666
+ const badge = tokens2.kit.moods[mood]?.badge;
16667
+ const isSpinner = badge === "spinner";
16668
+ useInterval(
16669
+ () => setFrame((current) => (current + 1) % spinnerFrames.length),
16670
+ animate && isSpinner ? 90 : null
16671
+ );
16672
+ const rows = kitCells(tokens2.kit, mood, animate && blink, tokens2.color("background"));
16673
+ const keyedRows = rows.map((cells) => ({
16674
+ cells: cells.map((cell, colIndex) => ({
16675
+ ...cell,
16676
+ key: `${cell.top}-${cell.bottom}-${colIndex}`
16677
+ })),
16678
+ key: cells.map((cell) => `${cell.top}/${cell.bottom}`).join("|")
16679
+ }));
16680
+ const badgeText = isSpinner ? spinnerFrames[frame] ?? "" : badge;
16681
+ return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", children: keyedRows.map((row, rowIndex) => /* @__PURE__ */ jsxs(Box2, { children: [
16682
+ row.cells.map((cell) => /* @__PURE__ */ jsx3(Text2, { color: cell.top, backgroundColor: cell.bottom, children: "\u2580" }, cell.key)),
16683
+ rowIndex === 0 && badgeText !== void 0 && badgeText.length > 0 ? /* @__PURE__ */ jsxs(Text2, { color: tokens2.color("primaryStrong"), children: [
16684
+ " ",
16685
+ badgeText
16686
+ ] }) : null
16687
+ ] }, row.key)) });
16688
+ }
16689
+
16690
+ // src/app/tui/design/components/Pill.tsx
16691
+ import { Text as Text3 } from "ink";
16692
+ import { jsxs as jsxs2 } from "react/jsx-runtime";
16693
+
16694
+ // src/app/tui/design/components/ProgressBar.tsx
16695
+ import { Box as Box3, Text as Text4 } from "ink";
16696
+ import { jsxs as jsxs3 } from "react/jsx-runtime";
16697
+
16698
+ // src/app/tui/design/components/PromptInput.tsx
16699
+ import { Box as Box4, Text as Text5, useInput } from "ink";
16700
+ import { useState as useState3 } from "react";
16701
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
16702
+ function PromptInput({ placeholder, onSubmit, isActive = true }) {
16703
+ const tokens2 = useTokens();
16704
+ const [value, setValue] = useState3("");
16705
+ useInput(
16706
+ (input, key) => {
16707
+ if (key.return) {
16708
+ onSubmit?.(value);
16709
+ setValue("");
16710
+ } else if (key.backspace || key.delete) {
16711
+ setValue((current) => current.slice(0, -1));
16712
+ } else if (input.length > 0 && !key.ctrl && !key.meta) {
16713
+ setValue((current) => current + input);
16714
+ }
16715
+ },
16716
+ { isActive }
16717
+ );
16718
+ const showPlaceholder = value.length === 0 && placeholder !== void 0;
16719
+ return /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
16720
+ /* @__PURE__ */ jsx4(Text5, { color: tokens2.color("primary"), children: tokens2.glyphs.prompt }),
16721
+ /* @__PURE__ */ jsx4(Text5, { color: showPlaceholder ? tokens2.color("textDim") : tokens2.color("text"), children: showPlaceholder ? placeholder : value })
16060
16722
  ] });
16061
16723
  }
16062
16724
 
16063
- // src/infra/logging/json_technical_logger.ts
16725
+ // src/app/tui/design/components/primitives.tsx
16726
+ import { Text as Text6 } from "ink";
16727
+ import { jsx as jsx5 } from "react/jsx-runtime";
16728
+
16729
+ // src/app/tui/design/components/SelectionList.tsx
16730
+ import { Box as Box5, Text as Text7, useInput as useInput2 } from "ink";
16731
+ import { useState as useState4 } from "react";
16732
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
16733
+ function SelectionList({ items, onSelect, isActive = true }) {
16734
+ const tokens2 = useTokens();
16735
+ const [index, setIndex] = useState4(0);
16736
+ useInput2(
16737
+ (_input, key) => {
16738
+ if (items.length === 0) {
16739
+ return;
16740
+ }
16741
+ if (key.upArrow) {
16742
+ setIndex((current) => (current - 1 + items.length) % items.length);
16743
+ } else if (key.downArrow) {
16744
+ setIndex((current) => (current + 1) % items.length);
16745
+ } else if (key.return) {
16746
+ onSelect?.(items[index]?.value ?? "");
16747
+ }
16748
+ },
16749
+ { isActive }
16750
+ );
16751
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: items.map((item, itemIndex) => {
16752
+ const selected = itemIndex === index;
16753
+ return /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
16754
+ /* @__PURE__ */ jsx6(Text7, { color: tokens2.color("primary"), children: selected ? tokens2.glyphs.prompt : " " }),
16755
+ /* @__PURE__ */ jsx6(Text7, { color: selected ? tokens2.color("text") : tokens2.color("textMuted"), children: item.label }),
16756
+ item.hint !== void 0 ? /* @__PURE__ */ jsx6(Text7, { color: tokens2.statusColor("ok"), children: item.hint }) : null
16757
+ ] }, item.value);
16758
+ }) });
16759
+ }
16760
+
16761
+ // src/app/tui/design/components/SpeechBubble.tsx
16762
+ import { Box as Box6, Text as Text8 } from "ink";
16763
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
16764
+ function SpeechBubble({
16765
+ text: text2,
16766
+ mood = "thinking",
16767
+ label,
16768
+ animate = true
16769
+ }) {
16770
+ const tokens2 = useTokens();
16771
+ return /* @__PURE__ */ jsxs6(Box6, { gap: 1, children: [
16772
+ /* @__PURE__ */ jsx7(Kit, { mood, animate }),
16773
+ /* @__PURE__ */ jsxs6(
16774
+ Box6,
16775
+ {
16776
+ flexDirection: "column",
16777
+ borderStyle: "round",
16778
+ borderColor: tokens2.color("border"),
16779
+ paddingX: 1,
16780
+ children: [
16781
+ label !== void 0 ? /* @__PURE__ */ jsx7(Text8, { color: tokens2.color("textDim"), children: label }) : null,
16782
+ /* @__PURE__ */ jsx7(Text8, { color: tokens2.color("text"), children: text2 })
16783
+ ]
16784
+ }
16785
+ )
16786
+ ] });
16787
+ }
16788
+
16789
+ // src/app/tui/design/components/StatCard.tsx
16790
+ import { Box as Box7, Text as Text9 } from "ink";
16791
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
16792
+
16793
+ // src/app/tui/design/components/StepList.tsx
16794
+ import { Box as Box8, Text as Text10 } from "ink";
16795
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
16796
+
16797
+ // src/app/tui/design/components/Table.tsx
16798
+ import { Box as Box9, Text as Text11 } from "ink";
16799
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
16800
+
16801
+ // src/app/tui/design/layouts/Panel.tsx
16802
+ import { Box as Box10, Text as Text12 } from "ink";
16803
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
16804
+
16805
+ // src/app/tui/design/layouts/TerminalChrome.tsx
16806
+ import { Box as Box11, Text as Text13 } from "ink";
16807
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
16808
+
16809
+ // src/app/tui/tokens.ts
16810
+ import { existsSync as existsSync9 } from "fs";
16064
16811
  import { homedir as homedir26 } from "os";
16812
+ import { dirname as dirname24, resolve as resolve10 } from "path";
16813
+ import { fileURLToPath as fileURLToPath19 } from "url";
16814
+
16815
+ // src/infra/assets/design_catalog.ts
16816
+ import { existsSync as existsSync8 } from "fs";
16817
+ import { dirname as dirname23, resolve as resolve9 } from "path";
16818
+ import { fileURLToPath as fileURLToPath18 } from "url";
16819
+
16820
+ // src/infra/bases/design.ts
16821
+ import { z as z42 } from "zod";
16822
+ var DesignSemanticsSchema = z42.object({
16823
+ schema: z42.literal("agent-devkit.design-semantics/v1"),
16824
+ status: z42.object({
16825
+ ok: z42.string().min(1),
16826
+ attention: z42.string().min(1),
16827
+ blocked: z42.string().min(1),
16828
+ "needs-setup": z42.string().min(1),
16829
+ pending: z42.string().min(1)
16830
+ }),
16831
+ risk: z42.object({
16832
+ destructive: z42.string().min(1),
16833
+ "external-write": z42.string().min(1),
16834
+ "read-only": z42.string().min(1),
16835
+ "writes-global-state": z42.string().min(1),
16836
+ "writes-project-state": z42.string().min(1)
16837
+ }),
16838
+ glyphs: z42.object({
16839
+ prompt: z42.string().min(1),
16840
+ check: z42.string().min(1),
16841
+ bulletActive: z42.string().min(1),
16842
+ bulletIdle: z42.string().min(1),
16843
+ progressFull: z42.string().min(1),
16844
+ progressEmpty: z42.string().min(1)
16845
+ })
16846
+ });
16847
+ var KitCellOverrideSchema = z42.tuple([z42.number().int(), z42.number().int(), z42.string().min(1)]);
16848
+ var KitMoodSchema = z42.object({
16849
+ overrides: z42.array(KitCellOverrideSchema).default([]),
16850
+ body: z42.string().optional(),
16851
+ dark: z42.string().optional(),
16852
+ badge: z42.string().optional()
16853
+ });
16854
+ var KitSpriteSchema = z42.object({
16855
+ schema: z42.literal("agent-devkit.kit/v1"),
16856
+ size: z42.object({
16857
+ rows: z42.number().int().positive(),
16858
+ cols: z42.number().int().positive()
16859
+ }),
16860
+ palette: z42.record(z42.string().min(1), z42.string().min(1)),
16861
+ base: z42.array(z42.string().min(1)).min(1),
16862
+ blink: KitMoodSchema,
16863
+ moods: z42.record(z42.string().min(1), KitMoodSchema)
16864
+ });
16865
+
16866
+ // src/infra/assets/design_catalog.ts
16867
+ function defaultAssetsRoot3() {
16868
+ const moduleDirectory13 = dirname23(fileURLToPath18(import.meta.url));
16869
+ const candidates = [
16870
+ resolve9(moduleDirectory13, "../../assets"),
16871
+ resolve9(moduleDirectory13, "../src/assets"),
16872
+ resolve9(process.cwd(), "src/assets")
16873
+ ];
16874
+ return candidates.find((candidate) => existsSync8(candidate)) ?? resolve9(process.cwd(), "src/assets");
16875
+ }
16876
+ var DesignCatalog = class {
16877
+ #loader;
16878
+ #semantics;
16879
+ #kit;
16880
+ constructor(options = {}) {
16881
+ this.#loader = options.loader ?? new AssetLoader({ rootDirectory: defaultAssetsRoot3() });
16882
+ }
16883
+ async semantics() {
16884
+ if (this.#semantics !== void 0) {
16885
+ return Result.ok(this.#semantics);
16886
+ }
16887
+ const payload = await this.#loader.loadJson("design", "semantics.json");
16888
+ if (payload.isErr()) {
16889
+ return Result.fail(payload.unwrapError());
16890
+ }
16891
+ const parsed = DesignSemanticsSchema.safeParse(payload.unwrap());
16892
+ if (!parsed.success) {
16893
+ return Result.fail(ErrorCodes.InvalidInput);
16894
+ }
16895
+ this.#semantics = parsed.data;
16896
+ return Result.ok(this.#semantics);
16897
+ }
16898
+ async kit() {
16899
+ if (this.#kit !== void 0) {
16900
+ return Result.ok(this.#kit);
16901
+ }
16902
+ const payload = await this.#loader.loadJson("design", "kit.json");
16903
+ if (payload.isErr()) {
16904
+ return Result.fail(payload.unwrapError());
16905
+ }
16906
+ const parsed = KitSpriteSchema.safeParse(payload.unwrap());
16907
+ if (!parsed.success) {
16908
+ return Result.fail(ErrorCodes.InvalidInput);
16909
+ }
16910
+ this.#kit = parsed.data;
16911
+ return Result.ok(this.#kit);
16912
+ }
16913
+ };
16914
+
16915
+ // src/app/tui/tokens.ts
16916
+ function assetsRoot() {
16917
+ const moduleDirectory13 = dirname24(fileURLToPath19(import.meta.url));
16918
+ const candidates = [
16919
+ resolve10(moduleDirectory13, "../../assets"),
16920
+ resolve10(moduleDirectory13, "../src/assets"),
16921
+ resolve10(process.cwd(), "src/assets")
16922
+ ];
16923
+ return candidates.find((candidate) => existsSync9(candidate)) ?? resolve10(process.cwd(), "src/assets");
16924
+ }
16925
+ async function activeThemeId() {
16926
+ const bindings = createUserModuleBindings({ homeDirectory: homedir26() });
16927
+ if (bindings.isErr()) {
16928
+ return "default-purple";
16929
+ }
16930
+ const preferences = await bindings.unwrap().capabilities.preferences.execute({ action: "view" });
16931
+ if (preferences.isErr()) {
16932
+ return "default-purple";
16933
+ }
16934
+ const payload = preferences.unwrap();
16935
+ return "preferences" in payload ? payload.preferences.theme : "default-purple";
16936
+ }
16937
+ async function loadTuiTokens() {
16938
+ const loader = new AssetLoader({ rootDirectory: assetsRoot() });
16939
+ const catalog = new DesignCatalog({ loader });
16940
+ const themeId = await activeThemeId();
16941
+ const themePayload = await loader.loadJson("themes", `${themeId}.json`);
16942
+ const fallbackPayload = themePayload.isErr() ? await loader.loadJson("themes", "default-purple.json") : themePayload;
16943
+ const theme = ThemeDefinitionSchema.safeParse(
16944
+ fallbackPayload.isOk() ? fallbackPayload.unwrap() : void 0
16945
+ );
16946
+ const semantics = await catalog.semantics();
16947
+ const kit = await catalog.kit();
16948
+ if (!theme.success || semantics.isErr() || kit.isErr()) {
16949
+ throw new Error("TUI design assets could not be loaded.");
16950
+ }
16951
+ return { kit: kit.unwrap(), semantics: semantics.unwrap(), theme: theme.data };
16952
+ }
16953
+
16954
+ // src/app/tui/App.tsx
16955
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
16956
+ var visibleMessages = 10;
16957
+ var happyMoodMs = 1500;
16958
+ var messageSequence = 0;
16959
+ function nextMessageId() {
16960
+ messageSequence += 1;
16961
+ return messageSequence;
16962
+ }
16963
+ function App({ currentVersion, initialPrompt, packageName, translator: translator2 }) {
16964
+ const [tokens2, setTokens] = useState5();
16965
+ const [bootError, setBootError] = useState5();
16966
+ const [messages, setMessages] = useState5([]);
16967
+ const [mood, setMood] = useState5("idle");
16968
+ const [busy, setBusy] = useState5(false);
16969
+ const [pendingApproval, setPendingApproval] = useState5();
16970
+ const [view, setView] = useState5("chat");
16971
+ const [sessionItems, setSessionItems] = useState5([]);
16972
+ const environmentRef = useRef2(void 0);
16973
+ const sessionIdRef = useRef2(void 0);
16974
+ const moodTimerRef = useRef2(void 0);
16975
+ const pushMessage = useCallback((role, text2) => {
16976
+ setMessages((current) => [...current, { id: nextMessageId(), role, text: text2 }]);
16977
+ }, []);
16978
+ const settleMood = useCallback((finalMood) => {
16979
+ setMood(finalMood);
16980
+ if (moodTimerRef.current !== void 0) {
16981
+ clearTimeout(moodTimerRef.current);
16982
+ }
16983
+ moodTimerRef.current = setTimeout(() => setMood("idle"), happyMoodMs);
16984
+ }, []);
16985
+ const runChat = useCallback(
16986
+ async (message) => {
16987
+ const environment = environmentRef.current;
16988
+ if (environment === void 0) {
16989
+ return;
16990
+ }
16991
+ setBusy(true);
16992
+ setMood("thinking");
16993
+ pushMessage("user", message);
16994
+ const result = await environment.agent.run({
16995
+ interface: "tui",
16996
+ message,
16997
+ mode: "chat",
16998
+ sessionId: sessionIdRef.current
16999
+ });
17000
+ if (result.isErr()) {
17001
+ pushMessage("info", translator2.t("tui.error", { error: result.unwrapError() }));
17002
+ settleMood("concerned");
17003
+ setBusy(false);
17004
+ return;
17005
+ }
17006
+ const payload = result.unwrap();
17007
+ if (payload.conversation !== void 0) {
17008
+ sessionIdRef.current = payload.conversation.sessionId;
17009
+ await environment.saveActiveSessionId(payload.conversation.sessionId);
17010
+ }
17011
+ pushMessage("agent", payload.reply);
17012
+ settleMood("happy");
17013
+ setBusy(false);
17014
+ },
17015
+ [pushMessage, settleMood, translator2.t]
17016
+ );
17017
+ const runTask = useCallback(
17018
+ async (task, approvedTools) => {
17019
+ const environment = environmentRef.current;
17020
+ if (environment === void 0) {
17021
+ return;
17022
+ }
17023
+ setBusy(true);
17024
+ setMood("thinking");
17025
+ if (approvedTools === void 0) {
17026
+ pushMessage("user", `/task ${task}`);
17027
+ }
17028
+ const onEvent = (event) => {
17029
+ setMood(moodForEvent(event));
17030
+ if (event.type === "tool") {
17031
+ pushMessage("info", `\u2192 ${event.tool}`);
17032
+ }
17033
+ if (event.type === "observation") {
17034
+ pushMessage("info", `${event.ok ? "\u2713" : "\u2717"} ${event.tool}: ${event.summary}`);
17035
+ }
17036
+ };
17037
+ const result = await environment.agent.run({
17038
+ approvedTools,
17039
+ interface: "tui",
17040
+ mode: "task",
17041
+ onEvent,
17042
+ sessionId: sessionIdRef.current,
17043
+ task
17044
+ });
17045
+ if (result.isErr()) {
17046
+ pushMessage("info", translator2.t("tui.error", { error: result.unwrapError() }));
17047
+ settleMood("concerned");
17048
+ setBusy(false);
17049
+ return;
17050
+ }
17051
+ const payload = result.unwrap();
17052
+ const waitingTool = approvalRequiredTool(payload.steps);
17053
+ pushMessage("agent", payload.reply);
17054
+ if (waitingTool !== void 0) {
17055
+ setPendingApproval({ task, tool: waitingTool });
17056
+ pushMessage("info", translator2.t("tui.approvalRequired", { tool: waitingTool }));
17057
+ setMood("concerned");
17058
+ setBusy(false);
17059
+ return;
17060
+ }
17061
+ settleMood("happy");
17062
+ setBusy(false);
17063
+ },
17064
+ [pushMessage, settleMood, translator2.t]
17065
+ );
17066
+ const openSessions = useCallback(async () => {
17067
+ const environment = environmentRef.current;
17068
+ if (environment === void 0) {
17069
+ return;
17070
+ }
17071
+ const listed = await environment.sessions.execute({
17072
+ action: "list",
17073
+ limit: 10,
17074
+ status: "active"
17075
+ });
17076
+ if (listed.isErr() || listed.unwrap().action !== "list") {
17077
+ pushMessage("info", translator2.t("tui.sessionsListFailed"));
17078
+ return;
17079
+ }
17080
+ const payload = listed.unwrap();
17081
+ const items = payload.action === "list" ? payload.sessions.map((session) => ({
17082
+ hint: session.sessionId,
17083
+ label: session.title,
17084
+ value: session.sessionId
17085
+ })) : [];
17086
+ if (items.length === 0) {
17087
+ pushMessage("info", translator2.t("tui.sessionsEmpty"));
17088
+ return;
17089
+ }
17090
+ setSessionItems(items);
17091
+ setView("sessions");
17092
+ }, [pushMessage, translator2.t]);
17093
+ const submit = useCallback(
17094
+ (value) => {
17095
+ if (busy) {
17096
+ return;
17097
+ }
17098
+ const command = parseTuiCommand(value, pendingApproval !== void 0);
17099
+ if (command.type === "empty") {
17100
+ return;
17101
+ }
17102
+ if (command.type === "approve-yes" && pendingApproval !== void 0) {
17103
+ const approval = pendingApproval;
17104
+ setPendingApproval(void 0);
17105
+ pushMessage("info", translator2.t("tui.approvalAccepted", { tool: approval.tool }));
17106
+ void runTask(approval.task, [approval.tool]);
17107
+ return;
17108
+ }
17109
+ if (command.type === "approve-no" && pendingApproval !== void 0) {
17110
+ setPendingApproval(void 0);
17111
+ pushMessage("info", translator2.t("tui.approvalDenied"));
17112
+ setMood("idle");
17113
+ return;
17114
+ }
17115
+ if (command.type === "sessions") {
17116
+ void openSessions();
17117
+ return;
17118
+ }
17119
+ if (command.type === "task") {
17120
+ void runTask(command.task);
17121
+ return;
17122
+ }
17123
+ if (command.type === "chat") {
17124
+ void runChat(command.message);
17125
+ }
17126
+ },
17127
+ [busy, openSessions, pendingApproval, pushMessage, runChat, runTask, translator2.t]
17128
+ );
17129
+ useEffect2(() => {
17130
+ let mounted = true;
17131
+ (async () => {
17132
+ try {
17133
+ const [loadedTokens, environment] = await Promise.all([
17134
+ loadTuiTokens(),
17135
+ Promise.resolve(
17136
+ createCliAgentEnvironment({ currentVersion, interface: "tui", packageName })
17137
+ )
17138
+ ]);
17139
+ const activeSessionId = await environment.loadActiveSessionId();
17140
+ if (!mounted) {
17141
+ return;
17142
+ }
17143
+ environmentRef.current = environment;
17144
+ sessionIdRef.current = activeSessionId;
17145
+ setTokens(loadedTokens);
17146
+ } catch (error) {
17147
+ if (mounted) {
17148
+ setBootError(error instanceof Error ? error.message : String(error));
17149
+ }
17150
+ }
17151
+ })();
17152
+ return () => {
17153
+ mounted = false;
17154
+ if (moodTimerRef.current !== void 0) {
17155
+ clearTimeout(moodTimerRef.current);
17156
+ }
17157
+ };
17158
+ }, [currentVersion, packageName]);
17159
+ useEffect2(() => {
17160
+ if (tokens2 !== void 0 && initialPrompt !== void 0 && initialPrompt.length > 0) {
17161
+ void runChat(initialPrompt);
17162
+ }
17163
+ }, [tokens2, initialPrompt, runChat]);
17164
+ if (bootError !== void 0) {
17165
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
17166
+ /* @__PURE__ */ jsx13(Text14, { bold: true, color: "red", children: translator2.t("tui.title") }),
17167
+ /* @__PURE__ */ jsx13(Text14, { children: bootError })
17168
+ ] });
17169
+ }
17170
+ if (tokens2 === void 0) {
17171
+ return /* @__PURE__ */ jsxs12(Text14, { children: [
17172
+ translator2.t("tui.title"),
17173
+ "..."
17174
+ ] });
17175
+ }
17176
+ const recent = messages.slice(-visibleMessages);
17177
+ const lastAgentMessage = [...messages].reverse().find((message) => message.role === "agent");
17178
+ return /* @__PURE__ */ jsx13(TokensProvider, { kit: tokens2.kit, semantics: tokens2.semantics, theme: tokens2.theme, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, gap: 1, children: [
17179
+ /* @__PURE__ */ jsxs12(Box12, { gap: 2, children: [
17180
+ /* @__PURE__ */ jsx13(Kit, { mood }),
17181
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", justifyContent: "center", children: [
17182
+ /* @__PURE__ */ jsxs12(Text14, { bold: true, children: [
17183
+ packageName,
17184
+ " v",
17185
+ currentVersion
17186
+ ] }),
17187
+ /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: sessionIdRef.current === void 0 ? translator2.t("tui.newSession") : translator2.t("tui.session", { sessionId: sessionIdRef.current }) })
17188
+ ] })
17189
+ ] }),
17190
+ /* @__PURE__ */ jsx13(Box12, { flexDirection: "column", children: recent.map(
17191
+ (message) => message.role === "agent" && message.id === lastAgentMessage?.id ? /* @__PURE__ */ jsx13(SpeechBubble, { mood, text: message.text }, message.id) : /* @__PURE__ */ jsxs12(
17192
+ Text14,
17193
+ {
17194
+ dimColor: message.role === "info",
17195
+ color: message.role === "user" ? "cyan" : void 0,
17196
+ children: [
17197
+ message.role === "user" ? "\u276F " : message.role === "info" ? "\xB7 " : "",
17198
+ message.text
17199
+ ]
17200
+ },
17201
+ message.id
17202
+ )
17203
+ ) }),
17204
+ view === "sessions" ? /* @__PURE__ */ jsx13(
17205
+ SelectionList,
17206
+ {
17207
+ items: sessionItems,
17208
+ onSelect: (value) => {
17209
+ sessionIdRef.current = value;
17210
+ void environmentRef.current?.saveActiveSessionId(value);
17211
+ setView("chat");
17212
+ pushMessage("info", translator2.t("tui.sessionResumed", { sessionId: value }));
17213
+ }
17214
+ }
17215
+ ) : /* @__PURE__ */ jsx13(
17216
+ PromptInput,
17217
+ {
17218
+ isActive: !busy,
17219
+ onSubmit: submit,
17220
+ placeholder: pendingApproval !== void 0 ? translator2.t("tui.approvalPlaceholder") : busy ? translator2.t("tui.thinking") : translator2.t("tui.helpHint")
17221
+ }
17222
+ ),
17223
+ /* @__PURE__ */ jsx13(
17224
+ KbdBar,
17225
+ {
17226
+ keys: [
17227
+ translator2.t("tui.kbd.send"),
17228
+ translator2.t("tui.kbd.task"),
17229
+ "/sessions",
17230
+ translator2.t("tui.kbd.exit")
17231
+ ]
17232
+ }
17233
+ )
17234
+ ] }) });
17235
+ }
17236
+
17237
+ // src/infra/logging/json_technical_logger.ts
17238
+ import { homedir as homedir27 } from "os";
16065
17239
  import { join as join18 } from "path";
16066
17240
  function defaultStateDirectory4() {
16067
- return join18(homedir26(), ".agent-devkit");
17241
+ return join18(homedir27(), ".agent-devkit");
16068
17242
  }
16069
17243
  function logFileName(timestamp) {
16070
17244
  return `technical-${timestamp.toISOString().slice(0, 10)}.jsonl`;
@@ -16153,10 +17327,10 @@ var JsonTechnicalLogger = class {
16153
17327
  };
16154
17328
 
16155
17329
  // src/infra/logging/json_usage_logger.ts
16156
- import { homedir as homedir27 } from "os";
17330
+ import { homedir as homedir28 } from "os";
16157
17331
  import { join as join19 } from "path";
16158
17332
  function defaultStateDirectory5() {
16159
- return join19(homedir27(), ".agent-devkit");
17333
+ return join19(homedir28(), ".agent-devkit");
16160
17334
  }
16161
17335
  function logFileName2(timestamp) {
16162
17336
  return `usage-${timestamp.toISOString().slice(0, 10)}.jsonl`;
@@ -16266,7 +17440,13 @@ program.name("agent").description(translator.t("cli.root.description")).version(
16266
17440
  return;
16267
17441
  }
16268
17442
  await ensureFirstRunModel(translator);
16269
- render(React.createElement(App, { translator }));
17443
+ render(
17444
+ React.createElement(App, {
17445
+ currentVersion: package_default.version,
17446
+ packageName: package_default.name,
17447
+ translator
17448
+ })
17449
+ );
16270
17450
  })
16271
17451
  );
16272
17452
  registerDoctorCommand(program, { appVersion: package_default.version, translator, usageLogging });