silvermoon 0.1.0 → 0.1.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/README.md +14 -10
- package/README.zh-CN.md +14 -10
- package/assets/silvermoon-avatar.svg +395 -0
- package/docs/getting-started.md +19 -3
- package/docs/maintaining.md +4 -1
- package/docs/npm-package-releases.md +25 -7
- package/docs/operations.md +21 -9
- package/docs/reference.md +44 -19
- package/docs/repository-tasks.md +9 -0
- package/package.json +1 -1
- package/skills/silvermoon/SKILL.md +7 -2
- package/src/cli.js +49 -9
- package/src/create-idea.js +9 -9
- package/src/dialogue.js +34 -10
- package/src/index.js +40 -3
- package/src/language.js +37 -0
- package/src/observation.js +63 -18
- package/src/whatsnext.js +20 -8
|
@@ -92,13 +92,24 @@ The [`publish-npm.yml`](../.github/workflows/publish-npm.yml) workflow then:
|
|
|
92
92
|
1. verifies the tagged commit is reachable from refreshed `origin/main`;
|
|
93
93
|
2. installs the frozen pnpm dependencies;
|
|
94
94
|
3. runs the allowlisted release planner and confirms the version is absent
|
|
95
|
-
from npm;
|
|
95
|
+
from npm, or records that an exact-version rerun must skip publication;
|
|
96
96
|
4. runs `pnpm test:unit`, `pnpm test:contract`, `pnpm test:integration`, and
|
|
97
97
|
`pnpm check:skills`;
|
|
98
|
-
5.
|
|
99
|
-
|
|
100
|
-
6.
|
|
101
|
-
|
|
98
|
+
5. creates an isolated `git archive` staging tree and generates commit-pinned
|
|
99
|
+
English and Chinese package READMEs without changing the tagged checkout;
|
|
100
|
+
6. creates one tarball, records its path, SHA-256, npm shasum, registry
|
|
101
|
+
integrity, and complete file list, then passes that same file to
|
|
102
|
+
`npm run pack:check` and `npm run test:e2e`;
|
|
103
|
+
7. publishes that exact tarball with provenance and the derived npm dist-tag
|
|
104
|
+
when the version was absent; and
|
|
105
|
+
8. runs `verify-npm-release.mjs` until the registry is consistent or the
|
|
106
|
+
bounded retry window expires.
|
|
107
|
+
|
|
108
|
+
The post-publication verifier requires the exact version and dist-tag, registry
|
|
109
|
+
integrity and tarball bytes, package-level README, both tarball READMEs, npm
|
|
110
|
+
publish and SLSA provenance attestations, tagged Git commit, and commit-pinned
|
|
111
|
+
jsDelivr SVG responses to match the candidate. A successful run prints
|
|
112
|
+
`VERIFY_NPM_RELEASE_OK` with the verified identities.
|
|
102
113
|
|
|
103
114
|
Release runs are serialized within this repository. The registry preflight and
|
|
104
115
|
`npm publish` cannot form one cross-system transaction, so an external
|
|
@@ -110,13 +121,20 @@ duplicate publication without replacing the existing version.
|
|
|
110
121
|
Publication stops before `npm publish` when the tag is malformed, the release
|
|
111
122
|
key is unknown, the package is private, the package name or version differs
|
|
112
123
|
from the mapping and tag, the npm publish configuration is not public npmjs,
|
|
113
|
-
the commit is outside `origin/main`,
|
|
114
|
-
|
|
124
|
+
the commit is outside `origin/main`, registry state cannot be observed, or
|
|
125
|
+
validation fails. If the exact version already exists during a workflow rerun,
|
|
126
|
+
the publish step is skipped and the verifier must prove that registry content
|
|
127
|
+
is byte-identical to the rebuilt candidate and carries the expected provenance.
|
|
128
|
+
Any mismatch is a hard failure.
|
|
115
129
|
|
|
116
130
|
For a transient GitHub or registry failure before publication, rerun the same
|
|
117
131
|
workflow run. Do not move or recreate the tag. For a source, manifest, or
|
|
118
132
|
validation failure, make a new commit on `main`, choose a new version, and push
|
|
119
133
|
a new tag after the fix is merged. npm versions and release tags are immutable.
|
|
134
|
+
For a transient verification failure after publication, rerun only the failed
|
|
135
|
+
workflow job when GitHub offers that option; the planner recognizes the
|
|
136
|
+
existing version, skips `npm publish`, and performs the same complete
|
|
137
|
+
verification again.
|
|
120
138
|
|
|
121
139
|
## Add another package
|
|
122
140
|
|
package/docs/operations.md
CHANGED
|
@@ -9,6 +9,7 @@ publishing Silvermoon ideas.
|
|
|
9
9
|
npx silvermoon whats-next
|
|
10
10
|
npx silvermoon whats-next 01M36QGPNTXEPP61DA4KP4AVZF
|
|
11
11
|
npx silvermoon whats-next publish-documentation --json
|
|
12
|
+
npx silvermoon whats-next publish-documentation --language zh-CN
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
Without a selector, Silvermoon asks for a choice among multiple active ideas,
|
|
@@ -17,10 +18,13 @@ one, or many active ideas: only a selector chooses work. Completed and abandoned
|
|
|
17
18
|
ideas are excluded from default candidates. A selector is either a canonical
|
|
18
19
|
uppercase ULID or an exact, unique, case-sensitive alias.
|
|
19
20
|
|
|
20
|
-
The shared observation
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
The shared observation exposes the resolved content preference as
|
|
22
|
+
`configuration.preferredLanguage` and the built-in rendering locale as
|
|
23
|
+
`outputLanguage`. Instructions use the content preference for world entries,
|
|
24
|
+
same-world supporting artifacts, and the ledger. A caller may use
|
|
25
|
+
`--language en-US|zh-CN` to override only Silvermoon-owned output for one
|
|
26
|
+
`whats-next` invocation. Commands, identifiers, schema fields, protocol
|
|
27
|
+
markers, and verbatim tool output retain their original form.
|
|
24
28
|
|
|
25
29
|
Every invocation follows three strict layers. It first checks Git,
|
|
26
30
|
configuration compatibility, and `.agents/skills/silvermoon`. It then checks
|
|
@@ -48,10 +52,12 @@ require local HEAD to be aligned with the remote tip. Its preparation reports
|
|
|
48
52
|
omit the active-idea inventory because existing work does not replace explicit
|
|
49
53
|
creation intent.
|
|
50
54
|
|
|
51
|
-
`--language`
|
|
52
|
-
|
|
53
|
-
creation writes no language field and the idea dynamically
|
|
54
|
-
user, or `en-US` defaults.
|
|
55
|
+
For `create-idea`, `--language` normalizes any valid BCP 47 tag and writes it
|
|
56
|
+
to the new idea's `status.yaml` as a persistent content-language preference.
|
|
57
|
+
Without the option, creation writes no language field and the idea dynamically
|
|
58
|
+
inherits project, user, or `en-US` defaults. This is distinct from the
|
|
59
|
+
non-persistent `en-US|zh-CN` output override accepted by `whats-next` and
|
|
60
|
+
`check`.
|
|
55
61
|
|
|
56
62
|
The generated files remain untracked for review. Complete `Idea.md`, optionally
|
|
57
63
|
add a concise unique alias, inspect every path, and publish the initial idea
|
|
@@ -79,7 +85,8 @@ diff. Preserve unknown and concurrent work. Never force-push, use
|
|
|
79
85
|
`reset --hard`, broadly clean the worktree, or silently rewrite history.
|
|
80
86
|
|
|
81
87
|
After an observable change, run `whats-next` again. Do not poll an unchanged
|
|
82
|
-
observation.
|
|
88
|
+
observation. When the invocation used `--language`, every generated retry
|
|
89
|
+
command preserves the same canonical output-language option.
|
|
83
90
|
|
|
84
91
|
## Author World Contracts
|
|
85
92
|
|
|
@@ -115,6 +122,7 @@ Validate the complete candidate:
|
|
|
115
122
|
|
|
116
123
|
```sh
|
|
117
124
|
silvermoon check --worktree
|
|
125
|
+
silvermoon check --worktree --language zh-CN
|
|
118
126
|
git add .silvermoon/ideas/<ULID>/status.yaml
|
|
119
127
|
silvermoon check --staged
|
|
120
128
|
```
|
|
@@ -129,6 +137,10 @@ means the chosen project snapshot is valid; `1` means invalid or unavailable
|
|
|
129
137
|
and must block the commit; `2` means invalid CLI usage. Do not treat the
|
|
130
138
|
existence of a report as permission to commit.
|
|
131
139
|
|
|
140
|
+
`check --language en-US|zh-CN` changes only Silvermoon-owned report framing.
|
|
141
|
+
It is orthogonal to every check target and never changes the selected snapshot,
|
|
142
|
+
validation conclusion, problems, or exit status.
|
|
143
|
+
|
|
132
144
|
`check` does not infer that a status field was newly written, prove who
|
|
133
145
|
authorized it, compare it with a commit parent, or search history for its
|
|
134
146
|
origin. Those are workflow responsibilities: match an explicit human decision
|
package/docs/reference.md
CHANGED
|
@@ -67,13 +67,21 @@ world revision and does not change lifecycle decisions. Explicit
|
|
|
67
67
|
`abandoned: false`, derived state, criteria mirrors, source locators, unknown
|
|
68
68
|
keys, YAML aliases or anchors, comments, and noncanonical YAML are rejected.
|
|
69
69
|
|
|
70
|
-
Effective language resolves as `idea language > project
|
|
71
|
-
user preferredLanguage > en-US`. Every complete
|
|
72
|
-
resolved non-empty tag as
|
|
73
|
-
language remains dynamically
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
Effective content language resolves as `idea language > project
|
|
71
|
+
preferredLanguage > user preferredLanguage > en-US`. Every complete
|
|
72
|
+
observation exposes the resolved non-empty tag as
|
|
73
|
+
`configuration.preferredLanguage`. Missing idea language remains dynamically
|
|
74
|
+
inherited and is never written back. Dialogue project status presents this
|
|
75
|
+
effective value as `content language` (`内容语言`).
|
|
76
|
+
|
|
77
|
+
Every command observation also exposes an independent `outputLanguage`.
|
|
78
|
+
Silvermoon's built-in output locales are exactly `en-US` and `zh-CN`.
|
|
79
|
+
`whats-next --language <tag>` and `check --language <tag>` normalize casing
|
|
80
|
+
before enforcing that allowlist, apply only to the current invocation, and
|
|
81
|
+
take display precedence over content language. Without an explicit output
|
|
82
|
+
override, content tags beginning with `zh` select `zh-CN`; every other content
|
|
83
|
+
tag selects `en-US`. Output selection never writes configuration or idea
|
|
84
|
+
status.
|
|
77
85
|
|
|
78
86
|
State is derived in order:
|
|
79
87
|
|
|
@@ -88,9 +96,9 @@ State is derived in order:
|
|
|
88
96
|
## Public Commands
|
|
89
97
|
|
|
90
98
|
```sh
|
|
91
|
-
silvermoon whats-next [idea] [--trace <file.trace.jsonl>]
|
|
99
|
+
silvermoon whats-next [idea] [--language <en-US|zh-CN>] [--trace <file.trace.jsonl>]
|
|
92
100
|
silvermoon create-idea [--language <tag>] [--trace <file.trace.jsonl>]
|
|
93
|
-
silvermoon check [--remote | --commit <revision> | --staged | --worktree] [--trace <file.trace.jsonl>]
|
|
101
|
+
silvermoon check [--remote | --commit <revision> | --staged | --worktree] [--language <en-US|zh-CN>] [--trace <file.trace.jsonl>]
|
|
94
102
|
```
|
|
95
103
|
|
|
96
104
|
`whats-next` and `create-idea` build one dialogue envelope:
|
|
@@ -100,19 +108,24 @@ silvermoon check [--remote | --commit <revision> | --staged | --worktree] [--tra
|
|
|
100
108
|
"intention": {
|
|
101
109
|
"command": "whats-next",
|
|
102
110
|
"args": {
|
|
103
|
-
"idea": null
|
|
111
|
+
"idea": null,
|
|
112
|
+
"language": null
|
|
104
113
|
}
|
|
105
114
|
},
|
|
106
|
-
"observation": {
|
|
115
|
+
"observation": {
|
|
116
|
+
"outputLanguage": "en-US"
|
|
117
|
+
},
|
|
107
118
|
"outcomes": [],
|
|
108
119
|
"instructions": ""
|
|
109
120
|
}
|
|
110
121
|
```
|
|
111
122
|
|
|
112
|
-
- `intention` contains the command and normalized business arguments.
|
|
113
|
-
|
|
123
|
+
- `intention` contains the command and normalized business arguments. For
|
|
124
|
+
`whats-next` and `check`, `args.language` is the canonical temporary output
|
|
125
|
+
override or `null`. Output format is not part of the intention.
|
|
114
126
|
- `observation` describes the reliable facts for the requested command and
|
|
115
|
-
intent, not a mandatory global idea inventory.
|
|
127
|
+
intent, not a mandatory global idea inventory. `outputLanguage` is present
|
|
128
|
+
even when Git, configuration, or a requested snapshot is unavailable.
|
|
116
129
|
- `outcomes` records only high-level repository side effects actually
|
|
117
130
|
attempted by this invocation. Each item has `type`, `status` (`success` or
|
|
118
131
|
`failure`), and `summary`. An empty array means no side effect was attempted.
|
|
@@ -150,7 +163,11 @@ stdout, or stderr. The path is relative to the caller's working directory when
|
|
|
150
163
|
not absolute. Events are buffered so a trace inside the repository cannot
|
|
151
164
|
affect that invocation's worktree observation. The file is written after the
|
|
152
165
|
measured command work finishes and uses exclusive creation, so an existing
|
|
153
|
-
normalized target is never overwritten.
|
|
166
|
+
normalized target is never overwritten. The top command span records the
|
|
167
|
+
canonical output-language override or `null` for `whats-next` and `check`.
|
|
168
|
+
|
|
169
|
+
Unsupported output locales, empty values, and invalid BCP 47 tags are usage
|
|
170
|
+
errors with exit status `2`, before repository inspection or fetch.
|
|
154
171
|
|
|
155
172
|
Observations are discriminated by command intent and `state`:
|
|
156
173
|
|
|
@@ -198,9 +215,9 @@ to discuss and run `create-idea`.
|
|
|
198
215
|
`create-idea` requires the configured primary branch and upstream plus a clean
|
|
199
216
|
worktree, then creates one canonical scaffold. It does not fetch, compare
|
|
200
217
|
remote ancestry, or require local HEAD to match the remote tip. Its optional
|
|
201
|
-
language
|
|
202
|
-
|
|
203
|
-
stage, commit, push, or record approval.
|
|
218
|
+
content-language choice accepts any canonical BCP 47 tag, is normalized before
|
|
219
|
+
preflight, and is persisted to the new idea; without it the status remains
|
|
220
|
+
dynamically inherited. It does not stage, commit, push, or record approval.
|
|
204
221
|
|
|
205
222
|
## Validation Targets
|
|
206
223
|
|
|
@@ -233,12 +250,16 @@ Unlike dialogue commands, `check --json` contains **only** `intention` and
|
|
|
233
250
|
{
|
|
234
251
|
"intention": {
|
|
235
252
|
"command": "check",
|
|
236
|
-
"args": {
|
|
253
|
+
"args": {
|
|
254
|
+
"target": { "type": "staged" },
|
|
255
|
+
"language": null
|
|
256
|
+
}
|
|
237
257
|
},
|
|
238
258
|
"observation": {
|
|
239
259
|
"state": "project-ready",
|
|
240
260
|
"root": "D:\\Code\\silvermoon",
|
|
241
261
|
"version": { "type": "staged" },
|
|
262
|
+
"outputLanguage": "en-US",
|
|
242
263
|
"configuration": {
|
|
243
264
|
"primaryRepository": "https://example.com/owner/repository.git",
|
|
244
265
|
"primaryBranch": "main",
|
|
@@ -267,6 +288,10 @@ Unlike dialogue commands, `check --json` contains **only** `intention` and
|
|
|
267
288
|
reports `commit: null` and a problem. Staged and worktree versions only
|
|
268
289
|
contain `type`.
|
|
269
290
|
|
|
291
|
+
`--language en-US|zh-CN` is orthogonal to every target. It changes only
|
|
292
|
+
Silvermoon-owned natural-language framing and leaves the target, snapshot,
|
|
293
|
+
validation state, problems, and exit status unchanged.
|
|
294
|
+
|
|
270
295
|
The `check` observation has its own discriminated states:
|
|
271
296
|
|
|
272
297
|
- `project-ready` has root, version, resolved configuration, idea summary,
|
package/docs/repository-tasks.md
CHANGED
|
@@ -11,8 +11,10 @@ optional transport and are not protocol state.
|
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
13
|
silvermoon whats-next [idea]
|
|
14
|
+
silvermoon whats-next [idea] --language zh-CN
|
|
14
15
|
silvermoon create-idea
|
|
15
16
|
silvermoon check
|
|
17
|
+
silvermoon check --language en-US
|
|
16
18
|
silvermoon check --worktree
|
|
17
19
|
silvermoon check --staged
|
|
18
20
|
silvermoon check --commit HEAD
|
|
@@ -33,6 +35,13 @@ HEAD to match the remote tip. If hygiene blocks explicit creation, perform only
|
|
|
33
35
|
that blocking action and then retry `create-idea` so active-idea selection
|
|
34
36
|
cannot replace the pending create intent.
|
|
35
37
|
|
|
38
|
+
Use `--language en-US|zh-CN` with `whats-next` or `check` only when the user
|
|
39
|
+
explicitly requests a temporary output locale. Preserve the canonical option
|
|
40
|
+
on every hygiene retry. It never changes the content language recorded in
|
|
41
|
+
project, user, or idea configuration. `create-idea --language <tag>` remains a
|
|
42
|
+
separate persistent content-language choice and accepts any canonical BCP 47
|
|
43
|
+
tag.
|
|
44
|
+
|
|
36
45
|
## Decisions And Publication
|
|
37
46
|
|
|
38
47
|
`whats-next` may fetch after local readiness passes, but it does not move the
|
package/package.json
CHANGED
|
@@ -19,6 +19,10 @@ repository or external actions with ordinary tools and Git.
|
|
|
19
19
|
- Bare `whats-next` lists active ideas and offers creation, even when exactly one idea is active.
|
|
20
20
|
Never infer selection; require an explicit ULID or alias.
|
|
21
21
|
- Use `--json` only when a programmatic consumer needs the envelope.
|
|
22
|
+
- Use `--language en-US|zh-CN` with `whats-next` or `check` only when the user
|
|
23
|
+
explicitly requests a temporary output locale. Preserve the same canonical
|
|
24
|
+
option in every hygiene retry. It changes Silvermoon-owned rendering for
|
|
25
|
+
that invocation only, never project or idea content language.
|
|
22
26
|
- Treat each command's `intention`, `observation`, `outcomes`, and `instructions`
|
|
23
27
|
as one report. Read every problem and all ordered instructions; never combine
|
|
24
28
|
reports.
|
|
@@ -73,8 +77,9 @@ review; never ask for approval of unpublished content. Publication is not
|
|
|
73
77
|
approval and must not change `status.yaml`.
|
|
74
78
|
|
|
75
79
|
An Agent may derive a concise, unique alias; do not ask for a name solely for
|
|
76
|
-
the alias. Pass
|
|
77
|
-
stable language override.
|
|
80
|
+
the alias. Pass `create-idea --language <tag>` only when the user explicitly
|
|
81
|
+
requests a stable content-language override. Unlike the temporary output
|
|
82
|
+
override, creation accepts any canonical BCP 47 tag and persists it.
|
|
78
83
|
|
|
79
84
|
## Continue The Selected Idea
|
|
80
85
|
|
package/src/cli.js
CHANGED
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
Option,
|
|
7
7
|
} from "commander";
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
canonicalizeLanguageTag,
|
|
11
|
+
canonicalizeOutputLanguage,
|
|
12
|
+
} from "./language.js";
|
|
10
13
|
import { renderCheck, renderDialogue } from "./dialogue.js";
|
|
11
14
|
import { checkRepository } from "./index.js";
|
|
12
15
|
import { createIdea } from "./create-idea.js";
|
|
@@ -51,7 +54,7 @@ export function render(report, json, io) {
|
|
|
51
54
|
);
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
function
|
|
57
|
+
function contentLanguageArgument(value) {
|
|
55
58
|
try {
|
|
56
59
|
return canonicalizeLanguageTag(value);
|
|
57
60
|
} catch (caught) {
|
|
@@ -59,6 +62,14 @@ function languageArgument(value) {
|
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
function outputLanguageArgument(value) {
|
|
66
|
+
try {
|
|
67
|
+
return canonicalizeOutputLanguage(value);
|
|
68
|
+
} catch (caught) {
|
|
69
|
+
throw new InvalidArgumentError(caught.message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
62
73
|
export function createProgram(io = console) {
|
|
63
74
|
const program = new Command();
|
|
64
75
|
program
|
|
@@ -79,10 +90,12 @@ export function createProgram(io = console) {
|
|
|
79
90
|
Examples:
|
|
80
91
|
$ silvermoon whats-next
|
|
81
92
|
$ silvermoon whats-next <idea>
|
|
93
|
+
$ silvermoon whats-next <idea> --language zh-CN
|
|
82
94
|
$ silvermoon whats-next <idea> --json
|
|
83
95
|
$ silvermoon whats-next <idea> --trace whats-next.trace.jsonl
|
|
84
96
|
$ silvermoon create-idea
|
|
85
97
|
$ silvermoon check
|
|
98
|
+
$ silvermoon check --language en-US
|
|
86
99
|
$ silvermoon check --worktree
|
|
87
100
|
$ silvermoon check --staged
|
|
88
101
|
$ silvermoon check --commit HEAD
|
|
@@ -91,13 +104,26 @@ Examples:
|
|
|
91
104
|
addCommonOptions(
|
|
92
105
|
program
|
|
93
106
|
.command("whats-next [idea]")
|
|
94
|
-
.description("observe project, repository, and idea readiness")
|
|
107
|
+
.description("observe project, repository, and idea readiness")
|
|
108
|
+
.option(
|
|
109
|
+
"--language <tag>",
|
|
110
|
+
"use a built-in output language (en-US or zh-CN) for this invocation",
|
|
111
|
+
outputLanguageArgument,
|
|
112
|
+
),
|
|
95
113
|
).action(async (idea, options) => {
|
|
96
114
|
const report = await withTraceFile(
|
|
97
115
|
options.trace,
|
|
98
116
|
"command.whats-next",
|
|
99
|
-
{
|
|
100
|
-
|
|
117
|
+
{
|
|
118
|
+
command: "whats-next",
|
|
119
|
+
outputLanguage: options.language ?? null,
|
|
120
|
+
processId: process.pid,
|
|
121
|
+
},
|
|
122
|
+
() => whatsNext({
|
|
123
|
+
idea,
|
|
124
|
+
language: options.language,
|
|
125
|
+
root: options.root,
|
|
126
|
+
}),
|
|
101
127
|
);
|
|
102
128
|
render(report, options.json, io);
|
|
103
129
|
program.setOptionValue("resultCode", 0);
|
|
@@ -109,14 +135,18 @@ Examples:
|
|
|
109
135
|
.description("create one structured idea scaffold after readiness checks")
|
|
110
136
|
.option(
|
|
111
137
|
"--language <tag>",
|
|
112
|
-
"persist a canonical language override on the new idea",
|
|
113
|
-
|
|
138
|
+
"persist a canonical content language override on the new idea",
|
|
139
|
+
contentLanguageArgument,
|
|
114
140
|
),
|
|
115
141
|
).action(async (options) => {
|
|
116
142
|
const report = await withTraceFile(
|
|
117
143
|
options.trace,
|
|
118
144
|
"command.create-idea",
|
|
119
|
-
{
|
|
145
|
+
{
|
|
146
|
+
command: "create-idea",
|
|
147
|
+
contentLanguage: options.language ?? null,
|
|
148
|
+
processId: process.pid,
|
|
149
|
+
},
|
|
120
150
|
() => createIdea({
|
|
121
151
|
language: options.language,
|
|
122
152
|
root: options.root,
|
|
@@ -130,6 +160,11 @@ Examples:
|
|
|
130
160
|
program
|
|
131
161
|
.command("check")
|
|
132
162
|
.description("validate Silvermoon configuration and idea state")
|
|
163
|
+
.option(
|
|
164
|
+
"--language <tag>",
|
|
165
|
+
"use a built-in output language (en-US or zh-CN) for this invocation",
|
|
166
|
+
outputLanguageArgument,
|
|
167
|
+
)
|
|
133
168
|
.addOption(new Option("--remote", "fetch and validate the configured primary tip").conflicts(["commit", "staged", "worktree"]))
|
|
134
169
|
.addOption(new Option("--commit <revision>", "validate one local commit snapshot").conflicts(["remote", "staged", "worktree"]))
|
|
135
170
|
.addOption(new Option("--staged", "validate the index snapshot").conflicts(["remote", "commit", "worktree"]))
|
|
@@ -138,9 +173,14 @@ Examples:
|
|
|
138
173
|
const report = await withTraceFile(
|
|
139
174
|
options.trace,
|
|
140
175
|
"command.check",
|
|
141
|
-
{
|
|
176
|
+
{
|
|
177
|
+
command: "check",
|
|
178
|
+
outputLanguage: options.language ?? null,
|
|
179
|
+
processId: process.pid,
|
|
180
|
+
},
|
|
142
181
|
() => checkRepository({
|
|
143
182
|
commit: options.commit,
|
|
183
|
+
language: options.language,
|
|
144
184
|
remote: options.remote,
|
|
145
185
|
root: options.root,
|
|
146
186
|
staged: options.staged,
|
package/src/create-idea.js
CHANGED
|
@@ -194,7 +194,7 @@ export async function createIdea({
|
|
|
194
194
|
projectInstructions(
|
|
195
195
|
observed,
|
|
196
196
|
observed.observation.root,
|
|
197
|
-
observed.
|
|
197
|
+
observed.outputLanguage,
|
|
198
198
|
recheckCommand,
|
|
199
199
|
),
|
|
200
200
|
);
|
|
@@ -243,7 +243,7 @@ export async function createIdea({
|
|
|
243
243
|
observation: readiness.observation,
|
|
244
244
|
outcomes,
|
|
245
245
|
cleanup: caught.cleanup,
|
|
246
|
-
language: observed.
|
|
246
|
+
language: observed.outputLanguage,
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -270,7 +270,7 @@ export async function createIdea({
|
|
|
270
270
|
observation: readiness.observation,
|
|
271
271
|
outcomes,
|
|
272
272
|
cleanup,
|
|
273
|
-
language: observed.
|
|
273
|
+
language: observed.outputLanguage,
|
|
274
274
|
});
|
|
275
275
|
}
|
|
276
276
|
|
|
@@ -318,7 +318,7 @@ export async function createIdea({
|
|
|
318
318
|
"create-idea-scaffold",
|
|
319
319
|
"success",
|
|
320
320
|
localize(
|
|
321
|
-
observed.
|
|
321
|
+
observed.outputLanguage,
|
|
322
322
|
`Created idea ${id} at ${paths.ideaPath}.`,
|
|
323
323
|
`已在 ${paths.ideaPath} 创建 idea ${id}。`,
|
|
324
324
|
),
|
|
@@ -330,9 +330,9 @@ export async function createIdea({
|
|
|
330
330
|
}),
|
|
331
331
|
outcomes,
|
|
332
332
|
localize(
|
|
333
|
-
observed.
|
|
334
|
-
`Use ${observed.
|
|
335
|
-
`使用 ${observed.
|
|
333
|
+
observed.outputLanguage,
|
|
334
|
+
`Use ${observed.contentLanguage} for natural-language content while describing the requested Ideal World in ${paths.ideaDocumentPath}; keep the stable IDs and placeholders in ${paths.implementationDocumentPath}, ${paths.deploymentDocumentPath}, and ${paths.ledgerPath} synchronized.`,
|
|
335
|
+
`使用 ${observed.contentLanguage} 在 ${paths.ideaDocumentPath} 中描述请求的理想契约,并保持 ${paths.implementationDocumentPath}、${paths.deploymentDocumentPath} 与 ${paths.ledgerPath} 中的稳定 ID 和占位同步。`,
|
|
336
336
|
),
|
|
337
337
|
);
|
|
338
338
|
} catch (caught) {
|
|
@@ -365,7 +365,7 @@ export async function createIdea({
|
|
|
365
365
|
observation: readiness.observation,
|
|
366
366
|
outcomes,
|
|
367
367
|
cleanup,
|
|
368
|
-
language: observed.
|
|
368
|
+
language: observed.outputLanguage,
|
|
369
369
|
});
|
|
370
370
|
}
|
|
371
371
|
}
|
|
@@ -379,6 +379,6 @@ export async function createIdea({
|
|
|
379
379
|
observation: readiness.observation,
|
|
380
380
|
outcomes,
|
|
381
381
|
cleanup,
|
|
382
|
-
language: observed.
|
|
382
|
+
language: observed.outputLanguage,
|
|
383
383
|
});
|
|
384
384
|
}
|
package/src/dialogue.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_LANGUAGE,
|
|
3
|
+
resolveOutputLanguage,
|
|
4
|
+
} from "./language.js";
|
|
5
|
+
|
|
1
6
|
const ACTIVE_STATES = new Set(["preparing", "implementing", "deploying"]);
|
|
2
7
|
const IDEA_STATES = [
|
|
3
8
|
"preparing",
|
|
@@ -71,11 +76,19 @@ export function createEnvelope(intention, observation, outcomes, instructions) {
|
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
export function dialogueReadyObservation(observation, state, details = {}) {
|
|
74
|
-
const { root, version, configuration, problems } = observation;
|
|
75
|
-
return {
|
|
79
|
+
const { root, version, configuration, outputLanguage, problems } = observation;
|
|
80
|
+
return {
|
|
81
|
+
state,
|
|
82
|
+
root,
|
|
83
|
+
version,
|
|
84
|
+
configuration,
|
|
85
|
+
outputLanguage,
|
|
86
|
+
problems,
|
|
87
|
+
...details,
|
|
88
|
+
};
|
|
76
89
|
}
|
|
77
90
|
|
|
78
|
-
function renderIntention(intention, language) {
|
|
91
|
+
function renderIntention(intention, language, contentLanguage) {
|
|
79
92
|
if (intention.command === "whats-next") {
|
|
80
93
|
return intention.args.idea === null
|
|
81
94
|
? localize(
|
|
@@ -93,8 +106,8 @@ function renderIntention(intention, language) {
|
|
|
93
106
|
return intention.args.language === null
|
|
94
107
|
? localize(
|
|
95
108
|
language,
|
|
96
|
-
`Create one new idea and use ${
|
|
97
|
-
`创建一个新 idea,并使用 ${
|
|
109
|
+
`Create one new idea and use ${contentLanguage} for natural-language content.`,
|
|
110
|
+
`创建一个新 idea,并使用 ${contentLanguage} 撰写自然语言内容。`,
|
|
98
111
|
)
|
|
99
112
|
: localize(
|
|
100
113
|
language,
|
|
@@ -198,7 +211,7 @@ function renderObservation(observation, language) {
|
|
|
198
211
|
`- ${localize(language, "primary", "主仓库")}: ${codeSpan(`${observation.configuration.primaryRepository}#${observation.configuration.primaryBranch}`)}`,
|
|
199
212
|
);
|
|
200
213
|
lines.push(
|
|
201
|
-
`- ${localize(language, "
|
|
214
|
+
`- ${localize(language, "content language", "内容语言")}: ${observation.configuration.preferredLanguage}`,
|
|
202
215
|
);
|
|
203
216
|
}
|
|
204
217
|
if (observation.ideas) {
|
|
@@ -240,9 +253,16 @@ function renderOutcomes(outcomes, language) {
|
|
|
240
253
|
}
|
|
241
254
|
|
|
242
255
|
export function renderDialogue(report) {
|
|
243
|
-
const
|
|
256
|
+
const contentLanguage =
|
|
244
257
|
report.observation.configuration?.preferredLanguage
|
|
245
|
-
??
|
|
258
|
+
?? DEFAULT_LANGUAGE;
|
|
259
|
+
const language = report.observation.outputLanguage
|
|
260
|
+
?? resolveOutputLanguage({
|
|
261
|
+
content: contentLanguage,
|
|
262
|
+
override: report.intention.command === "whats-next"
|
|
263
|
+
? report.intention.args.language ?? undefined
|
|
264
|
+
: undefined,
|
|
265
|
+
}).tag;
|
|
246
266
|
const visibleOutcomes = report.outcomes.filter((item) =>
|
|
247
267
|
!(item.type === "fetch-primary"
|
|
248
268
|
&& item.status === "success"
|
|
@@ -252,7 +272,7 @@ export function renderDialogue(report) {
|
|
|
252
272
|
const sections = [
|
|
253
273
|
[
|
|
254
274
|
localize(language, "Current instruction", "本次指示"),
|
|
255
|
-
renderIntention(report.intention, language),
|
|
275
|
+
renderIntention(report.intention, language, contentLanguage),
|
|
256
276
|
],
|
|
257
277
|
[
|
|
258
278
|
localize(language, "Project status", "项目现状"),
|
|
@@ -273,7 +293,11 @@ export function renderDialogue(report) {
|
|
|
273
293
|
}
|
|
274
294
|
|
|
275
295
|
export function renderCheck(report) {
|
|
276
|
-
const language = report.observation.
|
|
296
|
+
const language = report.observation.outputLanguage
|
|
297
|
+
?? resolveOutputLanguage({
|
|
298
|
+
content: report.observation.configuration?.preferredLanguage,
|
|
299
|
+
override: report.intention.args.language ?? undefined,
|
|
300
|
+
}).tag;
|
|
277
301
|
const { target } = report.intention.args;
|
|
278
302
|
const version = renderVersion(report.observation.version);
|
|
279
303
|
const label = target.type === "commit"
|