agent-sin 0.1.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 (150) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +81 -0
  4. package/assets/logo.png +0 -0
  5. package/builtin-skills/_shared/_models_lib.py +227 -0
  6. package/builtin-skills/_shared/_profile_lib.py +98 -0
  7. package/builtin-skills/_shared/_schedules_lib.py +313 -0
  8. package/builtin-skills/_shared/_skill_settings_lib.py +153 -0
  9. package/builtin-skills/_shared/i18n.py +26 -0
  10. package/builtin-skills/memo-delete/main.py +155 -0
  11. package/builtin-skills/memo-delete/skill.yaml +57 -0
  12. package/builtin-skills/memo-index/main.py +178 -0
  13. package/builtin-skills/memo-index/skill.yaml +53 -0
  14. package/builtin-skills/memo-save/README.md +5 -0
  15. package/builtin-skills/memo-save/main.py +74 -0
  16. package/builtin-skills/memo-save/skill.yaml +52 -0
  17. package/builtin-skills/memo-search/README.md +10 -0
  18. package/builtin-skills/memo-search/main.py +97 -0
  19. package/builtin-skills/memo-search/skill.yaml +51 -0
  20. package/builtin-skills/memo-vector-search/main.py +121 -0
  21. package/builtin-skills/memo-vector-search/skill.yaml +53 -0
  22. package/builtin-skills/model-add/main.py +180 -0
  23. package/builtin-skills/model-add/skill.yaml +112 -0
  24. package/builtin-skills/model-list/main.py +93 -0
  25. package/builtin-skills/model-list/skill.yaml +48 -0
  26. package/builtin-skills/model-set/main.py +123 -0
  27. package/builtin-skills/model-set/skill.yaml +69 -0
  28. package/builtin-skills/profile-delete/_profile_lib.py +98 -0
  29. package/builtin-skills/profile-delete/main.py +98 -0
  30. package/builtin-skills/profile-delete/skill.yaml +64 -0
  31. package/builtin-skills/profile-edit/_profile_lib.py +98 -0
  32. package/builtin-skills/profile-edit/main.py +97 -0
  33. package/builtin-skills/profile-edit/skill.yaml +72 -0
  34. package/builtin-skills/profile-save/main.py +52 -0
  35. package/builtin-skills/profile-save/skill.yaml +69 -0
  36. package/builtin-skills/schedule-add/_schedules_lib.py +303 -0
  37. package/builtin-skills/schedule-add/main.py +137 -0
  38. package/builtin-skills/schedule-add/skill.yaml +94 -0
  39. package/builtin-skills/schedule-list/_schedules_lib.py +303 -0
  40. package/builtin-skills/schedule-list/main.py +86 -0
  41. package/builtin-skills/schedule-list/skill.yaml +45 -0
  42. package/builtin-skills/schedule-remove/_schedules_lib.py +303 -0
  43. package/builtin-skills/schedule-remove/main.py +69 -0
  44. package/builtin-skills/schedule-remove/skill.yaml +49 -0
  45. package/builtin-skills/schedule-toggle/_schedules_lib.py +303 -0
  46. package/builtin-skills/schedule-toggle/main.py +78 -0
  47. package/builtin-skills/schedule-toggle/skill.yaml +61 -0
  48. package/builtin-skills/skills-disable/main.py +63 -0
  49. package/builtin-skills/skills-disable/skill.yaml +52 -0
  50. package/builtin-skills/skills-enable/main.py +62 -0
  51. package/builtin-skills/skills-enable/skill.yaml +51 -0
  52. package/builtin-skills/todo-add/main.py +68 -0
  53. package/builtin-skills/todo-add/skill.yaml +53 -0
  54. package/builtin-skills/todo-delete/main.py +65 -0
  55. package/builtin-skills/todo-delete/skill.yaml +47 -0
  56. package/builtin-skills/todo-done/main.py +75 -0
  57. package/builtin-skills/todo-done/skill.yaml +47 -0
  58. package/builtin-skills/todo-list/main.py +91 -0
  59. package/builtin-skills/todo-list/skill.yaml +48 -0
  60. package/builtin-skills/todo-tick/main.py +125 -0
  61. package/builtin-skills/todo-tick/skill.yaml +48 -0
  62. package/dist/builder/build-action-classifier.d.ts +18 -0
  63. package/dist/builder/build-action-classifier.js +142 -0
  64. package/dist/builder/build-commands.d.ts +19 -0
  65. package/dist/builder/build-commands.js +133 -0
  66. package/dist/builder/build-flow.d.ts +72 -0
  67. package/dist/builder/build-flow.js +416 -0
  68. package/dist/builder/builder-session.d.ts +117 -0
  69. package/dist/builder/builder-session.js +1129 -0
  70. package/dist/builder/conversation-router.d.ts +22 -0
  71. package/dist/builder/conversation-router.js +69 -0
  72. package/dist/builder/intent-runtime-store.d.ts +7 -0
  73. package/dist/builder/intent-runtime-store.js +60 -0
  74. package/dist/builder/progress-format.d.ts +7 -0
  75. package/dist/builder/progress-format.js +46 -0
  76. package/dist/cli/index.d.ts +2 -0
  77. package/dist/cli/index.js +2835 -0
  78. package/dist/cli/spinner.d.ts +30 -0
  79. package/dist/cli/spinner.js +164 -0
  80. package/dist/core/ai-provider.d.ts +75 -0
  81. package/dist/core/ai-provider.js +678 -0
  82. package/dist/core/builtin-skills.d.ts +27 -0
  83. package/dist/core/builtin-skills.js +120 -0
  84. package/dist/core/chat-engine.d.ts +70 -0
  85. package/dist/core/chat-engine.js +812 -0
  86. package/dist/core/config.d.ts +127 -0
  87. package/dist/core/config.js +1379 -0
  88. package/dist/core/daily-memory-promotion.d.ts +21 -0
  89. package/dist/core/daily-memory-promotion.js +422 -0
  90. package/dist/core/i18n.d.ts +23 -0
  91. package/dist/core/i18n.js +167 -0
  92. package/dist/core/info-lines.d.ts +5 -0
  93. package/dist/core/info-lines.js +39 -0
  94. package/dist/core/input-schema.d.ts +2 -0
  95. package/dist/core/input-schema.js +156 -0
  96. package/dist/core/intent-router.d.ts +27 -0
  97. package/dist/core/intent-router.js +160 -0
  98. package/dist/core/logger.d.ts +60 -0
  99. package/dist/core/logger.js +240 -0
  100. package/dist/core/memory.d.ts +10 -0
  101. package/dist/core/memory.js +72 -0
  102. package/dist/core/message-utils.d.ts +13 -0
  103. package/dist/core/message-utils.js +104 -0
  104. package/dist/core/notifier.d.ts +17 -0
  105. package/dist/core/notifier.js +424 -0
  106. package/dist/core/output-writer.d.ts +13 -0
  107. package/dist/core/output-writer.js +100 -0
  108. package/dist/core/plan-decision.d.ts +16 -0
  109. package/dist/core/plan-decision.js +88 -0
  110. package/dist/core/profile-memory.d.ts +17 -0
  111. package/dist/core/profile-memory.js +142 -0
  112. package/dist/core/runtime.d.ts +50 -0
  113. package/dist/core/runtime.js +187 -0
  114. package/dist/core/scheduler.d.ts +28 -0
  115. package/dist/core/scheduler.js +155 -0
  116. package/dist/core/secrets.d.ts +31 -0
  117. package/dist/core/secrets.js +214 -0
  118. package/dist/core/service.d.ts +35 -0
  119. package/dist/core/service.js +479 -0
  120. package/dist/core/skill-planner.d.ts +24 -0
  121. package/dist/core/skill-planner.js +100 -0
  122. package/dist/core/skill-registry.d.ts +98 -0
  123. package/dist/core/skill-registry.js +319 -0
  124. package/dist/core/skill-scaffold.d.ts +33 -0
  125. package/dist/core/skill-scaffold.js +256 -0
  126. package/dist/core/skill-settings.d.ts +11 -0
  127. package/dist/core/skill-settings.js +63 -0
  128. package/dist/core/transfer.d.ts +31 -0
  129. package/dist/core/transfer.js +270 -0
  130. package/dist/core/update-notifier.d.ts +2 -0
  131. package/dist/core/update-notifier.js +140 -0
  132. package/dist/discord/bot.d.ts +96 -0
  133. package/dist/discord/bot.js +2424 -0
  134. package/dist/runtimes/codex-app-server.d.ts +53 -0
  135. package/dist/runtimes/codex-app-server.js +305 -0
  136. package/dist/runtimes/python-runner.d.ts +7 -0
  137. package/dist/runtimes/python-runner.js +302 -0
  138. package/dist/runtimes/typescript-runner.d.ts +5 -0
  139. package/dist/runtimes/typescript-runner.js +172 -0
  140. package/dist/skills-sdk/types.d.ts +38 -0
  141. package/dist/skills-sdk/types.js +1 -0
  142. package/dist/telegram/bot.d.ts +94 -0
  143. package/dist/telegram/bot.js +1219 -0
  144. package/install.ps1 +132 -0
  145. package/install.sh +130 -0
  146. package/package.json +60 -0
  147. package/templates/skill-python/main.py +74 -0
  148. package/templates/skill-python/skill.yaml +48 -0
  149. package/templates/skill-typescript/main.ts +87 -0
  150. package/templates/skill-typescript/skill.yaml +42 -0
@@ -0,0 +1,142 @@
1
+ import { getAiProvider } from "../core/ai-provider.js";
2
+ const RECENT_HISTORY_TURNS = 8;
3
+ export async function classifyHandoffApproval(config, userText, history, pending, options = {}) {
4
+ const trimmed = userText.trim();
5
+ if (!trimmed) {
6
+ return { decision: "discuss", reason: "empty input" };
7
+ }
8
+ const system = handoffApprovalPrompt(pending);
9
+ const messages = buildMessages(system, history, trimmed);
10
+ const parsed = await callJsonClassifier(config, messages, options.modelId);
11
+ if (!parsed) {
12
+ return { decision: "discuss", reason: "classifier fallback" };
13
+ }
14
+ const raw = String(parsed.decision || "").trim().toLowerCase();
15
+ const decision = raw === "approve" ? "approve" : raw === "reject" ? "reject" : "discuss";
16
+ const carryOver = typeof parsed.carry_over_text === "string" ? parsed.carry_over_text.trim() : "";
17
+ return {
18
+ decision,
19
+ carry_over_text: carryOver || undefined,
20
+ reason: typeof parsed.reason === "string" ? parsed.reason.slice(0, 240) : undefined,
21
+ };
22
+ }
23
+ export async function classifyBuildModeAction(config, userText, history, build, options = {}) {
24
+ const trimmed = userText.trim();
25
+ if (!trimmed) {
26
+ return { action: "continue", reason: "empty input" };
27
+ }
28
+ const system = buildModeActionPrompt(build);
29
+ const messages = buildMessages(system, history, trimmed);
30
+ const parsed = await callJsonClassifier(config, messages, options.modelId);
31
+ if (!parsed) {
32
+ return { action: "continue", reason: "classifier fallback" };
33
+ }
34
+ const raw = String(parsed.action || "").trim().toLowerCase();
35
+ const action = raw === "exit" ? "exit"
36
+ : raw === "register" ? "register"
37
+ : raw === "test" ? "test"
38
+ : "continue";
39
+ return {
40
+ action,
41
+ reason: typeof parsed.reason === "string" ? parsed.reason.slice(0, 240) : undefined,
42
+ };
43
+ }
44
+ function buildMessages(system, history, userText) {
45
+ const recent = history.slice(-RECENT_HISTORY_TURNS).map((turn) => ({
46
+ role: (turn.role === "tool" ? "tool" : turn.role),
47
+ content: turn.content,
48
+ }));
49
+ return [
50
+ { role: "system", content: system },
51
+ ...recent,
52
+ {
53
+ role: "user",
54
+ content: `Classify the following user reply.\n\n<reply>${userText}</reply>\n\nReturn JSON only.`,
55
+ },
56
+ ];
57
+ }
58
+ async function callJsonClassifier(config, messages, modelId) {
59
+ let response;
60
+ try {
61
+ response = await getAiProvider()(config, {
62
+ model_id: modelId || config.chat_model_id,
63
+ messages,
64
+ temperature: 0,
65
+ });
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ return parseClassifierJson(response.text);
71
+ }
72
+ function parseClassifierJson(text) {
73
+ const stripped = text
74
+ .replace(/```json\s*/gi, "")
75
+ .replace(/```\s*$/g, "")
76
+ .trim();
77
+ const start = stripped.indexOf("{");
78
+ const end = stripped.lastIndexOf("}");
79
+ if (start < 0 || end <= start) {
80
+ return null;
81
+ }
82
+ try {
83
+ const parsed = JSON.parse(stripped.slice(start, end + 1));
84
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
85
+ return parsed;
86
+ }
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ return null;
92
+ }
93
+ function handoffApprovalPrompt(pending) {
94
+ const typeLabel = pending.type === "edit" ? "edit existing skill" : "create new skill";
95
+ return [
96
+ "You decide how the user is responding to a pending build-mode proposal.",
97
+ "There is a pending proposal:",
98
+ `- type: ${typeLabel}`,
99
+ `- skill_id: ${pending.skill_id}`,
100
+ `- reason: ${pending.reason}`,
101
+ `- original_user_request: ${truncate(pending.original_text, 400)}`,
102
+ "",
103
+ "Decide one of three labels:",
104
+ '- "approve": the user wants to go ahead with the proposal (any natural phrasing in any language: "yes", "do it", "make it", "go", "please", "create it", "let\'s do it", はい, つくって, 作って, やって, お願い, 進めて, etc., including approvals that bundle additional requirements or constraints).',
105
+ '- "reject": the user wants to cancel or abandon the proposal ("no", "cancel", "stop", やめて, キャンセル, やっぱり違う, etc.).',
106
+ '- "discuss": the user is asking a clarifying question, providing more requirements without explicit approval, or continuing the conversation without committing. When in doubt, choose discuss.',
107
+ "",
108
+ "If approve and the reply contains extra requirements or constraints beyond the bare approval, copy that extra part into carry_over_text verbatim (in the user's language). Omit pure approval words (yes / つくって / etc.). If there is nothing extra, omit carry_over_text.",
109
+ "",
110
+ "Return exactly one JSON object. No markdown fences:",
111
+ '{"decision":"approve|reject|discuss","carry_over_text":"...","reason":"short why"}',
112
+ ].join("\n");
113
+ }
114
+ function buildModeActionPrompt(build) {
115
+ const typeLabel = build.type === "edit" ? "editing an existing skill" : "creating a new skill";
116
+ return [
117
+ "You decide how the user wants to proceed inside build mode.",
118
+ "Current build session:",
119
+ `- mode: ${typeLabel}`,
120
+ `- skill_id: ${build.skill_id}`,
121
+ `- original_request: ${truncate(build.original_text, 400)}`,
122
+ "",
123
+ "Choose one of four actions:",
124
+ '- "exit": the user wants to leave build mode and return to plain chat ("stop", "go back", "/back", やめる, 戻る, もういい, 中止, キャンセル, or any natural cancel/exit phrase in any language).',
125
+ '- "register": the user wants to register/install the current draft as a usable skill ("register it", "install", 登録して, 本登録, これでOK, これで保存, 公開して).',
126
+ '- "test": the user wants to test/run the current draft ("test it", "run it", 動かして, 試して, テスト).',
127
+ '- "continue": anything else — additional requirements, edits, design discussion, environment variables, default request to keep building.',
128
+ "",
129
+ "If the user is asking to fix or change implementation details, prefer 'continue' over 'register' or 'test'.",
130
+ "If unsure, choose 'continue'.",
131
+ "",
132
+ "Return exactly one JSON object. No markdown fences:",
133
+ '{"action":"exit|register|test|continue","reason":"short why"}',
134
+ ].join("\n");
135
+ }
136
+ function truncate(text, max) {
137
+ if (!text)
138
+ return "";
139
+ if (text.length <= max)
140
+ return text;
141
+ return `${text.slice(0, max)}...`;
142
+ }
@@ -0,0 +1,19 @@
1
+ import type { AppConfig } from "../core/config.js";
2
+ import type { AiProgressHandler } from "../core/ai-provider.js";
3
+ import { type BuilderAccessMode } from "./builder-session.js";
4
+ export declare function buildLines(config: AppConfig, skillId: string | undefined, options?: {
5
+ prompt?: string;
6
+ runtime?: "python" | "typescript";
7
+ builder?: string;
8
+ accessMode?: BuilderAccessMode;
9
+ onProgress?: AiProgressHandler;
10
+ }): Promise<string[]>;
11
+ export declare function buildChatLines(config: AppConfig, skillId: string, message: string, options?: {
12
+ onProgress?: AiProgressHandler;
13
+ }): Promise<string[]>;
14
+ export declare function buildTestLines(config: AppConfig, skillId: string, payload?: Record<string, unknown>): Promise<string[]>;
15
+ export declare function buildStatusLines(config: AppConfig, skillId: string): Promise<string[]>;
16
+ export declare function buildRegisterLines(config: AppConfig, skillId: string, options?: {
17
+ overwrite?: boolean;
18
+ }): Promise<string[]>;
19
+ export declare function buildListLines(config: AppConfig): Promise<string[]>;
@@ -0,0 +1,133 @@
1
+ import { l } from "../core/i18n.js";
2
+ import { buildDraftWithAgent, createBuildSession, inspectBuildReadiness, listBuildDrafts, readBuildStatus, registerBuildSkill, testBuildDraft, } from "./builder-session.js";
3
+ export async function buildLines(config, skillId, options = {}) {
4
+ const session = await createBuildSession(config, skillId, {
5
+ runtime: options.runtime,
6
+ accessMode: options.accessMode,
7
+ });
8
+ const lines = [
9
+ l(`Build workspace ready: ${session.workspace}`, `ビルド用ワークスペース準備完了: ${session.workspace}`),
10
+ `Draft: ${session.draft_dir}`,
11
+ `Review: ${session.review_path}`,
12
+ l('Next: agent-sin build chat <skill-id> "what to build"', '次: agent-sin build chat <skill-id> "作りたい内容"'),
13
+ l("Test: agent-sin build test <skill-id>", "テスト: agent-sin build test <skill-id>"),
14
+ l("Use: the skill is saved under skills/<skill-id> as soon as files are written", "利用: ファイルが書かれた時点で skills/<skill-id> 配下に保存されています"),
15
+ ];
16
+ if (!options.prompt?.trim()) {
17
+ return lines;
18
+ }
19
+ const result = await buildDraftWithAgent(config, session.skill_id, options.prompt, {
20
+ runtime: options.runtime,
21
+ builder: options.builder,
22
+ accessMode: options.accessMode,
23
+ onProgress: options.onProgress,
24
+ });
25
+ return [
26
+ l(`Build draft updated: ${result.session.skill_id}`, `ビルドドラフトを更新しました: ${result.session.skill_id}`),
27
+ `Builder: ${result.model_id} (${result.provider})`,
28
+ l(`Summary: ${result.summary}`, `要約: ${result.summary}`),
29
+ ...result.files_written.map((file) => ` + ${file}`),
30
+ l(`Next: agent-sin build test ${result.session.skill_id}`, `次: agent-sin build test ${result.session.skill_id}`),
31
+ ];
32
+ }
33
+ export async function buildChatLines(config, skillId, message, options = {}) {
34
+ const result = await buildDraftWithAgent(config, skillId, message, {
35
+ onProgress: options.onProgress,
36
+ });
37
+ return [
38
+ l(`Build draft updated: ${result.session.skill_id}`, `ビルドドラフトを更新しました: ${result.session.skill_id}`),
39
+ `Builder: ${result.model_id} (${result.provider})`,
40
+ l(`Summary: ${result.summary}`, `要約: ${result.summary}`),
41
+ ...result.files_written.map((file) => ` + ${file}`),
42
+ l(`Next: agent-sin build test ${result.session.skill_id}`, `次: agent-sin build test ${result.session.skill_id}`),
43
+ ];
44
+ }
45
+ export async function buildTestLines(config, skillId, payload) {
46
+ const result = await testBuildDraft(config, skillId, payload);
47
+ if (result.missing_env && result.missing_env.length > 0) {
48
+ const lines = [l("Waiting for settings. These required values are missing:", "設定待ちです。必要な値がまだ入っていません:")];
49
+ for (const entry of result.missing_env) {
50
+ lines.push(` - ${entry.name}${entry.description ? ` - ${entry.description}` : ""}`);
51
+ }
52
+ lines.push(l("After saving them, ask to test again.", "保存できたら、もう一度「テストして」と伝えてください。"));
53
+ return lines;
54
+ }
55
+ if (result.safe_to_register) {
56
+ return [l(`✅ Ready to run. ${result.summary || ""}`, `✅ 動かせる状態です。${result.summary || ""}`).trim(), l("Ready to use.", "登録できます。")];
57
+ }
58
+ // failed
59
+ const lines = [l(`❌ Still needs fixes. ${result.summary || ""}`, `❌ まだ直す必要があります。${result.summary || ""}`).trim()];
60
+ for (const error of result.validation.errors) {
61
+ lines.push(`[error] ${error}`);
62
+ }
63
+ if (result.details) {
64
+ const tail = result.details.split("\n").slice(0, 20);
65
+ lines.push("```", ...tail, "```");
66
+ }
67
+ return lines;
68
+ }
69
+ export async function buildStatusLines(config, skillId) {
70
+ const status = await readBuildStatus(config, skillId);
71
+ const userState = buildUserState(config, status.result, status.state.status);
72
+ const lines = [
73
+ `${status.state.skill_id}: ${userState}`,
74
+ ];
75
+ if (status.result) {
76
+ if (typeof status.result.summary === "string") {
77
+ lines.push(status.result.summary);
78
+ }
79
+ const missing = Array.isArray(status.result.missing_env) ? status.result.missing_env : [];
80
+ for (const entry of missing) {
81
+ if (entry && typeof entry === "object" && typeof entry.name === "string") {
82
+ lines.push(l(`Required setting: ${entry.name}`, `必要な設定: ${entry.name}`));
83
+ }
84
+ }
85
+ }
86
+ return lines;
87
+ }
88
+ export async function buildRegisterLines(config, skillId, options = {}) {
89
+ const readiness = await inspectBuildReadiness(config, skillId);
90
+ if (readiness.status === "needs_config") {
91
+ const lines = [l("Waiting for settings. Save these required values before using it:", "設定待ちです。登録前に必要な値を保存してください:")];
92
+ for (const entry of readiness.missing_env || []) {
93
+ lines.push(` - ${entry.name}${entry.description ? ` - ${entry.description}` : ""}`);
94
+ }
95
+ return lines;
96
+ }
97
+ if (!readiness.safe_to_register) {
98
+ return [
99
+ readiness.status === "incomplete" ? l("Not complete yet. Describe what you want a little more.", "未完成です。もう少し要望を伝えてください。") : l("Still needs fixes.", "まだ直す必要があります。"),
100
+ readiness.summary,
101
+ ].filter(Boolean);
102
+ }
103
+ const registered = await registerBuildSkill(config, skillId, options);
104
+ return [l(`✅ "${registered.skill_id}" is ready and can be called from chat.`, `✅ "${registered.skill_id}" は登録済みです。チャットから呼び出せます。`)];
105
+ }
106
+ export async function buildListLines(config) {
107
+ const drafts = await listBuildDrafts(config);
108
+ if (drafts.length === 0) {
109
+ return [
110
+ l("No skill drafts.", "作成中のスキルはありません。"),
111
+ l("Create one: agent-sin build [skill-id] --prompt \"...\"", "新規作成: agent-sin build [skill-id] --prompt \"…\""),
112
+ ];
113
+ }
114
+ const lines = [
115
+ l(`Skill drafts (${drafts.length}):`, `作成中のスキル (${drafts.length}):`),
116
+ l("id\tstatus\tupdated", "id\t状態\tupdated"),
117
+ ];
118
+ for (const draft of drafts) {
119
+ const updated = draft.updated_at ? draft.updated_at.replace("T", " ").replace(/\..*$/, "") : "-";
120
+ lines.push(`${draft.skill_id}\t${buildUserState(config, { safe_to_register: draft.safe_to_register }, draft.status)}\t${updated}`);
121
+ }
122
+ lines.push("");
123
+ lines.push(l("To continue, send a request with that skill name.", "続きは、そのスキル名を指定して要望を送ってください。"));
124
+ return lines;
125
+ }
126
+ function buildUserState(_config, result, status) {
127
+ if (status === "needs_config" || result?.status === "needs_config")
128
+ return l("needs config", "設定待ち");
129
+ if (result?.safe_to_register === true || status === "ready") {
130
+ return l("ready", "登録済み");
131
+ }
132
+ return l("drafting", "未完成");
133
+ }
@@ -0,0 +1,72 @@
1
+ import type { AppConfig } from "../core/config.js";
2
+ import type { ChatTurn } from "../core/chat-engine.js";
3
+ import type { AiProgressHandler } from "../core/ai-provider.js";
4
+ import { type BuilderHandoffTurn } from "./builder-session.js";
5
+ export interface PendingHandoff {
6
+ type: "create" | "edit";
7
+ skill_id: string;
8
+ original_text: string;
9
+ reason: string;
10
+ }
11
+ export interface PendingBuildExit {
12
+ reason: string;
13
+ }
14
+ export type BuilderEventSource = "discord" | "telegram" | "cli";
15
+ export interface BuildModeState {
16
+ type: "create" | "edit";
17
+ skill_id: string;
18
+ skill_name?: string | null;
19
+ context_seed: BuilderHandoffTurn[];
20
+ context_consumed: boolean;
21
+ original_text: string;
22
+ event_source?: BuilderEventSource;
23
+ }
24
+ export interface IntentRuntime {
25
+ pending: PendingHandoff | null;
26
+ pending_exit: PendingBuildExit | null;
27
+ preferred_skill_id: string | null;
28
+ progress_detail: boolean;
29
+ enabled: boolean;
30
+ mode: "chat" | "build";
31
+ build: BuildModeState | null;
32
+ }
33
+ export declare function createIntentRuntime(enabled?: boolean): IntentRuntime;
34
+ export declare function parseEnvDirective(text: string): {
35
+ name: string;
36
+ value: string;
37
+ } | null;
38
+ export declare function isReservedAgentSinEnv(name: string): boolean;
39
+ export declare function looksLikeRawSecretValue(text: string): boolean;
40
+ export declare function extractAutoSaveSecretValue(text: string, envName?: string): string | null;
41
+ export declare function tryAutoSaveBuildEnv(config: AppConfig, build: BuildModeState, text: string): Promise<string[] | null>;
42
+ export interface BuildHandoffApproval {
43
+ decision: "approve" | "reject" | "discuss";
44
+ carry_over_text?: string;
45
+ }
46
+ export declare function classifyPendingHandoff(config: AppConfig, text: string, history: ChatTurn[], intentRuntime: IntentRuntime): Promise<BuildHandoffApproval>;
47
+ export declare function renderBuildFooter(intentRuntime: IntentRuntime, options: {
48
+ exitPrefix: "!" | "/";
49
+ languageHint?: string | string[];
50
+ }): string;
51
+ /**
52
+ * Decide whether to append the build-mode footer to a reply.
53
+ */
54
+ export declare function shouldShowBuildFooter(opts: {
55
+ intentRuntime: IntentRuntime;
56
+ userText: string;
57
+ replyLines: string[];
58
+ isBuildEntry?: boolean;
59
+ }): boolean;
60
+ export interface BuildModeHandlerOptions {
61
+ onProgress?: AiProgressHandler;
62
+ /** Kept for compatibility; build mode now exits only through explicit local commands. */
63
+ suggestExitOnOffTopic?: boolean;
64
+ /** Recent chat history used to detect off-topic skill-run / chat messages. */
65
+ history?: ChatTurn[];
66
+ }
67
+ export interface BuildAutoExitDecision {
68
+ preferred_skill_id: string | null;
69
+ reason: string;
70
+ }
71
+ export declare function enterBuildMode(config: AppConfig, history: ChatTurn[], intentRuntime: IntentRuntime, hooks?: BuildModeHandlerOptions, extraText?: string, eventSource?: BuilderEventSource): Promise<string[]>;
72
+ export declare function handleBuildModeMessage(config: AppConfig, text: string, intentRuntime: IntentRuntime, hooks?: BuildModeHandlerOptions, eventSource?: BuilderEventSource): Promise<string[] | null>;