@nseng-ai/kernel 0.1.2
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 +130 -0
- package/package.json +37 -0
- package/src/cli/completion.ts +30 -0
- package/src/cli/context.ts +110 -0
- package/src/cli/index.ts +668 -0
- package/src/cli/shell.ts +93 -0
- package/src/extensions/built-in-extension-commands.ts +306 -0
- package/src/extensions/command-registry.ts +342 -0
- package/src/extensions/discovery.ts +744 -0
- package/src/extensions/loader.ts +49 -0
- package/src/extensions/module-reference.ts +54 -0
- package/src/extensions/registry.ts +700 -0
- package/src/extensions/repo-local-catalog.ts +31 -0
- package/src/extensions/zod-issue-path.ts +65 -0
- package/src/project-config/points.ts +920 -0
- package/src/runtime/command-io.ts +149 -0
- package/src/runtime/diagnostics.ts +35 -0
- package/src/runtime/extension-root-discovery.ts +118 -0
- package/src/runtime/module-import.ts +4 -0
- package/src/runtime/module-loader.ts +75 -0
- package/src/runtime/pi-text-generation.ts +162 -0
- package/src/sdk/command-name.ts +2 -0
- package/src/sdk/command.ts +109 -0
- package/src/sdk/execution.ts +67 -0
- package/src/sdk/extension-manifest.ts +38 -0
- package/src/sdk/index.ts +73 -0
- package/src/sdk/progress-phase-state.ts +352 -0
- package/src/sdk/repo-local-ns-extension.ts +41 -0
- package/src/sdk/result.ts +11 -0
- package/src/sdk/schema.ts +3 -0
- package/src/sdk/services.ts +68 -0
- package/src/sdk/text-generation.ts +21 -0
package/src/cli/shell.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { failure, ok, requireInteractiveOrUsageError } from "@nseng-ai/clinkr";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
installMarkerBlock,
|
|
6
|
+
markerSurfaceInstallRequestSchema,
|
|
7
|
+
markerSurfaceInstallResultSchema,
|
|
8
|
+
markerSurfaceShowRequestSchema,
|
|
9
|
+
markerSurfaceShowResultSchema,
|
|
10
|
+
rcPathForShell,
|
|
11
|
+
renderCommandCdWrapperScript,
|
|
12
|
+
resolveRequestedShell,
|
|
13
|
+
} from "@nseng-ai/capability-kit/shell-support";
|
|
14
|
+
|
|
15
|
+
import type { NsCliContext } from "./context.ts";
|
|
16
|
+
|
|
17
|
+
export const nsShellIntegrationBeginMarker = "# >>> ns shell integration >>>";
|
|
18
|
+
export const nsShellIntegrationEndMarker = "# <<< ns shell integration <<<";
|
|
19
|
+
|
|
20
|
+
export const nsShellShowRequestSchema = markerSurfaceShowRequestSchema;
|
|
21
|
+
export const nsShellInstallRequestSchema = markerSurfaceInstallRequestSchema.extend({
|
|
22
|
+
yes: z.boolean().default(false).describe("Confirm shell rc-file update without prompting."),
|
|
23
|
+
});
|
|
24
|
+
export const nsShellShowResultSchema = markerSurfaceShowResultSchema;
|
|
25
|
+
export const nsShellInstallResultSchema = markerSurfaceInstallResultSchema.extend({
|
|
26
|
+
cancelled: z.boolean().default(false),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export type NsShellShowRequest = z.infer<typeof nsShellShowRequestSchema>;
|
|
30
|
+
export type NsShellInstallRequest = z.infer<typeof nsShellInstallRequestSchema>;
|
|
31
|
+
export type NsShellShowResult = z.infer<typeof nsShellShowResultSchema>;
|
|
32
|
+
export type NsShellInstallResult = z.infer<typeof nsShellInstallResultSchema>;
|
|
33
|
+
|
|
34
|
+
export async function runNsShellShow(ctx: NsCliContext, request: NsShellShowRequest) {
|
|
35
|
+
const selected = resolveRequestedShell(request.shell, ctx.env);
|
|
36
|
+
if (selected.type === "failure") return failure(selected.failure.type, selected.failure.message);
|
|
37
|
+
return ok({ shell: selected.shell, script: renderNsShellWrapperScript() });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function runNsShellInstall(ctx: NsCliContext, request: NsShellInstallRequest) {
|
|
41
|
+
const selected = resolveRequestedShell(request.shell, ctx.env);
|
|
42
|
+
if (selected.type === "failure") return failure(selected.failure.type, selected.failure.message);
|
|
43
|
+
const rcPath = rcPathForShell(selected.shell, ctx.env);
|
|
44
|
+
if (!request.yes) {
|
|
45
|
+
const gate = requireInteractiveOrUsageError(ctx.interaction, {
|
|
46
|
+
message: "Installing ns shell integration requires --yes when non-interactive.",
|
|
47
|
+
missingFlag: "--yes",
|
|
48
|
+
howToSupply: "Pass --yes (or -y) to update the shell rc file without prompting.",
|
|
49
|
+
});
|
|
50
|
+
if (gate) return gate;
|
|
51
|
+
const confirmed = await ctx.interaction.confirm({
|
|
52
|
+
message: `Install ns shell integration for ${selected.shell} in ${rcPath}?`,
|
|
53
|
+
defaultAnswer: "no",
|
|
54
|
+
});
|
|
55
|
+
if (confirmed.type === "aborted") return failure("aborted", "Aborted!");
|
|
56
|
+
if (confirmed.type === "declined") {
|
|
57
|
+
return ok({
|
|
58
|
+
shell: selected.shell,
|
|
59
|
+
rcPath: rcPath,
|
|
60
|
+
isAlreadyInstalled: false,
|
|
61
|
+
cancelled: true,
|
|
62
|
+
} satisfies NsShellInstallResult);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const installed = await installMarkerBlock({
|
|
66
|
+
rcPath,
|
|
67
|
+
beginMarker: nsShellIntegrationBeginMarker,
|
|
68
|
+
payload: renderNsShellWrapperScript(),
|
|
69
|
+
endMarker: nsShellIntegrationEndMarker,
|
|
70
|
+
});
|
|
71
|
+
return ok({
|
|
72
|
+
shell: selected.shell,
|
|
73
|
+
rcPath: installed.rcPath,
|
|
74
|
+
isAlreadyInstalled: installed.isAlreadyInstalled,
|
|
75
|
+
cancelled: false,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function renderNsShellShow(result: NsShellShowResult): string {
|
|
80
|
+
return result.script;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function renderNsShellInstall(result: NsShellInstallResult): string {
|
|
84
|
+
if (result.cancelled)
|
|
85
|
+
return `Cancelled ns shell integration install for ${result.shell} in ${result.rcPath}`;
|
|
86
|
+
if (result.isAlreadyInstalled)
|
|
87
|
+
return `ns shell integration already installed in ${result.rcPath}`;
|
|
88
|
+
return `Installed ns shell integration for ${result.shell} in ${result.rcPath}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function renderNsShellWrapperScript(): string {
|
|
92
|
+
return renderCommandCdWrapperScript({ commandName: "ns" });
|
|
93
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { ok, negative } from "@nseng-ai/clinkr";
|
|
2
|
+
import { optionalEntries } from "@nseng-ai/foundation/primitives";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
loadPointCatalog,
|
|
7
|
+
nodeProjectConfigGateway,
|
|
8
|
+
resolvePromptPointSource,
|
|
9
|
+
type PointCatalog,
|
|
10
|
+
type PointCatalogEntry,
|
|
11
|
+
type PointCatalogInstallation,
|
|
12
|
+
type ProjectConfigDiagnostic,
|
|
13
|
+
} from "../project-config/points.ts";
|
|
14
|
+
import {
|
|
15
|
+
nsExtensionPointAcceptsValues,
|
|
16
|
+
nsExtensionPointSemanticsValues,
|
|
17
|
+
} from "../sdk/extension-manifest.ts";
|
|
18
|
+
import type { NsCommand } from "../sdk/index.ts";
|
|
19
|
+
|
|
20
|
+
const knownPromptEnvOverride = {
|
|
21
|
+
pointId: "flow.submit.pr-description",
|
|
22
|
+
envVar: "NS_DEV_PR_DESCRIPTION_PROMPT",
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
const pointDiagnosticSchema = z.object({
|
|
26
|
+
severity: z.enum(["error", "info"]),
|
|
27
|
+
code: z.string(),
|
|
28
|
+
message: z.string(),
|
|
29
|
+
path: z.string().optional(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const pointSourceSchema = z.union([
|
|
33
|
+
z.object({ source: z.literal("env"), envVar: z.string(), path: z.string() }),
|
|
34
|
+
z.object({ source: z.literal("repo-prompt"), path: z.string() }),
|
|
35
|
+
z.object({ source: z.literal("repo-hook"), commands: z.array(z.string()) }),
|
|
36
|
+
z.object({ source: z.literal("conventional"), path: z.string() }),
|
|
37
|
+
z.object({ source: z.literal("default"), path: z.string(), manifestPath: z.string() }),
|
|
38
|
+
z.object({ source: z.literal("missing") }),
|
|
39
|
+
]);
|
|
40
|
+
type PointSourceView = z.infer<typeof pointSourceSchema>;
|
|
41
|
+
|
|
42
|
+
const pointSummarySchema = z.object({
|
|
43
|
+
id: z.string(),
|
|
44
|
+
accepts: z.enum(nsExtensionPointAcceptsValues),
|
|
45
|
+
semantics: z.enum(nsExtensionPointSemanticsValues),
|
|
46
|
+
description: z.string().optional(),
|
|
47
|
+
manifestPath: z.string().optional(),
|
|
48
|
+
defaultPath: z.string().optional(),
|
|
49
|
+
activeSource: pointSourceSchema,
|
|
50
|
+
installationCount: z.number().int().nonnegative(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const extensionPointsResultSchema = z.object({
|
|
54
|
+
points: z.array(pointSummarySchema),
|
|
55
|
+
diagnostics: z.array(pointDiagnosticSchema),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const extensionPointsRequestSchema = z.object({});
|
|
59
|
+
const extensionPointDetailRequestSchema = z.object({ id: z.string().min(1) });
|
|
60
|
+
|
|
61
|
+
const extensionPointDetailSchema = pointSummarySchema.extend({
|
|
62
|
+
installations: z.array(pointSourceSchema),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export const extensionPointDetailResultSchema = z.object({
|
|
66
|
+
point: extensionPointDetailSchema,
|
|
67
|
+
diagnostics: z.array(pointDiagnosticSchema),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const missingPointDataSchema = z.object({
|
|
71
|
+
pointId: z.string(),
|
|
72
|
+
availablePointIds: z.array(z.string()),
|
|
73
|
+
diagnostics: z.array(pointDiagnosticSchema),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const extensionPointResultSchema = z.union([
|
|
77
|
+
extensionPointDetailResultSchema,
|
|
78
|
+
missingPointDataSchema,
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
export const extensionPointsCommand: NsCommand<
|
|
82
|
+
typeof extensionPointsRequestSchema,
|
|
83
|
+
z.infer<typeof extensionPointsResultSchema>
|
|
84
|
+
> = {
|
|
85
|
+
name: "points",
|
|
86
|
+
summary: "List defined ns points and their active sources.",
|
|
87
|
+
description: "List defined ns points and their active sources.",
|
|
88
|
+
schema: extensionPointsRequestSchema,
|
|
89
|
+
resultSchema: extensionPointsResultSchema,
|
|
90
|
+
run: (ctx) => ok(toPointsResult(loadCatalog(ctx.cwd, ctx.env))),
|
|
91
|
+
renderHuman: (data) => renderPointsHuman(extensionPointsResultSchema.parse(data)),
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const extensionPointCommand: NsCommand<
|
|
95
|
+
typeof extensionPointDetailRequestSchema,
|
|
96
|
+
z.infer<typeof extensionPointResultSchema>
|
|
97
|
+
> = {
|
|
98
|
+
name: "point",
|
|
99
|
+
summary: "Show one ns point definition and its active source.",
|
|
100
|
+
description: "Show one ns point definition and its active source.",
|
|
101
|
+
schema: extensionPointDetailRequestSchema,
|
|
102
|
+
positionals: { id: { position: 0 } },
|
|
103
|
+
resultSchema: extensionPointResultSchema,
|
|
104
|
+
run: (ctx, request) => {
|
|
105
|
+
const catalog = loadCatalog(ctx.cwd, ctx.env);
|
|
106
|
+
const entry = catalog.entries.find((candidate) => candidate.definition.id === request.id);
|
|
107
|
+
if (entry === undefined) {
|
|
108
|
+
const data = missingPointDataSchema.parse({
|
|
109
|
+
pointId: request.id,
|
|
110
|
+
availablePointIds: catalog.entries.map((candidate) => candidate.definition.id),
|
|
111
|
+
diagnostics: catalog.diagnostics,
|
|
112
|
+
});
|
|
113
|
+
return negative(`Point ${request.id} is not defined.`, { data });
|
|
114
|
+
}
|
|
115
|
+
return ok(toPointDetailResult(catalog, entry));
|
|
116
|
+
},
|
|
117
|
+
renderHuman: (data) => renderPointDetailHuman(extensionPointDetailResultSchema.parse(data)),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
function loadCatalog(cwd: string, env: Record<string, string | undefined>): PointCatalog {
|
|
121
|
+
return loadPointCatalog({
|
|
122
|
+
repoRoot: cwd,
|
|
123
|
+
gateway: nodeProjectConfigGateway,
|
|
124
|
+
env,
|
|
125
|
+
promptEnvOverride: knownPromptEnvOverride,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toPointsResult(catalog: PointCatalog): z.infer<typeof extensionPointsResultSchema> {
|
|
130
|
+
return {
|
|
131
|
+
points: catalog.entries.map((entry) => toPointSummary(catalog, entry)),
|
|
132
|
+
diagnostics: [...catalog.diagnostics],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function toPointDetailResult(
|
|
137
|
+
catalog: PointCatalog,
|
|
138
|
+
entry: PointCatalogEntry,
|
|
139
|
+
): z.infer<typeof extensionPointDetailResultSchema> {
|
|
140
|
+
return {
|
|
141
|
+
point: {
|
|
142
|
+
...toPointSummary(catalog, entry),
|
|
143
|
+
installations: entry.installations.map(toPointSource),
|
|
144
|
+
},
|
|
145
|
+
diagnostics: [...diagnosticsForPoint(catalog.diagnostics, entry.definition.id)],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function toPointSummary(
|
|
150
|
+
catalog: PointCatalog,
|
|
151
|
+
entry: PointCatalogEntry,
|
|
152
|
+
): z.infer<typeof pointSummarySchema> {
|
|
153
|
+
return {
|
|
154
|
+
id: entry.definition.id,
|
|
155
|
+
accepts: entry.definition.accepts,
|
|
156
|
+
semantics: entry.definition.semantics,
|
|
157
|
+
...optionalEntries({
|
|
158
|
+
description: entry.definition.description,
|
|
159
|
+
manifestPath: entry.definition.manifestPath,
|
|
160
|
+
defaultPath: entry.definition.defaultPath,
|
|
161
|
+
}),
|
|
162
|
+
activeSource: activeSourceForEntry(catalog, entry),
|
|
163
|
+
installationCount: entry.installations.length,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function activeSourceForEntry(
|
|
168
|
+
catalog: PointCatalog,
|
|
169
|
+
entry: PointCatalogEntry,
|
|
170
|
+
): z.infer<typeof pointSourceSchema> {
|
|
171
|
+
if (entry.definition.accepts === "prompt") {
|
|
172
|
+
return pointSourceFromPromptSource(resolvePromptPointSource(catalog, entry.definition.id));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const installation = entry.installations.find(
|
|
176
|
+
(candidate) => candidate.source === "ns.toml" && candidate.installation.accepts === "hook",
|
|
177
|
+
);
|
|
178
|
+
if (installation?.source === "ns.toml" && installation.installation.accepts === "hook") {
|
|
179
|
+
return pointSourceFromHookCommands(installation.installation.commands);
|
|
180
|
+
}
|
|
181
|
+
return missingPointSource();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function toPointSource(installation: PointCatalogInstallation): z.infer<typeof pointSourceSchema> {
|
|
185
|
+
if (installation.source === "env-prompt") {
|
|
186
|
+
return envPointSource(installation.envVar, installation.path);
|
|
187
|
+
}
|
|
188
|
+
if (installation.source === "conventional-prompt") {
|
|
189
|
+
return conventionalPointSource(installation.path);
|
|
190
|
+
}
|
|
191
|
+
if (installation.installation.accepts === "hook") {
|
|
192
|
+
return pointSourceFromHookCommands(installation.installation.commands);
|
|
193
|
+
}
|
|
194
|
+
return repoPromptPointSource(installation.installation.path);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function pointSourceFromPromptSource(
|
|
198
|
+
source: ReturnType<typeof resolvePromptPointSource>,
|
|
199
|
+
): z.infer<typeof pointSourceSchema> {
|
|
200
|
+
switch (source.type) {
|
|
201
|
+
case "env":
|
|
202
|
+
return envPointSource(source.envVar, source.path);
|
|
203
|
+
case "ns.toml":
|
|
204
|
+
return repoPromptPointSource(source.path);
|
|
205
|
+
case "conventional":
|
|
206
|
+
return conventionalPointSource(source.path);
|
|
207
|
+
case "default":
|
|
208
|
+
return { source: "default", path: source.path, manifestPath: source.manifestPath };
|
|
209
|
+
case "missing":
|
|
210
|
+
return missingPointSource();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function envPointSource(envVar: string, path: string): z.infer<typeof pointSourceSchema> {
|
|
215
|
+
return { source: "env", envVar, path };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function repoPromptPointSource(path: string): z.infer<typeof pointSourceSchema> {
|
|
219
|
+
return { source: "repo-prompt", path };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function pointSourceFromHookCommands(
|
|
223
|
+
commands: readonly string[],
|
|
224
|
+
): z.infer<typeof pointSourceSchema> {
|
|
225
|
+
return { source: "repo-hook", commands: [...commands] };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function conventionalPointSource(path: string): z.infer<typeof pointSourceSchema> {
|
|
229
|
+
return { source: "conventional", path };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function missingPointSource(): z.infer<typeof pointSourceSchema> {
|
|
233
|
+
return { source: "missing" };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function diagnosticsForPoint(
|
|
237
|
+
diagnostics: readonly ProjectConfigDiagnostic[],
|
|
238
|
+
pointId: string,
|
|
239
|
+
): readonly ProjectConfigDiagnostic[] {
|
|
240
|
+
return diagnostics.filter(
|
|
241
|
+
(diagnostic) => diagnostic.path === pointId || diagnostic.path === `points.${pointId}`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderPointsHuman(result: z.infer<typeof extensionPointsResultSchema>): string {
|
|
246
|
+
const lines = ["ns points:"];
|
|
247
|
+
for (const point of result.points) {
|
|
248
|
+
lines.push(
|
|
249
|
+
`- ${point.id} (${point.accepts}, ${point.semantics}) — ${renderSource(point.activeSource)}`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
appendDiagnosticsSection(lines, result.diagnostics, { leadingBlank: true });
|
|
253
|
+
return `${lines.join("\n")}\n`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function renderPointDetailHuman(result: z.infer<typeof extensionPointDetailResultSchema>): string {
|
|
257
|
+
const point = result.point;
|
|
258
|
+
const lines = [
|
|
259
|
+
`${point.id}`,
|
|
260
|
+
`accepts: ${point.accepts}`,
|
|
261
|
+
`semantics: ${point.semantics}`,
|
|
262
|
+
`active source: ${renderSource(point.activeSource)}`,
|
|
263
|
+
];
|
|
264
|
+
if (point.description !== undefined) lines.push(`description: ${point.description}`);
|
|
265
|
+
if (point.manifestPath !== undefined) lines.push(`definition: ${point.manifestPath}`);
|
|
266
|
+
if (point.defaultPath !== undefined) lines.push(`default: ${point.defaultPath}`);
|
|
267
|
+
if (point.installations.length > 0) {
|
|
268
|
+
lines.push(
|
|
269
|
+
"installations:",
|
|
270
|
+
...point.installations.map((source) => `- ${renderSource(source)}`),
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
appendDiagnosticsSection(lines, result.diagnostics);
|
|
274
|
+
return `${lines.join("\n")}\n`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function appendDiagnosticsSection(
|
|
278
|
+
lines: string[],
|
|
279
|
+
diagnostics: readonly z.infer<typeof pointDiagnosticSchema>[],
|
|
280
|
+
options: { leadingBlank?: boolean } = {},
|
|
281
|
+
): void {
|
|
282
|
+
if (diagnostics.length === 0) return;
|
|
283
|
+
if (options.leadingBlank === true) lines.push("");
|
|
284
|
+
lines.push("diagnostics:", ...diagnostics.map(renderDiagnostic));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function renderSource(source: PointSourceView): string {
|
|
288
|
+
switch (source.source) {
|
|
289
|
+
case "env":
|
|
290
|
+
return `env ${source.envVar} -> ${source.path}`;
|
|
291
|
+
case "repo-prompt":
|
|
292
|
+
return `repo ns.toml -> ${source.path}`;
|
|
293
|
+
case "repo-hook":
|
|
294
|
+
return `repo ns.toml commands: ${source.commands.join(", ")}`;
|
|
295
|
+
case "conventional":
|
|
296
|
+
return `conventional ${source.path}`;
|
|
297
|
+
case "default":
|
|
298
|
+
return `default ${source.path}`;
|
|
299
|
+
case "missing":
|
|
300
|
+
return "missing";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function renderDiagnostic(diagnostic: z.infer<typeof pointDiagnosticSchema>): string {
|
|
305
|
+
return `- ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}`;
|
|
306
|
+
}
|