silvermoon 0.1.3 → 0.2.0-rc.1

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/src/dialogue.js CHANGED
@@ -1,24 +1,10 @@
1
+ import { localize } from "./language.js";
1
2
  import {
2
- DEFAULT_LANGUAGE,
3
- resolveOutputLanguage,
4
- } from "./language.js";
3
+ ACTIVE_IDEA_STATES,
4
+ IDEA_STATES,
5
+ } from "./ideas.js";
5
6
 
6
- const ACTIVE_STATES = new Set(["preparing", "implementing", "deploying"]);
7
- const IDEA_STATES = [
8
- "preparing",
9
- "implementing",
10
- "deploying",
11
- "completed",
12
- "abandoned",
13
- ];
14
-
15
- function isChinese(language) {
16
- return language?.toLowerCase().startsWith("zh");
17
- }
18
-
19
- export function localize(language, english, chinese) {
20
- return isChinese(language) ? chinese : english;
21
- }
7
+ const ACTIVE_STATES = new Set(ACTIVE_IDEA_STATES);
22
8
 
23
9
  export function diagnosticProblem(diagnostic, language = "en-US") {
24
10
  const location = diagnostic.path ? ` (${diagnostic.path})` : "";
@@ -44,10 +30,6 @@ export function diagnosticInstruction(diagnostic, language = "en-US") {
44
30
  );
45
31
  }
46
32
 
47
- export function outcome(type, status, summary) {
48
- return { type, status, summary };
49
- }
50
-
51
33
  export function summarizeIdeas(ideas) {
52
34
  const counts = Object.fromEntries(IDEA_STATES.map((state) => [state, 0]));
53
35
  const activeIdeas = [];
@@ -71,10 +53,6 @@ export function resolvedConfiguration(config, preferredLanguage) {
71
53
  };
72
54
  }
73
55
 
74
- export function createEnvelope(intention, observation, outcomes, instructions) {
75
- return { intention, observation, outcomes, instructions };
76
- }
77
-
78
56
  export function dialogueReadyObservation(observation, state, details = {}) {
79
57
  const { root, version, configuration, outputLanguage, problems } = observation;
80
58
  return {
@@ -88,281 +66,4 @@ export function dialogueReadyObservation(observation, state, details = {}) {
88
66
  };
89
67
  }
90
68
 
91
- function renderIntention(intention, language, contentLanguage) {
92
- if (intention.command === "whats-next") {
93
- return intention.args.idea === null
94
- ? localize(
95
- language,
96
- "Determine the available next work.",
97
- "查看当前可推进的工作。",
98
- )
99
- : localize(
100
- language,
101
- `Determine what is next for idea ${intention.args.idea}.`,
102
- `查看 idea ${intention.args.idea} 接下来应做什么。`,
103
- );
104
- }
105
- if (intention.command === "create-idea") {
106
- return intention.args.language === null
107
- ? localize(
108
- language,
109
- `Create one new idea and use ${contentLanguage} for natural-language content.`,
110
- `创建一个新 idea,并使用 ${contentLanguage} 撰写自然语言内容。`,
111
- )
112
- : localize(
113
- language,
114
- `Create one new idea with language ${intention.args.language}.`,
115
- `使用 ${intention.args.language} 创建一个新 idea。`,
116
- );
117
- }
118
- throw new Error(`Cannot render dialogue for ${intention.command}`);
119
- }
120
-
121
- function renderVersion(version) {
122
- if (!version) return null;
123
- if (version.type === "commit" || version.type === "remote") {
124
- return version.commit === null
125
- ? version.type
126
- : `${version.type} ${version.commit}`;
127
- }
128
- return version.type;
129
- }
130
-
131
- function codeSpan(value) {
132
- const text = String(value);
133
- let longest = 0;
134
- for (const [run] of text.matchAll(/`+/g)) {
135
- longest = Math.max(longest, run.length);
136
- }
137
- const fence = "`".repeat(longest + 1);
138
- return longest === 0 ? `${fence}${text}${fence}` : `${fence} ${text} ${fence}`;
139
- }
140
-
141
- function renderObservation(observation, language) {
142
- if (observation.state === "idea-selected") {
143
- const idea = observation.selectedIdea;
144
- const alias = idea.alias === undefined ? "" : ` (${idea.alias})`;
145
- return localize(
146
- language,
147
- `The project and repository are ready. Selected idea: ${codeSpan(idea.id)}${alias}; state: ${idea.state}.`,
148
- `项目与 repository 已就绪。当前 idea:${codeSpan(idea.id)}${alias};状态:${idea.state}。`,
149
- );
150
- }
151
- if (observation.state === "idea-created") {
152
- return localize(
153
- language,
154
- `The local repository was ready before creation. Created idea: ${codeSpan(observation.createdIdea.id)}; path: ${codeSpan(observation.createdIdea.path)}; state: preparing.`,
155
- `创建前项目与本地 repository 已就绪。新建 idea:${codeSpan(observation.createdIdea.id)};路径:${codeSpan(observation.createdIdea.path)};状态:preparing。`,
156
- );
157
- }
158
- if (observation.state === "idea-create-failed") {
159
- return localize(
160
- language,
161
- "The repository was ready before creation, but creating the idea failed.",
162
- "创建前项目与 repository 已就绪,但创建 idea 失败。",
163
- );
164
- }
165
- const state = {
166
- "project-setup-required": localize(
167
- language,
168
- "The project requires Silvermoon setup.",
169
- "项目需要完成 Silvermoon 整备。",
170
- ),
171
- "repository-sync-required": localize(
172
- language,
173
- "The project is configured, but the repository requires synchronization.",
174
- "项目配置已就绪,但 repository 仍需整备或同步。",
175
- ),
176
- "repository-preparation-required": localize(
177
- language,
178
- "The project is ready, but the local repository must be prepared before creating an idea.",
179
- "项目已就绪,但创建 idea 前仍需整备本地 repository。",
180
- ),
181
- "phase-guidance-invalid": localize(
182
- language,
183
- "The project and repository are ready, but the current phase guidance is invalid.",
184
- "项目与 repository 已就绪,但当前阶段 guidance 无效。",
185
- ),
186
- "navigation-ready": localize(
187
- language,
188
- observation.ideas?.activeIdeas.length > 0
189
- ? "The project and repository are ready, and work is available."
190
- : "The project and repository are ready, with no active idea.",
191
- observation.ideas?.activeIdeas.length > 0
192
- ? "项目与 repository 已就绪,当前有工作可以推进。"
193
- : "项目与 repository 已就绪,当前没有 active idea。",
194
- ),
195
- "idea-not-found": localize(
196
- language,
197
- "The project and repository are ready, but the requested idea was not found.",
198
- "项目与 repository 已就绪,但未找到指定的 idea。",
199
- ),
200
- }[observation.state];
201
- const lines = [
202
- state,
203
- `- ${localize(language, "root", "根目录")}: ${codeSpan(observation.root)}`,
204
- ];
205
- if (observation.observedThrough) {
206
- lines.push(
207
- `- ${localize(language, "observed through", "观测至")}: ${observation.observedThrough}`,
208
- );
209
- }
210
- const version = renderVersion(observation.version);
211
- if (version) {
212
- lines.push(`- ${localize(language, "version", "版本")}: ${codeSpan(version)}`);
213
- }
214
- if (observation.configuration) {
215
- lines.push(
216
- `- ${localize(language, "primary", "主仓库")}: ${codeSpan(`${observation.configuration.primaryRepository}#${observation.configuration.primaryBranch}`)}`,
217
- );
218
- lines.push(
219
- `- ${localize(language, "content language", "内容语言")}: ${observation.configuration.preferredLanguage}`,
220
- );
221
- }
222
- if (observation.ideas) {
223
- const counts = observation.ideas.counts;
224
- lines.push(
225
- `- ${localize(language, "ideas", "ideas")}: preparing=${counts.preparing}, implementing=${counts.implementing}, `
226
- + `deploying=${counts.deploying}, completed=${counts.completed}, abandoned=${counts.abandoned}`,
227
- );
228
- }
229
- if (
230
- observation.state === "phase-guidance-invalid"
231
- && observation.selectedIdea
232
- ) {
233
- const idea = observation.selectedIdea;
234
- const alias = idea.alias === undefined ? "" : ` (${idea.alias})`;
235
- lines.push(
236
- `- ${localize(language, "selected idea", "当前 idea")}: `
237
- + `${codeSpan(idea.id)}${alias}; ${localize(language, "state", "状态")}: ${idea.state}`,
238
- );
239
- }
240
- const sections = [`${lines[0]}\n\n${lines.slice(1).join("\n")}`];
241
- const candidates = observation.state === "idea-not-found"
242
- ? observation.candidates
243
- : observation.ideas?.activeIdeas;
244
- if (candidates?.length > 0) {
245
- const active = candidates.map((idea) => {
246
- const alias = idea.alias === undefined ? "" : ` (${idea.alias})`;
247
- return `- ${codeSpan(idea.id)}${alias} ${idea.state}`;
248
- });
249
- sections.push(`### ${localize(language, "Ideas you can continue", "可继续推进的想法")}\n\n${active.join("\n")}`);
250
- }
251
- if (observation.problems.length > 0) {
252
- const problems = observation.problems.map((problem) =>
253
- `- [${problem.type}] ${problem.summary}`
254
- );
255
- sections.push(`### ${localize(language, "Issues to address", "需要处理的问题")}\n\n${problems.join("\n")}`);
256
- }
257
- return sections.join("\n\n");
258
- }
259
-
260
- function renderOutcomes(outcomes, language) {
261
- return outcomes
262
- .map((item) => {
263
- const status = item.status === "success"
264
- ? localize(language, "success", "成功")
265
- : localize(language, "failure", "失败");
266
- return `- ${status} [${item.type}]: ${item.summary}`;
267
- })
268
- .join("\n");
269
- }
270
-
271
- function renderGuidance(guidance, language) {
272
- const content = guidance.content
273
- .split("\n")
274
- .map((line) => line.length === 0 ? ">" : `> ${line}`)
275
- .join("\n");
276
- return [
277
- `- ${localize(language, "source", "来源")}: ${localize(
278
- language,
279
- "repository-owned additive guidance",
280
- "repository-owned 追加 guidance",
281
- )}`,
282
- `- ${localize(language, "phase", "阶段")}: ${codeSpan(guidance.phase)}`,
283
- `- ${localize(language, "path", "路径")}: ${codeSpan(guidance.path)}`,
284
- `- ${localize(language, "content revision", "内容 revision")}: ${codeSpan(guidance.contentRevision)}`,
285
- "",
286
- content,
287
- ].join("\n");
288
- }
289
-
290
- export function renderDialogue(report) {
291
- const contentLanguage =
292
- report.observation.configuration?.preferredLanguage
293
- ?? DEFAULT_LANGUAGE;
294
- const language = report.observation.outputLanguage
295
- ?? resolveOutputLanguage({
296
- content: contentLanguage,
297
- override: report.intention.command === "whats-next"
298
- ? report.intention.args.language ?? undefined
299
- : undefined,
300
- }).tag;
301
- const visibleOutcomes = report.outcomes.filter((item) =>
302
- !(item.type === "fetch-primary"
303
- && item.status === "success"
304
- && ["navigation-ready", "idea-selected", "idea-not-found", "idea-created", "idea-create-failed"]
305
- .includes(report.observation.state))
306
- );
307
- const sections = [
308
- [
309
- localize(language, "Current instruction", "本次指示"),
310
- renderIntention(report.intention, language, contentLanguage),
311
- ],
312
- [
313
- localize(language, "Project status", "项目现状"),
314
- renderObservation(report.observation, language),
315
- ],
316
- ...(visibleOutcomes.length > 0
317
- ? [[
318
- localize(language, "Actions and results", "本次操作及结果"),
319
- renderOutcomes(visibleOutcomes, language),
320
- ]]
321
- : []),
322
- [
323
- localize(language, "Suggested next steps", "下一步建议"),
324
- report.instructions,
325
- ],
326
- ...(report.observation.guidance === undefined
327
- ? []
328
- : [[
329
- localize(language, "Project phase guidance", "项目阶段 guidance"),
330
- renderGuidance(report.observation.guidance, language),
331
- ]]),
332
- ];
333
- return sections.map(([heading, body]) => `## ${heading}\n\n${body}`).join("\n\n");
334
- }
335
-
336
- export function renderCheck(report) {
337
- const language = report.observation.outputLanguage
338
- ?? resolveOutputLanguage({
339
- content: report.observation.configuration?.preferredLanguage,
340
- override: report.intention.args.language ?? undefined,
341
- }).tag;
342
- const { target } = report.intention.args;
343
- const version = renderVersion(report.observation.version);
344
- const label = target.type === "commit"
345
- ? `${target.type} ${target.revision}`
346
- : target.type;
347
- const valid = report.observation.state === "project-ready";
348
- const lines = [
349
- `## ${localize(language, "Check", "检查")}`,
350
- "",
351
- `- ${localize(language, "Target", "目标")}: ${codeSpan(label)}`,
352
- ];
353
- if (version) lines.push(`- ${localize(language, "Version", "版本")}: ${codeSpan(version)}`);
354
- lines.push(
355
- `- ${localize(language, "Result", "结果")}: ${valid
356
- ? localize(language, "valid", "通过")
357
- : localize(language, "invalid or unavailable", "未通过或无法验证")}`,
358
- );
359
- if (report.observation.problems.length > 0) {
360
- lines.push("", `### ${localize(language, "Issues to address", "需要处理的问题")}`, "");
361
- for (const problem of report.observation.problems) {
362
- lines.push(`- [${problem.type}] ${problem.summary}`);
363
- }
364
- }
365
- return lines.join("\n");
366
- }
367
-
368
- export { ACTIVE_STATES, IDEA_STATES };
69
+ export { ACTIVE_STATES, IDEA_STATES, localize };