silvermoon 0.2.1 → 0.3.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/LICENSE +21 -0
- package/README.md +115 -121
- package/README.zh-CN.md +96 -95
- package/bin/silvermoon.js +7 -2
- package/docs/getting-started.md +23 -11
- package/docs/maintaining.md +83 -6
- package/docs/npm-package-releases.md +33 -4
- package/docs/operations.md +11 -7
- package/docs/reference.md +131 -32
- package/docs/repository-tasks.md +43 -15
- package/package.json +46 -8
- package/skills/silvermoon/SKILL.md +224 -123
- package/skills/silvermoon/references/adoption.md +3 -2
- package/src/adoption.js +51 -35
- package/src/cli.js +148 -39
- package/src/config.js +76 -16
- package/src/create-idea.js +22 -10
- package/src/git-snapshot.js +212 -0
- package/src/git.js +209 -18
- package/src/guidance.js +65 -23
- package/src/idea-layout.js +59 -23
- package/src/idea-metadata.js +48 -0
- package/src/idea-templates.js +133 -0
- package/src/index.js +64 -53
- package/src/language.js +4 -0
- package/src/list-ideas.js +118 -55
- package/src/observation.js +9 -1
- package/src/repository.js +2 -8
- package/src/response.js +93 -95
- package/src/subprocess.js +27 -0
- package/src/trace.js +37 -2
- package/src/tui-table.js +71 -0
- package/src/tui.js +205 -0
- package/src/whatsnext.js +71 -18
- package/assets/silvermoon-avatar.svg +0 -395
- package/assets/silvermoon.svg +0 -176
- package/docs/assets/silvermoon-avatar.svg +0 -395
package/src/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
|
|
3
|
+
import { REPOSITORY_SKILL_PATH } from "./adoption.js";
|
|
3
4
|
import {
|
|
4
5
|
diagnosticProblem,
|
|
5
6
|
} from "./dialogue.js";
|
|
6
|
-
import {
|
|
7
|
+
import { loadConfigSnapshot } from "./config.js";
|
|
7
8
|
import { createCommandRun } from "./domain.js";
|
|
8
9
|
import {
|
|
9
10
|
fetchPrimary,
|
|
10
11
|
indexSnapshot,
|
|
11
|
-
|
|
12
|
+
resolveSnapshot,
|
|
12
13
|
runGit,
|
|
13
14
|
sanitizeGitMessage,
|
|
14
15
|
worktreeSnapshot,
|
|
15
|
-
withTemporaryTree,
|
|
16
|
-
withTemporaryWorktree,
|
|
17
16
|
} from "./git.js";
|
|
17
|
+
import { createGitSnapshotFileSystem } from "./git-snapshot.js";
|
|
18
18
|
import {
|
|
19
19
|
canonicalizeOutputLanguage,
|
|
20
20
|
DEFAULT_LANGUAGE,
|
|
@@ -23,6 +23,24 @@ import {
|
|
|
23
23
|
observeSnapshot,
|
|
24
24
|
unavailableObservation,
|
|
25
25
|
} from "./observation.js";
|
|
26
|
+
import {
|
|
27
|
+
CONFIG_PATH,
|
|
28
|
+
GUIDANCE_ROOT,
|
|
29
|
+
IDEAS_ROOT,
|
|
30
|
+
} from "./layout.js";
|
|
31
|
+
|
|
32
|
+
function preloadCheckBlob({ name }) {
|
|
33
|
+
return (
|
|
34
|
+
name === CONFIG_PATH
|
|
35
|
+
|| name === "package.json"
|
|
36
|
+
|| name.startsWith(`${REPOSITORY_SKILL_PATH}/`)
|
|
37
|
+
|| name.startsWith(`${GUIDANCE_ROOT}/`)
|
|
38
|
+
|| (
|
|
39
|
+
name.startsWith(`${IDEAS_ROOT}/`)
|
|
40
|
+
&& name.endsWith("/status.yaml")
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
26
44
|
|
|
27
45
|
function targetArgument({ commit, remote, staged, worktree }) {
|
|
28
46
|
if (remote) return { type: "remote" };
|
|
@@ -59,18 +77,23 @@ async function inspectTree({
|
|
|
59
77
|
userHome,
|
|
60
78
|
version,
|
|
61
79
|
}) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
const filesystem = createGitSnapshotFileSystem({
|
|
81
|
+
gitRoot,
|
|
82
|
+
preload: preloadCheckBlob,
|
|
83
|
+
root,
|
|
84
|
+
tree,
|
|
85
|
+
});
|
|
86
|
+
return observeSnapshot({
|
|
87
|
+
contentRoot: root,
|
|
88
|
+
filesystem,
|
|
89
|
+
gitRoot,
|
|
90
|
+
outputLanguage,
|
|
91
|
+
root,
|
|
92
|
+
projectOnly: true,
|
|
93
|
+
snapshotTree: tree,
|
|
94
|
+
userHome,
|
|
95
|
+
version,
|
|
96
|
+
});
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
function finishCheck(runtime, observed) {
|
|
@@ -133,7 +156,7 @@ export async function checkRepository({
|
|
|
133
156
|
if (remote) {
|
|
134
157
|
let head;
|
|
135
158
|
try {
|
|
136
|
-
head =
|
|
159
|
+
head = resolveSnapshot(repositoryRoot, "HEAD");
|
|
137
160
|
} catch (caught) {
|
|
138
161
|
return failureReport({
|
|
139
162
|
runtime,
|
|
@@ -148,11 +171,10 @@ export async function checkRepository({
|
|
|
148
171
|
}
|
|
149
172
|
let bootstrap;
|
|
150
173
|
try {
|
|
151
|
-
bootstrap = await
|
|
152
|
-
repositoryRoot,
|
|
153
|
-
head,
|
|
154
|
-
|
|
155
|
-
);
|
|
174
|
+
bootstrap = await loadConfigSnapshot({
|
|
175
|
+
gitRoot: repositoryRoot,
|
|
176
|
+
tree: head.tree,
|
|
177
|
+
});
|
|
156
178
|
} catch (caught) {
|
|
157
179
|
return failureReport({
|
|
158
180
|
runtime,
|
|
@@ -205,20 +227,15 @@ export async function checkRepository({
|
|
|
205
227
|
}
|
|
206
228
|
const primary = fetched.result.commit;
|
|
207
229
|
try {
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
snapshotTree: tree,
|
|
218
|
-
userHome,
|
|
219
|
-
version: { type: "remote", commit: primary },
|
|
220
|
-
}),
|
|
221
|
-
);
|
|
230
|
+
const snapshot = resolveSnapshot(repositoryRoot, primary);
|
|
231
|
+
const observed = await inspectTree({
|
|
232
|
+
gitRoot: repositoryRoot,
|
|
233
|
+
outputLanguage: canonicalLanguage,
|
|
234
|
+
root: repositoryRoot,
|
|
235
|
+
tree: snapshot.tree,
|
|
236
|
+
userHome,
|
|
237
|
+
version: { type: "remote", commit: primary },
|
|
238
|
+
});
|
|
222
239
|
return finishCheck(runtime, observed);
|
|
223
240
|
} catch (caught) {
|
|
224
241
|
return failureReport({
|
|
@@ -236,9 +253,9 @@ export async function checkRepository({
|
|
|
236
253
|
|
|
237
254
|
if (commit !== undefined || (!staged && !worktree)) {
|
|
238
255
|
const revision = commit ?? "HEAD";
|
|
239
|
-
let
|
|
256
|
+
let snapshot;
|
|
240
257
|
try {
|
|
241
|
-
|
|
258
|
+
snapshot = resolveSnapshot(repositoryRoot, revision);
|
|
242
259
|
} catch (caught) {
|
|
243
260
|
return failureReport({
|
|
244
261
|
runtime,
|
|
@@ -252,20 +269,14 @@ export async function checkRepository({
|
|
|
252
269
|
});
|
|
253
270
|
}
|
|
254
271
|
try {
|
|
255
|
-
const observed = await
|
|
256
|
-
repositoryRoot,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
projectOnly: true,
|
|
264
|
-
snapshotTree: tree,
|
|
265
|
-
userHome,
|
|
266
|
-
version: { type: "commit", commit: resolvedCommit },
|
|
267
|
-
}),
|
|
268
|
-
);
|
|
272
|
+
const observed = await inspectTree({
|
|
273
|
+
gitRoot: repositoryRoot,
|
|
274
|
+
outputLanguage: canonicalLanguage,
|
|
275
|
+
root: repositoryRoot,
|
|
276
|
+
tree: snapshot.tree,
|
|
277
|
+
userHome,
|
|
278
|
+
version: { type: "commit", commit: snapshot.commit },
|
|
279
|
+
});
|
|
269
280
|
return finishCheck(runtime, observed);
|
|
270
281
|
} catch (caught) {
|
|
271
282
|
return failureReport({
|
|
@@ -276,7 +287,7 @@ export async function checkRepository({
|
|
|
276
287
|
summary: sanitizeGitMessage(caught.message),
|
|
277
288
|
},
|
|
278
289
|
root: repositoryRoot,
|
|
279
|
-
version: { type: "commit", commit:
|
|
290
|
+
version: { type: "commit", commit: snapshot.commit },
|
|
280
291
|
});
|
|
281
292
|
}
|
|
282
293
|
}
|
package/src/language.js
CHANGED
|
@@ -40,6 +40,10 @@ export function canonicalizeOutputLanguage(value) {
|
|
|
40
40
|
caught.exitCode = 2;
|
|
41
41
|
throw caught;
|
|
42
42
|
}
|
|
43
|
+
canonical = {
|
|
44
|
+
en: "en-US",
|
|
45
|
+
zh: "zh-CN",
|
|
46
|
+
}[canonical.toLowerCase()] ?? canonical;
|
|
43
47
|
if (!OUTPUT_LANGUAGE_SET.has(canonical)) {
|
|
44
48
|
const error = new Error(
|
|
45
49
|
`unsupported output language: ${canonical}; expected ${OUTPUT_LANGUAGES.join(" or ")}`,
|
package/src/list-ideas.js
CHANGED
|
@@ -1,71 +1,129 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
|
|
4
1
|
import { createCommandRun } from "./domain.js";
|
|
5
2
|
import {
|
|
6
|
-
extractIdeaTitle,
|
|
7
3
|
ideaInventoryItem,
|
|
8
4
|
normalizeIdeaQuery,
|
|
9
5
|
queryIdeaInventory,
|
|
10
6
|
} from "./idea-query.js";
|
|
11
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
metadataFailureObservation,
|
|
9
|
+
readIdeaInventoryItem,
|
|
10
|
+
} from "./idea-metadata.js";
|
|
11
|
+
import { canonicalizeOutputLanguage } from "./language.js";
|
|
12
12
|
import { observeSnapshot } from "./observation.js";
|
|
13
13
|
import { traceAsync } from "./trace.js";
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const source = await readFile(
|
|
19
|
-
resolve(root, ...documentPath.split("/")),
|
|
20
|
-
"utf8",
|
|
21
|
-
);
|
|
22
|
-
return ideaInventoryItem(idea, extractIdeaTitle(source));
|
|
23
|
-
} catch (caught) {
|
|
24
|
-
throw new Error(
|
|
25
|
-
`Cannot read idea metadata for ${idea.id} at ${documentPath}: ${caught.message}`,
|
|
26
|
-
{ cause: caught },
|
|
27
|
-
);
|
|
28
|
-
}
|
|
15
|
+
function withoutTitleQuery(query, { limit = query.limit } = {}) {
|
|
16
|
+
return { ...query, limit, query: null };
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
19
|
+
function matchesIdentity(item, needle) {
|
|
20
|
+
return [item.id, item.alias]
|
|
21
|
+
.filter((value) => value !== undefined)
|
|
22
|
+
.some((value) => value.toLowerCase().includes(needle));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function queryObservedInventory({
|
|
26
|
+
ideas,
|
|
27
|
+
metadataReader,
|
|
28
|
+
normalizedQuery,
|
|
29
|
+
root,
|
|
30
|
+
}) {
|
|
31
|
+
const ideasById = new Map(ideas.map((idea) => [idea.id, idea]));
|
|
32
|
+
const baseItems = ideas.map((idea) => ideaInventoryItem(idea));
|
|
33
|
+
const candidates = queryIdeaInventory(
|
|
34
|
+
baseItems,
|
|
35
|
+
withoutTitleQuery(normalizedQuery, { limit: null }),
|
|
36
|
+
).ideas;
|
|
37
|
+
|
|
38
|
+
return traceAsync(
|
|
39
|
+
"ideas.inventory-metadata",
|
|
40
|
+
{
|
|
41
|
+
candidateCount: candidates.length,
|
|
42
|
+
ideaCount: ideas.length,
|
|
47
43
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
44
|
+
async () => {
|
|
45
|
+
const loadedItems = new Map();
|
|
46
|
+
let queryCandidateCount = 0;
|
|
47
|
+
let titleReadCount = 0;
|
|
48
|
+
|
|
49
|
+
const readItems = async (items) => {
|
|
50
|
+
const unread = items.filter(({ id }) => !loadedItems.has(id));
|
|
51
|
+
titleReadCount += unread.length;
|
|
52
|
+
const loaded = await Promise.all(unread.map(({ id }) => {
|
|
53
|
+
const idea = ideasById.get(id);
|
|
54
|
+
if (idea === undefined) {
|
|
55
|
+
throw new Error(`Missing observed idea metadata for ${id}`);
|
|
56
|
+
}
|
|
57
|
+
return metadataReader(root, idea);
|
|
58
|
+
}));
|
|
59
|
+
for (const item of loaded) loadedItems.set(item.id, item);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let matchingItems = candidates;
|
|
63
|
+
if (normalizedQuery.query !== null) {
|
|
64
|
+
const needle = normalizedQuery.query.toLowerCase();
|
|
65
|
+
const directMatchIds = new Set(
|
|
66
|
+
candidates
|
|
67
|
+
.filter((item) => matchesIdentity(item, needle))
|
|
68
|
+
.map(({ id }) => id),
|
|
69
|
+
);
|
|
70
|
+
const titleCandidates = candidates.filter(
|
|
71
|
+
({ id }) => !directMatchIds.has(id),
|
|
72
|
+
);
|
|
73
|
+
queryCandidateCount = titleCandidates.length;
|
|
74
|
+
await readItems(titleCandidates);
|
|
75
|
+
matchingItems = candidates
|
|
76
|
+
.filter(({ id }) =>
|
|
77
|
+
directMatchIds.has(id)
|
|
78
|
+
|| loadedItems.get(id)?.title?.toLowerCase().includes(needle)
|
|
79
|
+
)
|
|
80
|
+
.map((item) => loadedItems.get(item.id) ?? item);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const selected = queryIdeaInventory(
|
|
84
|
+
matchingItems,
|
|
85
|
+
withoutTitleQuery(normalizedQuery),
|
|
86
|
+
);
|
|
87
|
+
await readItems(selected.ideas);
|
|
88
|
+
const inventory = {
|
|
89
|
+
summary: selected.summary,
|
|
90
|
+
ideas: selected.ideas.map(({ id }) => {
|
|
91
|
+
const item = loadedItems.get(id);
|
|
92
|
+
if (item === undefined) {
|
|
93
|
+
throw new Error(`Missing selected idea metadata for ${id}`);
|
|
94
|
+
}
|
|
95
|
+
return item;
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
return { inventory, queryCandidateCount, titleReadCount };
|
|
54
99
|
},
|
|
55
|
-
|
|
100
|
+
({ inventory, queryCandidateCount, titleReadCount }) => ({
|
|
101
|
+
attributes: {
|
|
102
|
+
matchedCount: inventory.summary.matched,
|
|
103
|
+
queryCandidateCount,
|
|
104
|
+
returnedCount: inventory.summary.returned,
|
|
105
|
+
titleReadCount,
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
56
109
|
}
|
|
57
110
|
|
|
58
111
|
export async function listIdeas({
|
|
59
112
|
all,
|
|
60
113
|
createdBefore,
|
|
61
114
|
createdSince,
|
|
115
|
+
language,
|
|
62
116
|
limit,
|
|
117
|
+
metadataReader = readIdeaInventoryItem,
|
|
63
118
|
query,
|
|
64
119
|
root = process.cwd(),
|
|
65
120
|
sort,
|
|
66
121
|
states,
|
|
67
122
|
userHome,
|
|
68
123
|
} = {}) {
|
|
124
|
+
const canonicalLanguage = language === undefined
|
|
125
|
+
? undefined
|
|
126
|
+
: canonicalizeOutputLanguage(language);
|
|
69
127
|
const normalizedQuery = normalizeIdeaQuery({
|
|
70
128
|
all,
|
|
71
129
|
createdBefore,
|
|
@@ -77,11 +135,15 @@ export async function listIdeas({
|
|
|
77
135
|
});
|
|
78
136
|
const intention = {
|
|
79
137
|
command: "list-ideas",
|
|
80
|
-
args:
|
|
138
|
+
args: {
|
|
139
|
+
...normalizedQuery,
|
|
140
|
+
language: canonicalLanguage ?? null,
|
|
141
|
+
},
|
|
81
142
|
};
|
|
82
143
|
const runtime = createCommandRun(intention);
|
|
83
144
|
const observed = await observeSnapshot({
|
|
84
145
|
root,
|
|
146
|
+
outputLanguage: canonicalLanguage,
|
|
85
147
|
userHome,
|
|
86
148
|
version: { type: "worktree" },
|
|
87
149
|
});
|
|
@@ -93,19 +155,20 @@ export async function listIdeas({
|
|
|
93
155
|
);
|
|
94
156
|
}
|
|
95
157
|
|
|
96
|
-
let
|
|
158
|
+
let queried;
|
|
97
159
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
),
|
|
105
|
-
),
|
|
106
|
-
);
|
|
160
|
+
queried = await queryObservedInventory({
|
|
161
|
+
ideas: observed.layout.ideas,
|
|
162
|
+
metadataReader,
|
|
163
|
+
normalizedQuery,
|
|
164
|
+
root: observed.observation.root,
|
|
165
|
+
});
|
|
107
166
|
} catch (caught) {
|
|
108
|
-
const failure = metadataFailureObservation(
|
|
167
|
+
const failure = metadataFailureObservation(
|
|
168
|
+
observed,
|
|
169
|
+
caught,
|
|
170
|
+
"silvermoon list-ideas",
|
|
171
|
+
);
|
|
109
172
|
return runtime.complete(
|
|
110
173
|
failure.observation,
|
|
111
174
|
failure.responseContext,
|
|
@@ -113,7 +176,7 @@ export async function listIdeas({
|
|
|
113
176
|
);
|
|
114
177
|
}
|
|
115
178
|
|
|
116
|
-
const inventory =
|
|
179
|
+
const { inventory } = queried;
|
|
117
180
|
const {
|
|
118
181
|
configuration,
|
|
119
182
|
outputLanguage,
|
package/src/observation.js
CHANGED
|
@@ -132,6 +132,7 @@ export function repositoryProblemObservation(observation, problems) {
|
|
|
132
132
|
async function observeSnapshotInternal({
|
|
133
133
|
allowMissingIdeas = false,
|
|
134
134
|
contentRoot,
|
|
135
|
+
filesystem,
|
|
135
136
|
gitRoot,
|
|
136
137
|
ideaLanguage,
|
|
137
138
|
outputLanguage: requestedOutputLanguage,
|
|
@@ -147,7 +148,12 @@ async function observeSnapshotInternal({
|
|
|
147
148
|
const adoption = await traceAsync(
|
|
148
149
|
"adoption.inspect",
|
|
149
150
|
{},
|
|
150
|
-
() => inspectAdoption({
|
|
151
|
+
() => inspectAdoption({
|
|
152
|
+
contentRoot,
|
|
153
|
+
filesystem,
|
|
154
|
+
repositoryRoot: gitRoot,
|
|
155
|
+
root,
|
|
156
|
+
}),
|
|
151
157
|
);
|
|
152
158
|
const user = await traceAsync(
|
|
153
159
|
"user-config.load",
|
|
@@ -233,6 +239,7 @@ async function observeSnapshotInternal({
|
|
|
233
239
|
{},
|
|
234
240
|
() => inspectIdeaLayout({
|
|
235
241
|
config: adoption.config,
|
|
242
|
+
filesystem,
|
|
236
243
|
gitRoot: gitRoot ?? adoption.root,
|
|
237
244
|
root: contentRoot ?? adoption.root,
|
|
238
245
|
snapshotTree,
|
|
@@ -257,6 +264,7 @@ async function observeSnapshotInternal({
|
|
|
257
264
|
|
|
258
265
|
const guidanceDiagnostics = projectOnly
|
|
259
266
|
? (await inspectAllGuidance({
|
|
267
|
+
filesystem,
|
|
260
268
|
gitRoot: gitRoot ?? adoption.root,
|
|
261
269
|
snapshotTree,
|
|
262
270
|
})).diagnostics
|
package/src/repository.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
2
|
|
|
4
3
|
const CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/;
|
|
5
4
|
const ENCODED_SEPARATOR = /%(?:2f|5c)/i;
|
|
@@ -58,6 +57,7 @@ export function validBranchName(value) {
|
|
|
58
57
|
typeof value !== "string" ||
|
|
59
58
|
value.length === 0 ||
|
|
60
59
|
value === "@" ||
|
|
60
|
+
value === "HEAD" ||
|
|
61
61
|
value.startsWith("-") ||
|
|
62
62
|
value.startsWith("refs/") ||
|
|
63
63
|
value.startsWith("remotes/") ||
|
|
@@ -74,13 +74,7 @@ export function validBranchName(value) {
|
|
|
74
74
|
const structurallyValid = value
|
|
75
75
|
.split("/")
|
|
76
76
|
.every((component) => component && !component.startsWith(".") && !component.endsWith(".lock"));
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const checked = spawnSync("git", ["check-ref-format", "--branch", value], {
|
|
80
|
-
encoding: "utf8",
|
|
81
|
-
windowsHide: true,
|
|
82
|
-
});
|
|
83
|
-
return checked.status === 0;
|
|
77
|
+
return structurallyValid;
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
export function effectiveSourceRepository(config, record) {
|