@falkenslab/agent-kit 0.17.0 → 0.19.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.
Files changed (111) hide show
  1. package/assets/extension-launcher.mjs +24 -0
  2. package/dist/chat/chatController.d.ts +264 -0
  3. package/dist/chat/chatController.js +510 -0
  4. package/dist/chat/extensions.d.ts +14 -0
  5. package/dist/chat/extensions.js +41 -0
  6. package/dist/chat/history.d.ts +17 -0
  7. package/dist/chat/history.js +39 -0
  8. package/dist/{tui → chat}/runs.d.ts +8 -1
  9. package/dist/{tui → chat}/runs.js +1 -1
  10. package/dist/core/agentSpec.d.ts +41 -27
  11. package/dist/core/extensions.d.ts +119 -0
  12. package/dist/core/extensions.js +97 -0
  13. package/dist/core/externalExtensions.d.ts +131 -0
  14. package/dist/core/externalExtensions.js +340 -0
  15. package/dist/core/hooks/fileScopeGate.d.ts +17 -2
  16. package/dist/core/hooks/fileScopeGate.js +45 -10
  17. package/dist/core/hooks/planGate.d.ts +2 -0
  18. package/dist/core/hooks/planGate.js +1 -10
  19. package/dist/core/hooks/stepGate.d.ts +1 -1
  20. package/dist/core/hooks/stepGate.js +3 -3
  21. package/dist/core/language.js +1 -1
  22. package/dist/core/messages/de.js +12 -33
  23. package/dist/core/messages/en.d.ts +13 -16
  24. package/dist/core/messages/en.js +12 -33
  25. package/dist/core/messages/es.js +12 -33
  26. package/dist/core/messages/fr.js +12 -33
  27. package/dist/core/messages/index.d.ts +6 -0
  28. package/dist/core/messages/index.js +12 -1
  29. package/dist/core/packaged.d.ts +10 -0
  30. package/dist/core/packaged.js +38 -0
  31. package/dist/core/pluginAgents.d.ts +20 -0
  32. package/dist/core/pluginAgents.js +76 -0
  33. package/dist/core/runner.js +16 -9
  34. package/dist/core/session.d.ts +42 -5
  35. package/dist/core/session.js +203 -99
  36. package/dist/core/sessionFacts.d.ts +80 -0
  37. package/dist/core/sessionFacts.js +48 -0
  38. package/dist/core/toolLabels.d.ts +24 -6
  39. package/dist/core/toolLabels.js +24 -39
  40. package/dist/core/tools/humanApproval.js +3 -3
  41. package/dist/extensions/awareness/index.d.ts +13 -0
  42. package/dist/extensions/awareness/index.js +39 -0
  43. package/dist/extensions/awareness/labels.d.ts +3 -0
  44. package/dist/extensions/awareness/labels.js +12 -0
  45. package/dist/extensions/awareness/tools.d.ts +5 -0
  46. package/dist/extensions/awareness/tools.js +54 -0
  47. package/dist/{core → extensions/knowledge}/fileKnowledgeStore.d.ts +1 -3
  48. package/dist/{core → extensions/knowledge}/fileKnowledgeStore.js +23 -29
  49. package/dist/extensions/knowledge/index.d.ts +8 -0
  50. package/dist/extensions/knowledge/index.js +35 -0
  51. package/dist/{core → extensions/knowledge}/knowledgeStore.d.ts +5 -9
  52. package/dist/{core → extensions/knowledge}/knowledgeStore.js +16 -2
  53. package/dist/extensions/knowledge/labels.d.ts +3 -0
  54. package/dist/extensions/knowledge/labels.js +119 -0
  55. package/dist/extensions/knowledge/prompt.d.ts +28 -0
  56. package/dist/extensions/knowledge/prompt.js +59 -0
  57. package/dist/{core/tools/knowledgeTools.d.ts → extensions/knowledge/tools.d.ts} +7 -7
  58. package/dist/{core/tools/knowledgeTools.js → extensions/knowledge/tools.js} +20 -55
  59. package/dist/extensions/memory/index.d.ts +12 -0
  60. package/dist/extensions/memory/index.js +56 -0
  61. package/dist/extensions/memory/labels.d.ts +3 -0
  62. package/dist/extensions/memory/labels.js +58 -0
  63. package/dist/extensions/memory/memoryStore.d.ts +53 -0
  64. package/dist/extensions/memory/memoryStore.js +88 -0
  65. package/dist/extensions/memory/tools.d.ts +9 -0
  66. package/dist/extensions/memory/tools.js +82 -0
  67. package/dist/extensions/sources/index.d.ts +9 -0
  68. package/dist/extensions/sources/index.js +40 -0
  69. package/dist/extensions/sources/labels.d.ts +3 -0
  70. package/dist/extensions/sources/labels.js +82 -0
  71. package/dist/{core → extensions/sources}/sources.d.ts +24 -31
  72. package/dist/{core → extensions/sources}/sources.js +45 -108
  73. package/dist/{core/tools/saveToSources.d.ts → extensions/sources/tools.d.ts} +7 -3
  74. package/dist/{core/tools/saveToSources.js → extensions/sources/tools.js} +22 -17
  75. package/dist/index.d.ts +14 -9
  76. package/dist/index.js +11 -7
  77. package/dist/tui/chatTui.d.ts +11 -20
  78. package/dist/tui/chatTui.js +75 -230
  79. package/dist/tui/extensionCommand.d.ts +21 -0
  80. package/dist/tui/extensionCommand.js +133 -0
  81. package/dist/tui/ink/runChatInk.d.ts +4 -3
  82. package/dist/tui/ink/runChatInk.js +101 -217
  83. package/extensions/awareness/.claude-plugin/plugin.json +10 -0
  84. package/{assets/agent-help → extensions/awareness/skills/help}/SKILL.md +4 -3
  85. package/{assets/knowledge-plugin → extensions/knowledge}/.claude-plugin/plugin.json +7 -1
  86. package/extensions/knowledge/commands/ingest.md +7 -0
  87. package/{assets/knowledge-plugin → extensions/knowledge}/skills/knowledge-ingest/SKILL.md +8 -3
  88. package/{assets/knowledge-plugin → extensions/knowledge}/skills/knowledge-lint/SKILL.md +12 -5
  89. package/extensions/memory/.claude-plugin/plugin.json +10 -0
  90. package/extensions/memory/commands/forget.md +8 -0
  91. package/extensions/memory/commands/list.md +5 -0
  92. package/extensions/sources/.claude-plugin/plugin.json +10 -0
  93. package/package.json +3 -2
  94. package/assets/knowledge-plugin/commands/ingest.md +0 -7
  95. package/assets/knowledge-plugin/commands/query.md +0 -5
  96. package/assets/knowledge-plugin-files/.claude-plugin/plugin.json +0 -4
  97. package/assets/knowledge-plugin-files/commands/ingest.md +0 -7
  98. package/assets/knowledge-plugin-files/commands/lint.md +0 -5
  99. package/assets/knowledge-plugin-files/skills/knowledge-ingest/SKILL.md +0 -46
  100. package/assets/knowledge-plugin-files/skills/knowledge-lint/SKILL.md +0 -26
  101. package/assets/knowledge-plugin-files/skills/knowledge-pages/SKILL.md +0 -137
  102. package/assets/knowledge-plugin-files/skills/knowledge-query/SKILL.md +0 -14
  103. package/dist/core/agentHelp.d.ts +0 -30
  104. package/dist/core/agentHelp.js +0 -55
  105. package/dist/core/knowledge.d.ts +0 -25
  106. package/dist/core/knowledge.js +0 -84
  107. /package/dist/{core → extensions/sources}/extractText.d.ts +0 -0
  108. /package/dist/{core → extensions/sources}/extractText.js +0 -0
  109. /package/{assets/knowledge-plugin → extensions/knowledge}/commands/lint.md +0 -0
  110. /package/{assets/knowledge-plugin-files → extensions/knowledge}/commands/query.md +0 -0
  111. /package/{assets/knowledge-plugin → extensions/knowledge}/skills/knowledge-query/SKILL.md +0 -0
@@ -29,6 +29,19 @@ export interface Messages {
29
29
  resumeHint: string;
30
30
  resumeQuestion: string;
31
31
  noEarlierRuns: string;
32
+ /** What the chat's own commands do, for a view that lists them. */
33
+ commandResume: string;
34
+ commandPlan: string;
35
+ commandExtensions: string;
36
+ /** /extensions (#37): what the session runs with, what's off and why, and enabling or disabling one. */
37
+ extensionsRunning(names: string): string;
38
+ extensionsNone: string;
39
+ extensionOff(name: string, reason: string): string;
40
+ extensionsInstalled: string;
41
+ extensionToggled(name: string, enabled: boolean): string;
42
+ extensionNotInstalled(name: string): string;
43
+ extensionsUsage: string;
44
+ extensionsCantReopen: string;
32
45
  currentRun: string;
33
46
  resumed(date: string): string;
34
47
  suggestionKey: string;
@@ -82,7 +95,6 @@ export interface Messages {
82
95
  labels: {
83
96
  askingApproval(summary: string): string;
84
97
  waitingManual: string;
85
- savingToSources(destination: string): string;
86
98
  checkingTime: string;
87
99
  calculatingDates: string;
88
100
  reading(file: string): string;
@@ -101,21 +113,6 @@ export interface Messages {
101
113
  applyingSkill(skill: string): string;
102
114
  aSkill: string;
103
115
  updatingTasks: string;
104
- listingSources: string;
105
- extractingText(source: string): string;
106
- downloading(url: string): string;
107
- requestingFile(description: string): string;
108
- retiringSource(source: string): string;
109
- knowledgeIndex: string;
110
- knowledgeSearch(query: string): string;
111
- knowledgeRead(page: string): string;
112
- knowledgeCreate(page: string): string;
113
- knowledgeEdit(page: string): string;
114
- knowledgeRewrite(page: string): string;
115
- knowledgeSupersede(page: string): string;
116
- knowledgeRetire(page: string): string;
117
- knowledgeLog: string;
118
- knowledgeCheck: string;
119
116
  askingHuman(question: string): string;
120
117
  presentingPlan: string;
121
118
  };
@@ -21,6 +21,17 @@ export const en = {
21
21
  resumeHint: "↑/↓ choose · Enter resume · Esc cancel",
22
22
  resumeQuestion: "Number of the conversation to resume (Enter to cancel): ",
23
23
  noEarlierRuns: "(no earlier conversations to resume)",
24
+ commandResume: "Pick an earlier conversation to go on with",
25
+ commandPlan: "Into plan mode, or back",
26
+ commandExtensions: "What runs, what's off and why; turn one on or off",
27
+ extensionsRunning: (names) => `Running with: ${names}`,
28
+ extensionsNone: "(no extensions)",
29
+ extensionOff: (name, reason) => `${name} is off: it ${reason}`,
30
+ extensionsInstalled: "Installed:",
31
+ extensionToggled: (name, enabled) => `(${name} ${enabled ? "enabled" : "disabled"}: the session reopens, with the same conversation)`,
32
+ extensionNotInstalled: (name) => `(${name} isn't installed: /extensions lists them)`,
33
+ extensionsUsage: "(usage: /extensions, /extensions enable <name>, /extensions disable <name>)",
34
+ extensionsCantReopen: "(this chat can't reopen its session: enable or disable it from the terminal, and start again)",
24
35
  currentRun: "(this one)",
25
36
  resumed: (date) => `(resumed the conversation of ${date})`,
26
37
  suggestionKey: "tab",
@@ -71,7 +82,7 @@ export const en = {
71
82
  planCommentQuestion: "What should change? (Enter to skip): ",
72
83
  retireLines: (source, why, reason, replacedBy, folder) => [
73
84
  `Source: ${source}`,
74
- why === "wrong" ? "Why: it's wrong; its summary will be retired" : "Why: it's replaced; its summary will be marked superseded",
85
+ why === "wrong" ? "Why: it's wrong" : "Why: it's replaced by a better one",
75
86
  `Reason: ${reason}`,
76
87
  ...(replacedBy ? [`Replaced by: ${replacedBy}`] : []),
77
88
  `It's moved to ${folder}.agent-kit/retired/, not deleted.`,
@@ -90,22 +101,6 @@ export const en = {
90
101
  Task: ["ran {n} subagent", "ran {n} subagents"],
91
102
  mcp__time__current_time: ["checked the time", "checked the time {n} times"],
92
103
  mcp__time__date_math: ["calculated dates", "calculated dates {n} times"],
93
- mcp__sourceFiles__list_sources: ["listed the sources", "listed the sources {n} times"],
94
- mcp__sourceFiles__extract_text: ["read {n} document", "read {n} documents"],
95
- mcp__sourceFiles__save_to_sources: ["saved {n} source", "saved {n} sources"],
96
- mcp__sourceFiles__download_to_sources: ["downloaded {n} source", "downloaded {n} sources"],
97
- mcp__sourceFiles__request_file: ["asked for {n} file", "asked for {n} files"],
98
- mcp__sourceFiles__retire_source: ["retired {n} source", "retired {n} sources"],
99
- mcp__knowledge__knowledge_index: ["read the index", "read the index {n} times"],
100
- mcp__knowledge__knowledge_search: ["searched the knowledge base", "searched the knowledge base {n} times"],
101
- mcp__knowledge__knowledge_read: ["read {n} page", "read {n} pages"],
102
- mcp__knowledge__knowledge_create: ["created {n} page", "created {n} pages"],
103
- mcp__knowledge__knowledge_edit: ["edited {n} page", "edited {n} pages"],
104
- mcp__knowledge__knowledge_rewrite: ["rewrote {n} page", "rewrote {n} pages"],
105
- mcp__knowledge__knowledge_supersede: ["superseded {n} page", "superseded {n} pages"],
106
- mcp__knowledge__knowledge_retire: ["retired {n} page", "retired {n} pages"],
107
- mcp__knowledge__knowledge_log: ["updated the log", "updated the log {n} times"],
108
- mcp__knowledge__knowledge_check: ["checked the knowledge base", "checked the knowledge base {n} times"],
109
104
  mcp__approvals__ask_human: ["asked {n} question", "asked {n} questions"],
110
105
  mcp__approvals__present_plan: ["presented the plan", "presented the plan {n} times"],
111
106
  },
@@ -119,7 +114,6 @@ export const en = {
119
114
  labels: {
120
115
  askingApproval: (summary) => `Asking for human approval: ${summary}`,
121
116
  waitingManual: "Waiting for a human to intervene manually",
122
- savingToSources: (destination) => `Saving ${destination} to the sources`,
123
117
  checkingTime: "Checking the date and time",
124
118
  calculatingDates: "Calculating dates",
125
119
  reading: (file) => `Reading ${file}`,
@@ -138,21 +132,6 @@ export const en = {
138
132
  applyingSkill: (skill) => `Applying the "${skill}" skill`,
139
133
  aSkill: "a skill",
140
134
  updatingTasks: "Updating the task list",
141
- listingSources: "Listing the sources",
142
- extractingText: (source) => `Reading ${source}`,
143
- downloading: (url) => `Downloading ${url} to the sources`,
144
- requestingFile: (description) => `Asking for a file: ${description}`,
145
- retiringSource: (source) => `Retiring the source ${source}`,
146
- knowledgeIndex: "Reading the knowledge base's index",
147
- knowledgeSearch: (query) => `Searching the knowledge base for "${query}"`,
148
- knowledgeRead: (page) => `Reading ${page}`,
149
- knowledgeCreate: (page) => `Creating ${page}`,
150
- knowledgeEdit: (page) => `Editing ${page}`,
151
- knowledgeRewrite: (page) => `Rewriting ${page}`,
152
- knowledgeSupersede: (page) => `Marking ${page} superseded`,
153
- knowledgeRetire: (page) => `Retiring ${page}`,
154
- knowledgeLog: "Updating the knowledge base's log",
155
- knowledgeCheck: "Checking the knowledge base",
156
135
  askingHuman: (question) => `Asking: ${question}`,
157
136
  presentingPlan: "Presenting the plan",
158
137
  },
@@ -22,6 +22,17 @@ export const es = {
22
22
  resumeHint: "↑/↓ elegir · Intro retomar · Esc cancelar",
23
23
  resumeQuestion: "Número de la conversación que retomar (Intro para cancelar): ",
24
24
  noEarlierRuns: "(no hay conversaciones anteriores que retomar)",
25
+ commandResume: "Elegir una conversación anterior para seguir con ella",
26
+ commandPlan: "Entrar en el modo plan, o volver",
27
+ commandExtensions: "Qué funciona, qué no y por qué; activar o desactivar una",
28
+ extensionsRunning: (names) => `Funcionando con: ${names}`,
29
+ extensionsNone: "(ninguna extensión)",
30
+ extensionOff: (name, reason) => `${name} está desactivada: ${reason}`,
31
+ extensionsInstalled: "Instaladas:",
32
+ extensionToggled: (name, enabled) => `(${name} ${enabled ? "activada" : "desactivada"}: la sesión se reabre, con la misma conversación)`,
33
+ extensionNotInstalled: (name) => `(${name} no está instalada: /extensions las lista)`,
34
+ extensionsUsage: "(uso: /extensions, /extensions enable <nombre>, /extensions disable <nombre>)",
35
+ extensionsCantReopen: "(este chat no puede reabrir su sesión: actívala o desactívala desde la terminal y vuelve a empezar)",
25
36
  currentRun: "(esta)",
26
37
  resumed: (date) => `(retomada la conversación del ${date})`,
27
38
  suggestionKey: "tab",
@@ -72,7 +83,7 @@ export const es = {
72
83
  planCommentQuestion: "¿Qué debería cambiar? (Enter para omitir): ",
73
84
  retireLines: (source, why, reason, replacedBy, folder) => [
74
85
  `Fuente: ${source}`,
75
- why === "wrong" ? "Motivo: es errónea; su resumen se retirará" : "Motivo: se sustituye; su resumen se marcará como sustituido",
86
+ why === "wrong" ? "Motivo: es errónea" : "Motivo: la sustituye una mejor",
76
87
  `Razón: ${reason}`,
77
88
  ...(replacedBy ? [`Sustituida por: ${replacedBy}`] : []),
78
89
  `Se mueve a ${folder}.agent-kit/retired/, no se borra.`,
@@ -91,22 +102,6 @@ export const es = {
91
102
  Task: ["lanzó {n} subagente", "lanzó {n} subagentes"],
92
103
  mcp__time__current_time: ["consultó la hora", "consultó la hora {n} veces"],
93
104
  mcp__time__date_math: ["calculó fechas", "calculó fechas {n} veces"],
94
- mcp__sourceFiles__list_sources: ["revisó las fuentes", "revisó las fuentes {n} veces"],
95
- mcp__sourceFiles__extract_text: ["leyó {n} documento", "leyó {n} documentos"],
96
- mcp__sourceFiles__save_to_sources: ["guardó {n} fuente", "guardó {n} fuentes"],
97
- mcp__sourceFiles__download_to_sources: ["descargó {n} fuente", "descargó {n} fuentes"],
98
- mcp__sourceFiles__request_file: ["pidió {n} fichero", "pidió {n} ficheros"],
99
- mcp__sourceFiles__retire_source: ["retiró {n} fuente", "retiró {n} fuentes"],
100
- mcp__knowledge__knowledge_index: ["leyó el índice", "leyó el índice {n} veces"],
101
- mcp__knowledge__knowledge_search: ["buscó en la base de conocimiento", "buscó en la base de conocimiento {n} veces"],
102
- mcp__knowledge__knowledge_read: ["leyó {n} página", "leyó {n} páginas"],
103
- mcp__knowledge__knowledge_create: ["creó {n} página", "creó {n} páginas"],
104
- mcp__knowledge__knowledge_edit: ["editó {n} página", "editó {n} páginas"],
105
- mcp__knowledge__knowledge_rewrite: ["reescribió {n} página", "reescribió {n} páginas"],
106
- mcp__knowledge__knowledge_supersede: ["sustituyó {n} página", "sustituyó {n} páginas"],
107
- mcp__knowledge__knowledge_retire: ["retiró {n} página", "retiró {n} páginas"],
108
- mcp__knowledge__knowledge_log: ["actualizó el registro", "actualizó el registro {n} veces"],
109
- mcp__knowledge__knowledge_check: ["revisó la base de conocimiento", "revisó la base de conocimiento {n} veces"],
110
105
  mcp__approvals__ask_human: ["hizo {n} pregunta", "hizo {n} preguntas"],
111
106
  mcp__approvals__present_plan: ["presentó el plan", "presentó el plan {n} veces"],
112
107
  },
@@ -120,7 +115,6 @@ export const es = {
120
115
  labels: {
121
116
  askingApproval: (summary) => `Pidiendo aprobación humana: ${summary}`,
122
117
  waitingManual: "Esperando a que una persona intervenga a mano",
123
- savingToSources: (destination) => `Guardando ${destination} en las fuentes`,
124
118
  checkingTime: "Consultando la fecha y la hora",
125
119
  calculatingDates: "Calculando fechas",
126
120
  reading: (file) => `Leyendo ${file}`,
@@ -139,21 +133,6 @@ export const es = {
139
133
  applyingSkill: (skill) => `Aplicando la skill "${skill}"`,
140
134
  aSkill: "una skill",
141
135
  updatingTasks: "Actualizando la lista de tareas",
142
- listingSources: "Revisando las fuentes",
143
- extractingText: (source) => `Leyendo ${source}`,
144
- downloading: (url) => `Descargando ${url} a las fuentes`,
145
- requestingFile: (description) => `Pidiendo un fichero: ${description}`,
146
- retiringSource: (source) => `Retirando la fuente ${source}`,
147
- knowledgeIndex: "Leyendo el índice de la base de conocimiento",
148
- knowledgeSearch: (query) => `Buscando "${query}" en la base de conocimiento`,
149
- knowledgeRead: (page) => `Leyendo ${page}`,
150
- knowledgeCreate: (page) => `Creando ${page}`,
151
- knowledgeEdit: (page) => `Editando ${page}`,
152
- knowledgeRewrite: (page) => `Reescribiendo ${page}`,
153
- knowledgeSupersede: (page) => `Marcando ${page} como sustituida`,
154
- knowledgeRetire: (page) => `Retirando ${page}`,
155
- knowledgeLog: "Actualizando el registro de la base de conocimiento",
156
- knowledgeCheck: "Revisando la base de conocimiento",
157
136
  askingHuman: (question) => `Preguntando: ${question}`,
158
137
  presentingPlan: "Presentando el plan",
159
138
  },
@@ -22,6 +22,17 @@ export const fr = {
22
22
  resumeHint: "↑/↓ choisir · Entrée reprendre · Échap annuler",
23
23
  resumeQuestion: "Numéro de la conversation à reprendre (Entrée pour annuler) : ",
24
24
  noEarlierRuns: "(aucune conversation précédente à reprendre)",
25
+ commandResume: "Choisir une conversation précédente pour la reprendre",
26
+ commandPlan: "Passer en mode plan, ou revenir",
27
+ commandExtensions: "Ce qui tourne, ce qui est éteint et pourquoi ; en activer ou désactiver une",
28
+ extensionsRunning: (names) => `En service : ${names}`,
29
+ extensionsNone: "(aucune extension)",
30
+ extensionOff: (name, reason) => `${name} est désactivée : ${reason}`,
31
+ extensionsInstalled: "Installées :",
32
+ extensionToggled: (name, enabled) => `(${name} ${enabled ? "activée" : "désactivée"} : la session se rouvre, avec la même conversation)`,
33
+ extensionNotInstalled: (name) => `(${name} n'est pas installée : /extensions les liste)`,
34
+ extensionsUsage: "(usage : /extensions, /extensions enable <nom>, /extensions disable <nom>)",
35
+ extensionsCantReopen: "(ce chat ne peut pas rouvrir sa session : activez-la ou désactivez-la depuis le terminal, puis recommencez)",
25
36
  currentRun: "(celle-ci)",
26
37
  resumed: (date) => `(conversation du ${date} reprise)`,
27
38
  suggestionKey: "tab",
@@ -72,7 +83,7 @@ export const fr = {
72
83
  planCommentQuestion: "Que faut-il changer ? (Entrée pour passer) : ",
73
84
  retireLines: (source, why, reason, replacedBy, folder) => [
74
85
  `Source : ${source}`,
75
- why === "wrong" ? "Motif : elle est erronée ; son résumé sera retiré" : "Motif : elle est remplacée ; son résumé sera marqué comme remplacé",
86
+ why === "wrong" ? "Motif : elle est erronée" : "Motif : une meilleure la remplace",
76
87
  `Raison : ${reason}`,
77
88
  ...(replacedBy ? [`Remplacée par : ${replacedBy}`] : []),
78
89
  `Elle est déplacée dans ${folder}.agent-kit/retired/, pas supprimée.`,
@@ -91,22 +102,6 @@ export const fr = {
91
102
  Task: ["a lancé {n} sous-agent", "a lancé {n} sous-agents"],
92
103
  mcp__time__current_time: ["a consulté l'heure", "a consulté l'heure {n} fois"],
93
104
  mcp__time__date_math: ["a calculé des dates", "a calculé des dates {n} fois"],
94
- mcp__sourceFiles__list_sources: ["a examiné les sources", "a examiné les sources {n} fois"],
95
- mcp__sourceFiles__extract_text: ["a lu {n} document", "a lu {n} documents"],
96
- mcp__sourceFiles__save_to_sources: ["a enregistré {n} source", "a enregistré {n} sources"],
97
- mcp__sourceFiles__download_to_sources: ["a téléchargé {n} source", "a téléchargé {n} sources"],
98
- mcp__sourceFiles__request_file: ["a demandé {n} fichier", "a demandé {n} fichiers"],
99
- mcp__sourceFiles__retire_source: ["a retiré {n} source", "a retiré {n} sources"],
100
- mcp__knowledge__knowledge_index: ["a lu l'index", "a lu l'index {n} fois"],
101
- mcp__knowledge__knowledge_search: ["a cherché dans la base", "a cherché dans la base {n} fois"],
102
- mcp__knowledge__knowledge_read: ["a lu {n} page", "a lu {n} pages"],
103
- mcp__knowledge__knowledge_create: ["a créé {n} page", "a créé {n} pages"],
104
- mcp__knowledge__knowledge_edit: ["a modifié {n} page", "a modifié {n} pages"],
105
- mcp__knowledge__knowledge_rewrite: ["a réécrit {n} page", "a réécrit {n} pages"],
106
- mcp__knowledge__knowledge_supersede: ["a remplacé {n} page", "a remplacé {n} pages"],
107
- mcp__knowledge__knowledge_retire: ["a retiré {n} page", "a retiré {n} pages"],
108
- mcp__knowledge__knowledge_log: ["a mis à jour le journal", "a mis à jour le journal {n} fois"],
109
- mcp__knowledge__knowledge_check: ["a vérifié la base", "a vérifié la base {n} fois"],
110
105
  mcp__approvals__ask_human: ["a posé {n} question", "a posé {n} questions"],
111
106
  mcp__approvals__present_plan: ["a présenté le plan", "a présenté le plan {n} fois"],
112
107
  },
@@ -120,7 +115,6 @@ export const fr = {
120
115
  labels: {
121
116
  askingApproval: (summary) => `Demande d'approbation humaine : ${summary}`,
122
117
  waitingManual: "En attente d'une intervention manuelle",
123
- savingToSources: (destination) => `Enregistrement de ${destination} dans les sources`,
124
118
  checkingTime: "Consultation de la date et de l'heure",
125
119
  calculatingDates: "Calcul de dates",
126
120
  reading: (file) => `Lecture de ${file}`,
@@ -139,21 +133,6 @@ export const fr = {
139
133
  applyingSkill: (skill) => `Application de la skill "${skill}"`,
140
134
  aSkill: "une skill",
141
135
  updatingTasks: "Mise à jour de la liste des tâches",
142
- listingSources: "Examen des sources",
143
- extractingText: (source) => `Lecture de ${source}`,
144
- downloading: (url) => `Téléchargement de ${url} dans les sources`,
145
- requestingFile: (description) => `Demande d'un fichier : ${description}`,
146
- retiringSource: (source) => `Retrait de la source ${source}`,
147
- knowledgeIndex: "Lecture de l'index de la base de connaissances",
148
- knowledgeSearch: (query) => `Recherche de "${query}" dans la base de connaissances`,
149
- knowledgeRead: (page) => `Lecture de ${page}`,
150
- knowledgeCreate: (page) => `Création de ${page}`,
151
- knowledgeEdit: (page) => `Modification de ${page}`,
152
- knowledgeRewrite: (page) => `Réécriture de ${page}`,
153
- knowledgeSupersede: (page) => `${page} marquée comme remplacée`,
154
- knowledgeRetire: (page) => `Retrait de ${page}`,
155
- knowledgeLog: "Mise à jour du journal de la base de connaissances",
156
- knowledgeCheck: "Vérification de la base de connaissances",
157
136
  askingHuman: (question) => `Question : ${question}`,
158
137
  presentingPlan: "Présentation du plan",
159
138
  },
@@ -17,6 +17,12 @@ export declare function getLanguage(): Language;
17
17
  * once per process.
18
18
  */
19
19
  export declare function chooseLanguage(option?: string): Language;
20
+ /**
21
+ * Switches the kit's language on purpose, e.g. the person picked another in a chat (#47): from
22
+ * then on it wins over `--language` and `config.language`, until switched again. The session
23
+ * says so to the model when it opens next (the controller's `setLanguage()` reopens it).
24
+ */
25
+ export declare function switchLanguage(language: Language): void;
20
26
  /** Warnings about unsupported language codes not shown yet (English, one line each). */
21
27
  export declare function takeLanguageWarnings(): string[];
22
28
  /** The kit's texts in the current language. */
@@ -23,6 +23,8 @@ export function withEnglishFallback(own) {
23
23
  let current = "en";
24
24
  let messages = en;
25
25
  let chosen = false;
26
+ // A language switched to on purpose (switchLanguage()): kept over --language and options.
27
+ let switched = false;
26
28
  let pendingWarnings = [];
27
29
  const warned = new Set();
28
30
  /** Sets the language of the kit's texts directly (a host that resolved it itself, tests). */
@@ -43,7 +45,7 @@ export function getLanguage() {
43
45
  * once per process.
44
46
  */
45
47
  export function chooseLanguage(option) {
46
- if (chosen && option === undefined)
48
+ if (switched || (chosen && option === undefined))
47
49
  return current;
48
50
  const resolved = detectLanguage(option);
49
51
  for (const warning of resolved.warnings) {
@@ -55,6 +57,15 @@ export function chooseLanguage(option) {
55
57
  setLanguage(resolved.language);
56
58
  return current;
57
59
  }
60
+ /**
61
+ * Switches the kit's language on purpose, e.g. the person picked another in a chat (#47): from
62
+ * then on it wins over `--language` and `config.language`, until switched again. The session
63
+ * says so to the model when it opens next (the controller's `setLanguage()` reopens it).
64
+ */
65
+ export function switchLanguage(language) {
66
+ setLanguage(language);
67
+ switched = true;
68
+ }
58
69
  /** Warnings about unsupported language codes not shown yet (English, one line each). */
59
70
  export function takeLanguageWarnings() {
60
71
  const taken = pendingWarnings;
@@ -0,0 +1,10 @@
1
+ /** A path inside `…/app.asar/…`, as the unpacked copy next to it (`…/app.asar.unpacked/…`); any other path as it is. */
2
+ export declare function outsideArchive(file: string): string;
3
+ /**
4
+ * The SDK's CLI binary unpacked next to the archive, when the kit runs packaged: the SDK would
5
+ * resolve it inside `app.asar`, where it can't be executed, and its first turn would hang with
6
+ * no error (confirmed empirically). Looked up as the SDK does (`@anthropic-ai/claude-agent-sdk-
7
+ * <platform>-<arch>`, either libc on Linux), with `resolve` replaceable for tests. `undefined`
8
+ * when not packaged, or when the build didn't unpack it: then the SDK finds its own.
9
+ */
10
+ export declare function unpackedClaudeExecutable(resolve?: (request: string) => string, platform?: NodeJS.Platform, arch?: string): string | undefined;
@@ -0,0 +1,38 @@
1
+ import { existsSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ /**
4
+ * Running packaged in an archive (Electron's `app.asar`, ADR-026, #42). Electron reads files
5
+ * inside the archive for its own process, but another process can't: not the Claude Code CLI
6
+ * reading a plugin, not the binary itself. So every path the kit hands to another process goes
7
+ * through `outsideArchive()`, which points it at the copy the build unpacked (`asarUnpack`).
8
+ */
9
+ const ARCHIVE = /([\\/])app\.asar([\\/])/;
10
+ /** A path inside `…/app.asar/…`, as the unpacked copy next to it (`…/app.asar.unpacked/…`); any other path as it is. */
11
+ export function outsideArchive(file) {
12
+ return file.replace(ARCHIVE, "$1app.asar.unpacked$2");
13
+ }
14
+ /**
15
+ * The SDK's CLI binary unpacked next to the archive, when the kit runs packaged: the SDK would
16
+ * resolve it inside `app.asar`, where it can't be executed, and its first turn would hang with
17
+ * no error (confirmed empirically). Looked up as the SDK does (`@anthropic-ai/claude-agent-sdk-
18
+ * <platform>-<arch>`, either libc on Linux), with `resolve` replaceable for tests. `undefined`
19
+ * when not packaged, or when the build didn't unpack it: then the SDK finds its own.
20
+ */
21
+ export function unpackedClaudeExecutable(resolve = createRequire(import.meta.url).resolve, platform = process.platform, arch = process.arch) {
22
+ const packages = platform === "linux" ? [`linux-${arch}`, `linux-${arch}-musl`] : [`${platform}-${arch}`];
23
+ for (const suffix of packages) {
24
+ let file;
25
+ try {
26
+ file = resolve(`@anthropic-ai/claude-agent-sdk-${suffix}/claude${platform === "win32" ? ".exe" : ""}`);
27
+ }
28
+ catch {
29
+ continue;
30
+ }
31
+ if (!ARCHIVE.test(file))
32
+ return undefined;
33
+ const unpacked = outsideArchive(file);
34
+ if (existsSync(unpacked))
35
+ return unpacked;
36
+ }
37
+ return undefined;
38
+ }
@@ -0,0 +1,20 @@
1
+ import type { AgentDefinition } from "@anthropic-ai/claude-agent-sdk";
2
+ /**
3
+ * A plugin's subagents (`agents/<file>.md`, ADR-025), read so the session registers them as it
4
+ * does an agent's own from `buildSubagents()`: in the type gate's allow-list, in the `Agent` and
5
+ * `Bash` decision, and with the reply-language line. The SDK loads them itself as
6
+ * `<plugin>:<name>`, the name from the frontmatter, not the file (confirmed empirically); a
7
+ * definition under that same key in `options.agents` replaces the plugin's (also confirmed), which
8
+ * is how the kit adds the line.
9
+ */
10
+ /** A markdown file's frontmatter: `key: value`, with `[a, b]`, `a, b` or a YAML list for lists. */
11
+ export declare function frontmatter(text: string): {
12
+ fields: Record<string, string | string[]>;
13
+ body: string;
14
+ };
15
+ /**
16
+ * The subagents of the plugins in `roots`, by the name the SDK gives them (`<plugin>:<name>`):
17
+ * `description` and the body as the prompt, `tools` (none listed: it inherits the session's),
18
+ * `model` and `maxTurns` when given.
19
+ */
20
+ export declare function pluginAgents(roots: readonly string[]): Promise<Record<string, AgentDefinition>>;
@@ -0,0 +1,76 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ /**
4
+ * A plugin's subagents (`agents/<file>.md`, ADR-025), read so the session registers them as it
5
+ * does an agent's own from `buildSubagents()`: in the type gate's allow-list, in the `Agent` and
6
+ * `Bash` decision, and with the reply-language line. The SDK loads them itself as
7
+ * `<plugin>:<name>`, the name from the frontmatter, not the file (confirmed empirically); a
8
+ * definition under that same key in `options.agents` replaces the plugin's (also confirmed), which
9
+ * is how the kit adds the line.
10
+ */
11
+ /** A markdown file's frontmatter: `key: value`, with `[a, b]`, `a, b` or a YAML list for lists. */
12
+ export function frontmatter(text) {
13
+ const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
14
+ if (!match)
15
+ return { fields: {}, body: text };
16
+ const fields = {};
17
+ const lines = match[1].split(/\r?\n/);
18
+ for (let i = 0; i < lines.length; i++) {
19
+ const kv = /^([A-Za-z_][\w-]*):\s*(.*)$/.exec(lines[i]);
20
+ if (!kv)
21
+ continue;
22
+ const [, key, raw] = kv;
23
+ if (raw === "") {
24
+ const items = [];
25
+ while (i + 1 < lines.length && /^\s+-\s/.test(lines[i + 1]))
26
+ items.push(lines[++i].replace(/^\s+-\s*/, ""));
27
+ fields[key] = items.map(unquote);
28
+ }
29
+ else if (/^\[.*\]$/.test(raw)) {
30
+ fields[key] = raw.slice(1, -1).split(",").map(unquote).filter(Boolean);
31
+ }
32
+ else {
33
+ fields[key] = unquote(raw);
34
+ }
35
+ }
36
+ return { fields, body: text.slice(match[0].length).trim() };
37
+ }
38
+ const unquote = (value) => value.trim().replace(/^["']|["']$/g, "");
39
+ /** A field as a list: a list as is, `a, b` split on commas. */
40
+ function list(value) {
41
+ if (value === undefined)
42
+ return undefined;
43
+ return Array.isArray(value) ? value : value.split(",").map(unquote).filter(Boolean);
44
+ }
45
+ /**
46
+ * The subagents of the plugins in `roots`, by the name the SDK gives them (`<plugin>:<name>`):
47
+ * `description` and the body as the prompt, `tools` (none listed: it inherits the session's),
48
+ * `model` and `maxTurns` when given.
49
+ */
50
+ export async function pluginAgents(roots) {
51
+ const agents = {};
52
+ for (const root of roots) {
53
+ let plugin;
54
+ try {
55
+ plugin = JSON.parse(await readFile(path.join(root, ".claude-plugin", "plugin.json"), "utf8")).name;
56
+ }
57
+ catch {
58
+ continue;
59
+ }
60
+ const files = await readdir(path.join(root, "agents")).catch(() => []);
61
+ for (const file of files.filter((name) => name.endsWith(".md"))) {
62
+ const { fields, body } = frontmatter(await readFile(path.join(root, "agents", file), "utf8"));
63
+ const name = typeof fields.name === "string" && fields.name ? fields.name : file.replace(/\.md$/, "");
64
+ const tools = list(fields.tools);
65
+ const maxTurns = typeof fields.maxTurns === "string" ? Number(fields.maxTurns) : undefined;
66
+ agents[`${plugin}:${name}`] = {
67
+ description: typeof fields.description === "string" ? fields.description : "",
68
+ prompt: body,
69
+ ...(tools ? { tools } : {}),
70
+ ...(typeof fields.model === "string" ? { model: fields.model } : {}),
71
+ ...(maxTurns && Number.isFinite(maxTurns) ? { maxTurns } : {}),
72
+ };
73
+ }
74
+ }
75
+ return agents;
76
+ }
@@ -1,4 +1,5 @@
1
1
  import { query } from "@anthropic-ai/claude-agent-sdk";
2
+ import { sessionViewOf } from "./sessionFacts.js";
2
3
  /**
3
4
  * A turn's errors without the CLI's internal diagnostics: an interrupted turn ends with
4
5
  * one like "[ede_diagnostic] result_type=user ... stop_reason=tool_use" (seen on Esc),
@@ -27,11 +28,16 @@ export function toolResultText(content) {
27
28
  */
28
29
  export function runQuery(prompt, options) {
29
30
  const result = query({ prompt, options });
31
+ // What the session is, for an extension that asks (sessionFacts.ts): the controls now, the
32
+ // tools and skills when the session starts.
33
+ const view = sessionViewOf(options);
34
+ view?.attach({ supportedCommands: () => result.supportedCommands(), contextUsage: () => contextUsage() });
30
35
  // The main agent's tool calls by id, to name the results that come back for them.
31
36
  const toolNames = new Map();
32
37
  async function* generateEvents() {
33
38
  for await (const message of result) {
34
39
  if (message.type === "system" && message.subtype === "init") {
40
+ view?.attach({ tools: message.tools, skills: message.skills });
35
41
  const failedServers = message.mcp_servers.filter((s) => s.status === "failed").map((s) => s.name);
36
42
  if (failedServers.length > 0)
37
43
  yield { type: "mcp-error", failedServers };
@@ -103,14 +109,15 @@ export function runQuery(prompt, options) {
103
109
  interrupt: () => result.interrupt(),
104
110
  close: () => result.close(),
105
111
  supportedCommands: () => result.supportedCommands(),
106
- contextUsage: async () => {
107
- try {
108
- const usage = await result.getContextUsage();
109
- return { percentage: usage.percentage, totalTokens: usage.totalTokens, maxTokens: usage.maxTokens };
110
- }
111
- catch {
112
- return null;
113
- }
114
- },
112
+ contextUsage,
115
113
  };
114
+ async function contextUsage() {
115
+ try {
116
+ const usage = await result.getContextUsage();
117
+ return { percentage: usage.percentage, totalTokens: usage.totalTokens, maxTokens: usage.maxTokens };
118
+ }
119
+ catch {
120
+ return null;
121
+ }
122
+ }
116
123
  }
@@ -1,7 +1,9 @@
1
1
  import type { Options, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
2
2
  import { type TranscriptLogger } from "./hooks/transcriptLogger.js";
3
3
  import { type ModeControl } from "./modeControl.js";
4
- import type { KnowledgeStore } from "./knowledgeStore.js";
4
+ import type { KnowledgeStore } from "../extensions/knowledge/knowledgeStore.js";
5
+ import { type ExtensionDirs, type InstalledExtension } from "./externalExtensions.js";
6
+ import type { ToolLabels } from "./toolLabels.js";
5
7
  import type { AgentSpec, BaseSessionConfig } from "./agentSpec.js";
6
8
  import { type Language } from "./language.js";
7
9
  import { type RunFolder } from "./runs.js";
@@ -12,9 +14,10 @@ import { type RunFolder } from "./runs.js";
12
14
  * one-shot run or an `AsyncIterable` for a multi-turn chat).
13
15
  *
14
16
  * Everything actually *about the domain* (which system prompt, which MCP servers besides
15
- * the generic human-in-the-loop/knowledge ones below, which plugin roots, which
16
- * subagents) is behind `spec` (see agentSpec.ts) — this function only knows the generic
17
- * fields on `BaseSessionConfig`.
17
+ * the generic human-in-the-loop ones below, which plugin roots, which subagents) is behind
18
+ * `spec` (see agentSpec.ts), and the kit's optional parts (the knowledge base, the sources
19
+ * folder) are extensions whose contributions this function puts together (extensions.ts,
20
+ * ADR-025): it names none of them.
18
21
  *
19
22
  * The per-mode behavioral differences (whether the approval/manual-intervention tools
20
23
  * exist, whether the interactive step gate or the plan gate decides) all fall out of
@@ -33,10 +36,44 @@ export declare function buildSessionOptions<TConfig extends BaseSessionConfig>(c
33
36
  transcriptPath: string;
34
37
  modeControl: ModeControl;
35
38
  language: Language;
36
- /** The knowledge base's store, when the agent reaches it through the `knowledge_*` tools. */
39
+ /** How the chat shows the extensions' tools (`runChatInk()` takes them from a session opener). */
40
+ toolLabels: ToolLabels;
41
+ /** The installed extensions and what this session runs with, for `/extensions` (#37). */
42
+ extensions: ExtensionsStatus;
43
+ /** The knowledge base's store, when the knowledge extension is on (for a host that reads the knowledge base). */
37
44
  knowledgeStore?: KnowledgeStore;
45
+ /** What each active extension hands the host (its contribution's `api`), by its name: the sources' `addSource`, the knowledge base's store. */
46
+ apis: Record<string, Record<string, unknown>>;
38
47
  }>;
39
48
  export { createModeControl, togglePlanMode, type ModeControl } from "./modeControl.js";
49
+ /** The extensions of a session: where they're installed, what's installed, what runs and what can't (with why). */
50
+ export interface ExtensionsStatus {
51
+ dirs: ExtensionDirs;
52
+ installed: InstalledExtension[];
53
+ /** The names of the extensions this session runs with, the kit's and the agent's too. */
54
+ active: string[];
55
+ /** What each active one is, from its manifest: for a view that lists them. */
56
+ about: Record<string, {
57
+ description: string;
58
+ provides: string[];
59
+ }>;
60
+ inactive: {
61
+ name: string;
62
+ reason: string;
63
+ }[];
64
+ }
65
+ /**
66
+ * The CLI's folder for a project, where it keeps each session's transcript and large tool
67
+ * results (`<session>/tool-results/`): the project's path with every character but letters
68
+ * and digits as "-" (confirmed empirically).
69
+ */
70
+ export declare function claudeProjectDir(projectDir: string): string;
71
+ /**
72
+ * The skills of the plugins in `roots`, as the SDK names them: `<plugin>:<folder>`, the
73
+ * plugin's name from its `.claude-plugin/plugin.json` and the skill's folder under `skills/`,
74
+ * whatever its frontmatter's `name` says (confirmed empirically).
75
+ */
76
+ export declare function pluginSkills(roots: readonly string[]): Promise<string[]>;
40
77
  /**
41
78
  * User message queue backed by a single long-lived generator, for any multi-turn
42
79
  * (chat-shaped) caller of `query()`.