silvermoon 0.0.1 → 0.0.3
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 +149 -236
- package/README.zh-CN.md +114 -199
- package/assets/silvermoon.svg +176 -175
- package/bin/silvermoon.js +0 -0
- package/docs/assets/silvermoon-avatar.svg +395 -0
- package/docs/core-concepts.md +69 -0
- package/docs/getting-started.md +115 -0
- package/docs/maintaining.md +56 -0
- package/docs/npm-package-releases.md +139 -0
- package/docs/operations.md +110 -0
- package/docs/reference.md +138 -0
- package/docs/repository-tasks.md +61 -0
- package/package.json +69 -65
- package/schema/v1/config.schema.json +27 -24
- package/schema/v1/definitions.schema.json +30 -25
- package/schema/v1/idea-status.schema.json +44 -41
- package/schema/v1/user-config.schema.json +19 -0
- package/skills/silvermoon/SKILL.md +216 -209
- package/skills/silvermoon/references/adoption.md +122 -122
- package/src/adoption.js +313 -313
- package/src/cli.js +200 -196
- package/src/config.js +193 -176
- package/src/create-idea.js +272 -235
- package/src/git.js +284 -284
- package/src/idea-layout.js +439 -439
- package/src/idea-templates.js +109 -109
- package/src/ideas.js +140 -131
- package/src/index.js +260 -260
- package/src/language.js +29 -0
- package/src/layout.js +21 -21
- package/src/repository.js +87 -87
- package/src/user-config.js +135 -0
- package/src/whatsnext.js +453 -378
- package/src/yaml.js +66 -66
package/src/idea-templates.js
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
export const IDEA_TEMPLATE = `#
|
|
2
|
-
|
|
3
|
-
## Intent
|
|
4
|
-
|
|
5
|
-
<!-- State the desired outcome in one or two sentences. -->
|
|
6
|
-
|
|
7
|
-
## Context
|
|
8
|
-
|
|
9
|
-
<!-- Describe the current problem, situation, or opportunity. -->
|
|
10
|
-
|
|
11
|
-
## Desired outcome
|
|
12
|
-
|
|
13
|
-
<!-- Describe the externally meaningful state that should become true. -->
|
|
14
|
-
|
|
15
|
-
## Scope
|
|
16
|
-
|
|
17
|
-
### In scope
|
|
18
|
-
|
|
19
|
-
<!-- Describe what this idea includes. -->
|
|
20
|
-
|
|
21
|
-
### Out of scope
|
|
22
|
-
|
|
23
|
-
<!-- Describe adjacent work this idea intentionally excludes. -->
|
|
24
|
-
|
|
25
|
-
## Constraints
|
|
26
|
-
|
|
27
|
-
<!-- Record material product, repository, compatibility, or operational constraints. -->
|
|
28
|
-
|
|
29
|
-
## Open questions
|
|
30
|
-
|
|
31
|
-
<!-- Record unresolved decisions. Remove this section when none remain. -->
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
export const IMPLEMENTATION_TEMPLATE = `# Implementation
|
|
35
|
-
|
|
36
|
-
## Steps
|
|
37
|
-
|
|
38
|
-
<!--
|
|
39
|
-
Give every step a stable I-Sxx identifier and a level-three heading.
|
|
40
|
-
Describe what will change, its boundaries, and important design details.
|
|
41
|
-
Do not use task-list checkboxes in this document.
|
|
42
|
-
-->
|
|
43
|
-
|
|
44
|
-
### I-S01: Step title
|
|
45
|
-
|
|
46
|
-
<!-- Describe this implementation step. -->
|
|
47
|
-
|
|
48
|
-
## Acceptance criteria
|
|
49
|
-
|
|
50
|
-
<!--
|
|
51
|
-
Give every criterion a stable I-ACxx identifier and a level-three heading.
|
|
52
|
-
Describe both the observable outcome and the method that proves it.
|
|
53
|
-
Do not create a separate validation section or use task-list checkboxes.
|
|
54
|
-
-->
|
|
55
|
-
|
|
56
|
-
### I-AC01: Criterion title
|
|
57
|
-
|
|
58
|
-
<!-- Describe the required outcome and how an Agent can prove it. -->
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
export const DEPLOYMENT_TEMPLATE = `# Deployment
|
|
62
|
-
|
|
63
|
-
## Steps
|
|
64
|
-
|
|
65
|
-
<!--
|
|
66
|
-
Give every step a stable D-Sxx identifier and a level-three heading.
|
|
67
|
-
Describe deployment or external-world verification work.
|
|
68
|
-
Do not use task-list checkboxes in this document.
|
|
69
|
-
-->
|
|
70
|
-
|
|
71
|
-
### D-S01: Step title
|
|
72
|
-
|
|
73
|
-
<!-- Describe this deployment or external-verification step. -->
|
|
74
|
-
|
|
75
|
-
## Acceptance criteria
|
|
76
|
-
|
|
77
|
-
<!--
|
|
78
|
-
Give every criterion a stable D-ACxx identifier and a level-three heading.
|
|
79
|
-
Describe both the observable external outcome and the method that proves it.
|
|
80
|
-
Do not create a separate validation section or use task-list checkboxes.
|
|
81
|
-
-->
|
|
82
|
-
|
|
83
|
-
### D-AC01: Criterion title
|
|
84
|
-
|
|
85
|
-
<!-- Describe the required external outcome and how an Agent can prove it. -->
|
|
86
|
-
`;
|
|
87
|
-
|
|
88
|
-
export const LEDGER_TEMPLATE = `# Ledger
|
|
89
|
-
|
|
90
|
-
## Implementation
|
|
91
|
-
|
|
92
|
-
###
|
|
93
|
-
|
|
94
|
-
- [ ] **I-S01:** Step title
|
|
95
|
-
|
|
96
|
-
###
|
|
97
|
-
|
|
98
|
-
- [ ] **I-AC01:** Criterion title
|
|
99
|
-
|
|
100
|
-
## Deployment
|
|
101
|
-
|
|
102
|
-
###
|
|
103
|
-
|
|
104
|
-
- [ ] **D-S01:** Step title
|
|
105
|
-
|
|
106
|
-
###
|
|
107
|
-
|
|
108
|
-
- [ ] **D-AC01:** Criterion title
|
|
109
|
-
`;
|
|
1
|
+
export const IDEA_TEMPLATE = `# Replace with a specific title for this idea
|
|
2
|
+
|
|
3
|
+
## Intent
|
|
4
|
+
|
|
5
|
+
<!-- State the desired outcome in one or two sentences. -->
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
<!-- Describe the current problem, situation, or opportunity. -->
|
|
10
|
+
|
|
11
|
+
## Desired outcome
|
|
12
|
+
|
|
13
|
+
<!-- Describe the externally meaningful state that should become true. -->
|
|
14
|
+
|
|
15
|
+
## Scope
|
|
16
|
+
|
|
17
|
+
### In scope
|
|
18
|
+
|
|
19
|
+
<!-- Describe what this idea includes. -->
|
|
20
|
+
|
|
21
|
+
### Out of scope
|
|
22
|
+
|
|
23
|
+
<!-- Describe adjacent work this idea intentionally excludes. -->
|
|
24
|
+
|
|
25
|
+
## Constraints
|
|
26
|
+
|
|
27
|
+
<!-- Record material product, repository, compatibility, or operational constraints. -->
|
|
28
|
+
|
|
29
|
+
## Open questions
|
|
30
|
+
|
|
31
|
+
<!-- Record unresolved decisions. Remove this section when none remain. -->
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export const IMPLEMENTATION_TEMPLATE = `# Implementation
|
|
35
|
+
|
|
36
|
+
## Steps
|
|
37
|
+
|
|
38
|
+
<!--
|
|
39
|
+
Give every step a stable I-Sxx identifier and a level-three heading.
|
|
40
|
+
Describe what will change, its boundaries, and important design details.
|
|
41
|
+
Do not use task-list checkboxes in this document.
|
|
42
|
+
-->
|
|
43
|
+
|
|
44
|
+
### I-S01: Step title
|
|
45
|
+
|
|
46
|
+
<!-- Describe this implementation step. -->
|
|
47
|
+
|
|
48
|
+
## Acceptance criteria
|
|
49
|
+
|
|
50
|
+
<!--
|
|
51
|
+
Give every criterion a stable I-ACxx identifier and a level-three heading.
|
|
52
|
+
Describe both the observable outcome and the method that proves it.
|
|
53
|
+
Do not create a separate validation section or use task-list checkboxes.
|
|
54
|
+
-->
|
|
55
|
+
|
|
56
|
+
### I-AC01: Criterion title
|
|
57
|
+
|
|
58
|
+
<!-- Describe the required outcome and how an Agent can prove it. -->
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const DEPLOYMENT_TEMPLATE = `# Deployment
|
|
62
|
+
|
|
63
|
+
## Steps
|
|
64
|
+
|
|
65
|
+
<!--
|
|
66
|
+
Give every step a stable D-Sxx identifier and a level-three heading.
|
|
67
|
+
Describe deployment or external-world verification work.
|
|
68
|
+
Do not use task-list checkboxes in this document.
|
|
69
|
+
-->
|
|
70
|
+
|
|
71
|
+
### D-S01: Step title
|
|
72
|
+
|
|
73
|
+
<!-- Describe this deployment or external-verification step. -->
|
|
74
|
+
|
|
75
|
+
## Acceptance criteria
|
|
76
|
+
|
|
77
|
+
<!--
|
|
78
|
+
Give every criterion a stable D-ACxx identifier and a level-three heading.
|
|
79
|
+
Describe both the observable external outcome and the method that proves it.
|
|
80
|
+
Do not create a separate validation section or use task-list checkboxes.
|
|
81
|
+
-->
|
|
82
|
+
|
|
83
|
+
### D-AC01: Criterion title
|
|
84
|
+
|
|
85
|
+
<!-- Describe the required external outcome and how an Agent can prove it. -->
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
export const LEDGER_TEMPLATE = `# Ledger
|
|
89
|
+
|
|
90
|
+
## Implementation
|
|
91
|
+
|
|
92
|
+
### Implementation steps
|
|
93
|
+
|
|
94
|
+
- [ ] **I-S01:** Step title
|
|
95
|
+
|
|
96
|
+
### Implementation acceptance criteria
|
|
97
|
+
|
|
98
|
+
- [ ] **I-AC01:** Criterion title
|
|
99
|
+
|
|
100
|
+
## Deployment
|
|
101
|
+
|
|
102
|
+
### Deployment steps
|
|
103
|
+
|
|
104
|
+
- [ ] **D-S01:** Step title
|
|
105
|
+
|
|
106
|
+
### Deployment acceptance criteria
|
|
107
|
+
|
|
108
|
+
- [ ] **D-AC01:** Criterion title
|
|
109
|
+
`;
|
package/src/ideas.js
CHANGED
|
@@ -1,132 +1,141 @@
|
|
|
1
|
-
import { parseStrictYaml, stringifyCanonicalYaml } from "./yaml.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
value
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
value =
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
1
|
+
import { parseStrictYaml, stringifyCanonicalYaml } from "./yaml.js";
|
|
2
|
+
import { isCanonicalLanguageTag } from "./language.js";
|
|
3
|
+
|
|
4
|
+
export const IDEA_STATES = [
|
|
5
|
+
"preparing",
|
|
6
|
+
"implementing",
|
|
7
|
+
"deploying",
|
|
8
|
+
"completed",
|
|
9
|
+
"abandoned",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const ULID = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
13
|
+
const OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
14
|
+
const CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
15
|
+
const STATUS_KEYS = new Set([
|
|
16
|
+
"version",
|
|
17
|
+
"id",
|
|
18
|
+
"alias",
|
|
19
|
+
"language",
|
|
20
|
+
"abandoned",
|
|
21
|
+
"approvedRevision",
|
|
22
|
+
"implementationAcceptedRevision",
|
|
23
|
+
"deploymentAcceptedRevision",
|
|
24
|
+
]);
|
|
25
|
+
const REVISION_KEYS = [
|
|
26
|
+
"approvedRevision",
|
|
27
|
+
"implementationAcceptedRevision",
|
|
28
|
+
"deploymentAcceptedRevision",
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function ideaStatusError(message) {
|
|
32
|
+
return new Error(`Invalid idea status: ${message}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isMapping(value) {
|
|
36
|
+
return value !== null && !Array.isArray(value) && typeof value === "object";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isValidAlias(value) {
|
|
40
|
+
return (
|
|
41
|
+
typeof value === "string" &&
|
|
42
|
+
value.length > 0 &&
|
|
43
|
+
value.trim() === value &&
|
|
44
|
+
[...value].length <= 120 &&
|
|
45
|
+
!CONTROL_CHARACTER.test(value)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isValidUlid(value) {
|
|
50
|
+
return typeof value === "string" && ULID.test(value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function validateIdeaStatus(value, { objectIdLength } = {}) {
|
|
54
|
+
if (!isMapping(value)) throw ideaStatusError("document must be a mapping");
|
|
55
|
+
for (const key of Object.keys(value)) {
|
|
56
|
+
if (!STATUS_KEYS.has(key)) throw ideaStatusError(`unknown field: ${key}`);
|
|
57
|
+
}
|
|
58
|
+
for (const key of ["version", "id"]) {
|
|
59
|
+
if (!Object.hasOwn(value, key)) throw ideaStatusError(`missing ${key}`);
|
|
60
|
+
}
|
|
61
|
+
if (value.version !== 1) throw ideaStatusError("version must be 1");
|
|
62
|
+
if (!isValidUlid(value.id)) throw ideaStatusError("id must be a canonical ULID");
|
|
63
|
+
if (Object.hasOwn(value, "alias") && !isValidAlias(value.alias)) {
|
|
64
|
+
throw ideaStatusError("alias must be 1 to 120 trimmed characters without controls");
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
Object.hasOwn(value, "language") &&
|
|
68
|
+
!isCanonicalLanguageTag(value.language)
|
|
69
|
+
) {
|
|
70
|
+
throw ideaStatusError("language must be a canonical BCP 47 language tag");
|
|
71
|
+
}
|
|
72
|
+
if (Object.hasOwn(value, "abandoned") && value.abandoned !== true) {
|
|
73
|
+
throw ideaStatusError("abandoned must be omitted or true");
|
|
74
|
+
}
|
|
75
|
+
if (
|
|
76
|
+
objectIdLength !== undefined &&
|
|
77
|
+
(!Number.isInteger(objectIdLength) || objectIdLength <= 0)
|
|
78
|
+
) {
|
|
79
|
+
throw ideaStatusError("objectIdLength must be a positive integer");
|
|
80
|
+
}
|
|
81
|
+
for (const key of REVISION_KEYS) {
|
|
82
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
83
|
+
if (
|
|
84
|
+
typeof value[key] !== "string" ||
|
|
85
|
+
!OBJECT_ID.test(value[key]) ||
|
|
86
|
+
(objectIdLength !== undefined && value[key].length !== objectIdLength)
|
|
87
|
+
) {
|
|
88
|
+
throw ideaStatusError(`${key} must be a lowercase hexadecimal Git object ID`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function serializeIdeaStatus(value, options) {
|
|
95
|
+
validateIdeaStatus(value, options);
|
|
96
|
+
const canonical = {
|
|
97
|
+
version: 1,
|
|
98
|
+
id: value.id,
|
|
99
|
+
};
|
|
100
|
+
if (Object.hasOwn(value, "alias")) canonical.alias = value.alias;
|
|
101
|
+
if (Object.hasOwn(value, "language")) canonical.language = value.language;
|
|
102
|
+
if (value.abandoned === true) canonical.abandoned = true;
|
|
103
|
+
for (const key of REVISION_KEYS) {
|
|
104
|
+
if (Object.hasOwn(value, key)) canonical[key] = value[key];
|
|
105
|
+
}
|
|
106
|
+
return stringifyCanonicalYaml(canonical);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function parseIdeaStatus(source, options) {
|
|
110
|
+
const normalizedSource = source.replaceAll("\r\n", "\n");
|
|
111
|
+
let value;
|
|
112
|
+
try {
|
|
113
|
+
value = parseStrictYaml(normalizedSource);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
throw ideaStatusError(error.message);
|
|
116
|
+
}
|
|
117
|
+
validateIdeaStatus(value, options);
|
|
118
|
+
if (serializeIdeaStatus(value, options) !== normalizedSource) {
|
|
119
|
+
throw ideaStatusError("status is not canonical");
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function deriveIdeaState(revisions, status) {
|
|
125
|
+
if (revisions === null || Array.isArray(revisions) || typeof revisions !== "object") {
|
|
126
|
+
throw ideaStatusError("revisions must be a mapping");
|
|
127
|
+
}
|
|
128
|
+
for (const key of ["idealRevision", "implementationRevision", "deploymentRevision"]) {
|
|
129
|
+
if (typeof revisions[key] !== "string" || !OBJECT_ID.test(revisions[key])) {
|
|
130
|
+
throw ideaStatusError(`${key} must be a lowercase hexadecimal Git object ID`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
validateIdeaStatus(status);
|
|
134
|
+
if (status.abandoned) return "abandoned";
|
|
135
|
+
if (status.approvedRevision !== revisions.idealRevision) return "preparing";
|
|
136
|
+
if (
|
|
137
|
+
status.implementationAcceptedRevision !== revisions.implementationRevision
|
|
138
|
+
) return "implementing";
|
|
139
|
+
if (status.deploymentAcceptedRevision !== revisions.deploymentRevision) return "deploying";
|
|
140
|
+
return "completed";
|
|
132
141
|
}
|