@promptscript/cli 1.12.1 → 1.13.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/README.md +64 -35
- package/index.js +680 -209
- package/package.json +2 -1
- package/skills/promptscript/SKILL.md +6 -2
- package/src/cli.d.ts.map +1 -1
- package/src/commands/compile.d.ts.map +1 -1
- package/src/commands/skills.d.ts.map +1 -1
- package/src/prettier/index.d.ts +1 -0
- package/src/prettier/index.d.ts.map +1 -1
- package/src/prettier/post-format.d.ts +23 -0
- package/src/prettier/post-format.d.ts.map +1 -0
- package/src/types.d.ts +8 -0
- package/src/types.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -11760,6 +11760,14 @@ var init_base_formatter = __esm({
|
|
|
11760
11760
|
referencesMode() {
|
|
11761
11761
|
return "none";
|
|
11762
11762
|
}
|
|
11763
|
+
/**
|
|
11764
|
+
* Default pass-through for injected skill content. Formatters whose target
|
|
11765
|
+
* tools restrict skill frontmatter (e.g. Factory AI) override this hook to
|
|
11766
|
+
* filter unsupported fields before the compiler writes the file.
|
|
11767
|
+
*/
|
|
11768
|
+
transformInjectedSkillContent(content) {
|
|
11769
|
+
return content;
|
|
11770
|
+
}
|
|
11763
11771
|
/**
|
|
11764
11772
|
* Generate a provenance comment for a reference file.
|
|
11765
11773
|
*/
|
|
@@ -16365,6 +16373,24 @@ ${lines.join("\n")}
|
|
|
16365
16373
|
}
|
|
16366
16374
|
return filtered;
|
|
16367
16375
|
}
|
|
16376
|
+
/**
|
|
16377
|
+
* Filter the frontmatter of an externally-supplied SKILL.md file (such as
|
|
16378
|
+
* the bundled PromptScript skill injected by the compiler) so it only
|
|
16379
|
+
* contains fields Factory AI recognises. The body is preserved verbatim.
|
|
16380
|
+
* Files without a YAML frontmatter block are returned unchanged.
|
|
16381
|
+
*/
|
|
16382
|
+
transformInjectedSkillContent(content) {
|
|
16383
|
+
if (!content.startsWith("---")) return content;
|
|
16384
|
+
const closing = content.indexOf("\n---", 3);
|
|
16385
|
+
if (closing === -1) return content;
|
|
16386
|
+
const rawFrontmatter = content.slice(4, closing);
|
|
16387
|
+
const body = content.slice(closing + 4);
|
|
16388
|
+
const filteredLines = this.filterFactoryFrontmatter(rawFrontmatter);
|
|
16389
|
+
const filteredFrontmatter = filteredLines.join("\n");
|
|
16390
|
+
return `---
|
|
16391
|
+
${filteredFrontmatter}
|
|
16392
|
+
---${body}`;
|
|
16393
|
+
}
|
|
16368
16394
|
};
|
|
16369
16395
|
}
|
|
16370
16396
|
});
|
|
@@ -20847,9 +20873,9 @@ var require_rate_limit = __commonJS({
|
|
|
20847
20873
|
let ttl = 0;
|
|
20848
20874
|
let ttlInSeconds = 0;
|
|
20849
20875
|
try {
|
|
20850
|
-
const res = await new Promise((
|
|
20876
|
+
const res = await new Promise((resolve22, reject) => {
|
|
20851
20877
|
store.incr(key, (err, res2) => {
|
|
20852
|
-
err ? reject(err) :
|
|
20878
|
+
err ? reject(err) : resolve22(res2);
|
|
20853
20879
|
}, timeWindow, max);
|
|
20854
20880
|
});
|
|
20855
20881
|
current = res.current;
|
|
@@ -20956,12 +20982,12 @@ var init_health = __esm({
|
|
|
20956
20982
|
|
|
20957
20983
|
// packages/server/src/source-dirs.ts
|
|
20958
20984
|
import { readFile as readFile24 } from "fs/promises";
|
|
20959
|
-
import { join as
|
|
20985
|
+
import { join as join23, dirname as dirname14 } from "path";
|
|
20960
20986
|
import { parse as parseYaml13 } from "yaml";
|
|
20961
20987
|
async function readProjectConfig(workspace) {
|
|
20962
20988
|
for (const filename of CONFIG_FILENAMES) {
|
|
20963
20989
|
try {
|
|
20964
|
-
const raw = await readFile24(
|
|
20990
|
+
const raw = await readFile24(join23(workspace, filename), "utf-8");
|
|
20965
20991
|
const config = parseYaml13(raw);
|
|
20966
20992
|
if (config) return config;
|
|
20967
20993
|
} catch {
|
|
@@ -20972,10 +20998,10 @@ async function readProjectConfig(workspace) {
|
|
|
20972
20998
|
async function resolveSourceDir(workspace) {
|
|
20973
20999
|
for (const filename of CONFIG_FILENAMES) {
|
|
20974
21000
|
try {
|
|
20975
|
-
const raw = await readFile24(
|
|
21001
|
+
const raw = await readFile24(join23(workspace, filename), "utf-8");
|
|
20976
21002
|
const config = parseYaml13(raw);
|
|
20977
21003
|
if (config?.input?.entry) {
|
|
20978
|
-
return
|
|
21004
|
+
return dirname14(config.input.entry);
|
|
20979
21005
|
}
|
|
20980
21006
|
} catch {
|
|
20981
21007
|
}
|
|
@@ -20989,9 +21015,9 @@ async function resolveFileGlobs(workspace) {
|
|
|
20989
21015
|
async function resolveWatchPaths(workspace) {
|
|
20990
21016
|
const sourceDir = await resolveSourceDir(workspace);
|
|
20991
21017
|
return [
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
21018
|
+
join23(workspace, sourceDir),
|
|
21019
|
+
join23(workspace, "promptscript.yaml"),
|
|
21020
|
+
join23(workspace, "promptscript.yml")
|
|
20995
21021
|
];
|
|
20996
21022
|
}
|
|
20997
21023
|
var DEFAULT_SOURCE_DIR, CONFIG_FILENAMES;
|
|
@@ -21018,13 +21044,13 @@ var init_config2 = __esm({
|
|
|
21018
21044
|
});
|
|
21019
21045
|
|
|
21020
21046
|
// packages/server/src/path-guard.ts
|
|
21021
|
-
import { resolve as
|
|
21047
|
+
import { resolve as resolve21, relative as relative4, isAbsolute as isAbsolute6 } from "path";
|
|
21022
21048
|
function resolveSafePath(workspace, requestedPath) {
|
|
21023
21049
|
const decoded = decodeURIComponent(requestedPath);
|
|
21024
21050
|
if (isAbsolute6(decoded)) {
|
|
21025
21051
|
throw new PathTraversalError(requestedPath);
|
|
21026
21052
|
}
|
|
21027
|
-
const resolved =
|
|
21053
|
+
const resolved = resolve21(workspace, decoded);
|
|
21028
21054
|
const rel = relative4(workspace, resolved);
|
|
21029
21055
|
if (rel.startsWith("..") || isAbsolute6(rel)) {
|
|
21030
21056
|
throw new PathTraversalError(requestedPath);
|
|
@@ -21046,7 +21072,7 @@ var init_path_guard = __esm({
|
|
|
21046
21072
|
|
|
21047
21073
|
// packages/server/src/routes/files.ts
|
|
21048
21074
|
import { readFile as readFile25, writeFile as writeFile13, unlink as unlink2, stat as stat3, mkdir as mkdir10 } from "fs/promises";
|
|
21049
|
-
import { dirname as
|
|
21075
|
+
import { dirname as dirname15 } from "path";
|
|
21050
21076
|
import fg from "fast-glob";
|
|
21051
21077
|
function registerRoutes(app, workspace, readOnly) {
|
|
21052
21078
|
app.get("/api/files", async () => {
|
|
@@ -21106,7 +21132,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21106
21132
|
return reply.status(409).send({ error: "File already exists" });
|
|
21107
21133
|
} catch {
|
|
21108
21134
|
}
|
|
21109
|
-
await mkdir10(
|
|
21135
|
+
await mkdir10(dirname15(resolved), { recursive: true });
|
|
21110
21136
|
await writeFile13(resolved, request.body.content, "utf-8");
|
|
21111
21137
|
return reply.status(201).send({ path: filePath, status: "created" });
|
|
21112
21138
|
} catch (err) {
|
|
@@ -21332,14 +21358,14 @@ init_src();
|
|
|
21332
21358
|
init_init();
|
|
21333
21359
|
import { Command } from "commander";
|
|
21334
21360
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
21335
|
-
import { dirname as
|
|
21361
|
+
import { dirname as dirname16 } from "path";
|
|
21336
21362
|
|
|
21337
21363
|
// packages/cli/src/commands/compile.ts
|
|
21338
21364
|
init_src();
|
|
21339
|
-
import { resolve as
|
|
21365
|
+
import { resolve as resolve8, dirname as dirname9, isAbsolute as isAbsolute5 } from "path";
|
|
21340
21366
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21341
21367
|
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile12 } from "fs/promises";
|
|
21342
|
-
import { existsSync as
|
|
21368
|
+
import { existsSync as existsSync12 } from "fs";
|
|
21343
21369
|
import chokidar from "chokidar";
|
|
21344
21370
|
|
|
21345
21371
|
// packages/cli/src/config/loader.ts
|
|
@@ -21403,6 +21429,56 @@ async function loadConfig(customPath) {
|
|
|
21403
21429
|
|
|
21404
21430
|
// packages/cli/src/commands/compile.ts
|
|
21405
21431
|
init_loader();
|
|
21432
|
+
|
|
21433
|
+
// packages/cli/src/prettier/post-format.ts
|
|
21434
|
+
import { resolve as resolve4 } from "path";
|
|
21435
|
+
var MARKDOWN_RE = /\.(md|mdx|markdown)$/i;
|
|
21436
|
+
async function postFormatWithPrettier(outputs, projectRoot, logger) {
|
|
21437
|
+
let prettier;
|
|
21438
|
+
try {
|
|
21439
|
+
prettier = await import("prettier");
|
|
21440
|
+
} catch {
|
|
21441
|
+
logger.verbose("Prettier not available; skipping markdown post-format.");
|
|
21442
|
+
return;
|
|
21443
|
+
}
|
|
21444
|
+
const queue = [];
|
|
21445
|
+
for (const output of outputs.values()) {
|
|
21446
|
+
collectOutputs(output, queue);
|
|
21447
|
+
}
|
|
21448
|
+
for (const output of queue) {
|
|
21449
|
+
if (!MARKDOWN_RE.test(output.path)) continue;
|
|
21450
|
+
const absPath = resolve4(projectRoot, output.path);
|
|
21451
|
+
let config = null;
|
|
21452
|
+
try {
|
|
21453
|
+
config = await prettier.resolveConfig(absPath);
|
|
21454
|
+
} catch (err) {
|
|
21455
|
+
logger.verbose(
|
|
21456
|
+
`Could not resolve Prettier config for ${output.path}: ${err instanceof Error ? err.message : String(err)}`
|
|
21457
|
+
);
|
|
21458
|
+
}
|
|
21459
|
+
try {
|
|
21460
|
+
output.content = await prettier.format(output.content, {
|
|
21461
|
+
...config ?? {},
|
|
21462
|
+
filepath: absPath,
|
|
21463
|
+
parser: "markdown"
|
|
21464
|
+
});
|
|
21465
|
+
} catch (err) {
|
|
21466
|
+
logger.verbose(
|
|
21467
|
+
`Prettier rejected ${output.path}: ${err instanceof Error ? err.message : String(err)}`
|
|
21468
|
+
);
|
|
21469
|
+
}
|
|
21470
|
+
}
|
|
21471
|
+
}
|
|
21472
|
+
function collectOutputs(output, into) {
|
|
21473
|
+
into.push(output);
|
|
21474
|
+
if (output.additionalFiles) {
|
|
21475
|
+
for (const child of output.additionalFiles) {
|
|
21476
|
+
collectOutputs(child, into);
|
|
21477
|
+
}
|
|
21478
|
+
}
|
|
21479
|
+
}
|
|
21480
|
+
|
|
21481
|
+
// packages/cli/src/commands/compile.ts
|
|
21406
21482
|
init_console();
|
|
21407
21483
|
|
|
21408
21484
|
// packages/compiler/src/compiler.ts
|
|
@@ -21419,7 +21495,7 @@ import { basename as basename11, dirname as dirname7, join as join8 } from "path
|
|
|
21419
21495
|
// packages/resolver/src/loader.ts
|
|
21420
21496
|
init_src();
|
|
21421
21497
|
import { readFile as readFile7 } from "fs/promises";
|
|
21422
|
-
import { resolve as
|
|
21498
|
+
import { resolve as resolve5, dirname as dirname5, basename as basename7, isAbsolute as isAbsolute2, relative } from "path";
|
|
21423
21499
|
|
|
21424
21500
|
// packages/resolver/src/alias-resolver.ts
|
|
21425
21501
|
init_src();
|
|
@@ -21509,8 +21585,8 @@ var FileLoader = class {
|
|
|
21509
21585
|
options;
|
|
21510
21586
|
constructor(options) {
|
|
21511
21587
|
this.registryPath = options.registryPath;
|
|
21512
|
-
this.localPath =
|
|
21513
|
-
this.projectRoot =
|
|
21588
|
+
this.localPath = resolve5(options.localPath ?? process.cwd());
|
|
21589
|
+
this.projectRoot = resolve5(
|
|
21514
21590
|
options.projectRoot ?? (basename7(this.localPath) === ".promptscript" ? dirname5(this.localPath) : this.localPath)
|
|
21515
21591
|
);
|
|
21516
21592
|
this.options = options;
|
|
@@ -21553,11 +21629,11 @@ var FileLoader = class {
|
|
|
21553
21629
|
const namespace = match[1];
|
|
21554
21630
|
const segments = match[2];
|
|
21555
21631
|
const fileName2 = segments.endsWith(".prs") || segments.endsWith(".md") ? segments : `${segments}.prs`;
|
|
21556
|
-
return
|
|
21632
|
+
return resolve5(this.registryPath, `@${namespace}`, fileName2);
|
|
21557
21633
|
}
|
|
21558
21634
|
}
|
|
21559
21635
|
const fileName = path.endsWith(".prs") || path.endsWith(".md") ? path : `${path}.prs`;
|
|
21560
|
-
return
|
|
21636
|
+
return resolve5(this.localPath, fileName);
|
|
21561
21637
|
}
|
|
21562
21638
|
/**
|
|
21563
21639
|
* Resolve a PathReference to an absolute path.
|
|
@@ -21570,7 +21646,7 @@ var FileLoader = class {
|
|
|
21570
21646
|
if (ref.isRelative) {
|
|
21571
21647
|
const dir = dirname5(fromFile);
|
|
21572
21648
|
const rawPath = ref.raw.endsWith(".prs") || ref.raw.endsWith(".md") ? ref.raw : `${ref.raw}.prs`;
|
|
21573
|
-
const resolved =
|
|
21649
|
+
const resolved = resolve5(dir, rawPath);
|
|
21574
21650
|
const rel = relative(this.projectRoot, resolved);
|
|
21575
21651
|
if (rel.startsWith("..") || isAbsolute2(rel)) {
|
|
21576
21652
|
throw new Error(`Path traversal outside project root is not allowed: ${ref.raw}`);
|
|
@@ -22511,7 +22587,7 @@ function uniqueConcat3(parent, child) {
|
|
|
22511
22587
|
// packages/resolver/src/skills.ts
|
|
22512
22588
|
init_src();
|
|
22513
22589
|
import { readFile as readFile8, readdir as readdir2, access, lstat, realpath } from "fs/promises";
|
|
22514
|
-
import { basename as basename8, resolve as
|
|
22590
|
+
import { basename as basename8, resolve as resolve6, dirname as dirname6, relative as relative2, normalize as normalize2, isAbsolute as isAbsolute3, sep as sep2 } from "path";
|
|
22515
22591
|
function parseSkillMd(content) {
|
|
22516
22592
|
const lines = content.split("\n");
|
|
22517
22593
|
let inFrontmatter = false;
|
|
@@ -22957,10 +23033,10 @@ function parseSkillIgnore(content) {
|
|
|
22957
23033
|
return { patterns };
|
|
22958
23034
|
}
|
|
22959
23035
|
function isIgnoredByRules(relPath, rules) {
|
|
22960
|
-
const
|
|
23036
|
+
const basename16 = relPath.split("/").pop() ?? relPath;
|
|
22961
23037
|
let ignored = false;
|
|
22962
23038
|
for (const { regex, matchPath, negated } of rules.patterns) {
|
|
22963
|
-
const target = matchPath ? relPath :
|
|
23039
|
+
const target = matchPath ? relPath : basename16;
|
|
22964
23040
|
if (regex.test(target)) {
|
|
22965
23041
|
ignored = !negated;
|
|
22966
23042
|
}
|
|
@@ -22968,7 +23044,7 @@ function isIgnoredByRules(relPath, rules) {
|
|
|
22968
23044
|
return ignored;
|
|
22969
23045
|
}
|
|
22970
23046
|
async function loadSkillIgnore(skillDir) {
|
|
22971
|
-
const ignorePath =
|
|
23047
|
+
const ignorePath = resolve6(skillDir, ".skillignore");
|
|
22972
23048
|
try {
|
|
22973
23049
|
const content = await readFile8(ignorePath, "utf-8");
|
|
22974
23050
|
return parseSkillIgnore(content);
|
|
@@ -23014,7 +23090,7 @@ async function discoverSkillResources(skillDir, logger = noopLogger2) {
|
|
|
23014
23090
|
}
|
|
23015
23091
|
if (entry.isSymbolicLink()) continue;
|
|
23016
23092
|
if (SKIP_FILES.has(entry.name)) continue;
|
|
23017
|
-
const fullPath =
|
|
23093
|
+
const fullPath = resolve6(entry.parentPath, entry.name);
|
|
23018
23094
|
const relPath = relative2(skillDir, fullPath);
|
|
23019
23095
|
const relPathNormalized = relPath.split(sep2).join("/");
|
|
23020
23096
|
const pathSegments = relPath.split(sep2);
|
|
@@ -23073,7 +23149,7 @@ async function resolveSkillReferences(references, basePath, logger) {
|
|
|
23073
23149
|
column: 0
|
|
23074
23150
|
});
|
|
23075
23151
|
}
|
|
23076
|
-
const fullPath =
|
|
23152
|
+
const fullPath = resolve6(basePath, ref);
|
|
23077
23153
|
let content;
|
|
23078
23154
|
try {
|
|
23079
23155
|
content = await readFile8(fullPath, "utf-8");
|
|
@@ -23145,8 +23221,8 @@ async function discoverSkillDirs(basePath) {
|
|
|
23145
23221
|
if (!entry.isDirectory()) continue;
|
|
23146
23222
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
23147
23223
|
if (!isSafeSkillName(entry.name)) continue;
|
|
23148
|
-
const subDir =
|
|
23149
|
-
const skillMd =
|
|
23224
|
+
const subDir = resolve6(dir, entry.name);
|
|
23225
|
+
const skillMd = resolve6(subDir, "SKILL.md");
|
|
23150
23226
|
if (await fileExists(skillMd)) {
|
|
23151
23227
|
if (!result.has(entry.name)) {
|
|
23152
23228
|
result.set(entry.name, subDir);
|
|
@@ -23173,9 +23249,9 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23173
23249
|
const isSkillsDir = sourceDir.includes("@skills") || sourceDir.endsWith("/skills");
|
|
23174
23250
|
const discoveredSkillPaths = /* @__PURE__ */ new Map();
|
|
23175
23251
|
if (!isSkillsDir && localPath) {
|
|
23176
|
-
const discoveryDirs = [
|
|
23252
|
+
const discoveryDirs = [resolve6(localPath, "skills")];
|
|
23177
23253
|
if (options?.universalDir && localPath) {
|
|
23178
|
-
discoveryDirs.push(
|
|
23254
|
+
discoveryDirs.push(resolve6(localPath, "..", options.universalDir, "skills"));
|
|
23179
23255
|
}
|
|
23180
23256
|
for (const dir of discoveryDirs) {
|
|
23181
23257
|
const discovered = await discoverSkillDirs(dir);
|
|
@@ -23196,7 +23272,7 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23196
23272
|
}
|
|
23197
23273
|
let sharedResources = [];
|
|
23198
23274
|
if (localPath) {
|
|
23199
|
-
const sharedDir =
|
|
23275
|
+
const sharedDir = resolve6(localPath, "shared");
|
|
23200
23276
|
if (await fileExists(sharedDir)) {
|
|
23201
23277
|
try {
|
|
23202
23278
|
sharedResources = await discoverSkillResources(sharedDir, logger);
|
|
@@ -23217,12 +23293,12 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23217
23293
|
continue;
|
|
23218
23294
|
}
|
|
23219
23295
|
const skillObj = skillValue;
|
|
23220
|
-
const skillMdPath = isSkillsDir ?
|
|
23296
|
+
const skillMdPath = isSkillsDir ? resolve6(sourceDir, skillName, "SKILL.md") : await (async () => {
|
|
23221
23297
|
const discoveredDir = discoveredSkillPaths.get(skillName);
|
|
23222
|
-
if (discoveredDir) return
|
|
23223
|
-
const localCandidate = localPath ?
|
|
23224
|
-
const universalCandidate = options?.universalDir && localPath ?
|
|
23225
|
-
const registryCandidate =
|
|
23298
|
+
if (discoveredDir) return resolve6(discoveredDir, "SKILL.md");
|
|
23299
|
+
const localCandidate = localPath ? resolve6(localPath, "skills", skillName, "SKILL.md") : null;
|
|
23300
|
+
const universalCandidate = options?.universalDir && localPath ? resolve6(localPath, "..", options.universalDir, "skills", skillName, "SKILL.md") : null;
|
|
23301
|
+
const registryCandidate = resolve6(registryPath, "@skills", skillName, "SKILL.md");
|
|
23226
23302
|
if (localCandidate && await fileExists(localCandidate)) return localCandidate;
|
|
23227
23303
|
if (universalCandidate && await fileExists(universalCandidate))
|
|
23228
23304
|
return universalCandidate;
|
|
@@ -23312,7 +23388,7 @@ async function discoverCommandFiles(dir, logger = noopLogger2) {
|
|
|
23312
23388
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
23313
23389
|
if (entry.isSymbolicLink()) continue;
|
|
23314
23390
|
const cmdName = "/" + entry.name.replace(/\.md$/, "");
|
|
23315
|
-
const fullPath =
|
|
23391
|
+
const fullPath = resolve6(dir, entry.name);
|
|
23316
23392
|
try {
|
|
23317
23393
|
const fileStat = await lstat(fullPath);
|
|
23318
23394
|
if (fileStat.isSymbolicLink()) continue;
|
|
@@ -23343,11 +23419,11 @@ async function resolveNativeCommands(ast, sourceFile, localPath, options) {
|
|
|
23343
23419
|
if (!localPath) return ast;
|
|
23344
23420
|
const logger = options?.logger ?? noopLogger2;
|
|
23345
23421
|
const allCommands = {};
|
|
23346
|
-
const localCommands = await discoverCommandFiles(
|
|
23422
|
+
const localCommands = await discoverCommandFiles(resolve6(localPath, "commands"), logger);
|
|
23347
23423
|
Object.assign(allCommands, localCommands);
|
|
23348
23424
|
if (options?.universalDir) {
|
|
23349
23425
|
const universalCommands = await discoverCommandFiles(
|
|
23350
|
-
|
|
23426
|
+
resolve6(localPath, "..", options.universalDir, "commands"),
|
|
23351
23427
|
logger
|
|
23352
23428
|
);
|
|
23353
23429
|
for (const [name, value] of Object.entries(universalCommands)) {
|
|
@@ -23428,7 +23504,7 @@ async function discoverAgentFiles(dir, logger = noopLogger2) {
|
|
|
23428
23504
|
for (const entry of entries) {
|
|
23429
23505
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
23430
23506
|
if (entry.isSymbolicLink()) continue;
|
|
23431
|
-
const fullPath =
|
|
23507
|
+
const fullPath = resolve6(dir, entry.name);
|
|
23432
23508
|
try {
|
|
23433
23509
|
const fileStat = await lstat(fullPath);
|
|
23434
23510
|
if (fileStat.isSymbolicLink()) continue;
|
|
@@ -23492,11 +23568,11 @@ async function resolveNativeAgents(ast, sourceFile, localPath, options) {
|
|
|
23492
23568
|
if (!localPath) return ast;
|
|
23493
23569
|
const logger = options?.logger ?? noopLogger2;
|
|
23494
23570
|
const allAgents = {};
|
|
23495
|
-
const localAgents = await discoverAgentFiles(
|
|
23571
|
+
const localAgents = await discoverAgentFiles(resolve6(localPath, "agents"), logger);
|
|
23496
23572
|
Object.assign(allAgents, localAgents);
|
|
23497
23573
|
if (options?.universalDir) {
|
|
23498
23574
|
const universalAgents = await discoverAgentFiles(
|
|
23499
|
-
|
|
23575
|
+
resolve6(localPath, "..", options.universalDir, "agents"),
|
|
23500
23576
|
logger
|
|
23501
23577
|
);
|
|
23502
23578
|
for (const [name, value] of Object.entries(universalAgents)) {
|
|
@@ -25124,7 +25200,7 @@ var RegistryCache = class {
|
|
|
25124
25200
|
|
|
25125
25201
|
// packages/resolver/src/auto-discovery.ts
|
|
25126
25202
|
import { readFile as readFile10, readdir as readdir3, access as access2, lstat as lstat2 } from "fs/promises";
|
|
25127
|
-
import { resolve as
|
|
25203
|
+
import { resolve as resolve7, basename as basename10 } from "path";
|
|
25128
25204
|
var CONTEXT_FILES = ["CLAUDE.md", ".clinerules", ".cursorrules"];
|
|
25129
25205
|
async function fileExists2(path) {
|
|
25130
25206
|
try {
|
|
@@ -25160,9 +25236,9 @@ async function discoverSkills(dir) {
|
|
|
25160
25236
|
const properties = {};
|
|
25161
25237
|
for (const entry of entries) {
|
|
25162
25238
|
if (!entry.isDirectory()) continue;
|
|
25163
|
-
let skillMdPath =
|
|
25239
|
+
let skillMdPath = resolve7(dir, entry.name, "SKILL.md");
|
|
25164
25240
|
if (!await fileExists2(skillMdPath)) {
|
|
25165
|
-
const dirnameMdPath =
|
|
25241
|
+
const dirnameMdPath = resolve7(dir, entry.name, `${entry.name}.md`);
|
|
25166
25242
|
if (await fileExists2(dirnameMdPath)) {
|
|
25167
25243
|
skillMdPath = dirnameMdPath;
|
|
25168
25244
|
} else {
|
|
@@ -25189,7 +25265,7 @@ async function discoverSkills(dir) {
|
|
|
25189
25265
|
return Object.keys(properties).length > 0 ? properties : null;
|
|
25190
25266
|
}
|
|
25191
25267
|
async function discoverRootSkill(dir) {
|
|
25192
|
-
const skillMdPath =
|
|
25268
|
+
const skillMdPath = resolve7(dir, "SKILL.md");
|
|
25193
25269
|
if (!await fileExists2(skillMdPath)) return null;
|
|
25194
25270
|
try {
|
|
25195
25271
|
const raw = await readFile10(skillMdPath, "utf-8");
|
|
@@ -25220,7 +25296,7 @@ async function discoverAgents(dir) {
|
|
|
25220
25296
|
const properties = {};
|
|
25221
25297
|
for (const entry of entries) {
|
|
25222
25298
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25223
|
-
const fullPath =
|
|
25299
|
+
const fullPath = resolve7(dir, entry.name);
|
|
25224
25300
|
try {
|
|
25225
25301
|
const stat4 = await lstat2(fullPath);
|
|
25226
25302
|
if (stat4.isSymbolicLink()) continue;
|
|
@@ -25256,7 +25332,7 @@ async function discoverCommands(dir) {
|
|
|
25256
25332
|
for (const entry of entries) {
|
|
25257
25333
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25258
25334
|
if (entry.name === "SKILL.md") continue;
|
|
25259
|
-
const fullPath =
|
|
25335
|
+
const fullPath = resolve7(dir, entry.name);
|
|
25260
25336
|
try {
|
|
25261
25337
|
const stat4 = await lstat2(fullPath);
|
|
25262
25338
|
if (stat4.isSymbolicLink()) continue;
|
|
@@ -25273,7 +25349,7 @@ async function discoverCommands(dir) {
|
|
|
25273
25349
|
}
|
|
25274
25350
|
async function discoverContext(dir) {
|
|
25275
25351
|
for (const fileName of CONTEXT_FILES) {
|
|
25276
|
-
const fullPath =
|
|
25352
|
+
const fullPath = resolve7(dir, fileName);
|
|
25277
25353
|
if (!await fileExists2(fullPath)) continue;
|
|
25278
25354
|
try {
|
|
25279
25355
|
const content = await readFile10(fullPath, "utf-8");
|
|
@@ -25303,7 +25379,7 @@ async function discoverNativeContent(dir) {
|
|
|
25303
25379
|
const subSkills = await discoverSkills(dir);
|
|
25304
25380
|
const wrappedSkillResults = await Promise.all(
|
|
25305
25381
|
SKILL_WRAPPER_DIRS.map(async (name) => {
|
|
25306
|
-
const candidate =
|
|
25382
|
+
const candidate = resolve7(dir, name);
|
|
25307
25383
|
if (!await safeIsDirectory(candidate)) return null;
|
|
25308
25384
|
return discoverSkills(candidate);
|
|
25309
25385
|
})
|
|
@@ -25324,7 +25400,7 @@ async function discoverNativeContent(dir) {
|
|
|
25324
25400
|
const rootAgents = await discoverAgents(dir) ?? {};
|
|
25325
25401
|
const wrappedAgents = {};
|
|
25326
25402
|
for (const name of AGENT_WRAPPER_DIRS) {
|
|
25327
|
-
const candidate =
|
|
25403
|
+
const candidate = resolve7(dir, name);
|
|
25328
25404
|
if (await safeIsDirectory(candidate)) {
|
|
25329
25405
|
const found = await discoverAgents(candidate);
|
|
25330
25406
|
if (found) Object.assign(wrappedAgents, found);
|
|
@@ -25337,7 +25413,7 @@ async function discoverNativeContent(dir) {
|
|
|
25337
25413
|
const rootCommands = await discoverCommands(dir) ?? {};
|
|
25338
25414
|
const wrappedCommands = {};
|
|
25339
25415
|
for (const name of COMMAND_WRAPPER_DIRS) {
|
|
25340
|
-
const candidate =
|
|
25416
|
+
const candidate = resolve7(dir, name);
|
|
25341
25417
|
if (await safeIsDirectory(candidate)) {
|
|
25342
25418
|
const found = await discoverCommands(candidate);
|
|
25343
25419
|
if (found) Object.assign(wrappedCommands, found);
|
|
@@ -25838,6 +25914,12 @@ var Resolver = class {
|
|
|
25838
25914
|
errors.push(new ResolveError(e.message, e.location));
|
|
25839
25915
|
}
|
|
25840
25916
|
}
|
|
25917
|
+
} else if (isMdPath) {
|
|
25918
|
+
errors.push(
|
|
25919
|
+
new ResolveError(
|
|
25920
|
+
`Cannot resolve registry import: file '${subPath}' not found in ${repoUrl} (looked for ${resolvedFullPath}). Verify the path inside the repository.`
|
|
25921
|
+
)
|
|
25922
|
+
);
|
|
25841
25923
|
} else {
|
|
25842
25924
|
const discoverDir = isRoot ? cachePath : join8(cachePath, subPath);
|
|
25843
25925
|
this.logger.debug(`No .prs found, trying auto-discovery: ${discoverDir}`);
|
|
@@ -26080,7 +26162,7 @@ var HttpRegistry = class {
|
|
|
26080
26162
|
* Sleep for specified milliseconds.
|
|
26081
26163
|
*/
|
|
26082
26164
|
sleep(ms) {
|
|
26083
|
-
return new Promise((
|
|
26165
|
+
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
26084
26166
|
}
|
|
26085
26167
|
/**
|
|
26086
26168
|
* Fetch with timeout.
|
|
@@ -26224,9 +26306,251 @@ function createHttpRegistry(options) {
|
|
|
26224
26306
|
// packages/resolver/src/vendor-registry.ts
|
|
26225
26307
|
init_src();
|
|
26226
26308
|
|
|
26309
|
+
// packages/resolver/src/skill-validation.ts
|
|
26310
|
+
import { basename as basename12, dirname as dirname8, join as join10 } from "path";
|
|
26311
|
+
import { existsSync as existsSync11 } from "fs";
|
|
26312
|
+
function validateSkillFrontmatter(rawContent, options = {}) {
|
|
26313
|
+
const issues = [];
|
|
26314
|
+
if (!hasFrontmatterDelimiters(rawContent)) {
|
|
26315
|
+
issues.push({
|
|
26316
|
+
severity: "error",
|
|
26317
|
+
code: "SK001",
|
|
26318
|
+
message: "SKILL.md must start with a YAML frontmatter block delimited by `---` lines."
|
|
26319
|
+
});
|
|
26320
|
+
return { valid: false, issues };
|
|
26321
|
+
}
|
|
26322
|
+
const parsed = parseSkillMd(rawContent);
|
|
26323
|
+
validateName(parsed, options, issues);
|
|
26324
|
+
validateDescription(parsed, issues);
|
|
26325
|
+
validateCompatibility(parsed.rawFrontmatter, issues);
|
|
26326
|
+
validateLicense(parsed.rawFrontmatter, issues);
|
|
26327
|
+
validateBody(parsed.content, issues);
|
|
26328
|
+
validateReferences(parsed.references, options.filePath, issues);
|
|
26329
|
+
validateAllowedTools(parsed.rawFrontmatter, issues);
|
|
26330
|
+
const hasErrors = issues.some((i) => i.severity === "error");
|
|
26331
|
+
return { valid: !hasErrors, issues };
|
|
26332
|
+
}
|
|
26333
|
+
var NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
26334
|
+
var MAX_NAME_LEN = 64;
|
|
26335
|
+
var MIN_DESC_LEN = 1;
|
|
26336
|
+
var MAX_DESC_LEN = 1024;
|
|
26337
|
+
var MAX_COMPATIBILITY_LEN = 500;
|
|
26338
|
+
var SHORT_DESC_WARN_LEN = 40;
|
|
26339
|
+
var MAX_BODY_LINES = 500;
|
|
26340
|
+
function validateName(parsed, options, issues) {
|
|
26341
|
+
const name = parsed.name;
|
|
26342
|
+
if (!name || name.length === 0) {
|
|
26343
|
+
issues.push({
|
|
26344
|
+
severity: "error",
|
|
26345
|
+
code: "SK002",
|
|
26346
|
+
field: "name",
|
|
26347
|
+
message: "`name` is required in SKILL.md frontmatter."
|
|
26348
|
+
});
|
|
26349
|
+
return;
|
|
26350
|
+
}
|
|
26351
|
+
if (name.length > MAX_NAME_LEN) {
|
|
26352
|
+
issues.push({
|
|
26353
|
+
severity: "error",
|
|
26354
|
+
code: "SK003",
|
|
26355
|
+
field: "name",
|
|
26356
|
+
message: `\`name\` must be at most ${MAX_NAME_LEN} characters (got ${name.length}).`
|
|
26357
|
+
});
|
|
26358
|
+
}
|
|
26359
|
+
if (!NAME_PATTERN.test(name)) {
|
|
26360
|
+
issues.push({
|
|
26361
|
+
severity: "error",
|
|
26362
|
+
code: "SK004",
|
|
26363
|
+
field: "name",
|
|
26364
|
+
message: `\`name\` "${name}" is invalid. Use lowercase letters, digits, and single hyphens only. Cannot start or end with a hyphen or contain consecutive hyphens.`
|
|
26365
|
+
});
|
|
26366
|
+
}
|
|
26367
|
+
if (options.filePath) {
|
|
26368
|
+
const parentDir = basename12(dirname8(options.filePath));
|
|
26369
|
+
if (parentDir && parentDir !== name) {
|
|
26370
|
+
issues.push({
|
|
26371
|
+
severity: "error",
|
|
26372
|
+
code: "SK005",
|
|
26373
|
+
field: "name",
|
|
26374
|
+
message: `\`name\` "${name}" must match the parent directory name "${parentDir}".`
|
|
26375
|
+
});
|
|
26376
|
+
}
|
|
26377
|
+
}
|
|
26378
|
+
if (options.existingNames?.has(name)) {
|
|
26379
|
+
issues.push({
|
|
26380
|
+
severity: "error",
|
|
26381
|
+
code: "SK006",
|
|
26382
|
+
field: "name",
|
|
26383
|
+
message: `Skill name "${name}" collides with an already-installed skill. Two skills cannot share the same name (they would be written to the same output folder).`
|
|
26384
|
+
});
|
|
26385
|
+
}
|
|
26386
|
+
}
|
|
26387
|
+
function validateDescription(parsed, issues) {
|
|
26388
|
+
const fromRaw = parsed.rawFrontmatter ? extractScalarField(parsed.rawFrontmatter, "description") : void 0;
|
|
26389
|
+
const description = fromRaw !== void 0 ? fromRaw : parsed.description;
|
|
26390
|
+
if (!description || description.trim().length < MIN_DESC_LEN) {
|
|
26391
|
+
issues.push({
|
|
26392
|
+
severity: "error",
|
|
26393
|
+
code: "SK010",
|
|
26394
|
+
field: "description",
|
|
26395
|
+
message: "`description` is required and must be non-empty."
|
|
26396
|
+
});
|
|
26397
|
+
return;
|
|
26398
|
+
}
|
|
26399
|
+
if (description.length > MAX_DESC_LEN) {
|
|
26400
|
+
issues.push({
|
|
26401
|
+
severity: "error",
|
|
26402
|
+
code: "SK011",
|
|
26403
|
+
field: "description",
|
|
26404
|
+
message: `\`description\` must be at most ${MAX_DESC_LEN} characters (got ${description.length}).`
|
|
26405
|
+
});
|
|
26406
|
+
}
|
|
26407
|
+
if (description.length < SHORT_DESC_WARN_LEN) {
|
|
26408
|
+
issues.push({
|
|
26409
|
+
severity: "warning",
|
|
26410
|
+
code: "SK012",
|
|
26411
|
+
field: "description",
|
|
26412
|
+
message: `\`description\` is very short (${description.length} chars). The spec recommends describing both what the skill does AND when to use it so agents can match it to tasks.`
|
|
26413
|
+
});
|
|
26414
|
+
} else if (!/\bwhen\b|\buse\b/i.test(description)) {
|
|
26415
|
+
issues.push({
|
|
26416
|
+
severity: "warning",
|
|
26417
|
+
code: "SK013",
|
|
26418
|
+
field: "description",
|
|
26419
|
+
message: '`description` should mention WHEN to use the skill (e.g. "Use when \u2026"). This improves agent trigger accuracy.'
|
|
26420
|
+
});
|
|
26421
|
+
}
|
|
26422
|
+
}
|
|
26423
|
+
function validateCompatibility(rawFrontmatter, issues) {
|
|
26424
|
+
if (!rawFrontmatter) return;
|
|
26425
|
+
const value = extractScalarField(rawFrontmatter, "compatibility");
|
|
26426
|
+
if (value === void 0) return;
|
|
26427
|
+
if (value.length > MAX_COMPATIBILITY_LEN) {
|
|
26428
|
+
issues.push({
|
|
26429
|
+
severity: "error",
|
|
26430
|
+
code: "SK020",
|
|
26431
|
+
field: "compatibility",
|
|
26432
|
+
message: `\`compatibility\` must be at most ${MAX_COMPATIBILITY_LEN} characters (got ${value.length}).`
|
|
26433
|
+
});
|
|
26434
|
+
}
|
|
26435
|
+
}
|
|
26436
|
+
function validateLicense(rawFrontmatter, issues) {
|
|
26437
|
+
if (!rawFrontmatter) {
|
|
26438
|
+
issues.push({
|
|
26439
|
+
severity: "warning",
|
|
26440
|
+
code: "SK030",
|
|
26441
|
+
field: "license",
|
|
26442
|
+
message: "`license` is missing. Enterprises typically require an explicit license declaration before adopting a third-party skill."
|
|
26443
|
+
});
|
|
26444
|
+
return;
|
|
26445
|
+
}
|
|
26446
|
+
const value = extractScalarField(rawFrontmatter, "license");
|
|
26447
|
+
if (value === void 0 || value.length === 0) {
|
|
26448
|
+
issues.push({
|
|
26449
|
+
severity: "warning",
|
|
26450
|
+
code: "SK030",
|
|
26451
|
+
field: "license",
|
|
26452
|
+
message: "`license` is missing. Enterprises typically require an explicit license declaration before adopting a third-party skill."
|
|
26453
|
+
});
|
|
26454
|
+
}
|
|
26455
|
+
}
|
|
26456
|
+
function validateBody(body, issues) {
|
|
26457
|
+
const lines = body.split("\n").length;
|
|
26458
|
+
if (lines > MAX_BODY_LINES) {
|
|
26459
|
+
issues.push({
|
|
26460
|
+
severity: "warning",
|
|
26461
|
+
code: "SK040",
|
|
26462
|
+
message: `SKILL.md body has ${lines} lines (>${MAX_BODY_LINES}). The spec recommends splitting long content into separate files under references/ for progressive disclosure.`
|
|
26463
|
+
});
|
|
26464
|
+
}
|
|
26465
|
+
}
|
|
26466
|
+
function validateReferences(references, filePath, issues) {
|
|
26467
|
+
if (!references || references.length === 0) return;
|
|
26468
|
+
if (!filePath) return;
|
|
26469
|
+
const skillDir = dirname8(filePath);
|
|
26470
|
+
for (const ref of references) {
|
|
26471
|
+
if (ref.startsWith("/") || ref.startsWith("..")) {
|
|
26472
|
+
issues.push({
|
|
26473
|
+
severity: "error",
|
|
26474
|
+
code: "SK050",
|
|
26475
|
+
field: "references",
|
|
26476
|
+
message: `Reference "${ref}" must be a relative path inside the skill directory (no leading "/" or "..").`
|
|
26477
|
+
});
|
|
26478
|
+
continue;
|
|
26479
|
+
}
|
|
26480
|
+
const target = join10(skillDir, ref);
|
|
26481
|
+
if (!existsSync11(target)) {
|
|
26482
|
+
issues.push({
|
|
26483
|
+
severity: "error",
|
|
26484
|
+
code: "SK051",
|
|
26485
|
+
field: "references",
|
|
26486
|
+
message: `Reference "${ref}" listed in frontmatter does not exist (looked for ${target}).`
|
|
26487
|
+
});
|
|
26488
|
+
}
|
|
26489
|
+
}
|
|
26490
|
+
}
|
|
26491
|
+
function validateAllowedTools(rawFrontmatter, issues) {
|
|
26492
|
+
if (!rawFrontmatter) return;
|
|
26493
|
+
const value = extractScalarField(rawFrontmatter, "allowed-tools");
|
|
26494
|
+
if (value === void 0) return;
|
|
26495
|
+
const tokens = value.split(/\s+/).filter((t) => t.length > 0);
|
|
26496
|
+
for (const token of tokens) {
|
|
26497
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*(\([^)]*\))?$/.test(token)) {
|
|
26498
|
+
issues.push({
|
|
26499
|
+
severity: "warning",
|
|
26500
|
+
code: "SK060",
|
|
26501
|
+
field: "allowed-tools",
|
|
26502
|
+
message: `\`allowed-tools\` entry "${token}" does not match the expected \`Tool\` or \`Tool(scope:pattern)\` shape.`
|
|
26503
|
+
});
|
|
26504
|
+
}
|
|
26505
|
+
}
|
|
26506
|
+
}
|
|
26507
|
+
function hasFrontmatterDelimiters(content) {
|
|
26508
|
+
const lines = content.split("\n");
|
|
26509
|
+
let first2 = -1;
|
|
26510
|
+
for (let i = 0; i < lines.length; i++) {
|
|
26511
|
+
if ((lines[i] ?? "").trim() === "---") {
|
|
26512
|
+
first2 = i;
|
|
26513
|
+
break;
|
|
26514
|
+
}
|
|
26515
|
+
}
|
|
26516
|
+
if (first2 === -1) return false;
|
|
26517
|
+
for (let i = first2 + 1; i < lines.length; i++) {
|
|
26518
|
+
if ((lines[i] ?? "").trim() === "---") return true;
|
|
26519
|
+
}
|
|
26520
|
+
return false;
|
|
26521
|
+
}
|
|
26522
|
+
function extractScalarField(rawFrontmatter, field) {
|
|
26523
|
+
const lines = rawFrontmatter.split("\n");
|
|
26524
|
+
const pattern = new RegExp(`^${escapeRegex(field)}:\\s*(?:"([^"]*)"|'([^']*)'|(.*))\\s*$`);
|
|
26525
|
+
for (const line of lines) {
|
|
26526
|
+
const match = line.match(pattern);
|
|
26527
|
+
if (match) {
|
|
26528
|
+
return (match[1] ?? match[2] ?? match[3] ?? "").trim();
|
|
26529
|
+
}
|
|
26530
|
+
}
|
|
26531
|
+
return void 0;
|
|
26532
|
+
}
|
|
26533
|
+
function escapeRegex(input2) {
|
|
26534
|
+
return input2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26535
|
+
}
|
|
26536
|
+
function formatSkillValidationIssues(issues) {
|
|
26537
|
+
return issues.map((i) => {
|
|
26538
|
+
const tag = i.severity === "error" ? "\u2717" : "\u26A0";
|
|
26539
|
+
const field = i.field ? ` [${i.field}]` : "";
|
|
26540
|
+
return ` ${tag} ${i.code}${field}: ${i.message}`;
|
|
26541
|
+
}).join("\n");
|
|
26542
|
+
}
|
|
26543
|
+
|
|
26227
26544
|
// packages/resolver/src/index.ts
|
|
26228
26545
|
init_src();
|
|
26229
26546
|
|
|
26547
|
+
// packages/resolver/src/reference-hasher.ts
|
|
26548
|
+
import { createHash as createHash2 } from "crypto";
|
|
26549
|
+
function hashContent(content) {
|
|
26550
|
+
const hex = createHash2("sha256").update(content).digest("hex");
|
|
26551
|
+
return `sha256-${hex}`;
|
|
26552
|
+
}
|
|
26553
|
+
|
|
26230
26554
|
// packages/validator/src/validator.ts
|
|
26231
26555
|
init_src();
|
|
26232
26556
|
|
|
@@ -29679,7 +30003,7 @@ var Compiler = class _Compiler {
|
|
|
29679
30003
|
outputPathOwners.set(skillPath, `${formatter.name}:promptscript-skill`);
|
|
29680
30004
|
const skillOutput = {
|
|
29681
30005
|
path: skillPath,
|
|
29682
|
-
content: this.options.skillContent
|
|
30006
|
+
content: formatter.transformInjectedSkillContent ? formatter.transformInjectedSkillContent(this.options.skillContent) : this.options.skillContent
|
|
29683
30007
|
};
|
|
29684
30008
|
outputs.set(skillPath, addMarkerToOutput(skillOutput, sourceLabel, "promptscript"));
|
|
29685
30009
|
this.logger.verbose(` \u2192 ${skillPath} (auto-injected promptscript skill)`);
|
|
@@ -29760,12 +30084,12 @@ var Compiler = class _Compiler {
|
|
|
29760
30084
|
*/
|
|
29761
30085
|
async watch(entryPath, options = {}) {
|
|
29762
30086
|
const { default: chokidar2 } = await import("chokidar");
|
|
29763
|
-
const { dirname:
|
|
29764
|
-
const baseDir =
|
|
30087
|
+
const { dirname: dirname17, resolve: resolve22 } = await import("path");
|
|
30088
|
+
const baseDir = dirname17(resolve22(entryPath));
|
|
29765
30089
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
29766
30090
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
29767
30091
|
const debounceMs = options.debounce ?? 300;
|
|
29768
|
-
const watchPatterns = includePatterns.map((p) =>
|
|
30092
|
+
const watchPatterns = includePatterns.map((p) => resolve22(baseDir, p));
|
|
29769
30093
|
let debounceTimer = null;
|
|
29770
30094
|
let pendingChanges = [];
|
|
29771
30095
|
const handleChange = async (changedFiles) => {
|
|
@@ -29940,7 +30264,7 @@ var Pager = class {
|
|
|
29940
30264
|
}
|
|
29941
30265
|
return;
|
|
29942
30266
|
}
|
|
29943
|
-
return new Promise((
|
|
30267
|
+
return new Promise((resolve22) => {
|
|
29944
30268
|
const pagerCmd = getPagerCommand();
|
|
29945
30269
|
const [cmd, ...args] = pagerCmd.split(" ");
|
|
29946
30270
|
if (cmd === "less" && !args.includes("-R")) {
|
|
@@ -29948,7 +30272,7 @@ var Pager = class {
|
|
|
29948
30272
|
}
|
|
29949
30273
|
if (!cmd) {
|
|
29950
30274
|
console.log(content);
|
|
29951
|
-
|
|
30275
|
+
resolve22();
|
|
29952
30276
|
return;
|
|
29953
30277
|
}
|
|
29954
30278
|
const pager = spawn(cmd, args, {
|
|
@@ -29961,17 +30285,17 @@ var Pager = class {
|
|
|
29961
30285
|
});
|
|
29962
30286
|
pager.on("error", (_err) => {
|
|
29963
30287
|
console.log(content);
|
|
29964
|
-
|
|
30288
|
+
resolve22();
|
|
29965
30289
|
});
|
|
29966
30290
|
pager.on("close", () => {
|
|
29967
|
-
|
|
30291
|
+
resolve22();
|
|
29968
30292
|
});
|
|
29969
30293
|
if (pager.stdin) {
|
|
29970
30294
|
pager.stdin.write(content);
|
|
29971
30295
|
pager.stdin.end();
|
|
29972
30296
|
} else {
|
|
29973
30297
|
console.log(content);
|
|
29974
|
-
|
|
30298
|
+
resolve22();
|
|
29975
30299
|
}
|
|
29976
30300
|
});
|
|
29977
30301
|
}
|
|
@@ -29984,7 +30308,7 @@ function createPager(enabled = true) {
|
|
|
29984
30308
|
init_services();
|
|
29985
30309
|
|
|
29986
30310
|
// packages/cli/src/utils/registry-resolver.ts
|
|
29987
|
-
import { join as
|
|
30311
|
+
import { join as join11 } from "path";
|
|
29988
30312
|
async function resolveRegistryPath(config) {
|
|
29989
30313
|
if (config.registry?.git) {
|
|
29990
30314
|
const gitConfig = config.registry.git;
|
|
@@ -29998,7 +30322,7 @@ async function resolveRegistryPath(config) {
|
|
|
29998
30322
|
if (isValid) {
|
|
29999
30323
|
const subPath2 = gitConfig.path ?? "";
|
|
30000
30324
|
return {
|
|
30001
|
-
path: subPath2 ?
|
|
30325
|
+
path: subPath2 ? join11(cachePath, subPath2) : cachePath,
|
|
30002
30326
|
isRemote: true,
|
|
30003
30327
|
source: "git"
|
|
30004
30328
|
};
|
|
@@ -30027,7 +30351,7 @@ async function resolveRegistryPath(config) {
|
|
|
30027
30351
|
}
|
|
30028
30352
|
const subPath = gitConfig.path ?? "";
|
|
30029
30353
|
return {
|
|
30030
|
-
path: subPath ?
|
|
30354
|
+
path: subPath ? join11(cachePath, subPath) : cachePath,
|
|
30031
30355
|
isRemote: true,
|
|
30032
30356
|
source: "git"
|
|
30033
30357
|
};
|
|
@@ -30077,17 +30401,17 @@ function detectOutputConflicts(targets) {
|
|
|
30077
30401
|
|
|
30078
30402
|
// packages/cli/src/commands/compile.ts
|
|
30079
30403
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
30080
|
-
var __dirname2 =
|
|
30404
|
+
var __dirname2 = dirname9(__filename2);
|
|
30081
30405
|
async function loadBundledSkillContent(logger) {
|
|
30082
30406
|
const skillRelPath = "skills/promptscript/SKILL.md";
|
|
30083
30407
|
const candidates = [
|
|
30084
|
-
|
|
30408
|
+
resolve8(__dirname2, skillRelPath),
|
|
30085
30409
|
// bundled: dist/packages/cli/skills/...
|
|
30086
|
-
|
|
30410
|
+
resolve8(__dirname2, "..", "..", skillRelPath)
|
|
30087
30411
|
// dev: packages/cli/skills/...
|
|
30088
30412
|
];
|
|
30089
30413
|
for (const candidate of candidates) {
|
|
30090
|
-
if (
|
|
30414
|
+
if (existsSync12(candidate)) {
|
|
30091
30415
|
try {
|
|
30092
30416
|
const content = await readFile12(candidate, "utf-8");
|
|
30093
30417
|
logger.debug(
|
|
@@ -30104,8 +30428,8 @@ async function loadBundledSkillContent(logger) {
|
|
|
30104
30428
|
}
|
|
30105
30429
|
function findConfigInDir(dir) {
|
|
30106
30430
|
for (const file of CONFIG_FILES) {
|
|
30107
|
-
const fullPath =
|
|
30108
|
-
if (
|
|
30431
|
+
const fullPath = resolve8(dir, file);
|
|
30432
|
+
if (existsSync12(fullPath)) {
|
|
30109
30433
|
return fullPath;
|
|
30110
30434
|
}
|
|
30111
30435
|
}
|
|
@@ -30161,7 +30485,7 @@ function getBuildProfile(config, buildName) {
|
|
|
30161
30485
|
}
|
|
30162
30486
|
function resolveOutputBase(projectRoot, output) {
|
|
30163
30487
|
if (!output) return projectRoot;
|
|
30164
|
-
return isAbsolute5(output) ? output :
|
|
30488
|
+
return isAbsolute5(output) ? output : resolve8(projectRoot, output);
|
|
30165
30489
|
}
|
|
30166
30490
|
async function isPromptScriptGenerated2(filePath) {
|
|
30167
30491
|
try {
|
|
@@ -30205,13 +30529,13 @@ async function writeOutputs(outputs, options, _config, services) {
|
|
|
30205
30529
|
const targetErrors = [];
|
|
30206
30530
|
async function safeWrite(path, content) {
|
|
30207
30531
|
try {
|
|
30208
|
-
await mkdir4(
|
|
30532
|
+
await mkdir4(dirname9(path), { recursive: true });
|
|
30209
30533
|
await writeFile4(path, content, "utf-8");
|
|
30210
30534
|
return true;
|
|
30211
30535
|
} catch (err) {
|
|
30212
30536
|
const nodeErr = err;
|
|
30213
30537
|
if (nodeErr.code === "ENOTDIR") {
|
|
30214
|
-
const conflictPath = nodeErr.path ??
|
|
30538
|
+
const conflictPath = nodeErr.path ?? dirname9(path);
|
|
30215
30539
|
const msg = `Cannot create directory because '${conflictPath}' already exists as a file. Remove it or disable this target.`;
|
|
30216
30540
|
targetErrors.push(msg);
|
|
30217
30541
|
ConsoleOutput.error(msg);
|
|
@@ -30227,8 +30551,8 @@ async function writeOutputs(outputs, options, _config, services) {
|
|
|
30227
30551
|
}
|
|
30228
30552
|
}
|
|
30229
30553
|
for (const output of outputs.values()) {
|
|
30230
|
-
const outputPath = options.output ?
|
|
30231
|
-
const fileExists3 =
|
|
30554
|
+
const outputPath = options.output ? resolve8(options.output, output.path) : resolve8(output.path);
|
|
30555
|
+
const fileExists3 = existsSync12(outputPath);
|
|
30232
30556
|
if (options.dryRun) {
|
|
30233
30557
|
if (fileExists3) {
|
|
30234
30558
|
const isGenerated2 = await isPromptScriptGenerated2(outputPath);
|
|
@@ -30361,7 +30685,7 @@ async function compileCommand(options, services = createDefaultServices()) {
|
|
|
30361
30685
|
const spinner = createSpinner("Loading configuration...").start();
|
|
30362
30686
|
const logger = createCliLogger();
|
|
30363
30687
|
try {
|
|
30364
|
-
const projectRoot = options.cwd ?
|
|
30688
|
+
const projectRoot = options.cwd ? resolve8(options.cwd) : process.cwd();
|
|
30365
30689
|
logger.verbose("Loading configuration...");
|
|
30366
30690
|
const configPath = options.config ? options.config : options.cwd ? findConfigInDir(projectRoot) : void 0;
|
|
30367
30691
|
const config = await loadConfig(configPath);
|
|
@@ -30401,7 +30725,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30401
30725
|
}
|
|
30402
30726
|
}
|
|
30403
30727
|
let lockfile;
|
|
30404
|
-
const lockfilePath =
|
|
30728
|
+
const lockfilePath = resolve8(projectRoot, "promptscript.lock");
|
|
30405
30729
|
try {
|
|
30406
30730
|
const lockfileContent = await readFile12(lockfilePath, "utf-8");
|
|
30407
30731
|
const parsed = parseYaml5(lockfileContent, { maxAliasCount: 100 });
|
|
@@ -30421,7 +30745,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30421
30745
|
if (config.includePromptScriptSkill !== false) {
|
|
30422
30746
|
skillContent = await loadBundledSkillContent(logger);
|
|
30423
30747
|
}
|
|
30424
|
-
const localPath =
|
|
30748
|
+
const localPath = resolve8(projectRoot, ".promptscript");
|
|
30425
30749
|
const compiler = new Compiler({
|
|
30426
30750
|
resolver: {
|
|
30427
30751
|
registryPath,
|
|
@@ -30441,8 +30765,8 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30441
30765
|
ignoreHashes: options.ignoreHashes
|
|
30442
30766
|
});
|
|
30443
30767
|
const entry = buildProfile?.entry ?? config.input?.entry;
|
|
30444
|
-
const entryPath = entry ?
|
|
30445
|
-
if (!
|
|
30768
|
+
const entryPath = entry ? resolve8(projectRoot, entry) : resolve8(localPath, "project.prs");
|
|
30769
|
+
if (!existsSync12(entryPath)) {
|
|
30446
30770
|
spinner.fail("Entry file not found");
|
|
30447
30771
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
30448
30772
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -30467,6 +30791,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30467
30791
|
...options,
|
|
30468
30792
|
output: resolveOutputBase(projectRoot, configuredOutput)
|
|
30469
30793
|
};
|
|
30794
|
+
await postFormatWithPrettier(result.outputs, projectRoot, logger);
|
|
30470
30795
|
const writeResult = await writeOutputs(result.outputs, effectiveOptions, config, services);
|
|
30471
30796
|
if (writeResult.unchanged.length > 0) {
|
|
30472
30797
|
ConsoleOutput.muted(`Unchanged ${writeResult.unchanged.length} file(s)`);
|
|
@@ -30480,7 +30805,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30480
30805
|
ConsoleOutput.newline();
|
|
30481
30806
|
ConsoleOutput.info("Watching for changes... (Ctrl+C to stop)");
|
|
30482
30807
|
watchForChanges(
|
|
30483
|
-
|
|
30808
|
+
resolve8(projectRoot, ".promptscript"),
|
|
30484
30809
|
() => compileCommand({ ...options, watch: false }, services)
|
|
30485
30810
|
);
|
|
30486
30811
|
}
|
|
@@ -30531,8 +30856,8 @@ function watchForChanges(dir, callback) {
|
|
|
30531
30856
|
}
|
|
30532
30857
|
|
|
30533
30858
|
// packages/cli/src/commands/validate.ts
|
|
30534
|
-
import { resolve as
|
|
30535
|
-
import { existsSync as
|
|
30859
|
+
import { resolve as resolve9, join as join12 } from "path";
|
|
30860
|
+
import { existsSync as existsSync13, readFileSync as readFileSync4, writeFileSync, readdirSync } from "fs";
|
|
30536
30861
|
init_console();
|
|
30537
30862
|
init_src();
|
|
30538
30863
|
init_src2();
|
|
@@ -30641,7 +30966,7 @@ function discoverPrsFiles(dir) {
|
|
|
30641
30966
|
try {
|
|
30642
30967
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
30643
30968
|
for (const entry of entries) {
|
|
30644
|
-
const fullPath =
|
|
30969
|
+
const fullPath = join12(dir, entry.name);
|
|
30645
30970
|
if (entry.isDirectory()) {
|
|
30646
30971
|
results.push(...discoverPrsFiles(fullPath));
|
|
30647
30972
|
} else if (entry.name.endsWith(".prs")) {
|
|
@@ -30681,8 +31006,8 @@ async function validateCommand(options) {
|
|
|
30681
31006
|
formatters: []
|
|
30682
31007
|
// No formatters needed for validation only
|
|
30683
31008
|
});
|
|
30684
|
-
const entryPath =
|
|
30685
|
-
if (!
|
|
31009
|
+
const entryPath = resolve9("./.promptscript/project.prs");
|
|
31010
|
+
if (!existsSync13(entryPath)) {
|
|
30686
31011
|
handleEntryNotFound(entryPath, isJsonFormat, spinner);
|
|
30687
31012
|
return;
|
|
30688
31013
|
}
|
|
@@ -30764,8 +31089,8 @@ ${fixedCount} file(s) fixed.`);
|
|
|
30764
31089
|
|
|
30765
31090
|
// packages/cli/src/commands/pull.ts
|
|
30766
31091
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
30767
|
-
import { existsSync as
|
|
30768
|
-
import { resolve as
|
|
31092
|
+
import { existsSync as existsSync14 } from "fs";
|
|
31093
|
+
import { resolve as resolve10, dirname as dirname10 } from "path";
|
|
30769
31094
|
init_console();
|
|
30770
31095
|
async function pullCommand(options) {
|
|
30771
31096
|
const spinner = createSpinner("Loading configuration...").start();
|
|
@@ -30790,8 +31115,8 @@ async function pullCommand(options) {
|
|
|
30790
31115
|
}
|
|
30791
31116
|
spinner.text = `Fetching ${inheritPath}...`;
|
|
30792
31117
|
const content = await registry2.fetch(inheritPath);
|
|
30793
|
-
const destPath =
|
|
30794
|
-
if (
|
|
31118
|
+
const destPath = resolve10("./.promptscript/.inherited", inheritPath);
|
|
31119
|
+
if (existsSync14(destPath) && !options.force && !options.dryRun) {
|
|
30795
31120
|
spinner.warn("File already exists (use --force to overwrite)");
|
|
30796
31121
|
ConsoleOutput.muted(destPath);
|
|
30797
31122
|
return;
|
|
@@ -30801,12 +31126,12 @@ async function pullCommand(options) {
|
|
|
30801
31126
|
ConsoleOutput.newline();
|
|
30802
31127
|
ConsoleOutput.dryRun(`Would fetch: ${config.inherit}`);
|
|
30803
31128
|
ConsoleOutput.dryRun(` to: ${destPath}`);
|
|
30804
|
-
if (
|
|
31129
|
+
if (existsSync14(destPath)) {
|
|
30805
31130
|
ConsoleOutput.dryRun("(would overwrite existing file)");
|
|
30806
31131
|
}
|
|
30807
31132
|
return;
|
|
30808
31133
|
}
|
|
30809
|
-
await mkdir5(
|
|
31134
|
+
await mkdir5(dirname10(destPath), { recursive: true });
|
|
30810
31135
|
await writeFile5(destPath, content, "utf-8");
|
|
30811
31136
|
spinner.succeed("Pulled from registry");
|
|
30812
31137
|
ConsoleOutput.success(destPath);
|
|
@@ -30849,10 +31174,10 @@ async function createRegistry(config, options, spinner) {
|
|
|
30849
31174
|
}
|
|
30850
31175
|
const registryPath = config.registry?.path ?? "./registry";
|
|
30851
31176
|
spinner.text = `Using local registry: ${registryPath}...`;
|
|
30852
|
-
if (!
|
|
31177
|
+
if (!existsSync14(registryPath)) {
|
|
30853
31178
|
throw new Error(`Local registry path not found: ${registryPath}`);
|
|
30854
31179
|
}
|
|
30855
|
-
return createFileSystemRegistry(
|
|
31180
|
+
return createFileSystemRegistry(resolve10(registryPath));
|
|
30856
31181
|
}
|
|
30857
31182
|
function parseInheritPath(inheritPath) {
|
|
30858
31183
|
const versionIndex = inheritPath.lastIndexOf("@");
|
|
@@ -30899,9 +31224,9 @@ function handlePullError(error, spinner) {
|
|
|
30899
31224
|
}
|
|
30900
31225
|
|
|
30901
31226
|
// packages/cli/src/commands/diff.ts
|
|
30902
|
-
import { resolve as
|
|
31227
|
+
import { resolve as resolve11 } from "path";
|
|
30903
31228
|
import { readFile as readFile13 } from "fs/promises";
|
|
30904
|
-
import { existsSync as
|
|
31229
|
+
import { existsSync as existsSync15 } from "fs";
|
|
30905
31230
|
init_console();
|
|
30906
31231
|
import chalk2 from "chalk";
|
|
30907
31232
|
function configureColors(options) {
|
|
@@ -30936,9 +31261,9 @@ function printNewFilePreview(content, showFull, pager) {
|
|
|
30936
31261
|
}
|
|
30937
31262
|
}
|
|
30938
31263
|
async function compareOutput(_name, output, _config, showFull, pager) {
|
|
30939
|
-
const outputPath =
|
|
31264
|
+
const outputPath = resolve11(output.path);
|
|
30940
31265
|
const newContent = output.content;
|
|
30941
|
-
if (!
|
|
31266
|
+
if (!existsSync15(outputPath)) {
|
|
30942
31267
|
pager.write(chalk2.green(`+ ${outputPath} (new file)`));
|
|
30943
31268
|
pager.write("");
|
|
30944
31269
|
printNewFilePreview(newContent, showFull, pager);
|
|
@@ -30978,8 +31303,8 @@ async function diffCommand(options) {
|
|
|
30978
31303
|
formatters: targets,
|
|
30979
31304
|
customConventions: config.customConventions
|
|
30980
31305
|
});
|
|
30981
|
-
const entryPath =
|
|
30982
|
-
if (!
|
|
31306
|
+
const entryPath = resolve11("./.promptscript/project.prs");
|
|
31307
|
+
if (!existsSync15(entryPath)) {
|
|
30983
31308
|
spinner.fail("Entry file not found");
|
|
30984
31309
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
30985
31310
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -31047,8 +31372,8 @@ function printSimpleDiff(existingLines, newLines, showFull, pager) {
|
|
|
31047
31372
|
}
|
|
31048
31373
|
|
|
31049
31374
|
// packages/cli/src/commands/check.ts
|
|
31050
|
-
import { existsSync as
|
|
31051
|
-
import { resolve as
|
|
31375
|
+
import { existsSync as existsSync16 } from "fs";
|
|
31376
|
+
import { resolve as resolve12 } from "path";
|
|
31052
31377
|
init_console();
|
|
31053
31378
|
async function checkCommand(_options) {
|
|
31054
31379
|
const spinner = createSpinner("Checking project health...").start();
|
|
@@ -31111,7 +31436,7 @@ async function checkCommand(_options) {
|
|
|
31111
31436
|
});
|
|
31112
31437
|
}
|
|
31113
31438
|
const entryPath = config.input?.entry ?? ".promptscript/project.prs";
|
|
31114
|
-
if (
|
|
31439
|
+
if (existsSync16(entryPath)) {
|
|
31115
31440
|
results.push({
|
|
31116
31441
|
name: "Entry file",
|
|
31117
31442
|
status: "ok",
|
|
@@ -31126,8 +31451,8 @@ async function checkCommand(_options) {
|
|
|
31126
31451
|
hasErrors = true;
|
|
31127
31452
|
}
|
|
31128
31453
|
if (config.registry?.path) {
|
|
31129
|
-
const registryPath =
|
|
31130
|
-
if (
|
|
31454
|
+
const registryPath = resolve12(config.registry.path);
|
|
31455
|
+
if (existsSync16(registryPath)) {
|
|
31131
31456
|
results.push({
|
|
31132
31457
|
name: "Registry path",
|
|
31133
31458
|
status: "ok",
|
|
@@ -31212,21 +31537,21 @@ function printResults(results) {
|
|
|
31212
31537
|
init_src();
|
|
31213
31538
|
init_console();
|
|
31214
31539
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
31215
|
-
import { dirname as
|
|
31540
|
+
import { dirname as dirname11 } from "path";
|
|
31216
31541
|
|
|
31217
31542
|
// packages/cli/src/utils/version-check.ts
|
|
31218
31543
|
init_console();
|
|
31219
31544
|
import { homedir as homedir3 } from "os";
|
|
31220
|
-
import { join as
|
|
31545
|
+
import { join as join13 } from "path";
|
|
31221
31546
|
import { readFile as readFile14, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
|
|
31222
31547
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@promptscript/cli/latest";
|
|
31223
31548
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
31224
31549
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
31225
31550
|
function getCacheDir() {
|
|
31226
|
-
return
|
|
31551
|
+
return join13(homedir3(), ".promptscript", ".cache");
|
|
31227
31552
|
}
|
|
31228
31553
|
function getCachePath() {
|
|
31229
|
-
return
|
|
31554
|
+
return join13(getCacheDir(), "version.json");
|
|
31230
31555
|
}
|
|
31231
31556
|
async function readCache() {
|
|
31232
31557
|
try {
|
|
@@ -31365,7 +31690,7 @@ function printUpdateNotification(info) {
|
|
|
31365
31690
|
|
|
31366
31691
|
// packages/cli/src/commands/update-check.ts
|
|
31367
31692
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
31368
|
-
var __dirname3 =
|
|
31693
|
+
var __dirname3 = dirname11(__filename3);
|
|
31369
31694
|
async function updateCheckCommand() {
|
|
31370
31695
|
const currentVersion = getPackageVersion(__dirname3, "./package.json");
|
|
31371
31696
|
console.log(`@promptscript/cli v${currentVersion}`);
|
|
@@ -31393,7 +31718,7 @@ init_services();
|
|
|
31393
31718
|
init_console();
|
|
31394
31719
|
|
|
31395
31720
|
// packages/cli/src/utils/registry-scaffolder.ts
|
|
31396
|
-
import { join as
|
|
31721
|
+
import { join as join14 } from "path";
|
|
31397
31722
|
var SEED_BASE = `@meta {
|
|
31398
31723
|
id: "@core/base"
|
|
31399
31724
|
syntax: "1.0.0"
|
|
@@ -31494,14 +31819,14 @@ async function scaffoldRegistry(options, services) {
|
|
|
31494
31819
|
const createdFiles = [];
|
|
31495
31820
|
await fs4.mkdir(directory, { recursive: true });
|
|
31496
31821
|
const manifest = generateManifest(name, description, namespaces, seed);
|
|
31497
|
-
const manifestPath =
|
|
31822
|
+
const manifestPath = join14(directory, "registry-manifest.yaml");
|
|
31498
31823
|
await fs4.writeFile(manifestPath, manifest, "utf-8");
|
|
31499
31824
|
createdFiles.push(manifestPath);
|
|
31500
31825
|
const readme = generateReadme(name, description, namespaces);
|
|
31501
|
-
const readmePath =
|
|
31826
|
+
const readmePath = join14(directory, "README.md");
|
|
31502
31827
|
await fs4.writeFile(readmePath, readme, "utf-8");
|
|
31503
31828
|
createdFiles.push(readmePath);
|
|
31504
|
-
const gitignorePath =
|
|
31829
|
+
const gitignorePath = join14(directory, ".gitignore");
|
|
31505
31830
|
await fs4.writeFile(
|
|
31506
31831
|
gitignorePath,
|
|
31507
31832
|
".DS_Store\nnode_modules/\n*.log\n*.swp\n*.bak\n.env*\n",
|
|
@@ -31509,20 +31834,20 @@ async function scaffoldRegistry(options, services) {
|
|
|
31509
31834
|
);
|
|
31510
31835
|
createdFiles.push(gitignorePath);
|
|
31511
31836
|
for (const ns of namespaces) {
|
|
31512
|
-
const nsDir =
|
|
31837
|
+
const nsDir = join14(directory, ns);
|
|
31513
31838
|
await fs4.mkdir(nsDir, { recursive: true });
|
|
31514
31839
|
if (seed && ns === "@core") {
|
|
31515
|
-
const basePath =
|
|
31840
|
+
const basePath = join14(nsDir, "base.prs");
|
|
31516
31841
|
await fs4.writeFile(basePath, SEED_BASE, "utf-8");
|
|
31517
31842
|
createdFiles.push(basePath);
|
|
31518
|
-
const qualityPath =
|
|
31843
|
+
const qualityPath = join14(nsDir, "quality.prs");
|
|
31519
31844
|
await fs4.writeFile(qualityPath, SEED_QUALITY, "utf-8");
|
|
31520
31845
|
createdFiles.push(qualityPath);
|
|
31521
|
-
const securityPath =
|
|
31846
|
+
const securityPath = join14(nsDir, "security.prs");
|
|
31522
31847
|
await fs4.writeFile(securityPath, SEED_SECURITY, "utf-8");
|
|
31523
31848
|
createdFiles.push(securityPath);
|
|
31524
31849
|
} else {
|
|
31525
|
-
const gitkeepPath =
|
|
31850
|
+
const gitkeepPath = join14(nsDir, ".gitkeep");
|
|
31526
31851
|
await fs4.writeFile(gitkeepPath, "", "utf-8");
|
|
31527
31852
|
createdFiles.push(gitkeepPath);
|
|
31528
31853
|
}
|
|
@@ -31631,7 +31956,7 @@ Then reference configs with \`@inherit\` or \`@use\`:
|
|
|
31631
31956
|
}
|
|
31632
31957
|
|
|
31633
31958
|
// packages/cli/src/utils/resolve-target-directory.ts
|
|
31634
|
-
import { join as
|
|
31959
|
+
import { join as join15, resolve as resolve13 } from "path";
|
|
31635
31960
|
|
|
31636
31961
|
// packages/cli/src/utils/slugify.ts
|
|
31637
31962
|
function slugify(name) {
|
|
@@ -31642,7 +31967,7 @@ function slugify(name) {
|
|
|
31642
31967
|
async function resolveTargetDirectory(options, services) {
|
|
31643
31968
|
const { cwd, directoryArg, registryName, nonInteractive } = options;
|
|
31644
31969
|
if (directoryArg) {
|
|
31645
|
-
return
|
|
31970
|
+
return resolve13(directoryArg);
|
|
31646
31971
|
}
|
|
31647
31972
|
const empty = await isDirectoryEmpty(cwd, services.fs);
|
|
31648
31973
|
if (empty && nonInteractive) {
|
|
@@ -31656,9 +31981,9 @@ async function resolveTargetDirectory(options, services) {
|
|
|
31656
31981
|
{ name: `Subdirectory (./${slugify(registryName)})`, value: "subdirectory" }
|
|
31657
31982
|
]
|
|
31658
31983
|
});
|
|
31659
|
-
return choice === "here" ? cwd :
|
|
31984
|
+
return choice === "here" ? cwd : join15(cwd, slugify(registryName));
|
|
31660
31985
|
}
|
|
31661
|
-
return
|
|
31986
|
+
return join15(cwd, slugify(registryName));
|
|
31662
31987
|
}
|
|
31663
31988
|
async function isDirectoryEmpty(dir, fs4) {
|
|
31664
31989
|
const entries = await fs4.readdir(dir);
|
|
@@ -31749,15 +32074,15 @@ async function registryInitCommand(directory, options, services = createDefaultS
|
|
|
31749
32074
|
// packages/cli/src/commands/registry/validate.ts
|
|
31750
32075
|
init_services();
|
|
31751
32076
|
init_console();
|
|
31752
|
-
import { resolve as
|
|
32077
|
+
import { resolve as resolve14 } from "path";
|
|
31753
32078
|
|
|
31754
32079
|
// packages/cli/src/utils/registry-validator.ts
|
|
31755
|
-
import { join as
|
|
32080
|
+
import { join as join16 } from "path";
|
|
31756
32081
|
import { parse as parseYaml6 } from "yaml";
|
|
31757
32082
|
async function validateRegistry(registryPath, services) {
|
|
31758
32083
|
const { fs: fs4 } = services;
|
|
31759
32084
|
const issues = [];
|
|
31760
|
-
const manifestPath =
|
|
32085
|
+
const manifestPath = join16(registryPath, "registry-manifest.yaml");
|
|
31761
32086
|
if (!fs4.existsSync(manifestPath)) {
|
|
31762
32087
|
return {
|
|
31763
32088
|
valid: false,
|
|
@@ -31849,7 +32174,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31849
32174
|
});
|
|
31850
32175
|
}
|
|
31851
32176
|
if (entry.path) {
|
|
31852
|
-
const prsPath =
|
|
32177
|
+
const prsPath = join16(registryPath, entry.path);
|
|
31853
32178
|
if (!fs4.existsSync(prsPath)) {
|
|
31854
32179
|
issues.push({
|
|
31855
32180
|
severity: "error",
|
|
@@ -31884,7 +32209,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31884
32209
|
});
|
|
31885
32210
|
}
|
|
31886
32211
|
for (const ns of namespaceNames) {
|
|
31887
|
-
const nsDir =
|
|
32212
|
+
const nsDir = join16(registryPath, ns);
|
|
31888
32213
|
if (fs4.existsSync(nsDir)) {
|
|
31889
32214
|
try {
|
|
31890
32215
|
const files = await fs4.readdir(nsDir);
|
|
@@ -31898,7 +32223,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31898
32223
|
issues.push({
|
|
31899
32224
|
severity: "warning",
|
|
31900
32225
|
message: `Orphaned .prs file not in catalog: ${relativePath}`,
|
|
31901
|
-
path:
|
|
32226
|
+
path: join16(nsDir, file)
|
|
31902
32227
|
});
|
|
31903
32228
|
}
|
|
31904
32229
|
}
|
|
@@ -31949,7 +32274,7 @@ function detectCircularDependencies(catalog) {
|
|
|
31949
32274
|
|
|
31950
32275
|
// packages/cli/src/commands/registry/validate.ts
|
|
31951
32276
|
async function registryValidateCommand(path, options, services = createDefaultServices()) {
|
|
31952
|
-
const registryPath =
|
|
32277
|
+
const registryPath = resolve14(path ?? ".");
|
|
31953
32278
|
const spinner = createSpinner("Validating registry...").start();
|
|
31954
32279
|
try {
|
|
31955
32280
|
const result = await validateRegistry(registryPath, services);
|
|
@@ -32001,10 +32326,10 @@ async function registryValidateCommand(path, options, services = createDefaultSe
|
|
|
32001
32326
|
// packages/cli/src/commands/registry/publish.ts
|
|
32002
32327
|
init_services();
|
|
32003
32328
|
init_console();
|
|
32004
|
-
import { resolve as
|
|
32329
|
+
import { resolve as resolve15, join as join17 } from "path";
|
|
32005
32330
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
32006
32331
|
async function registryPublishCommand(path, options, services = createDefaultServices()) {
|
|
32007
|
-
const registryPath =
|
|
32332
|
+
const registryPath = resolve15(path ?? ".");
|
|
32008
32333
|
try {
|
|
32009
32334
|
if (!options.force) {
|
|
32010
32335
|
const spinner2 = createSpinner("Validating registry...").start();
|
|
@@ -32024,7 +32349,7 @@ async function registryPublishCommand(path, options, services = createDefaultSer
|
|
|
32024
32349
|
`Registry valid (${result.stats.catalogEntries} entries, ${result.stats.prsFiles} files)`
|
|
32025
32350
|
);
|
|
32026
32351
|
}
|
|
32027
|
-
const manifestPath =
|
|
32352
|
+
const manifestPath = join17(registryPath, "registry-manifest.yaml");
|
|
32028
32353
|
if (services.fs.existsSync(manifestPath)) {
|
|
32029
32354
|
const content = await services.fs.readFile(manifestPath, "utf-8");
|
|
32030
32355
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -32152,8 +32477,8 @@ async function registryListCommand() {
|
|
|
32152
32477
|
// packages/cli/src/commands/registry/add.ts
|
|
32153
32478
|
init_console();
|
|
32154
32479
|
import { readFile as readFile16, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
32155
|
-
import { existsSync as
|
|
32156
|
-
import { dirname as
|
|
32480
|
+
import { existsSync as existsSync17 } from "fs";
|
|
32481
|
+
import { dirname as dirname12 } from "path";
|
|
32157
32482
|
import { parse as parseYaml8, stringify as stringifyYaml } from "yaml";
|
|
32158
32483
|
init_user_config();
|
|
32159
32484
|
async function registryAddCommand(alias, url, options) {
|
|
@@ -32183,12 +32508,12 @@ async function registryAddCommand(alias, url, options) {
|
|
|
32183
32508
|
}
|
|
32184
32509
|
}
|
|
32185
32510
|
async function addToGlobalConfig(alias, url) {
|
|
32186
|
-
const configDir =
|
|
32187
|
-
if (!
|
|
32511
|
+
const configDir = dirname12(USER_CONFIG_PATH);
|
|
32512
|
+
if (!existsSync17(configDir)) {
|
|
32188
32513
|
await mkdir7(configDir, { recursive: true });
|
|
32189
32514
|
}
|
|
32190
32515
|
let config = { version: "1" };
|
|
32191
|
-
if (
|
|
32516
|
+
if (existsSync17(USER_CONFIG_PATH)) {
|
|
32192
32517
|
const content = await readFile16(USER_CONFIG_PATH, "utf-8");
|
|
32193
32518
|
const parsed = parseYaml8(content);
|
|
32194
32519
|
if (parsed && typeof parsed === "object") {
|
|
@@ -32238,8 +32563,8 @@ function registerRegistryCommands(registry2) {
|
|
|
32238
32563
|
|
|
32239
32564
|
// packages/cli/src/commands/lock.ts
|
|
32240
32565
|
import { writeFile as writeFile8, readFile as readFile18 } from "fs/promises";
|
|
32241
|
-
import { existsSync as
|
|
32242
|
-
import { resolve as
|
|
32566
|
+
import { existsSync as existsSync19 } from "fs";
|
|
32567
|
+
import { resolve as resolve16 } from "path";
|
|
32243
32568
|
import { parse as parseYaml9, stringify as stringifyYaml2 } from "yaml";
|
|
32244
32569
|
init_console();
|
|
32245
32570
|
init_src();
|
|
@@ -32247,9 +32572,9 @@ init_src();
|
|
|
32247
32572
|
// packages/cli/src/commands/lock-scanner.ts
|
|
32248
32573
|
init_src2();
|
|
32249
32574
|
import { readFile as readFile17 } from "fs/promises";
|
|
32250
|
-
import { existsSync as
|
|
32575
|
+
import { existsSync as existsSync18 } from "fs";
|
|
32251
32576
|
async function collectRemoteImports(entryPath, options) {
|
|
32252
|
-
if (!
|
|
32577
|
+
if (!existsSync18(entryPath)) {
|
|
32253
32578
|
return [];
|
|
32254
32579
|
}
|
|
32255
32580
|
const loader = new FileLoader({
|
|
@@ -32286,7 +32611,7 @@ async function collectRemoteImports(entryPath, options) {
|
|
|
32286
32611
|
results.push(marker);
|
|
32287
32612
|
}
|
|
32288
32613
|
} else {
|
|
32289
|
-
if (
|
|
32614
|
+
if (existsSync18(resolved)) {
|
|
32290
32615
|
await scan(resolved);
|
|
32291
32616
|
}
|
|
32292
32617
|
}
|
|
@@ -32312,8 +32637,8 @@ async function lockCommand(options) {
|
|
|
32312
32637
|
const aliases = config.registries ?? {};
|
|
32313
32638
|
const aliasEntries = Object.entries(aliases);
|
|
32314
32639
|
const projectRoot = process.cwd();
|
|
32315
|
-
const localPath =
|
|
32316
|
-
const entryPath = config.input?.entry ?
|
|
32640
|
+
const localPath = resolve16(projectRoot, ".promptscript");
|
|
32641
|
+
const entryPath = config.input?.entry ? resolve16(projectRoot, config.input.entry) : resolve16(localPath, "project.prs");
|
|
32317
32642
|
const scannedImports = await collectRemoteImports(entryPath, {
|
|
32318
32643
|
localPath,
|
|
32319
32644
|
registries: config.registries
|
|
@@ -32324,7 +32649,7 @@ async function lockCommand(options) {
|
|
|
32324
32649
|
return;
|
|
32325
32650
|
}
|
|
32326
32651
|
let existing = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
32327
|
-
if (
|
|
32652
|
+
if (existsSync19(LOCKFILE_PATH)) {
|
|
32328
32653
|
try {
|
|
32329
32654
|
const raw = await readFile18(LOCKFILE_PATH, "utf-8");
|
|
32330
32655
|
const parsed = parseYaml9(raw, { maxAliasCount: 100 });
|
|
@@ -32393,7 +32718,7 @@ async function lockCommand(options) {
|
|
|
32393
32718
|
|
|
32394
32719
|
// packages/cli/src/commands/update.ts
|
|
32395
32720
|
import { writeFile as writeFile9, readFile as readFile19 } from "fs/promises";
|
|
32396
|
-
import { existsSync as
|
|
32721
|
+
import { existsSync as existsSync20 } from "fs";
|
|
32397
32722
|
import { parse as parseYaml10, stringify as stringifyYaml3 } from "yaml";
|
|
32398
32723
|
init_console();
|
|
32399
32724
|
init_src();
|
|
@@ -32416,7 +32741,7 @@ async function updateCommand(packageArg, options) {
|
|
|
32416
32741
|
return;
|
|
32417
32742
|
}
|
|
32418
32743
|
let existing = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
32419
|
-
if (
|
|
32744
|
+
if (existsSync20(LOCKFILE_PATH)) {
|
|
32420
32745
|
try {
|
|
32421
32746
|
const raw = await readFile19(LOCKFILE_PATH, "utf-8");
|
|
32422
32747
|
const parsed = parseYaml10(raw, { maxAliasCount: 100 });
|
|
@@ -32480,12 +32805,12 @@ async function updateCommand(packageArg, options) {
|
|
|
32480
32805
|
init_console();
|
|
32481
32806
|
init_src();
|
|
32482
32807
|
import { readFile as readFile20, writeFile as writeFile10, mkdir as mkdir8, readdir as readdir5 } from "fs/promises";
|
|
32483
|
-
import { existsSync as
|
|
32484
|
-
import { join as
|
|
32808
|
+
import { existsSync as existsSync21 } from "fs";
|
|
32809
|
+
import { join as join18, resolve as resolve17 } from "path";
|
|
32485
32810
|
import { homedir as homedir4 } from "os";
|
|
32486
32811
|
import { parse as parseYaml11 } from "yaml";
|
|
32487
32812
|
var VENDOR_DIR = ".promptscript/vendor";
|
|
32488
|
-
var CACHE_BASE =
|
|
32813
|
+
var CACHE_BASE = join18(homedir4(), ".promptscript", "cache", "registries");
|
|
32489
32814
|
async function vendorSyncCommand(options) {
|
|
32490
32815
|
const spinner = createSpinner("Syncing vendor directory...").start();
|
|
32491
32816
|
try {
|
|
@@ -32503,13 +32828,13 @@ async function vendorSyncCommand(options) {
|
|
|
32503
32828
|
}
|
|
32504
32829
|
const results = [];
|
|
32505
32830
|
for (const [repoUrl, dep] of deps) {
|
|
32506
|
-
const cacheDir =
|
|
32507
|
-
if (!
|
|
32831
|
+
const cacheDir = join18(CACHE_BASE, repoUrl.replace(/[/:]/g, "_"), dep.version);
|
|
32832
|
+
if (!existsSync21(cacheDir)) {
|
|
32508
32833
|
results.push({ repoUrl, status: "missing" });
|
|
32509
32834
|
continue;
|
|
32510
32835
|
}
|
|
32511
32836
|
if (!options.dryRun) {
|
|
32512
|
-
const vendorTarget =
|
|
32837
|
+
const vendorTarget = resolve17(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32513
32838
|
await mkdir8(vendorTarget, { recursive: true });
|
|
32514
32839
|
await copyDirectory(cacheDir, vendorTarget);
|
|
32515
32840
|
}
|
|
@@ -32555,7 +32880,7 @@ async function vendorCheckCommand(_options) {
|
|
|
32555
32880
|
spinner.warn("No dependencies in lockfile");
|
|
32556
32881
|
return;
|
|
32557
32882
|
}
|
|
32558
|
-
if (!
|
|
32883
|
+
if (!existsSync21(VENDOR_DIR)) {
|
|
32559
32884
|
spinner.fail("Vendor directory does not exist");
|
|
32560
32885
|
ConsoleOutput.muted("Run: prs vendor sync");
|
|
32561
32886
|
process.exitCode = 1;
|
|
@@ -32563,8 +32888,8 @@ async function vendorCheckCommand(_options) {
|
|
|
32563
32888
|
}
|
|
32564
32889
|
const issues = [];
|
|
32565
32890
|
for (const [repoUrl] of deps) {
|
|
32566
|
-
const vendorTarget =
|
|
32567
|
-
if (!
|
|
32891
|
+
const vendorTarget = resolve17(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32892
|
+
if (!existsSync21(vendorTarget)) {
|
|
32568
32893
|
issues.push({ repoUrl, issue: "missing from vendor directory" });
|
|
32569
32894
|
}
|
|
32570
32895
|
}
|
|
@@ -32587,7 +32912,7 @@ async function vendorCheckCommand(_options) {
|
|
|
32587
32912
|
}
|
|
32588
32913
|
}
|
|
32589
32914
|
async function loadLockfile() {
|
|
32590
|
-
if (!
|
|
32915
|
+
if (!existsSync21(LOCKFILE_PATH)) {
|
|
32591
32916
|
return null;
|
|
32592
32917
|
}
|
|
32593
32918
|
try {
|
|
@@ -32601,8 +32926,8 @@ async function loadLockfile() {
|
|
|
32601
32926
|
async function copyDirectory(src, dest) {
|
|
32602
32927
|
const entries = await readdir5(src, { withFileTypes: true });
|
|
32603
32928
|
for (const entry of entries) {
|
|
32604
|
-
const srcPath =
|
|
32605
|
-
const destPath =
|
|
32929
|
+
const srcPath = join18(src, entry.name);
|
|
32930
|
+
const destPath = join18(dest, entry.name);
|
|
32606
32931
|
if (entry.isDirectory()) {
|
|
32607
32932
|
await mkdir8(destPath, { recursive: true });
|
|
32608
32933
|
await copyDirectory(srcPath, destPath);
|
|
@@ -32614,12 +32939,12 @@ async function copyDirectory(src, dest) {
|
|
|
32614
32939
|
}
|
|
32615
32940
|
|
|
32616
32941
|
// packages/cli/src/commands/resolve-cmd.ts
|
|
32617
|
-
import { existsSync as
|
|
32618
|
-
import { join as
|
|
32942
|
+
import { existsSync as existsSync22 } from "fs";
|
|
32943
|
+
import { join as join19 } from "path";
|
|
32619
32944
|
import { homedir as homedir5 } from "os";
|
|
32620
32945
|
init_user_config();
|
|
32621
32946
|
init_console();
|
|
32622
|
-
var CACHE_BASE2 =
|
|
32947
|
+
var CACHE_BASE2 = join19(homedir5(), ".promptscript", "cache", "registries");
|
|
32623
32948
|
async function resolveCommand(importPath, _options) {
|
|
32624
32949
|
try {
|
|
32625
32950
|
const configFile = findConfigFile();
|
|
@@ -32661,11 +32986,11 @@ async function resolveCommand(importPath, _options) {
|
|
|
32661
32986
|
}
|
|
32662
32987
|
const { repoUrl, path, version } = expanded;
|
|
32663
32988
|
const cacheVersion = version ?? "latest";
|
|
32664
|
-
const cacheDir =
|
|
32665
|
-
const cacheExists =
|
|
32989
|
+
const cacheDir = join19(CACHE_BASE2, repoUrl.replace(/[/:]/g, "_"), cacheVersion);
|
|
32990
|
+
const cacheExists = existsSync22(cacheDir);
|
|
32666
32991
|
const filePath = path.endsWith(".prs") ? path : `${path}.prs`;
|
|
32667
|
-
const cachedFile =
|
|
32668
|
-
const fileExists3 = cacheExists &&
|
|
32992
|
+
const cachedFile = join19(cacheDir, filePath);
|
|
32993
|
+
const fileExists3 = cacheExists && existsSync22(cachedFile);
|
|
32669
32994
|
ConsoleOutput.newline();
|
|
32670
32995
|
console.log(` Alias: ${aliasName} \u2192 ${repoUrl}`);
|
|
32671
32996
|
console.log(` Repo: ${repoUrl}`);
|
|
@@ -32682,7 +33007,7 @@ async function resolveCommand(importPath, _options) {
|
|
|
32682
33007
|
ConsoleOutput.newline();
|
|
32683
33008
|
} else {
|
|
32684
33009
|
const resolvedPath = importPath.endsWith(".prs") ? importPath : `${importPath}.prs`;
|
|
32685
|
-
const exists =
|
|
33010
|
+
const exists = existsSync22(resolvedPath);
|
|
32686
33011
|
ConsoleOutput.newline();
|
|
32687
33012
|
console.log(` Import: ${importPath}`);
|
|
32688
33013
|
console.log(` Type: local file`);
|
|
@@ -32699,8 +33024,8 @@ async function resolveCommand(importPath, _options) {
|
|
|
32699
33024
|
}
|
|
32700
33025
|
|
|
32701
33026
|
// packages/cli/src/commands/inspect.ts
|
|
32702
|
-
import { existsSync as
|
|
32703
|
-
import { resolve as
|
|
33027
|
+
import { existsSync as existsSync23 } from "fs";
|
|
33028
|
+
import { resolve as resolve18, basename as basename13 } from "path";
|
|
32704
33029
|
init_console();
|
|
32705
33030
|
async function inspectCommand(skillName, options) {
|
|
32706
33031
|
const isJson = options.format === "json";
|
|
@@ -32713,8 +33038,8 @@ async function inspectCommand(skillName, options) {
|
|
|
32713
33038
|
localPath: "./.promptscript",
|
|
32714
33039
|
registries: config.registries
|
|
32715
33040
|
});
|
|
32716
|
-
const entryPath =
|
|
32717
|
-
if (!
|
|
33041
|
+
const entryPath = resolve18("./.promptscript/project.prs");
|
|
33042
|
+
if (!existsSync23(entryPath)) {
|
|
32718
33043
|
spinner.stop();
|
|
32719
33044
|
ConsoleOutput.error(`Entry file not found: ${entryPath}`);
|
|
32720
33045
|
process.exitCode = 1;
|
|
@@ -32786,7 +33111,7 @@ function summarizeValue(val) {
|
|
|
32786
33111
|
return String(val);
|
|
32787
33112
|
}
|
|
32788
33113
|
function shortPath(source) {
|
|
32789
|
-
return
|
|
33114
|
+
return basename13(source);
|
|
32790
33115
|
}
|
|
32791
33116
|
function getPropertySource(propName, trace, baseSource) {
|
|
32792
33117
|
for (let i = trace.length - 1; i >= 0; i--) {
|
|
@@ -32894,8 +33219,8 @@ init_console();
|
|
|
32894
33219
|
// packages/cli/src/commands/import.ts
|
|
32895
33220
|
init_src3();
|
|
32896
33221
|
init_console();
|
|
32897
|
-
import { resolve as
|
|
32898
|
-
import { writeFileSync as writeFileSync2, mkdirSync, existsSync as
|
|
33222
|
+
import { resolve as resolve19, join as join20, basename as basename14 } from "path";
|
|
33223
|
+
import { writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync24 } from "fs";
|
|
32899
33224
|
import { stat as stat2, readdir as readdir6, readFile as readFile21, writeFile as writeFile11, mkdir as mkdir9 } from "fs/promises";
|
|
32900
33225
|
function parseInstructionFrontmatter(content) {
|
|
32901
33226
|
const match = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/.exec(content);
|
|
@@ -32923,10 +33248,10 @@ async function importDirectory(dirPath) {
|
|
|
32923
33248
|
}
|
|
32924
33249
|
const lines = ["@meta {", ' version: "1.0"', "}", "", "@guards {"];
|
|
32925
33250
|
for (const filename of instructionFiles) {
|
|
32926
|
-
const filePath =
|
|
33251
|
+
const filePath = join20(dirPath, filename);
|
|
32927
33252
|
const content = await readFile21(filePath, "utf-8");
|
|
32928
33253
|
const frontmatter = parseInstructionFrontmatter(content);
|
|
32929
|
-
const entryName =
|
|
33254
|
+
const entryName = basename14(filename).replace(/\.instructions\.md$/i, "");
|
|
32930
33255
|
if (frontmatter) {
|
|
32931
33256
|
const globPatterns = frontmatter.applyTo.map((p) => `"${p}"`).join(", ");
|
|
32932
33257
|
lines.push(` ${entryName}(${globPatterns}) {`);
|
|
@@ -32949,7 +33274,7 @@ async function importDirectory(dirPath) {
|
|
|
32949
33274
|
return lines.join("\n");
|
|
32950
33275
|
}
|
|
32951
33276
|
async function importCommand(file, options) {
|
|
32952
|
-
const filepath =
|
|
33277
|
+
const filepath = resolve19(file);
|
|
32953
33278
|
const inputStat = await stat2(filepath).catch(() => null);
|
|
32954
33279
|
if (inputStat?.isDirectory()) {
|
|
32955
33280
|
const prsContent = await importDirectory(filepath);
|
|
@@ -32959,7 +33284,7 @@ async function importCommand(file, options) {
|
|
|
32959
33284
|
}
|
|
32960
33285
|
const outputDir = options.output ?? ".promptscript";
|
|
32961
33286
|
await mkdir9(outputDir, { recursive: true });
|
|
32962
|
-
const outputPath =
|
|
33287
|
+
const outputPath = join20(outputDir, "imported.prs");
|
|
32963
33288
|
await writeFile11(outputPath, prsContent);
|
|
32964
33289
|
console.log(`\u2714 Imported directory to ${outputPath}`);
|
|
32965
33290
|
return;
|
|
@@ -32981,11 +33306,11 @@ async function importCommand(file, options) {
|
|
|
32981
33306
|
console.log(result.prsContent);
|
|
32982
33307
|
return;
|
|
32983
33308
|
}
|
|
32984
|
-
const outputDir =
|
|
32985
|
-
if (!
|
|
33309
|
+
const outputDir = resolve19(options.output ?? ".promptscript");
|
|
33310
|
+
if (!existsSync24(outputDir)) {
|
|
32986
33311
|
mkdirSync(outputDir, { recursive: true });
|
|
32987
33312
|
}
|
|
32988
|
-
const outputPath =
|
|
33313
|
+
const outputPath = resolve19(outputDir, "imported.prs");
|
|
32989
33314
|
writeFileSync2(outputPath, result.prsContent, "utf-8");
|
|
32990
33315
|
ConsoleOutput.success(`Written to ${outputPath}`);
|
|
32991
33316
|
if (options.validate) {
|
|
@@ -33100,18 +33425,18 @@ async function detectMarker(filePath) {
|
|
|
33100
33425
|
}
|
|
33101
33426
|
|
|
33102
33427
|
// packages/cli/src/hooks/debounce-lock.ts
|
|
33103
|
-
import { createHash as
|
|
33104
|
-
import { existsSync as
|
|
33428
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
33429
|
+
import { existsSync as existsSync25, writeFileSync as writeFileSync4, unlinkSync, statSync } from "node:fs";
|
|
33105
33430
|
import { tmpdir } from "node:os";
|
|
33106
|
-
import { join as
|
|
33431
|
+
import { join as join21 } from "node:path";
|
|
33107
33432
|
var STALE_THRESHOLD_MS = 3e4;
|
|
33108
33433
|
function getLockPath(projectDir) {
|
|
33109
|
-
const hash =
|
|
33110
|
-
return
|
|
33434
|
+
const hash = createHash3("md5").update(projectDir).digest("hex").slice(0, 12);
|
|
33435
|
+
return join21(tmpdir(), `prs-compile-${hash}.lock`);
|
|
33111
33436
|
}
|
|
33112
33437
|
function acquireLock(projectDir) {
|
|
33113
33438
|
const lockPath = getLockPath(projectDir);
|
|
33114
|
-
if (
|
|
33439
|
+
if (existsSync25(lockPath)) {
|
|
33115
33440
|
try {
|
|
33116
33441
|
const stat4 = statSync(lockPath);
|
|
33117
33442
|
const age = Date.now() - stat4.mtimeMs;
|
|
@@ -33219,9 +33544,10 @@ Usage: echo '{"file_path":"..."}' | prs hook ${action}
|
|
|
33219
33544
|
init_hooks();
|
|
33220
33545
|
|
|
33221
33546
|
// packages/cli/src/commands/skills.ts
|
|
33222
|
-
import { writeFile as writeFile12, readFile as readFile23, readdir as readdir7 } from "fs/promises";
|
|
33223
|
-
import { resolve as
|
|
33224
|
-
import { existsSync as
|
|
33547
|
+
import { writeFile as writeFile12, readFile as readFile23, readdir as readdir7, mkdtemp, rm } from "fs/promises";
|
|
33548
|
+
import { resolve as resolve20, join as join22, basename as basename15, dirname as dirname13 } from "path";
|
|
33549
|
+
import { existsSync as existsSync26 } from "fs";
|
|
33550
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
33225
33551
|
import { parse as parseYaml12, stringify as stringifyYaml4 } from "yaml";
|
|
33226
33552
|
init_console();
|
|
33227
33553
|
init_src();
|
|
@@ -33241,6 +33567,77 @@ function normalizeSkillSource(input2) {
|
|
|
33241
33567
|
}
|
|
33242
33568
|
return source;
|
|
33243
33569
|
}
|
|
33570
|
+
function extractSubPath(source) {
|
|
33571
|
+
const parts = source.replace(/^https?:\/\//, "").split("/");
|
|
33572
|
+
return parts.length > 3 ? parts.slice(3).join("/") : "";
|
|
33573
|
+
}
|
|
33574
|
+
function deriveSkillFolderName(source) {
|
|
33575
|
+
const subPath = extractSubPath(source);
|
|
33576
|
+
if (!subPath) return void 0;
|
|
33577
|
+
if (!subPath.toLowerCase().endsWith(".md")) return void 0;
|
|
33578
|
+
const parent = dirname13(subPath);
|
|
33579
|
+
if (parent === "." || parent === "") return void 0;
|
|
33580
|
+
return basename15(parent);
|
|
33581
|
+
}
|
|
33582
|
+
function collectExistingSkillNames(lockfile, exclude) {
|
|
33583
|
+
const names = /* @__PURE__ */ new Set();
|
|
33584
|
+
for (const [key, dep] of Object.entries(lockfile.dependencies)) {
|
|
33585
|
+
if (dep.source !== "md") continue;
|
|
33586
|
+
if (exclude && key === exclude) continue;
|
|
33587
|
+
const name = deriveSkillFolderName(key);
|
|
33588
|
+
if (name) names.add(name);
|
|
33589
|
+
}
|
|
33590
|
+
return names;
|
|
33591
|
+
}
|
|
33592
|
+
async function fetchAndValidateRemoteSkill(source, options) {
|
|
33593
|
+
const subPath = extractSubPath(source);
|
|
33594
|
+
if (!subPath || !subPath.toLowerCase().endsWith(".md")) {
|
|
33595
|
+
return void 0;
|
|
33596
|
+
}
|
|
33597
|
+
const repoUrl = extractRepoUrl(source);
|
|
33598
|
+
const tmp = await mkdtemp(join22(tmpdir2(), "prs-skill-validate-"));
|
|
33599
|
+
try {
|
|
33600
|
+
const gitRegistry = createGitRegistry({ url: repoUrl });
|
|
33601
|
+
await gitRegistry.cloneAtTag(repoUrl, options.version, tmp);
|
|
33602
|
+
const filePath = join22(tmp, subPath);
|
|
33603
|
+
if (!existsSync26(filePath)) {
|
|
33604
|
+
return {
|
|
33605
|
+
content: "",
|
|
33606
|
+
integrity: "",
|
|
33607
|
+
valid: false,
|
|
33608
|
+
issues: [
|
|
33609
|
+
{
|
|
33610
|
+
severity: "error",
|
|
33611
|
+
code: "SK000",
|
|
33612
|
+
message: `File '${subPath}' does not exist in ${repoUrl} at ${options.version}.`
|
|
33613
|
+
}
|
|
33614
|
+
]
|
|
33615
|
+
};
|
|
33616
|
+
}
|
|
33617
|
+
const content = await readFile23(filePath, "utf-8");
|
|
33618
|
+
const integrity = hashContent(Buffer.from(content, "utf-8"));
|
|
33619
|
+
const result = validateSkillFrontmatter(content, {
|
|
33620
|
+
filePath,
|
|
33621
|
+
existingNames: options.existingNames
|
|
33622
|
+
});
|
|
33623
|
+
return { content, integrity, valid: result.valid, issues: result.issues };
|
|
33624
|
+
} finally {
|
|
33625
|
+
await rm(tmp, { recursive: true, force: true }).catch(() => {
|
|
33626
|
+
});
|
|
33627
|
+
}
|
|
33628
|
+
}
|
|
33629
|
+
function printValidationIssues(issues) {
|
|
33630
|
+
if (issues.length === 0) return;
|
|
33631
|
+
ConsoleOutput.newline();
|
|
33632
|
+
const formatted = formatSkillValidationIssues(issues);
|
|
33633
|
+
for (const line of formatted.split("\n")) {
|
|
33634
|
+
if (line.includes("\u2717")) {
|
|
33635
|
+
ConsoleOutput.error(line);
|
|
33636
|
+
} else {
|
|
33637
|
+
ConsoleOutput.warn(line);
|
|
33638
|
+
}
|
|
33639
|
+
}
|
|
33640
|
+
}
|
|
33244
33641
|
var HEADER_DIRECTIVES = ["@use ", "@inherit ", "@meta "];
|
|
33245
33642
|
function extractRepoUrl(source) {
|
|
33246
33643
|
const parts = source.replace(/^https?:\/\//, "").split("/");
|
|
@@ -33268,8 +33665,8 @@ function validateRemoteSource(source) {
|
|
|
33268
33665
|
}
|
|
33269
33666
|
async function resolveEntryFile(fileFlag) {
|
|
33270
33667
|
if (fileFlag) {
|
|
33271
|
-
const resolved =
|
|
33272
|
-
if (!
|
|
33668
|
+
const resolved = resolve20(fileFlag);
|
|
33669
|
+
if (!existsSync26(resolved)) {
|
|
33273
33670
|
throw new Error(`File not found: ${resolved}`);
|
|
33274
33671
|
}
|
|
33275
33672
|
return resolved;
|
|
@@ -33279,24 +33676,24 @@ async function resolveEntryFile(fileFlag) {
|
|
|
33279
33676
|
try {
|
|
33280
33677
|
const config = await loadConfig();
|
|
33281
33678
|
if (config.input?.entry) {
|
|
33282
|
-
const entryPath =
|
|
33283
|
-
if (
|
|
33679
|
+
const entryPath = resolve20(config.input.entry);
|
|
33680
|
+
if (existsSync26(entryPath)) {
|
|
33284
33681
|
return entryPath;
|
|
33285
33682
|
}
|
|
33286
33683
|
}
|
|
33287
33684
|
} catch {
|
|
33288
33685
|
}
|
|
33289
33686
|
}
|
|
33290
|
-
const promptscriptDir =
|
|
33291
|
-
if (
|
|
33687
|
+
const promptscriptDir = resolve20(".promptscript");
|
|
33688
|
+
if (existsSync26(promptscriptDir)) {
|
|
33292
33689
|
const entries = await readdir7(promptscriptDir);
|
|
33293
33690
|
const prsFiles = entries.filter((f) => f.endsWith(".prs"));
|
|
33294
33691
|
if (prsFiles.length === 1) {
|
|
33295
|
-
return
|
|
33692
|
+
return resolve20(promptscriptDir, prsFiles[0]);
|
|
33296
33693
|
}
|
|
33297
33694
|
if (prsFiles.length > 1) {
|
|
33298
33695
|
if (prsFiles.includes("project.prs")) {
|
|
33299
|
-
return
|
|
33696
|
+
return resolve20(promptscriptDir, "project.prs");
|
|
33300
33697
|
}
|
|
33301
33698
|
throw new Error(
|
|
33302
33699
|
`Multiple .prs files found in .promptscript/. Use --file to specify which one.`
|
|
@@ -33340,7 +33737,7 @@ function extractUsePath(line) {
|
|
|
33340
33737
|
}
|
|
33341
33738
|
async function loadLockfile2() {
|
|
33342
33739
|
const defaultLockfile = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
33343
|
-
if (!
|
|
33740
|
+
if (!existsSync26(LOCKFILE_PATH)) {
|
|
33344
33741
|
return defaultLockfile;
|
|
33345
33742
|
}
|
|
33346
33743
|
try {
|
|
@@ -33359,6 +33756,14 @@ async function saveLockfile(lockfile) {
|
|
|
33359
33756
|
async function skillsAddCommand(rawSource, options) {
|
|
33360
33757
|
const spinner = createSpinner("Adding skill...").start();
|
|
33361
33758
|
try {
|
|
33759
|
+
if (/^http:\/\//i.test(rawSource.trim())) {
|
|
33760
|
+
spinner.fail("Plain HTTP sources are not allowed (security)");
|
|
33761
|
+
ConsoleOutput.error(
|
|
33762
|
+
"Use https:// or git@host:owner/repo. Cleartext git transport is rejected to prevent man-in-the-middle attacks."
|
|
33763
|
+
);
|
|
33764
|
+
process.exitCode = 1;
|
|
33765
|
+
return;
|
|
33766
|
+
}
|
|
33362
33767
|
const source = normalizeSkillSource(rawSource);
|
|
33363
33768
|
const sourceError = validateRemoteSource(source);
|
|
33364
33769
|
if (sourceError) {
|
|
@@ -33387,15 +33792,52 @@ async function skillsAddCommand(rawSource, options) {
|
|
|
33387
33792
|
process.exitCode = 1;
|
|
33388
33793
|
return;
|
|
33389
33794
|
}
|
|
33795
|
+
const lockfile = await loadLockfile2();
|
|
33796
|
+
let integrity = "sha256-pending";
|
|
33797
|
+
let validationFailed = false;
|
|
33798
|
+
if (!options.skipValidation) {
|
|
33799
|
+
spinner.text = "Validating SKILL.md frontmatter...";
|
|
33800
|
+
try {
|
|
33801
|
+
const fetched = await fetchAndValidateRemoteSkill(source, {
|
|
33802
|
+
existingNames: collectExistingSkillNames(lockfile),
|
|
33803
|
+
version: "main"
|
|
33804
|
+
});
|
|
33805
|
+
if (fetched) {
|
|
33806
|
+
integrity = fetched.integrity || integrity;
|
|
33807
|
+
const hasErrors = !fetched.valid;
|
|
33808
|
+
const hasWarnings = fetched.issues.some((i) => i.severity === "warning");
|
|
33809
|
+
if (hasErrors || options.strict && hasWarnings) {
|
|
33810
|
+
spinner.fail("SKILL.md failed validation");
|
|
33811
|
+
printValidationIssues(fetched.issues);
|
|
33812
|
+
ConsoleOutput.newline();
|
|
33813
|
+
ConsoleOutput.muted(
|
|
33814
|
+
"Re-run with --skip-validation to bypass (not recommended) or fix the upstream SKILL.md."
|
|
33815
|
+
);
|
|
33816
|
+
process.exitCode = 1;
|
|
33817
|
+
validationFailed = true;
|
|
33818
|
+
} else if (fetched.issues.length > 0) {
|
|
33819
|
+
spinner.warn("SKILL.md has validation warnings");
|
|
33820
|
+
printValidationIssues(fetched.issues);
|
|
33821
|
+
spinner.start("Adding skill...");
|
|
33822
|
+
}
|
|
33823
|
+
}
|
|
33824
|
+
} catch (err) {
|
|
33825
|
+
spinner.warn("Could not validate SKILL.md ahead of time");
|
|
33826
|
+
ConsoleOutput.muted(
|
|
33827
|
+
`Reason: ${err instanceof Error ? err.message : String(err)}. Proceeding without frontmatter check.`
|
|
33828
|
+
);
|
|
33829
|
+
spinner.start("Adding skill...");
|
|
33830
|
+
}
|
|
33831
|
+
}
|
|
33832
|
+
if (validationFailed) return;
|
|
33390
33833
|
const insertionPoint = findInsertionPoint(lines);
|
|
33391
33834
|
const newLine = `@use ${source}`;
|
|
33392
33835
|
lines.splice(insertionPoint, 0, newLine);
|
|
33393
33836
|
const updatedContent = lines.join("\n");
|
|
33394
|
-
const lockfile = await loadLockfile2();
|
|
33395
33837
|
const lockEntry = {
|
|
33396
33838
|
version: "latest",
|
|
33397
33839
|
commit: validation.headCommit ?? "0000000000000000000000000000000000000000",
|
|
33398
|
-
integrity
|
|
33840
|
+
integrity,
|
|
33399
33841
|
source: "md"
|
|
33400
33842
|
};
|
|
33401
33843
|
lockfile.dependencies[source] = lockEntry;
|
|
@@ -33523,10 +33965,39 @@ async function skillsUpdateCommand(name, options) {
|
|
|
33523
33965
|
});
|
|
33524
33966
|
continue;
|
|
33525
33967
|
}
|
|
33968
|
+
let integrity = dep.integrity ?? "sha256-pending";
|
|
33969
|
+
if (!options.skipValidation) {
|
|
33970
|
+
try {
|
|
33971
|
+
const fetched = await fetchAndValidateRemoteSkill(key, {
|
|
33972
|
+
existingNames: collectExistingSkillNames(lockfile, key),
|
|
33973
|
+
version: dep.version === "latest" ? "main" : dep.version
|
|
33974
|
+
});
|
|
33975
|
+
if (fetched) {
|
|
33976
|
+
integrity = fetched.integrity || integrity;
|
|
33977
|
+
const hasErrors = !fetched.valid;
|
|
33978
|
+
const hasWarnings = fetched.issues.some((i) => i.severity === "warning");
|
|
33979
|
+
if (hasErrors || options.strict && hasWarnings) {
|
|
33980
|
+
skipped.push({
|
|
33981
|
+
key,
|
|
33982
|
+
reason: "SKILL.md failed validation after update"
|
|
33983
|
+
});
|
|
33984
|
+
printValidationIssues(fetched.issues);
|
|
33985
|
+
continue;
|
|
33986
|
+
} else if (hasWarnings) {
|
|
33987
|
+
ConsoleOutput.warn(`${key}: validation warnings`);
|
|
33988
|
+
printValidationIssues(fetched.issues);
|
|
33989
|
+
}
|
|
33990
|
+
}
|
|
33991
|
+
} catch (err) {
|
|
33992
|
+
ConsoleOutput.warn(
|
|
33993
|
+
`${key}: could not re-validate (${err instanceof Error ? err.message : String(err)})`
|
|
33994
|
+
);
|
|
33995
|
+
}
|
|
33996
|
+
}
|
|
33526
33997
|
lockfile.dependencies[key] = {
|
|
33527
33998
|
version: dep.version ?? "latest",
|
|
33528
33999
|
commit: validation.headCommit,
|
|
33529
|
-
integrity
|
|
34000
|
+
integrity,
|
|
33530
34001
|
source: "md",
|
|
33531
34002
|
fetchedAt
|
|
33532
34003
|
};
|
|
@@ -33573,7 +34044,7 @@ async function skillsUpdateCommand(name, options) {
|
|
|
33573
34044
|
|
|
33574
34045
|
// packages/cli/src/cli.ts
|
|
33575
34046
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
33576
|
-
var __dirname4 =
|
|
34047
|
+
var __dirname4 = dirname16(__filename4);
|
|
33577
34048
|
var program = new Command();
|
|
33578
34049
|
program.name("prs").description("PromptScript CLI - Standardize AI instructions").version(getPackageVersion(__dirname3, "./package.json")).option("--verbose", "Enable verbose output").option("--debug", "Enable debug output (includes verbose)").option("--quiet", "Suppress non-error output").hook("preAction", async (thisCommand, actionCommand) => {
|
|
33579
34050
|
const opts = thisCommand.opts();
|
|
@@ -33632,10 +34103,10 @@ program.command("resolve <import>").description("Show full resolution chain for
|
|
|
33632
34103
|
program.command("hook").argument("<action>", "Hook action: pre-edit or post-edit").description("Hook handler invoked by AI tools (not for direct use)").action(hookCommand);
|
|
33633
34104
|
program.command("hooks").argument("<action>", "Action: install or uninstall").argument("[tool]", "Tool: claude, gemini, copilot, cursor, windsurf, factory, cline").option("--all", "Install/uninstall for all detected tools").description("Manage PromptScript hooks for AI tools").action(hooksCommand);
|
|
33634
34105
|
var skills = program.command("skills").description("Manage PromptScript skills");
|
|
33635
|
-
skills.command("add <source>").description("Add a remote skill to the project").option("-f, --file <file>", "Target .prs file to modify").option("--dry-run", "Preview changes without writing").action((source, opts) => skillsAddCommand(source, opts));
|
|
34106
|
+
skills.command("add <source>").description("Add a remote skill to the project").option("-f, --file <file>", "Target .prs file to modify").option("--dry-run", "Preview changes without writing").option("--skip-validation", "Skip SKILL.md frontmatter validation (not recommended)").option("--strict", "Treat validation warnings as errors").action((source, opts) => skillsAddCommand(source, opts));
|
|
33636
34107
|
skills.command("remove <name>").description("Remove a skill from the project").option("--dry-run", "Preview changes without writing").action((name, opts) => skillsRemoveCommand(name, opts));
|
|
33637
34108
|
skills.command("list").description("List skills imported in the current project").action(() => skillsListCommand());
|
|
33638
|
-
skills.command("update [name]").description("Update lock entries for markdown-sourced skills").option("--dry-run", "Preview changes without writing").action((name, opts) => skillsUpdateCommand(name, opts));
|
|
34109
|
+
skills.command("update [name]").description("Update lock entries for markdown-sourced skills").option("--dry-run", "Preview changes without writing").option("--skip-validation", "Skip SKILL.md frontmatter validation (not recommended)").option("--strict", "Treat validation warnings as errors").action((name, opts) => skillsUpdateCommand(name, opts));
|
|
33639
34110
|
var registry = program.command("registry").description("Manage PromptScript registries");
|
|
33640
34111
|
registerRegistryCommands(registry);
|
|
33641
34112
|
function run(args = process.argv) {
|