@nseng-ai/areg 0.1.1 → 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/package.json +7 -6
- package/src/cli.ts +0 -33
- package/src/context.ts +3 -29
- package/src/fake-gateways.ts +108 -380
- package/src/gateways/errors.ts +2 -2
- package/src/gateways/fs-utils.ts +2 -2
- package/src/gateways/project-fs.ts +29 -41
- package/src/gateways/project-gateway.ts +98 -31
- package/src/gateways.ts +34 -150
- package/src/index.ts +2 -28
- package/src/operations/check.ts +33 -20
- package/src/operations/doctor-skills.ts +71 -7
- package/src/operations/file-state.ts +4 -4
- package/src/operations/manifest-source-findings.ts +45 -0
- package/src/operations/manifest-sources.ts +119 -0
- package/src/operations/pi-settings.ts +2 -5
- package/src/operations/project-inspection.ts +32 -28
- package/src/operations/project-mutations.ts +5 -21
- package/src/operations/project-resolution.ts +2 -2
- package/src/operations/skill-find.ts +23 -3
- package/src/operations/skill-kind-apply-plan.ts +2 -2
- package/src/operations/skill-kind-frontmatter.ts +1 -1
- package/src/operations/skill-kind-inference.ts +30 -14
- package/src/operations/skill-kind.ts +34 -12
- package/src/sort.ts +3 -3
- package/src/gateways/command-constants.ts +0 -1
- package/src/gateways/github-gateway.ts +0 -111
- package/src/gateways/host-gateway.ts +0 -35
- package/src/gateways/mutation-policy.ts +0 -94
- package/src/gateways/npx-skills-gateway.ts +0 -53
- package/src/gateways/prompt-gateway.ts +0 -21
- package/src/gateways/skillx-workspace-gateway.ts +0 -220
- package/src/operations/frontmatter.ts +0 -151
- package/src/operations/init.ts +0 -548
- package/src/operations/lockfile.ts +0 -107
- package/src/operations/managed-markdown-block.ts +0 -47
- package/src/operations/project-agents.ts +0 -115
- package/src/operations/skill-mirror-conventions.ts +0 -126
- package/src/operations/skillx.ts +0 -305
- package/src/operations/toml-section.ts +0 -53
- package/src/operations/update-skills.ts +0 -325
- package/src/real-gateways.ts +0 -6
- package/src/skill-lookup.ts +0 -254
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
HarnessId,
|
|
5
|
+
HarnessScope,
|
|
6
|
+
PathState,
|
|
7
|
+
TextFileState,
|
|
8
|
+
} from "@nseng-ai/harness-artifacts/api";
|
|
9
|
+
|
|
10
|
+
export type AregManifestSourceType = "first-party" | "npm-module";
|
|
11
|
+
|
|
12
|
+
export interface AregManifestSkillSourceProvenance {
|
|
13
|
+
type: AregManifestSourceType;
|
|
14
|
+
packageName: string;
|
|
15
|
+
relativePath: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AregManifestSkillSourceInspection {
|
|
20
|
+
skillName: string;
|
|
21
|
+
harness: HarnessId;
|
|
22
|
+
scope: HarnessScope;
|
|
23
|
+
manifestPath: string;
|
|
24
|
+
manifestKey: string;
|
|
25
|
+
provenance: AregManifestSkillSourceProvenance;
|
|
26
|
+
targetRootRelativePath: string;
|
|
27
|
+
targetSkillRelativePath: string;
|
|
28
|
+
skillDir: PathState;
|
|
29
|
+
skillMd: TextFileState;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const aregManifestSkillSourceViewSchema = z.object({
|
|
33
|
+
harness: z.string(),
|
|
34
|
+
scope: z.string(),
|
|
35
|
+
manifestPath: z.string(),
|
|
36
|
+
manifestKey: z.string(),
|
|
37
|
+
sourceType: z.enum(["first-party", "npm-module"]),
|
|
38
|
+
packageName: z.string(),
|
|
39
|
+
sourceRelativePath: z.string(),
|
|
40
|
+
version: z.string(),
|
|
41
|
+
targetSkillRelativePath: z.string(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export type AregManifestSkillSourceView = z.infer<typeof aregManifestSkillSourceViewSchema>;
|
|
45
|
+
|
|
46
|
+
export function toManifestSkillSourceView(
|
|
47
|
+
source: AregManifestSkillSourceInspection,
|
|
48
|
+
): AregManifestSkillSourceView {
|
|
49
|
+
return {
|
|
50
|
+
harness: source.harness,
|
|
51
|
+
scope: source.scope,
|
|
52
|
+
manifestPath: source.manifestPath,
|
|
53
|
+
manifestKey: source.manifestKey,
|
|
54
|
+
sourceType: source.provenance.type,
|
|
55
|
+
packageName: source.provenance.packageName,
|
|
56
|
+
sourceRelativePath: source.provenance.relativePath,
|
|
57
|
+
version: source.provenance.version,
|
|
58
|
+
targetSkillRelativePath: source.targetSkillRelativePath,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function groupBySkillName(
|
|
63
|
+
sources: readonly AregManifestSkillSourceInspection[],
|
|
64
|
+
): ReadonlyMap<string, readonly AregManifestSkillSourceInspection[]> {
|
|
65
|
+
const grouped = new Map<string, AregManifestSkillSourceInspection[]>();
|
|
66
|
+
for (const source of sources) {
|
|
67
|
+
const existing = grouped.get(source.skillName) ?? [];
|
|
68
|
+
existing.push(source);
|
|
69
|
+
grouped.set(source.skillName, existing);
|
|
70
|
+
}
|
|
71
|
+
return grouped;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function manifestSourceViewsBySkillName(
|
|
75
|
+
sources: readonly AregManifestSkillSourceInspection[],
|
|
76
|
+
): ReadonlyMap<string, readonly AregManifestSkillSourceView[]> {
|
|
77
|
+
return new Map(
|
|
78
|
+
[...groupBySkillName(sources)].map(([skillName, skillSources]) => [
|
|
79
|
+
skillName,
|
|
80
|
+
skillSources.map((source) => toManifestSkillSourceView(source)),
|
|
81
|
+
]),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function isSkillKindLookupPath(relativePath: string): boolean {
|
|
86
|
+
return relativePath.startsWith("skills/") || relativePath.startsWith(".agents/skills/");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function manifestSkillKindNames(
|
|
90
|
+
sources: readonly AregManifestSkillSourceInspection[],
|
|
91
|
+
): readonly string[] {
|
|
92
|
+
return sources
|
|
93
|
+
.filter(
|
|
94
|
+
(source) =>
|
|
95
|
+
source.skillDir.type === "directory" &&
|
|
96
|
+
source.skillMd.type === "file" &&
|
|
97
|
+
isSkillKindLookupPath(source.targetSkillRelativePath),
|
|
98
|
+
)
|
|
99
|
+
.map((source) => source.skillName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type ManifestSkillSourceStatus = "ok" | "target-missing" | "md-missing";
|
|
103
|
+
|
|
104
|
+
export function classifyManifestSkillSource(
|
|
105
|
+
source: AregManifestSkillSourceInspection,
|
|
106
|
+
): ManifestSkillSourceStatus {
|
|
107
|
+
if (source.skillDir.type === "missing") return "target-missing";
|
|
108
|
+
if (source.skillMd.type === "missing") return "md-missing";
|
|
109
|
+
return "ok";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type AregManifestInspectionError =
|
|
113
|
+
| { type: "manifest"; manifestPath: string; message: string }
|
|
114
|
+
| { type: "harness"; harness: HarnessId; message: string };
|
|
115
|
+
|
|
116
|
+
export interface AregManifestSkillSourcesInspection {
|
|
117
|
+
sources: readonly AregManifestSkillSourceInspection[];
|
|
118
|
+
errors: readonly AregManifestInspectionError[];
|
|
119
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { formatErrorMessage, isRecord } from "@nseng-ai/foundation/primitives";
|
|
2
2
|
import { err, type Result } from "@nseng-ai/foundation/result";
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { PathState, TextFileState } from "@nseng-ai/harness-artifacts/api";
|
|
5
5
|
import { rejectTextState, validateOptionalDirectoryState } from "./file-state.ts";
|
|
6
6
|
|
|
7
7
|
export interface PiSettingsData {
|
|
@@ -12,10 +12,7 @@ export interface PiSettingsData {
|
|
|
12
12
|
|
|
13
13
|
export type ParsePiSettingsResult = Result<PiSettingsData>;
|
|
14
14
|
|
|
15
|
-
export function parsePiSettings(
|
|
16
|
-
piDir: AregPathState,
|
|
17
|
-
settings: AregTextFileState,
|
|
18
|
-
): ParsePiSettingsResult {
|
|
15
|
+
export function parsePiSettings(piDir: PathState, settings: TextFileState): ParsePiSettingsResult {
|
|
19
16
|
const piDirectory = validateOptionalDirectoryState({
|
|
20
17
|
pathLabel: ".pi",
|
|
21
18
|
state: piDir,
|
|
@@ -1,62 +1,54 @@
|
|
|
1
|
+
import type { PathState, TextFileState } from "@nseng-ai/harness-artifacts/api";
|
|
2
|
+
|
|
1
3
|
import type { AregCliContext } from "../context.ts";
|
|
2
4
|
import type {
|
|
3
5
|
AregCheckPairingDirectory,
|
|
4
6
|
AregCheckSkillInspection,
|
|
5
|
-
AregInstructionFilesInspection,
|
|
6
|
-
AregPathState,
|
|
7
7
|
AregProjectBaseInspection,
|
|
8
8
|
AregReplacementInspection,
|
|
9
9
|
AregSkillKindSkillInspection,
|
|
10
10
|
AregSkillNameInventory,
|
|
11
|
-
AregTextFileState,
|
|
12
11
|
} from "../gateways.ts";
|
|
12
|
+
import {
|
|
13
|
+
manifestSkillKindNames,
|
|
14
|
+
type AregManifestSkillSourcesInspection,
|
|
15
|
+
} from "./manifest-sources.ts";
|
|
13
16
|
import { uniqueSortedStrings } from "../sort.ts";
|
|
14
|
-
import { parseInspectedLockfile } from "
|
|
17
|
+
import { parseInspectedLockfile } from "@nseng-ai/harness-artifacts/api";
|
|
15
18
|
|
|
16
19
|
export interface AregProjectInspectionFacts extends AregProjectBaseInspection {
|
|
17
|
-
piDir:
|
|
18
|
-
piSettings:
|
|
20
|
+
piDir: PathState;
|
|
21
|
+
piSettings: TextFileState;
|
|
19
22
|
replacement: AregReplacementInspection;
|
|
20
23
|
skillInventory: AregSkillNameInventory;
|
|
24
|
+
manifestSkillSources: AregManifestSkillSourcesInspection;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
export interface AregCheckProjectInspection {
|
|
24
28
|
projectDir: string;
|
|
25
|
-
projectPathState:
|
|
26
|
-
lockfile:
|
|
29
|
+
projectPathState: PathState;
|
|
30
|
+
lockfile: TextFileState;
|
|
27
31
|
skillsDirectoryNames: readonly string[];
|
|
28
32
|
agentsSkillNames: readonly string[];
|
|
29
33
|
excludedSkillNames: readonly string[];
|
|
30
|
-
piDir:
|
|
31
|
-
piSettings:
|
|
34
|
+
piDir: PathState;
|
|
35
|
+
piSettings: TextFileState;
|
|
32
36
|
replacement: AregReplacementInspection;
|
|
37
|
+
manifestSkillSources: AregManifestSkillSourcesInspection;
|
|
33
38
|
skills: readonly AregCheckSkillInspection[];
|
|
34
39
|
pairingDirectories: readonly AregCheckPairingDirectory[];
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
export interface AregSkillKindProjectInspection {
|
|
38
43
|
projectDir: string;
|
|
39
|
-
projectPathState:
|
|
40
|
-
piDir:
|
|
41
|
-
piSettings:
|
|
44
|
+
projectPathState: PathState;
|
|
45
|
+
piDir: PathState;
|
|
46
|
+
piSettings: TextFileState;
|
|
42
47
|
replacement: AregReplacementInspection;
|
|
48
|
+
manifestSkillSources: AregManifestSkillSourcesInspection;
|
|
43
49
|
skills: readonly AregSkillKindSkillInspection[];
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
export type AregInitProjectInspection = AregProjectBaseInspection & AregInstructionFilesInspection;
|
|
47
|
-
|
|
48
|
-
export async function inspectInitProject(
|
|
49
|
-
ctx: AregCliContext,
|
|
50
|
-
projectPath: string,
|
|
51
|
-
): Promise<AregInitProjectInspection> {
|
|
52
|
-
const base = await ctx.project.inspectProjectBase({ cwd: ctx.cwd, projectPath, env: ctx.env });
|
|
53
|
-
const instructionFiles = await ctx.project.inspectInstructionFiles({
|
|
54
|
-
projectDir: base.projectDir,
|
|
55
|
-
env: ctx.env,
|
|
56
|
-
});
|
|
57
|
-
return { ...base, ...instructionFiles };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
52
|
export async function collectProjectInspectionFacts(
|
|
61
53
|
ctx: AregCliContext,
|
|
62
54
|
projectPath: string,
|
|
@@ -70,12 +62,17 @@ export async function collectProjectInspectionFacts(
|
|
|
70
62
|
projectDir: base.projectDir,
|
|
71
63
|
env: ctx.env,
|
|
72
64
|
});
|
|
65
|
+
const manifestSkillSources = await ctx.project.inspectManifestSkillSources({
|
|
66
|
+
projectDir: base.projectDir,
|
|
67
|
+
env: ctx.env,
|
|
68
|
+
});
|
|
73
69
|
return {
|
|
74
70
|
...base,
|
|
75
71
|
piDir: piArtifacts.piDir,
|
|
76
72
|
piSettings: piArtifacts.piSettings,
|
|
77
73
|
replacement: piArtifacts.replacement,
|
|
78
74
|
skillInventory,
|
|
75
|
+
manifestSkillSources,
|
|
79
76
|
};
|
|
80
77
|
}
|
|
81
78
|
|
|
@@ -92,11 +89,13 @@ export async function inspectCheckProject(
|
|
|
92
89
|
const lockfileSkillNames = lockfileResult.ok
|
|
93
90
|
? lockfileResult.value.skills.map((skill) => skill.name)
|
|
94
91
|
: [];
|
|
92
|
+
const manifestSkillNames = facts.manifestSkillSources.sources.map((source) => source.skillName);
|
|
95
93
|
const skillNames = uniqueSortedStrings([
|
|
96
94
|
...lockfileSkillNames,
|
|
97
95
|
...facts.skillInventory.skillsDirectoryNames,
|
|
98
96
|
...facts.skillInventory.agentsSkillNames,
|
|
99
97
|
...facts.skillInventory.claudeSkillNames,
|
|
98
|
+
...manifestSkillNames,
|
|
100
99
|
]);
|
|
101
100
|
return {
|
|
102
101
|
projectDir: facts.projectDir,
|
|
@@ -108,6 +107,7 @@ export async function inspectCheckProject(
|
|
|
108
107
|
piDir: facts.piDir,
|
|
109
108
|
piSettings: facts.piSettings,
|
|
110
109
|
replacement: facts.replacement,
|
|
110
|
+
manifestSkillSources: facts.manifestSkillSources,
|
|
111
111
|
skills: await collectCheckSkillInspections(ctx, facts.projectDir, skillNames),
|
|
112
112
|
pairingDirectories: await ctx.project.inspectPairingDirectories({
|
|
113
113
|
projectDir: facts.projectDir,
|
|
@@ -127,10 +127,14 @@ export async function inspectSkillKindProject(
|
|
|
127
127
|
piDir: facts.piDir,
|
|
128
128
|
piSettings: facts.piSettings,
|
|
129
129
|
replacement: facts.replacement,
|
|
130
|
+
manifestSkillSources: facts.manifestSkillSources,
|
|
130
131
|
skills: await collectSkillKindInspections(
|
|
131
132
|
ctx,
|
|
132
133
|
facts.projectDir,
|
|
133
|
-
|
|
134
|
+
uniqueSortedStrings([
|
|
135
|
+
...facts.skillInventory.skillKindNames,
|
|
136
|
+
...manifestSkillKindNames(facts.manifestSkillSources.sources),
|
|
137
|
+
]),
|
|
134
138
|
),
|
|
135
139
|
};
|
|
136
140
|
}
|
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
AregErrorInfo,
|
|
4
4
|
AregProjectGateway,
|
|
5
5
|
AregProjectManagedTargetRequest,
|
|
6
|
-
AregProjectMutationPolicy,
|
|
7
6
|
AregProjectMutationResult,
|
|
8
7
|
} from "../gateways.ts";
|
|
9
8
|
|
|
@@ -29,34 +28,23 @@ interface ProjectDeleteSymlinkPlan {
|
|
|
29
28
|
description: string;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
interface
|
|
31
|
+
interface ApplyProjectMutationPlanRequest {
|
|
33
32
|
ctx: AregCliContext;
|
|
34
33
|
projectDir: string;
|
|
35
34
|
writes: readonly ProjectTextWritePlan[];
|
|
35
|
+
deletes: readonly ProjectDeletePlan[];
|
|
36
|
+
deleteSymlinks: readonly ProjectDeleteSymlinkPlan[];
|
|
37
|
+
removeEmptyDirs: readonly ProjectRemoveEmptyDirPlan[];
|
|
36
38
|
execute?: boolean;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
type ApplyProjectMutationPlanRequest =
|
|
40
|
-
| (BaseApplyProjectMutationPlanRequest & {
|
|
41
|
-
policy: Exclude<AregProjectMutationPolicy, "skill-kind">;
|
|
42
|
-
})
|
|
43
|
-
| (BaseApplyProjectMutationPlanRequest & {
|
|
44
|
-
policy: "skill-kind";
|
|
45
|
-
deletes: readonly ProjectDeletePlan[];
|
|
46
|
-
deleteSymlinks: readonly ProjectDeleteSymlinkPlan[];
|
|
47
|
-
removeEmptyDirs: readonly ProjectRemoveEmptyDirPlan[];
|
|
48
|
-
});
|
|
49
|
-
|
|
50
41
|
export const PROJECT_FILE_MUTATION_OPERATION_TYPES = [
|
|
51
42
|
"write",
|
|
52
43
|
"delete",
|
|
53
44
|
"delete-symlink",
|
|
54
45
|
"remove-empty-dir",
|
|
55
46
|
] as const;
|
|
56
|
-
export const PROJECT_MUTATION_OPERATION_TYPES = [
|
|
57
|
-
...PROJECT_FILE_MUTATION_OPERATION_TYPES,
|
|
58
|
-
"external",
|
|
59
|
-
] as const;
|
|
47
|
+
export const PROJECT_MUTATION_OPERATION_TYPES = [...PROJECT_FILE_MUTATION_OPERATION_TYPES] as const;
|
|
60
48
|
export const PROJECT_MUTATION_OPERATION_STATUSES = [
|
|
61
49
|
"applied",
|
|
62
50
|
"failed",
|
|
@@ -211,7 +199,6 @@ function flattenProjectMutationPlan(
|
|
|
211
199
|
plan,
|
|
212
200
|
}),
|
|
213
201
|
);
|
|
214
|
-
if (request.policy !== "skill-kind") return writes;
|
|
215
202
|
const deletes = request.deletes.map(
|
|
216
203
|
(plan): DeleteOperation => ({
|
|
217
204
|
type: "delete",
|
|
@@ -248,7 +235,6 @@ const PROJECT_MUTATION_OPERATION_HANDLERS = {
|
|
|
248
235
|
content: operation.plan.content,
|
|
249
236
|
description: operation.plan.description,
|
|
250
237
|
createParent: operation.plan.createParent,
|
|
251
|
-
policy: request.policy,
|
|
252
238
|
env: request.ctx.env,
|
|
253
239
|
});
|
|
254
240
|
},
|
|
@@ -259,7 +245,6 @@ const PROJECT_MUTATION_OPERATION_HANDLERS = {
|
|
|
259
245
|
content: operation.plan.content,
|
|
260
246
|
description: operation.plan.description,
|
|
261
247
|
createParent: operation.plan.createParent,
|
|
262
|
-
policy: request.policy,
|
|
263
248
|
env: request.ctx.env,
|
|
264
249
|
});
|
|
265
250
|
},
|
|
@@ -339,7 +324,6 @@ function managedTargetRequest(
|
|
|
339
324
|
projectDir: request.projectDir,
|
|
340
325
|
relativePath: operation.plan.relativePath,
|
|
341
326
|
description: operation.plan.description,
|
|
342
|
-
policy: "skill-kind",
|
|
343
327
|
env: request.ctx.env,
|
|
344
328
|
};
|
|
345
329
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { AregCliContext } from "../context.ts";
|
|
2
|
-
import type {
|
|
2
|
+
import type { PathState } from "@nseng-ai/harness-artifacts/api";
|
|
3
3
|
|
|
4
4
|
export interface ProjectPathInspection {
|
|
5
5
|
projectDir: string;
|
|
6
|
-
projectPathState:
|
|
6
|
+
projectPathState: PathState;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export type ResolvedProjectGitRoot<TInspection extends ProjectPathInspection> =
|
|
@@ -7,13 +7,18 @@ import {
|
|
|
7
7
|
skillLookupFileRelativePath,
|
|
8
8
|
skillLookupRootRank,
|
|
9
9
|
type SkillLookupRoot,
|
|
10
|
-
} from "
|
|
10
|
+
} from "@nseng-ai/foundation/skill-lookup";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import type { AregCliContext } from "../context.ts";
|
|
14
14
|
import type { AregSkillFindSkillInspection } from "../gateways.ts";
|
|
15
|
+
import {
|
|
16
|
+
aregManifestSkillSourceViewSchema,
|
|
17
|
+
manifestSourceViewsBySkillName,
|
|
18
|
+
type AregManifestSkillSourceView,
|
|
19
|
+
} from "./manifest-sources.ts";
|
|
15
20
|
import { toProjectPath } from "../gateways/project-fs.ts";
|
|
16
|
-
import { parseSkillFrontmatterBlock } from "
|
|
21
|
+
import { parseSkillFrontmatterBlock } from "@nseng-ai/harness-artifacts/api";
|
|
17
22
|
import { inspectResolvedProjectGitRoot } from "./project-resolution.ts";
|
|
18
23
|
|
|
19
24
|
const skillFindRootSchema = z.enum(SKILL_LOOKUP_ROOTS);
|
|
@@ -25,6 +30,8 @@ const skillFindWarningSchema = z.object({
|
|
|
25
30
|
path: z.string(),
|
|
26
31
|
});
|
|
27
32
|
|
|
33
|
+
const skillFindManifestSourceSchema = aregManifestSkillSourceViewSchema;
|
|
34
|
+
|
|
28
35
|
const skillFindMatchSchema = z.object({
|
|
29
36
|
name: z.string(),
|
|
30
37
|
root: skillFindRootSchema,
|
|
@@ -37,6 +44,7 @@ const skillFindMatchSchema = z.object({
|
|
|
37
44
|
frontmatterName: z.string().optional(),
|
|
38
45
|
description: z.string().optional(),
|
|
39
46
|
shouldDisableModelInvocation: z.boolean().optional(),
|
|
47
|
+
manifestSources: z.array(skillFindManifestSourceSchema).optional(),
|
|
40
48
|
warnings: z.array(skillFindWarningSchema).optional(),
|
|
41
49
|
});
|
|
42
50
|
|
|
@@ -103,13 +111,18 @@ export async function runSkillFind(
|
|
|
103
111
|
if (resolved.type === "error") return failure("project-inspection-failed", resolved.message);
|
|
104
112
|
const projectDir = resolved.projectDir;
|
|
105
113
|
const inspection = await ctx.project.inspectSkillFindRoots({ projectDir, env: ctx.env });
|
|
114
|
+
const manifestSources = await ctx.project.inspectManifestSkillSources({
|
|
115
|
+
projectDir,
|
|
116
|
+
env: ctx.env,
|
|
117
|
+
});
|
|
118
|
+
const manifestSourceViews = manifestSourceViewsBySkillName(manifestSources.sources);
|
|
106
119
|
const searchedRoots = buildSkillFindSearchedRoots(projectDir, request.skill);
|
|
107
120
|
const exactSkills = inspection.skills
|
|
108
121
|
.filter((skill) => skill.name === request.skill)
|
|
109
122
|
.toSorted(compareSkillFindInspection);
|
|
110
123
|
if (exactSkills.length > 0) {
|
|
111
124
|
const matches = exactSkills.map((skill, index) =>
|
|
112
|
-
toSkillFindMatch(projectDir, skill, index === 0),
|
|
125
|
+
toSkillFindMatch(projectDir, skill, index === 0, manifestSourceViews.get(skill.name)),
|
|
113
126
|
);
|
|
114
127
|
const preferred = matches[0];
|
|
115
128
|
if (preferred === undefined)
|
|
@@ -155,6 +168,7 @@ function toSkillFindMatch(
|
|
|
155
168
|
projectDir: string,
|
|
156
169
|
skill: AregSkillFindSkillInspection,
|
|
157
170
|
isPreferred: boolean,
|
|
171
|
+
manifestSources: readonly AregManifestSkillSourceView[] | undefined,
|
|
158
172
|
): SkillFindMatch {
|
|
159
173
|
const skillFileRelativePath = skillLookupFileRelativePath(skill.root, skill.name);
|
|
160
174
|
const skillFilePath = toProjectPath(projectDir, skillFileRelativePath);
|
|
@@ -169,6 +183,7 @@ function toSkillFindMatch(
|
|
|
169
183
|
basePath: toProjectPath(projectDir, skill.baseRelativePath),
|
|
170
184
|
skillFilePath,
|
|
171
185
|
...frontmatter.fields,
|
|
186
|
+
...(manifestSources === undefined ? {} : { manifestSources: [...manifestSources] }),
|
|
172
187
|
...(frontmatter.warnings.length === 0 ? {} : { warnings: frontmatter.warnings }),
|
|
173
188
|
};
|
|
174
189
|
}
|
|
@@ -280,6 +295,11 @@ function renderSkillFindSuccess(result: SkillFindSuccessResult): string {
|
|
|
280
295
|
for (const match of result.matches) {
|
|
281
296
|
const marker = hasDuplicates ? (match.isPreferred ? "* " : " ") : "";
|
|
282
297
|
lines.push(` ${marker}${match.skillFileRelativePath}`);
|
|
298
|
+
for (const source of match.manifestSources ?? []) {
|
|
299
|
+
lines.push(
|
|
300
|
+
` manifest: ${source.harness} ${source.manifestKey} ${source.packageName}@${source.version}`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
283
303
|
}
|
|
284
304
|
return lines.join("\n");
|
|
285
305
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
claudeSkillMirrorRelativePath,
|
|
14
14
|
expectedAgentsSkillSymlinkTarget,
|
|
15
15
|
expectedClaudeSkillSymlinkTarget,
|
|
16
|
-
} from "
|
|
16
|
+
} from "@nseng-ai/harness-artifacts/api";
|
|
17
17
|
import { parsePiSettings, type PiSettingsData } from "./pi-settings.ts";
|
|
18
18
|
import {
|
|
19
19
|
PROJECT_FILE_MUTATION_OPERATION_TYPES,
|
|
@@ -416,7 +416,7 @@ export function deletionPrompt(plan: SkillKindApplyPlan): string {
|
|
|
416
416
|
.filter(isDeletionOperation)
|
|
417
417
|
.map((operation) => `- ${operation.relativePath}`)
|
|
418
418
|
.join("\n");
|
|
419
|
-
return `Apply ${plan.kind} to ${plan.skill} will delete
|
|
419
|
+
return `Apply ${plan.kind} to ${plan.skill} will delete harness overlays:\n${paths}\nContinue?`;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
function isDeletionOperation(operation: PlannedApplyOperation): boolean {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { err, type Result } from "@nseng-ai/foundation/result";
|
|
2
2
|
|
|
3
3
|
import type { AregSkillKindSkillInspection } from "../gateways.ts";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { sortStringsLocaleAware } from "../sort.ts";
|
|
5
|
+
import {
|
|
6
|
+
manifestSourceViewsBySkillName,
|
|
7
|
+
type AregManifestSkillSourceView,
|
|
8
|
+
} from "./manifest-sources.ts";
|
|
9
|
+
import {
|
|
10
|
+
parseSkillFrontmatterBlock,
|
|
11
|
+
type SkillFrontmatterData,
|
|
12
|
+
} from "@nseng-ai/harness-artifacts/api";
|
|
6
13
|
import {
|
|
7
14
|
formatReplacementLabel,
|
|
8
15
|
replacementAdvice,
|
|
@@ -90,6 +97,8 @@ export interface SkillKindReplacementInfo {
|
|
|
90
97
|
advice?: string;
|
|
91
98
|
}
|
|
92
99
|
|
|
100
|
+
export type SkillKindManifestSourceInfo = AregManifestSkillSourceView;
|
|
101
|
+
|
|
93
102
|
export interface SkillKindRecord {
|
|
94
103
|
skill: string;
|
|
95
104
|
kind: InferredSkillInvocationKind;
|
|
@@ -98,6 +107,7 @@ export interface SkillKindRecord {
|
|
|
98
107
|
piExtension: PiExtensionStatus;
|
|
99
108
|
artifacts: SkillKindArtifactFacts;
|
|
100
109
|
replacement: SkillKindReplacementInfo;
|
|
110
|
+
manifestSources: readonly SkillKindManifestSourceInfo[];
|
|
101
111
|
notes: readonly string[];
|
|
102
112
|
}
|
|
103
113
|
|
|
@@ -164,6 +174,7 @@ export function inferSkillKindRecord(options: {
|
|
|
164
174
|
piExtension: piExtensionStatus(kind, artifacts, options.replacement),
|
|
165
175
|
artifacts,
|
|
166
176
|
replacement,
|
|
177
|
+
manifestSources: [],
|
|
167
178
|
notes: buildNotes({
|
|
168
179
|
skillName: options.skillName,
|
|
169
180
|
kind,
|
|
@@ -188,6 +199,9 @@ export function buildSkillKindRecords(
|
|
|
188
199
|
const piSettings = parsePiSettings(inspection.piDir, inspection.piSettings);
|
|
189
200
|
if (!piSettings.ok) return piSettings;
|
|
190
201
|
const records: SkillKindRecord[] = [];
|
|
202
|
+
const manifestSourceViews = manifestSourceViewsBySkillName(
|
|
203
|
+
inspection.manifestSkillSources.sources,
|
|
204
|
+
);
|
|
191
205
|
for (const skill of sortSkills(inspection.skills)) {
|
|
192
206
|
const readiness = validateInspectableSkill(skill);
|
|
193
207
|
if (!readiness.ok) return readiness;
|
|
@@ -202,17 +216,19 @@ export function buildSkillKindRecords(
|
|
|
202
216
|
);
|
|
203
217
|
if (!frontmatter.ok) return frontmatter;
|
|
204
218
|
const replacement = verifyPiReplacement(skill.name, inspection.replacement);
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
219
|
+
const record = inferSkillKindRecord({
|
|
220
|
+
skillName: skill.name,
|
|
221
|
+
frontmatter: frontmatter.value,
|
|
222
|
+
hasCodexSidecar: skill.openaiPolicy.type === "file",
|
|
223
|
+
isPiExcluded: piSettings.value.exclusions.includes(`-skills/${skill.name}`),
|
|
224
|
+
hasAgentsMirror: skill.agentsPath.type !== "missing",
|
|
225
|
+
hasClaudeMirror: skill.claudePath.type !== "missing",
|
|
226
|
+
replacement,
|
|
227
|
+
});
|
|
228
|
+
records.push({
|
|
229
|
+
...record,
|
|
230
|
+
manifestSources: manifestSourceViews.get(skill.name) ?? [],
|
|
231
|
+
});
|
|
216
232
|
}
|
|
217
233
|
return { ok: true, value: records };
|
|
218
234
|
}
|
|
@@ -385,7 +401,7 @@ function sortSkills(
|
|
|
385
401
|
skills: readonly AregSkillKindSkillInspection[],
|
|
386
402
|
): readonly AregSkillKindSkillInspection[] {
|
|
387
403
|
const byName = new Map(skills.map((skill) => [skill.name, skill]));
|
|
388
|
-
return
|
|
404
|
+
return sortStringsLocaleAware([...byName.keys()])
|
|
389
405
|
.map((name) => byName.get(name))
|
|
390
406
|
.filter((skill): skill is AregSkillKindSkillInspection => skill !== undefined);
|
|
391
407
|
}
|