@vibe-engineer/adapter-pi 0.1.0
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/dist/capabilities/index.d.ts +12 -0
- package/dist/capabilities/index.js +21 -0
- package/dist/chunk-PJHJYGIJ.js +392 -0
- package/dist/chunk-RC3EILIE.js +243 -0
- package/dist/chunk-VXZJPOEE.js +751 -0
- package/dist/create-consumption/index.d.ts +56 -0
- package/dist/create-consumption/index.js +14 -0
- package/dist/generated-file-manifest/index.d.ts +10 -0
- package/dist/generated-file-manifest/index.js +24 -0
- package/dist/schema/index.d.ts +214 -0
- package/dist/schema/index.js +28 -0
- package/package.json +61 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AdapterCapabilityMatrix, AdapterCapability, ValidationResult } from '../schema/index.js';
|
|
2
|
+
|
|
3
|
+
declare const PI_ADAPTER_ID: "pi";
|
|
4
|
+
declare const PI_ADAPTER_CAPABILITY_SCHEMA_VERSION: "pi-adapter-capability-matrix/v1";
|
|
5
|
+
declare const VIBE_ENGINEER_SKILLS: ("brainstorm" | "grill-me" | "task" | "plan" | "build" | "ship")[];
|
|
6
|
+
declare const PI_ADAPTER_CAPABILITY_MATRIX: AdapterCapabilityMatrix;
|
|
7
|
+
declare const getPiAdapterCapabilityMatrix: () => AdapterCapabilityMatrix;
|
|
8
|
+
declare const validatePiAdapterCapabilityMatrix: (value: unknown) => ValidationResult<AdapterCapabilityMatrix>;
|
|
9
|
+
declare const getAdapterCapabilityById: (matrix: AdapterCapabilityMatrix, adapterId: string) => AdapterCapability | undefined;
|
|
10
|
+
declare const isAdapterManifestSelectable: (matrix: AdapterCapabilityMatrix, adapterId: string) => boolean;
|
|
11
|
+
|
|
12
|
+
export { PI_ADAPTER_CAPABILITY_MATRIX, PI_ADAPTER_CAPABILITY_SCHEMA_VERSION, PI_ADAPTER_ID, VIBE_ENGINEER_SKILLS, getAdapterCapabilityById, getPiAdapterCapabilityMatrix, isAdapterManifestSelectable, validatePiAdapterCapabilityMatrix };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PI_ADAPTER_CAPABILITY_MATRIX,
|
|
3
|
+
PI_ADAPTER_CAPABILITY_SCHEMA_VERSION,
|
|
4
|
+
PI_ADAPTER_ID,
|
|
5
|
+
VIBE_ENGINEER_SKILLS,
|
|
6
|
+
getAdapterCapabilityById,
|
|
7
|
+
getPiAdapterCapabilityMatrix,
|
|
8
|
+
isAdapterManifestSelectable,
|
|
9
|
+
validatePiAdapterCapabilityMatrix
|
|
10
|
+
} from "../chunk-RC3EILIE.js";
|
|
11
|
+
import "../chunk-VXZJPOEE.js";
|
|
12
|
+
export {
|
|
13
|
+
PI_ADAPTER_CAPABILITY_MATRIX,
|
|
14
|
+
PI_ADAPTER_CAPABILITY_SCHEMA_VERSION,
|
|
15
|
+
PI_ADAPTER_ID,
|
|
16
|
+
VIBE_ENGINEER_SKILLS,
|
|
17
|
+
getAdapterCapabilityById,
|
|
18
|
+
getPiAdapterCapabilityMatrix,
|
|
19
|
+
isAdapterManifestSelectable,
|
|
20
|
+
validatePiAdapterCapabilityMatrix
|
|
21
|
+
};
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPiAdapterCapabilityMatrix
|
|
3
|
+
} from "./chunk-RC3EILIE.js";
|
|
4
|
+
import {
|
|
5
|
+
SKILL_IDS,
|
|
6
|
+
createDownstreamManifestSummary,
|
|
7
|
+
validateCapabilityMatrix,
|
|
8
|
+
validateGeneratedFileManifest
|
|
9
|
+
} from "./chunk-VXZJPOEE.js";
|
|
10
|
+
|
|
11
|
+
// src/generated-file-manifest/index.ts
|
|
12
|
+
var PI_GENERATED_FILE_MANIFEST_SCHEMA_VERSION = "pi-generated-file-manifest/v1";
|
|
13
|
+
var version = (formatName, formatVersion) => ({
|
|
14
|
+
formatName,
|
|
15
|
+
formatVersion,
|
|
16
|
+
schemaVersion: PI_GENERATED_FILE_MANIFEST_SCHEMA_VERSION,
|
|
17
|
+
adapterCapabilityVersion: "pi-adapter-capability-matrix/v1"
|
|
18
|
+
});
|
|
19
|
+
var trustSecurity = (overrides) => ({
|
|
20
|
+
...overrides,
|
|
21
|
+
evidence: {
|
|
22
|
+
state: "known",
|
|
23
|
+
source: "DL-06-agentic-harness-integrations.md + DL-22-security-safety-model.md",
|
|
24
|
+
notes: "Generated-file family carries explicit trust, sandbox, credential, command, external-integration, and destructive-operation semantics."
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
var family = (familyId, description, pathPatterns, producedByLane, consumedByLanes, security, fileVersion, readinessState, reason) => ({
|
|
28
|
+
familyId,
|
|
29
|
+
description,
|
|
30
|
+
pathPatterns,
|
|
31
|
+
owner: {
|
|
32
|
+
ownerKind: "lane",
|
|
33
|
+
ownerId: producedByLane,
|
|
34
|
+
writePathScope: pathPatterns,
|
|
35
|
+
allowedOperations: ["generate-in-later-lane", "validate"]
|
|
36
|
+
},
|
|
37
|
+
producedByLane,
|
|
38
|
+
consumedByLanes,
|
|
39
|
+
trustSecurity: security,
|
|
40
|
+
version: fileVersion,
|
|
41
|
+
readiness: {
|
|
42
|
+
state: readinessState,
|
|
43
|
+
reason
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
var projectInstructionSecurity = trustSecurity({
|
|
47
|
+
classification: "project-instruction",
|
|
48
|
+
trustBoundary: "Project-local instructions are loaded by pi after project trust; content must remain domain-neutral and cannot embed secrets.",
|
|
49
|
+
projectTrustRequired: true,
|
|
50
|
+
executesCode: false,
|
|
51
|
+
commandPolicy: "not-applicable",
|
|
52
|
+
sandboxCapability: "not_provided",
|
|
53
|
+
credentialPolicy: "no-credentials-required",
|
|
54
|
+
externalIntegration: "disabled-by-default",
|
|
55
|
+
destructiveOperationPolicy: "forbidden"
|
|
56
|
+
});
|
|
57
|
+
var PI_GENERATED_FILE_MANIFEST = {
|
|
58
|
+
schemaVersion: PI_GENERATED_FILE_MANIFEST_SCHEMA_VERSION,
|
|
59
|
+
adapterId: "pi",
|
|
60
|
+
adapterCapabilityVersion: "pi-adapter-capability-matrix/v1",
|
|
61
|
+
producedByLane: "I-14A-pi-adapter-capability-generated-file-manifest",
|
|
62
|
+
families: [
|
|
63
|
+
family(
|
|
64
|
+
"pi-skill-files",
|
|
65
|
+
"Agent Skills-compatible files for the six locked vibe-engineer skills.",
|
|
66
|
+
[".pi/skills/<skill>/SKILL.md", ".agents/skills/<skill>/SKILL.md"],
|
|
67
|
+
"I-14B-pi-adapter-runtime-skill-consumption",
|
|
68
|
+
["I-14B-pi-adapter-runtime-skill-consumption", "I-15A-create-import-cli-ux-selected-harness", "I-21-build-skill-orchestration"],
|
|
69
|
+
projectInstructionSecurity,
|
|
70
|
+
version("Agent Skills SKILL.md", "v1"),
|
|
71
|
+
"ready",
|
|
72
|
+
"Manifest family is declared and validated by I-14A; actual file generation/runtime proof belongs to I-14B/I-15A."
|
|
73
|
+
),
|
|
74
|
+
family(
|
|
75
|
+
"pi-prompt-templates",
|
|
76
|
+
"Reusable pi slash-command prompt templates for generated skill workflows.",
|
|
77
|
+
[".pi/prompts/<name>.md"],
|
|
78
|
+
"I-14B-pi-adapter-runtime-skill-consumption",
|
|
79
|
+
["I-14B-pi-adapter-runtime-skill-consumption", "I-15A-create-import-cli-ux-selected-harness"],
|
|
80
|
+
projectInstructionSecurity,
|
|
81
|
+
version("Pi prompt template markdown", "v1"),
|
|
82
|
+
"ready",
|
|
83
|
+
"Templates are an allowed family only when downstream lanes validate manifest metadata and avoid silent unsupported behavior."
|
|
84
|
+
),
|
|
85
|
+
family(
|
|
86
|
+
"pi-extensions",
|
|
87
|
+
"Optional TypeScript extensions for commands, tools, hooks, permission/path gates, subagent or plan-mode-like behavior, and dynamic resources.",
|
|
88
|
+
[".pi/extensions/<name>.ts", ".pi/extensions/<name>/index.ts"],
|
|
89
|
+
"I-14B-pi-adapter-runtime-skill-consumption",
|
|
90
|
+
["I-14B-pi-adapter-runtime-skill-consumption", "I-18-security-safety-hooks-policy", "I-21-build-skill-orchestration"],
|
|
91
|
+
trustSecurity({
|
|
92
|
+
classification: "executable-extension",
|
|
93
|
+
trustBoundary: "TypeScript extension code executes with pi/package permissions after project trust; no sandbox isolation is claimed by I-14A.",
|
|
94
|
+
projectTrustRequired: true,
|
|
95
|
+
executesCode: true,
|
|
96
|
+
commandPolicy: "default-deny",
|
|
97
|
+
sandboxCapability: "not_provided",
|
|
98
|
+
credentialPolicy: "operator-supplied-only",
|
|
99
|
+
externalIntegration: "disabled-by-default",
|
|
100
|
+
destructiveOperationPolicy: "approval-required"
|
|
101
|
+
}),
|
|
102
|
+
version("Pi TypeScript extension", "v1"),
|
|
103
|
+
"blocked",
|
|
104
|
+
"Executable extension generation and live loading are intentionally blocked until I-14B/I-18 prove the actual runtime/security boundary."
|
|
105
|
+
),
|
|
106
|
+
family(
|
|
107
|
+
"pi-package-manifest",
|
|
108
|
+
"Optional package.json `pi` key for shareable resources.",
|
|
109
|
+
["package.json#pi"],
|
|
110
|
+
"I-14B-pi-adapter-runtime-skill-consumption",
|
|
111
|
+
["I-14B-pi-adapter-runtime-skill-consumption", "I-15B-starter-template-harness-consumption"],
|
|
112
|
+
trustSecurity({
|
|
113
|
+
classification: "package-manifest",
|
|
114
|
+
trustBoundary: "Pi package install/update/trust behavior must be explicit before a package manifest is generated or consumed.",
|
|
115
|
+
projectTrustRequired: true,
|
|
116
|
+
executesCode: true,
|
|
117
|
+
commandPolicy: "default-deny",
|
|
118
|
+
sandboxCapability: "not_provided",
|
|
119
|
+
credentialPolicy: "operator-supplied-only",
|
|
120
|
+
externalIntegration: "disabled-by-default",
|
|
121
|
+
destructiveOperationPolicy: "approval-required"
|
|
122
|
+
}),
|
|
123
|
+
version("Pi package manifest key", "v1"),
|
|
124
|
+
"deferred",
|
|
125
|
+
"Optional package distribution is declared for compatibility but not generated by I-14A."
|
|
126
|
+
),
|
|
127
|
+
family(
|
|
128
|
+
"context-files",
|
|
129
|
+
"Project context/instruction files loaded by pi and optional cross-harness compatibility context.",
|
|
130
|
+
["AGENTS.md", "CLAUDE.md"],
|
|
131
|
+
"I-15A-create-import-cli-ux-selected-harness",
|
|
132
|
+
["I-15A-create-import-cli-ux-selected-harness", "I-08-context-graph-index-drift", "I-21-build-skill-orchestration"],
|
|
133
|
+
projectInstructionSecurity,
|
|
134
|
+
version("Pi context file", "v1"),
|
|
135
|
+
"ready",
|
|
136
|
+
"Context file family is ready as manifest data; actual starter/create writes belong to I-15A."
|
|
137
|
+
),
|
|
138
|
+
family(
|
|
139
|
+
"harness-config",
|
|
140
|
+
"Generated harness config fields recording `agenticHarness: pi` and adapter capability/version metadata.",
|
|
141
|
+
["generated harness config field: agenticHarness=pi", "generated harness config field: adapterCapabilityVersion", "generated harness config field: generatedFileManifestVersion"],
|
|
142
|
+
"I-15A-create-import-cli-ux-selected-harness",
|
|
143
|
+
["I-15A-create-import-cli-ux-selected-harness", "I-15B-starter-template-harness-consumption", "I-21-build-skill-orchestration"],
|
|
144
|
+
trustSecurity({
|
|
145
|
+
classification: "configuration",
|
|
146
|
+
trustBoundary: "Configuration selects the typed pi adapter manifest only; it must not silently enable unsupported non-pi harnesses or runtime claims.",
|
|
147
|
+
projectTrustRequired: false,
|
|
148
|
+
executesCode: false,
|
|
149
|
+
commandPolicy: "not-applicable",
|
|
150
|
+
sandboxCapability: "not_provided",
|
|
151
|
+
credentialPolicy: "no-credentials-required",
|
|
152
|
+
externalIntegration: "disabled-by-default",
|
|
153
|
+
destructiveOperationPolicy: "forbidden"
|
|
154
|
+
}),
|
|
155
|
+
version("vibe-engineer harness adapter config", "v1"),
|
|
156
|
+
"ready",
|
|
157
|
+
"Config metadata is ready for downstream consumption after this manifest validates; create/import behavior remains I-15A-owned."
|
|
158
|
+
)
|
|
159
|
+
]
|
|
160
|
+
};
|
|
161
|
+
var getPiGeneratedFileManifest = () => structuredClone(PI_GENERATED_FILE_MANIFEST);
|
|
162
|
+
var validatePiGeneratedFileManifest = (value) => validateGeneratedFileManifest(value);
|
|
163
|
+
var createPiDownstreamManifestSummary = () => createDownstreamManifestSummary(getPiAdapterCapabilityMatrix(), getPiGeneratedFileManifest());
|
|
164
|
+
|
|
165
|
+
// src/create-consumption/index.ts
|
|
166
|
+
var CREATE_PI_ASSET_FAMILIES = Object.freeze(["pi-skill-files", "pi-prompt-templates"]);
|
|
167
|
+
var CREATE_CONSUMER_LANE = "I-15A-create-import-cli-ux-selected-harness";
|
|
168
|
+
var RUNTIME_PRODUCER_LANE = "I-14B-pi-adapter-runtime-skill-consumption";
|
|
169
|
+
var PI_SKILL_PATTERN = ".pi/skills/<skill>/SKILL.md";
|
|
170
|
+
var PI_PROMPT_PATTERN = ".pi/prompts/<name>.md";
|
|
171
|
+
var EXCLUDED_FAMILY_IDS = Object.freeze(["pi-extensions", "pi-package-manifest", "context-files", "harness-config"]);
|
|
172
|
+
var forbiddenDomainMarkers = () => Object.freeze([
|
|
173
|
+
"ecommerce",
|
|
174
|
+
"fashion",
|
|
175
|
+
"inventory",
|
|
176
|
+
"tenant",
|
|
177
|
+
"checkout",
|
|
178
|
+
"telegram",
|
|
179
|
+
"instagram",
|
|
180
|
+
"billz",
|
|
181
|
+
"pharmacy",
|
|
182
|
+
"ai-pipeline"
|
|
183
|
+
]);
|
|
184
|
+
var isCreateFamilyId = (familyId) => CREATE_PI_ASSET_FAMILIES.includes(familyId);
|
|
185
|
+
var issue = (issues, path, code, message) => {
|
|
186
|
+
issues.push({ path, code, message, severity: "error" });
|
|
187
|
+
};
|
|
188
|
+
var familyById = (manifest, familyId) => manifest.families.find((family2) => family2.familyId === familyId);
|
|
189
|
+
var sameStringSet = (actual, expected) => {
|
|
190
|
+
if (actual.length !== expected.length) return false;
|
|
191
|
+
const actualSet = new Set(actual);
|
|
192
|
+
return actualSet.size === actual.length && expected.every((expectedValue) => actualSet.has(expectedValue));
|
|
193
|
+
};
|
|
194
|
+
var relativePathSafe = (path) => path.length > 0 && !path.startsWith("/") && !path.startsWith("~") && !path.includes(":\\") && !path.split("/").some((segment) => segment === "" || segment === "..");
|
|
195
|
+
var hasDomainMarker = (content) => {
|
|
196
|
+
const lower = content.toLowerCase();
|
|
197
|
+
for (const marker of forbiddenDomainMarkers()) {
|
|
198
|
+
if (lower.includes(marker.toLowerCase())) return marker;
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
};
|
|
202
|
+
var validateManifestAndMatrix = (manifest, capabilityMatrix, issues) => {
|
|
203
|
+
const matrixValidation = validateCapabilityMatrix(capabilityMatrix);
|
|
204
|
+
if (!matrixValidation.valid) {
|
|
205
|
+
for (const matrixIssue of matrixValidation.issues) {
|
|
206
|
+
issue(issues, `capabilityMatrix${matrixIssue.path.slice(1)}`, matrixIssue.code, matrixIssue.message);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const manifestValidation = validateGeneratedFileManifest(manifest);
|
|
210
|
+
if (!manifestValidation.valid) {
|
|
211
|
+
for (const manifestIssue of manifestValidation.issues) {
|
|
212
|
+
issue(issues, `generatedFileManifest${manifestIssue.path.slice(1)}`, manifestIssue.code, manifestIssue.message);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const selectedFamilies = manifest.families.filter((family2) => isCreateFamilyId(family2.familyId));
|
|
216
|
+
if (!sameStringSet(selectedFamilies.map((family2) => family2.familyId), [...CREATE_PI_ASSET_FAMILIES])) {
|
|
217
|
+
issue(issues, "generatedFileManifest.families", "create_pi_asset_family_set_mismatch", "Create pi asset selector must be exactly pi-skill-files plus pi-prompt-templates.");
|
|
218
|
+
}
|
|
219
|
+
for (const familyId of CREATE_PI_ASSET_FAMILIES) {
|
|
220
|
+
const family2 = familyById(manifest, familyId);
|
|
221
|
+
if (family2 === void 0) {
|
|
222
|
+
issue(issues, `generatedFileManifest.families.${familyId}`, "missing_create_pi_asset_family", `Required create pi asset family '${familyId}' is absent.`);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (family2.readiness.state !== "ready") {
|
|
226
|
+
issue(issues, `generatedFileManifest.families.${familyId}.readiness`, "create_pi_asset_family_not_ready", `Create pi asset family '${familyId}' must be ready.`);
|
|
227
|
+
}
|
|
228
|
+
if (family2.producedByLane !== RUNTIME_PRODUCER_LANE) {
|
|
229
|
+
issue(issues, `generatedFileManifest.families.${familyId}.producedByLane`, "create_pi_asset_family_wrong_producer", `Create pi asset family '${familyId}' must be produced by ${RUNTIME_PRODUCER_LANE}.`);
|
|
230
|
+
}
|
|
231
|
+
if (!family2.consumedByLanes.includes(CREATE_CONSUMER_LANE)) {
|
|
232
|
+
issue(issues, `generatedFileManifest.families.${familyId}.consumedByLanes`, "create_pi_asset_family_not_consumed_by_create", `Create pi asset family '${familyId}' must be consumed by ${CREATE_CONSUMER_LANE}.`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const excludedFamilyId of EXCLUDED_FAMILY_IDS) {
|
|
236
|
+
if (CREATE_PI_ASSET_FAMILIES.includes(excludedFamilyId)) {
|
|
237
|
+
issue(issues, `generatedFileManifest.families.${excludedFamilyId}`, "blocked_or_i15a_family_selected", `Family '${excludedFamilyId}' must never be selected for create pi asset writes.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
var promptPath = (skillId) => `.pi/prompts/vibe-${skillId}.md`;
|
|
242
|
+
var skillPath = (skillId) => `.pi/skills/${skillId}/SKILL.md`;
|
|
243
|
+
var selectCreatePiAssets = (input) => {
|
|
244
|
+
const manifest = input?.manifest ?? getPiGeneratedFileManifest();
|
|
245
|
+
const capabilityMatrix = input?.capabilityMatrix ?? getPiAdapterCapabilityMatrix();
|
|
246
|
+
const issues = [];
|
|
247
|
+
validateManifestAndMatrix(manifest, capabilityMatrix, issues);
|
|
248
|
+
const skillFamily = familyById(manifest, "pi-skill-files");
|
|
249
|
+
const promptFamily = familyById(manifest, "pi-prompt-templates");
|
|
250
|
+
if (skillFamily !== void 0 && !skillFamily.pathPatterns.includes(PI_SKILL_PATTERN)) {
|
|
251
|
+
issue(issues, "generatedFileManifest.families.pi-skill-files.pathPatterns", "missing_pi_skill_path_pattern", "Create pi assets require the .pi skill path pattern, not an alternate only.");
|
|
252
|
+
}
|
|
253
|
+
if (promptFamily !== void 0 && !promptFamily.pathPatterns.includes(PI_PROMPT_PATTERN)) {
|
|
254
|
+
issue(issues, "generatedFileManifest.families.pi-prompt-templates.pathPatterns", "missing_pi_prompt_path_pattern", "Create pi assets require the .pi prompt path pattern.");
|
|
255
|
+
}
|
|
256
|
+
if (issues.length > 0) {
|
|
257
|
+
throw new CreatePiAssetValidationError("Create pi asset family selection failed.", issues);
|
|
258
|
+
}
|
|
259
|
+
return Object.freeze([
|
|
260
|
+
...SKILL_IDS.map((skillId) => ({
|
|
261
|
+
kind: "skill",
|
|
262
|
+
familyId: "pi-skill-files",
|
|
263
|
+
skillId,
|
|
264
|
+
path: skillPath(skillId),
|
|
265
|
+
shippedTemplatePath: `templates/pi/runtime-fixtures/${skillPath(skillId)}`,
|
|
266
|
+
manifestPathPattern: PI_SKILL_PATTERN
|
|
267
|
+
})),
|
|
268
|
+
...SKILL_IDS.map((skillId) => ({
|
|
269
|
+
kind: "prompt-template",
|
|
270
|
+
familyId: "pi-prompt-templates",
|
|
271
|
+
skillId,
|
|
272
|
+
path: promptPath(skillId),
|
|
273
|
+
shippedTemplatePath: `templates/pi/runtime-fixtures/${promptPath(skillId)}`,
|
|
274
|
+
manifestPathPattern: PI_PROMPT_PATTERN
|
|
275
|
+
}))
|
|
276
|
+
]);
|
|
277
|
+
};
|
|
278
|
+
var CreatePiAssetValidationError = class _CreatePiAssetValidationError extends Error {
|
|
279
|
+
issues;
|
|
280
|
+
constructor(message, issues) {
|
|
281
|
+
super(message);
|
|
282
|
+
this.name = "CreatePiAssetValidationError";
|
|
283
|
+
this.issues = issues;
|
|
284
|
+
Object.setPrototypeOf(this, _CreatePiAssetValidationError.prototype);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var validateCreatePiAssetWritePlan = (input) => {
|
|
288
|
+
const issues = [];
|
|
289
|
+
validateManifestAndMatrix(input.manifest, input.capabilityMatrix, issues);
|
|
290
|
+
let expectedAssets = [];
|
|
291
|
+
try {
|
|
292
|
+
expectedAssets = selectCreatePiAssets({ manifest: input.manifest, capabilityMatrix: input.capabilityMatrix });
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if (error instanceof CreatePiAssetValidationError) {
|
|
295
|
+
issues.push(...error.issues);
|
|
296
|
+
} else {
|
|
297
|
+
issue(issues, "generatedFileManifest", "create_pi_asset_selection_failed", "Create pi asset selector failed unexpectedly.");
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const expectedByPath = new Map(expectedAssets.map((asset) => [asset.path, asset]));
|
|
301
|
+
if (input.writes.length !== expectedAssets.length) {
|
|
302
|
+
issue(issues, "writes", "create_pi_asset_write_count_mismatch", "Create pi asset write plan must contain exactly six skill files and six prompt templates.");
|
|
303
|
+
}
|
|
304
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
305
|
+
for (let index = 0; index < input.writes.length; index += 1) {
|
|
306
|
+
const write = input.writes[index];
|
|
307
|
+
if (write === void 0) {
|
|
308
|
+
issue(issues, `writes[${index}]`, "missing_write", "Create pi asset write is missing.");
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (!relativePathSafe(write.path)) {
|
|
312
|
+
issue(issues, `writes[${index}].path`, "unsafe_write_path", "Create pi asset write path must be relative and non-traversing.");
|
|
313
|
+
}
|
|
314
|
+
if (seenPaths.has(write.path)) {
|
|
315
|
+
issue(issues, `writes[${index}].path`, "duplicate_write_path", "Create pi asset write paths must be unique.");
|
|
316
|
+
}
|
|
317
|
+
seenPaths.add(write.path);
|
|
318
|
+
const expected = expectedByPath.get(write.path);
|
|
319
|
+
if (expected === void 0) {
|
|
320
|
+
issue(issues, `writes[${index}].path`, "write_path_not_in_create_pi_asset_manifest", "Write path is not one of the selected create pi asset paths.");
|
|
321
|
+
} else if (write.familyId !== expected.familyId || write.kind !== expected.kind || write.skillId !== expected.skillId || write.manifestPathPattern !== expected.manifestPathPattern || write.shippedTemplatePath !== expected.shippedTemplatePath) {
|
|
322
|
+
issue(issues, `writes[${index}]`, "write_descriptor_mismatch", "Write descriptor must match the selected create pi asset descriptor exactly.");
|
|
323
|
+
}
|
|
324
|
+
if (write.content.trim().length === 0) {
|
|
325
|
+
issue(issues, `writes[${index}].content`, "empty_create_pi_asset_content", "Create pi asset content must be non-empty.");
|
|
326
|
+
}
|
|
327
|
+
const marker = hasDomainMarker(write.content);
|
|
328
|
+
if (marker !== null) {
|
|
329
|
+
issue(issues, `writes[${index}].content`, "create_pi_asset_domain_marker", `Create pi asset content contains forbidden domain marker '${marker}'.`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
for (const expected of expectedAssets) {
|
|
333
|
+
if (!seenPaths.has(expected.path)) {
|
|
334
|
+
issue(issues, `writes.${expected.path}`, "missing_create_pi_asset_write", `Missing create pi asset write for ${expected.path}.`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const existingByPath = new Map(input.existingPaths.map((entry) => [entry.path, entry]));
|
|
338
|
+
for (const write of input.writes) {
|
|
339
|
+
const pathSegments = write.path.split("/");
|
|
340
|
+
for (let segmentCount = 1; segmentCount < pathSegments.length; segmentCount += 1) {
|
|
341
|
+
const parentPath = pathSegments.slice(0, segmentCount).join("/");
|
|
342
|
+
const parent = existingByPath.get(parentPath);
|
|
343
|
+
if (parent === void 0 || parent.kind === "missing" || parent.kind === "directory") continue;
|
|
344
|
+
if (parent.kind === "symlink") {
|
|
345
|
+
issue(issues, `existingPaths.${parentPath}`, "ancestor_symlink_write_escape", "Create pi asset write refuses symlink ancestors because they may escape the project root.");
|
|
346
|
+
} else {
|
|
347
|
+
issue(issues, `existingPaths.${parentPath}`, "parent_path_not_directory", "Create pi asset write requires every existing parent path to be a directory.");
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const existing = existingByPath.get(write.path);
|
|
351
|
+
if (existing === void 0 || existing.kind === "missing") continue;
|
|
352
|
+
if (existing.kind === "symlink") {
|
|
353
|
+
issue(issues, `existingPaths.${write.path}`, "symlink_write_escape", "Create pi asset write refuses symlink targets because they may escape the project root.");
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (existing.kind === "directory") {
|
|
357
|
+
issue(issues, `existingPaths.${write.path}`, "unsafe_overwrite_conflict", "Create pi asset write refuses to overwrite a directory.");
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (input.conflictPolicy === "fail-on-conflict") {
|
|
361
|
+
issue(issues, `existingPaths.${write.path}`, "unsafe_overwrite_conflict", "Create pi asset write refuses existing files under fail-on-conflict policy.");
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (existing.currentContent !== write.content) {
|
|
365
|
+
issue(issues, `existingPaths.${write.path}`, "unsafe_overwrite_conflict", "Create pi asset write only permits identical-content overwrites in import mode.");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (issues.length > 0) {
|
|
369
|
+
return { valid: false, issues };
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
valid: true,
|
|
373
|
+
value: {
|
|
374
|
+
conflictPolicy: input.conflictPolicy,
|
|
375
|
+
writes: input.writes,
|
|
376
|
+
families: [...CREATE_PI_ASSET_FAMILIES]
|
|
377
|
+
},
|
|
378
|
+
issues: []
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
export {
|
|
383
|
+
CREATE_PI_ASSET_FAMILIES,
|
|
384
|
+
selectCreatePiAssets,
|
|
385
|
+
CreatePiAssetValidationError,
|
|
386
|
+
validateCreatePiAssetWritePlan,
|
|
387
|
+
PI_GENERATED_FILE_MANIFEST_SCHEMA_VERSION,
|
|
388
|
+
PI_GENERATED_FILE_MANIFEST,
|
|
389
|
+
getPiGeneratedFileManifest,
|
|
390
|
+
validatePiGeneratedFileManifest,
|
|
391
|
+
createPiDownstreamManifestSummary
|
|
392
|
+
};
|