@promptscript/cli 1.12.0 → 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 +740 -211
- package/package.json +3 -2
- package/skills/promptscript/SKILL.md +170 -3
- 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
|
*/
|
|
@@ -15878,7 +15886,7 @@ var init_factory = __esm({
|
|
|
15878
15886
|
outputPath: "AGENTS.md"
|
|
15879
15887
|
}
|
|
15880
15888
|
};
|
|
15881
|
-
FactoryFormatter = class extends MarkdownInstructionFormatter {
|
|
15889
|
+
FactoryFormatter = class _FactoryFormatter extends MarkdownInstructionFormatter {
|
|
15882
15890
|
constructor() {
|
|
15883
15891
|
super({
|
|
15884
15892
|
name: "factory",
|
|
@@ -16022,7 +16030,7 @@ var init_factory = __esm({
|
|
|
16022
16030
|
const skillName = factoryConfig2.name.replace(/\./g, "-");
|
|
16023
16031
|
lines.push("---");
|
|
16024
16032
|
if (factoryConfig2.rawFrontmatter) {
|
|
16025
|
-
lines.push(factoryConfig2.rawFrontmatter);
|
|
16033
|
+
lines.push(...this.filterFactoryFrontmatter(factoryConfig2.rawFrontmatter));
|
|
16026
16034
|
} else {
|
|
16027
16035
|
lines.push(`name: ${skillName}`);
|
|
16028
16036
|
lines.push(`description: ${this.yamlString(factoryConfig2.description)}`);
|
|
@@ -16307,6 +16315,82 @@ ${lines.join("\n")}
|
|
|
16307
16315
|
}
|
|
16308
16316
|
return handoffs;
|
|
16309
16317
|
}
|
|
16318
|
+
// ============================================================
|
|
16319
|
+
// Frontmatter Filtering (Factory-specific)
|
|
16320
|
+
// ============================================================
|
|
16321
|
+
/**
|
|
16322
|
+
* Factory AI supported frontmatter fields for skills.
|
|
16323
|
+
* Fields not in this set are stripped to avoid parsing failures.
|
|
16324
|
+
*
|
|
16325
|
+
* @see https://docs.factory.ai/cli/configuration/skills
|
|
16326
|
+
*/
|
|
16327
|
+
static FACTORY_SKILL_FRONTMATTER_FIELDS = /* @__PURE__ */ new Set([
|
|
16328
|
+
"name",
|
|
16329
|
+
"description",
|
|
16330
|
+
"user-invocable",
|
|
16331
|
+
"disable-model-invocation"
|
|
16332
|
+
]);
|
|
16333
|
+
/**
|
|
16334
|
+
* Filter raw YAML frontmatter to only include fields that Factory AI
|
|
16335
|
+
* recognizes in skill SKILL.md files. Strips unsupported fields like
|
|
16336
|
+
* `license`, `metadata`, `compatibility`, `allowed-tools`, and comments,
|
|
16337
|
+
* which cause Factory to fail to load the skill.
|
|
16338
|
+
*
|
|
16339
|
+
* @param rawFrontmatter - Raw YAML frontmatter string (between --- markers)
|
|
16340
|
+
* @returns Array of filtered frontmatter lines
|
|
16341
|
+
*/
|
|
16342
|
+
filterFactoryFrontmatter(rawFrontmatter) {
|
|
16343
|
+
const lines = rawFrontmatter.split("\n");
|
|
16344
|
+
const filtered = [];
|
|
16345
|
+
let skipBlock = false;
|
|
16346
|
+
let blockIndent = -1;
|
|
16347
|
+
for (const line of lines) {
|
|
16348
|
+
const trimmed = line.trim();
|
|
16349
|
+
if (trimmed.startsWith("#")) continue;
|
|
16350
|
+
if (skipBlock) {
|
|
16351
|
+
if (trimmed === "") {
|
|
16352
|
+
skipBlock = false;
|
|
16353
|
+
blockIndent = -1;
|
|
16354
|
+
continue;
|
|
16355
|
+
}
|
|
16356
|
+
const currentIndent = line.length - line.trimStart().length;
|
|
16357
|
+
if (currentIndent > blockIndent) continue;
|
|
16358
|
+
skipBlock = false;
|
|
16359
|
+
blockIndent = -1;
|
|
16360
|
+
}
|
|
16361
|
+
if (trimmed === "") continue;
|
|
16362
|
+
const keyMatch = trimmed.match(/^([a-zA-Z][a-zA-Z0-9_-]*):/);
|
|
16363
|
+
if (keyMatch) {
|
|
16364
|
+
const key = keyMatch[1];
|
|
16365
|
+
const indent = line.length - line.trimStart().length;
|
|
16366
|
+
if (!_FactoryFormatter.FACTORY_SKILL_FRONTMATTER_FIELDS.has(key)) {
|
|
16367
|
+
skipBlock = true;
|
|
16368
|
+
blockIndent = indent;
|
|
16369
|
+
continue;
|
|
16370
|
+
}
|
|
16371
|
+
}
|
|
16372
|
+
filtered.push(line);
|
|
16373
|
+
}
|
|
16374
|
+
return filtered;
|
|
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
|
+
}
|
|
16310
16394
|
};
|
|
16311
16395
|
}
|
|
16312
16396
|
});
|
|
@@ -20789,9 +20873,9 @@ var require_rate_limit = __commonJS({
|
|
|
20789
20873
|
let ttl = 0;
|
|
20790
20874
|
let ttlInSeconds = 0;
|
|
20791
20875
|
try {
|
|
20792
|
-
const res = await new Promise((
|
|
20876
|
+
const res = await new Promise((resolve22, reject) => {
|
|
20793
20877
|
store.incr(key, (err, res2) => {
|
|
20794
|
-
err ? reject(err) :
|
|
20878
|
+
err ? reject(err) : resolve22(res2);
|
|
20795
20879
|
}, timeWindow, max);
|
|
20796
20880
|
});
|
|
20797
20881
|
current = res.current;
|
|
@@ -20898,12 +20982,12 @@ var init_health = __esm({
|
|
|
20898
20982
|
|
|
20899
20983
|
// packages/server/src/source-dirs.ts
|
|
20900
20984
|
import { readFile as readFile24 } from "fs/promises";
|
|
20901
|
-
import { join as
|
|
20985
|
+
import { join as join23, dirname as dirname14 } from "path";
|
|
20902
20986
|
import { parse as parseYaml13 } from "yaml";
|
|
20903
20987
|
async function readProjectConfig(workspace) {
|
|
20904
20988
|
for (const filename of CONFIG_FILENAMES) {
|
|
20905
20989
|
try {
|
|
20906
|
-
const raw = await readFile24(
|
|
20990
|
+
const raw = await readFile24(join23(workspace, filename), "utf-8");
|
|
20907
20991
|
const config = parseYaml13(raw);
|
|
20908
20992
|
if (config) return config;
|
|
20909
20993
|
} catch {
|
|
@@ -20914,10 +20998,10 @@ async function readProjectConfig(workspace) {
|
|
|
20914
20998
|
async function resolveSourceDir(workspace) {
|
|
20915
20999
|
for (const filename of CONFIG_FILENAMES) {
|
|
20916
21000
|
try {
|
|
20917
|
-
const raw = await readFile24(
|
|
21001
|
+
const raw = await readFile24(join23(workspace, filename), "utf-8");
|
|
20918
21002
|
const config = parseYaml13(raw);
|
|
20919
21003
|
if (config?.input?.entry) {
|
|
20920
|
-
return
|
|
21004
|
+
return dirname14(config.input.entry);
|
|
20921
21005
|
}
|
|
20922
21006
|
} catch {
|
|
20923
21007
|
}
|
|
@@ -20931,9 +21015,9 @@ async function resolveFileGlobs(workspace) {
|
|
|
20931
21015
|
async function resolveWatchPaths(workspace) {
|
|
20932
21016
|
const sourceDir = await resolveSourceDir(workspace);
|
|
20933
21017
|
return [
|
|
20934
|
-
|
|
20935
|
-
|
|
20936
|
-
|
|
21018
|
+
join23(workspace, sourceDir),
|
|
21019
|
+
join23(workspace, "promptscript.yaml"),
|
|
21020
|
+
join23(workspace, "promptscript.yml")
|
|
20937
21021
|
];
|
|
20938
21022
|
}
|
|
20939
21023
|
var DEFAULT_SOURCE_DIR, CONFIG_FILENAMES;
|
|
@@ -20960,13 +21044,13 @@ var init_config2 = __esm({
|
|
|
20960
21044
|
});
|
|
20961
21045
|
|
|
20962
21046
|
// packages/server/src/path-guard.ts
|
|
20963
|
-
import { resolve as
|
|
21047
|
+
import { resolve as resolve21, relative as relative4, isAbsolute as isAbsolute6 } from "path";
|
|
20964
21048
|
function resolveSafePath(workspace, requestedPath) {
|
|
20965
21049
|
const decoded = decodeURIComponent(requestedPath);
|
|
20966
21050
|
if (isAbsolute6(decoded)) {
|
|
20967
21051
|
throw new PathTraversalError(requestedPath);
|
|
20968
21052
|
}
|
|
20969
|
-
const resolved =
|
|
21053
|
+
const resolved = resolve21(workspace, decoded);
|
|
20970
21054
|
const rel = relative4(workspace, resolved);
|
|
20971
21055
|
if (rel.startsWith("..") || isAbsolute6(rel)) {
|
|
20972
21056
|
throw new PathTraversalError(requestedPath);
|
|
@@ -20988,7 +21072,7 @@ var init_path_guard = __esm({
|
|
|
20988
21072
|
|
|
20989
21073
|
// packages/server/src/routes/files.ts
|
|
20990
21074
|
import { readFile as readFile25, writeFile as writeFile13, unlink as unlink2, stat as stat3, mkdir as mkdir10 } from "fs/promises";
|
|
20991
|
-
import { dirname as
|
|
21075
|
+
import { dirname as dirname15 } from "path";
|
|
20992
21076
|
import fg from "fast-glob";
|
|
20993
21077
|
function registerRoutes(app, workspace, readOnly) {
|
|
20994
21078
|
app.get("/api/files", async () => {
|
|
@@ -21048,7 +21132,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21048
21132
|
return reply.status(409).send({ error: "File already exists" });
|
|
21049
21133
|
} catch {
|
|
21050
21134
|
}
|
|
21051
|
-
await mkdir10(
|
|
21135
|
+
await mkdir10(dirname15(resolved), { recursive: true });
|
|
21052
21136
|
await writeFile13(resolved, request.body.content, "utf-8");
|
|
21053
21137
|
return reply.status(201).send({ path: filePath, status: "created" });
|
|
21054
21138
|
} catch (err) {
|
|
@@ -21274,14 +21358,14 @@ init_src();
|
|
|
21274
21358
|
init_init();
|
|
21275
21359
|
import { Command } from "commander";
|
|
21276
21360
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
21277
|
-
import { dirname as
|
|
21361
|
+
import { dirname as dirname16 } from "path";
|
|
21278
21362
|
|
|
21279
21363
|
// packages/cli/src/commands/compile.ts
|
|
21280
21364
|
init_src();
|
|
21281
|
-
import { resolve as
|
|
21365
|
+
import { resolve as resolve8, dirname as dirname9, isAbsolute as isAbsolute5 } from "path";
|
|
21282
21366
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21283
21367
|
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile12 } from "fs/promises";
|
|
21284
|
-
import { existsSync as
|
|
21368
|
+
import { existsSync as existsSync12 } from "fs";
|
|
21285
21369
|
import chokidar from "chokidar";
|
|
21286
21370
|
|
|
21287
21371
|
// packages/cli/src/config/loader.ts
|
|
@@ -21345,6 +21429,56 @@ async function loadConfig(customPath) {
|
|
|
21345
21429
|
|
|
21346
21430
|
// packages/cli/src/commands/compile.ts
|
|
21347
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
|
|
21348
21482
|
init_console();
|
|
21349
21483
|
|
|
21350
21484
|
// packages/compiler/src/compiler.ts
|
|
@@ -21361,7 +21495,7 @@ import { basename as basename11, dirname as dirname7, join as join8 } from "path
|
|
|
21361
21495
|
// packages/resolver/src/loader.ts
|
|
21362
21496
|
init_src();
|
|
21363
21497
|
import { readFile as readFile7 } from "fs/promises";
|
|
21364
|
-
import { resolve as
|
|
21498
|
+
import { resolve as resolve5, dirname as dirname5, basename as basename7, isAbsolute as isAbsolute2, relative } from "path";
|
|
21365
21499
|
|
|
21366
21500
|
// packages/resolver/src/alias-resolver.ts
|
|
21367
21501
|
init_src();
|
|
@@ -21451,8 +21585,8 @@ var FileLoader = class {
|
|
|
21451
21585
|
options;
|
|
21452
21586
|
constructor(options) {
|
|
21453
21587
|
this.registryPath = options.registryPath;
|
|
21454
|
-
this.localPath =
|
|
21455
|
-
this.projectRoot =
|
|
21588
|
+
this.localPath = resolve5(options.localPath ?? process.cwd());
|
|
21589
|
+
this.projectRoot = resolve5(
|
|
21456
21590
|
options.projectRoot ?? (basename7(this.localPath) === ".promptscript" ? dirname5(this.localPath) : this.localPath)
|
|
21457
21591
|
);
|
|
21458
21592
|
this.options = options;
|
|
@@ -21495,11 +21629,11 @@ var FileLoader = class {
|
|
|
21495
21629
|
const namespace = match[1];
|
|
21496
21630
|
const segments = match[2];
|
|
21497
21631
|
const fileName2 = segments.endsWith(".prs") || segments.endsWith(".md") ? segments : `${segments}.prs`;
|
|
21498
|
-
return
|
|
21632
|
+
return resolve5(this.registryPath, `@${namespace}`, fileName2);
|
|
21499
21633
|
}
|
|
21500
21634
|
}
|
|
21501
21635
|
const fileName = path.endsWith(".prs") || path.endsWith(".md") ? path : `${path}.prs`;
|
|
21502
|
-
return
|
|
21636
|
+
return resolve5(this.localPath, fileName);
|
|
21503
21637
|
}
|
|
21504
21638
|
/**
|
|
21505
21639
|
* Resolve a PathReference to an absolute path.
|
|
@@ -21512,7 +21646,7 @@ var FileLoader = class {
|
|
|
21512
21646
|
if (ref.isRelative) {
|
|
21513
21647
|
const dir = dirname5(fromFile);
|
|
21514
21648
|
const rawPath = ref.raw.endsWith(".prs") || ref.raw.endsWith(".md") ? ref.raw : `${ref.raw}.prs`;
|
|
21515
|
-
const resolved =
|
|
21649
|
+
const resolved = resolve5(dir, rawPath);
|
|
21516
21650
|
const rel = relative(this.projectRoot, resolved);
|
|
21517
21651
|
if (rel.startsWith("..") || isAbsolute2(rel)) {
|
|
21518
21652
|
throw new Error(`Path traversal outside project root is not allowed: ${ref.raw}`);
|
|
@@ -22453,7 +22587,7 @@ function uniqueConcat3(parent, child) {
|
|
|
22453
22587
|
// packages/resolver/src/skills.ts
|
|
22454
22588
|
init_src();
|
|
22455
22589
|
import { readFile as readFile8, readdir as readdir2, access, lstat, realpath } from "fs/promises";
|
|
22456
|
-
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";
|
|
22457
22591
|
function parseSkillMd(content) {
|
|
22458
22592
|
const lines = content.split("\n");
|
|
22459
22593
|
let inFrontmatter = false;
|
|
@@ -22899,10 +23033,10 @@ function parseSkillIgnore(content) {
|
|
|
22899
23033
|
return { patterns };
|
|
22900
23034
|
}
|
|
22901
23035
|
function isIgnoredByRules(relPath, rules) {
|
|
22902
|
-
const
|
|
23036
|
+
const basename16 = relPath.split("/").pop() ?? relPath;
|
|
22903
23037
|
let ignored = false;
|
|
22904
23038
|
for (const { regex, matchPath, negated } of rules.patterns) {
|
|
22905
|
-
const target = matchPath ? relPath :
|
|
23039
|
+
const target = matchPath ? relPath : basename16;
|
|
22906
23040
|
if (regex.test(target)) {
|
|
22907
23041
|
ignored = !negated;
|
|
22908
23042
|
}
|
|
@@ -22910,7 +23044,7 @@ function isIgnoredByRules(relPath, rules) {
|
|
|
22910
23044
|
return ignored;
|
|
22911
23045
|
}
|
|
22912
23046
|
async function loadSkillIgnore(skillDir) {
|
|
22913
|
-
const ignorePath =
|
|
23047
|
+
const ignorePath = resolve6(skillDir, ".skillignore");
|
|
22914
23048
|
try {
|
|
22915
23049
|
const content = await readFile8(ignorePath, "utf-8");
|
|
22916
23050
|
return parseSkillIgnore(content);
|
|
@@ -22956,7 +23090,7 @@ async function discoverSkillResources(skillDir, logger = noopLogger2) {
|
|
|
22956
23090
|
}
|
|
22957
23091
|
if (entry.isSymbolicLink()) continue;
|
|
22958
23092
|
if (SKIP_FILES.has(entry.name)) continue;
|
|
22959
|
-
const fullPath =
|
|
23093
|
+
const fullPath = resolve6(entry.parentPath, entry.name);
|
|
22960
23094
|
const relPath = relative2(skillDir, fullPath);
|
|
22961
23095
|
const relPathNormalized = relPath.split(sep2).join("/");
|
|
22962
23096
|
const pathSegments = relPath.split(sep2);
|
|
@@ -23015,7 +23149,7 @@ async function resolveSkillReferences(references, basePath, logger) {
|
|
|
23015
23149
|
column: 0
|
|
23016
23150
|
});
|
|
23017
23151
|
}
|
|
23018
|
-
const fullPath =
|
|
23152
|
+
const fullPath = resolve6(basePath, ref);
|
|
23019
23153
|
let content;
|
|
23020
23154
|
try {
|
|
23021
23155
|
content = await readFile8(fullPath, "utf-8");
|
|
@@ -23087,8 +23221,8 @@ async function discoverSkillDirs(basePath) {
|
|
|
23087
23221
|
if (!entry.isDirectory()) continue;
|
|
23088
23222
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
23089
23223
|
if (!isSafeSkillName(entry.name)) continue;
|
|
23090
|
-
const subDir =
|
|
23091
|
-
const skillMd =
|
|
23224
|
+
const subDir = resolve6(dir, entry.name);
|
|
23225
|
+
const skillMd = resolve6(subDir, "SKILL.md");
|
|
23092
23226
|
if (await fileExists(skillMd)) {
|
|
23093
23227
|
if (!result.has(entry.name)) {
|
|
23094
23228
|
result.set(entry.name, subDir);
|
|
@@ -23115,9 +23249,9 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23115
23249
|
const isSkillsDir = sourceDir.includes("@skills") || sourceDir.endsWith("/skills");
|
|
23116
23250
|
const discoveredSkillPaths = /* @__PURE__ */ new Map();
|
|
23117
23251
|
if (!isSkillsDir && localPath) {
|
|
23118
|
-
const discoveryDirs = [
|
|
23252
|
+
const discoveryDirs = [resolve6(localPath, "skills")];
|
|
23119
23253
|
if (options?.universalDir && localPath) {
|
|
23120
|
-
discoveryDirs.push(
|
|
23254
|
+
discoveryDirs.push(resolve6(localPath, "..", options.universalDir, "skills"));
|
|
23121
23255
|
}
|
|
23122
23256
|
for (const dir of discoveryDirs) {
|
|
23123
23257
|
const discovered = await discoverSkillDirs(dir);
|
|
@@ -23138,7 +23272,7 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23138
23272
|
}
|
|
23139
23273
|
let sharedResources = [];
|
|
23140
23274
|
if (localPath) {
|
|
23141
|
-
const sharedDir =
|
|
23275
|
+
const sharedDir = resolve6(localPath, "shared");
|
|
23142
23276
|
if (await fileExists(sharedDir)) {
|
|
23143
23277
|
try {
|
|
23144
23278
|
sharedResources = await discoverSkillResources(sharedDir, logger);
|
|
@@ -23159,12 +23293,12 @@ async function resolveNativeSkills(ast, registryPath, sourceFile, localPath, opt
|
|
|
23159
23293
|
continue;
|
|
23160
23294
|
}
|
|
23161
23295
|
const skillObj = skillValue;
|
|
23162
|
-
const skillMdPath = isSkillsDir ?
|
|
23296
|
+
const skillMdPath = isSkillsDir ? resolve6(sourceDir, skillName, "SKILL.md") : await (async () => {
|
|
23163
23297
|
const discoveredDir = discoveredSkillPaths.get(skillName);
|
|
23164
|
-
if (discoveredDir) return
|
|
23165
|
-
const localCandidate = localPath ?
|
|
23166
|
-
const universalCandidate = options?.universalDir && localPath ?
|
|
23167
|
-
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");
|
|
23168
23302
|
if (localCandidate && await fileExists(localCandidate)) return localCandidate;
|
|
23169
23303
|
if (universalCandidate && await fileExists(universalCandidate))
|
|
23170
23304
|
return universalCandidate;
|
|
@@ -23254,7 +23388,7 @@ async function discoverCommandFiles(dir, logger = noopLogger2) {
|
|
|
23254
23388
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
23255
23389
|
if (entry.isSymbolicLink()) continue;
|
|
23256
23390
|
const cmdName = "/" + entry.name.replace(/\.md$/, "");
|
|
23257
|
-
const fullPath =
|
|
23391
|
+
const fullPath = resolve6(dir, entry.name);
|
|
23258
23392
|
try {
|
|
23259
23393
|
const fileStat = await lstat(fullPath);
|
|
23260
23394
|
if (fileStat.isSymbolicLink()) continue;
|
|
@@ -23285,11 +23419,11 @@ async function resolveNativeCommands(ast, sourceFile, localPath, options) {
|
|
|
23285
23419
|
if (!localPath) return ast;
|
|
23286
23420
|
const logger = options?.logger ?? noopLogger2;
|
|
23287
23421
|
const allCommands = {};
|
|
23288
|
-
const localCommands = await discoverCommandFiles(
|
|
23422
|
+
const localCommands = await discoverCommandFiles(resolve6(localPath, "commands"), logger);
|
|
23289
23423
|
Object.assign(allCommands, localCommands);
|
|
23290
23424
|
if (options?.universalDir) {
|
|
23291
23425
|
const universalCommands = await discoverCommandFiles(
|
|
23292
|
-
|
|
23426
|
+
resolve6(localPath, "..", options.universalDir, "commands"),
|
|
23293
23427
|
logger
|
|
23294
23428
|
);
|
|
23295
23429
|
for (const [name, value] of Object.entries(universalCommands)) {
|
|
@@ -23370,7 +23504,7 @@ async function discoverAgentFiles(dir, logger = noopLogger2) {
|
|
|
23370
23504
|
for (const entry of entries) {
|
|
23371
23505
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
23372
23506
|
if (entry.isSymbolicLink()) continue;
|
|
23373
|
-
const fullPath =
|
|
23507
|
+
const fullPath = resolve6(dir, entry.name);
|
|
23374
23508
|
try {
|
|
23375
23509
|
const fileStat = await lstat(fullPath);
|
|
23376
23510
|
if (fileStat.isSymbolicLink()) continue;
|
|
@@ -23434,11 +23568,11 @@ async function resolveNativeAgents(ast, sourceFile, localPath, options) {
|
|
|
23434
23568
|
if (!localPath) return ast;
|
|
23435
23569
|
const logger = options?.logger ?? noopLogger2;
|
|
23436
23570
|
const allAgents = {};
|
|
23437
|
-
const localAgents = await discoverAgentFiles(
|
|
23571
|
+
const localAgents = await discoverAgentFiles(resolve6(localPath, "agents"), logger);
|
|
23438
23572
|
Object.assign(allAgents, localAgents);
|
|
23439
23573
|
if (options?.universalDir) {
|
|
23440
23574
|
const universalAgents = await discoverAgentFiles(
|
|
23441
|
-
|
|
23575
|
+
resolve6(localPath, "..", options.universalDir, "agents"),
|
|
23442
23576
|
logger
|
|
23443
23577
|
);
|
|
23444
23578
|
for (const [name, value] of Object.entries(universalAgents)) {
|
|
@@ -25066,7 +25200,7 @@ var RegistryCache = class {
|
|
|
25066
25200
|
|
|
25067
25201
|
// packages/resolver/src/auto-discovery.ts
|
|
25068
25202
|
import { readFile as readFile10, readdir as readdir3, access as access2, lstat as lstat2 } from "fs/promises";
|
|
25069
|
-
import { resolve as
|
|
25203
|
+
import { resolve as resolve7, basename as basename10 } from "path";
|
|
25070
25204
|
var CONTEXT_FILES = ["CLAUDE.md", ".clinerules", ".cursorrules"];
|
|
25071
25205
|
async function fileExists2(path) {
|
|
25072
25206
|
try {
|
|
@@ -25102,9 +25236,9 @@ async function discoverSkills(dir) {
|
|
|
25102
25236
|
const properties = {};
|
|
25103
25237
|
for (const entry of entries) {
|
|
25104
25238
|
if (!entry.isDirectory()) continue;
|
|
25105
|
-
let skillMdPath =
|
|
25239
|
+
let skillMdPath = resolve7(dir, entry.name, "SKILL.md");
|
|
25106
25240
|
if (!await fileExists2(skillMdPath)) {
|
|
25107
|
-
const dirnameMdPath =
|
|
25241
|
+
const dirnameMdPath = resolve7(dir, entry.name, `${entry.name}.md`);
|
|
25108
25242
|
if (await fileExists2(dirnameMdPath)) {
|
|
25109
25243
|
skillMdPath = dirnameMdPath;
|
|
25110
25244
|
} else {
|
|
@@ -25131,7 +25265,7 @@ async function discoverSkills(dir) {
|
|
|
25131
25265
|
return Object.keys(properties).length > 0 ? properties : null;
|
|
25132
25266
|
}
|
|
25133
25267
|
async function discoverRootSkill(dir) {
|
|
25134
|
-
const skillMdPath =
|
|
25268
|
+
const skillMdPath = resolve7(dir, "SKILL.md");
|
|
25135
25269
|
if (!await fileExists2(skillMdPath)) return null;
|
|
25136
25270
|
try {
|
|
25137
25271
|
const raw = await readFile10(skillMdPath, "utf-8");
|
|
@@ -25162,7 +25296,7 @@ async function discoverAgents(dir) {
|
|
|
25162
25296
|
const properties = {};
|
|
25163
25297
|
for (const entry of entries) {
|
|
25164
25298
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25165
|
-
const fullPath =
|
|
25299
|
+
const fullPath = resolve7(dir, entry.name);
|
|
25166
25300
|
try {
|
|
25167
25301
|
const stat4 = await lstat2(fullPath);
|
|
25168
25302
|
if (stat4.isSymbolicLink()) continue;
|
|
@@ -25198,7 +25332,7 @@ async function discoverCommands(dir) {
|
|
|
25198
25332
|
for (const entry of entries) {
|
|
25199
25333
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25200
25334
|
if (entry.name === "SKILL.md") continue;
|
|
25201
|
-
const fullPath =
|
|
25335
|
+
const fullPath = resolve7(dir, entry.name);
|
|
25202
25336
|
try {
|
|
25203
25337
|
const stat4 = await lstat2(fullPath);
|
|
25204
25338
|
if (stat4.isSymbolicLink()) continue;
|
|
@@ -25215,7 +25349,7 @@ async function discoverCommands(dir) {
|
|
|
25215
25349
|
}
|
|
25216
25350
|
async function discoverContext(dir) {
|
|
25217
25351
|
for (const fileName of CONTEXT_FILES) {
|
|
25218
|
-
const fullPath =
|
|
25352
|
+
const fullPath = resolve7(dir, fileName);
|
|
25219
25353
|
if (!await fileExists2(fullPath)) continue;
|
|
25220
25354
|
try {
|
|
25221
25355
|
const content = await readFile10(fullPath, "utf-8");
|
|
@@ -25245,7 +25379,7 @@ async function discoverNativeContent(dir) {
|
|
|
25245
25379
|
const subSkills = await discoverSkills(dir);
|
|
25246
25380
|
const wrappedSkillResults = await Promise.all(
|
|
25247
25381
|
SKILL_WRAPPER_DIRS.map(async (name) => {
|
|
25248
|
-
const candidate =
|
|
25382
|
+
const candidate = resolve7(dir, name);
|
|
25249
25383
|
if (!await safeIsDirectory(candidate)) return null;
|
|
25250
25384
|
return discoverSkills(candidate);
|
|
25251
25385
|
})
|
|
@@ -25266,7 +25400,7 @@ async function discoverNativeContent(dir) {
|
|
|
25266
25400
|
const rootAgents = await discoverAgents(dir) ?? {};
|
|
25267
25401
|
const wrappedAgents = {};
|
|
25268
25402
|
for (const name of AGENT_WRAPPER_DIRS) {
|
|
25269
|
-
const candidate =
|
|
25403
|
+
const candidate = resolve7(dir, name);
|
|
25270
25404
|
if (await safeIsDirectory(candidate)) {
|
|
25271
25405
|
const found = await discoverAgents(candidate);
|
|
25272
25406
|
if (found) Object.assign(wrappedAgents, found);
|
|
@@ -25279,7 +25413,7 @@ async function discoverNativeContent(dir) {
|
|
|
25279
25413
|
const rootCommands = await discoverCommands(dir) ?? {};
|
|
25280
25414
|
const wrappedCommands = {};
|
|
25281
25415
|
for (const name of COMMAND_WRAPPER_DIRS) {
|
|
25282
|
-
const candidate =
|
|
25416
|
+
const candidate = resolve7(dir, name);
|
|
25283
25417
|
if (await safeIsDirectory(candidate)) {
|
|
25284
25418
|
const found = await discoverCommands(candidate);
|
|
25285
25419
|
if (found) Object.assign(wrappedCommands, found);
|
|
@@ -25780,6 +25914,12 @@ var Resolver = class {
|
|
|
25780
25914
|
errors.push(new ResolveError(e.message, e.location));
|
|
25781
25915
|
}
|
|
25782
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
|
+
);
|
|
25783
25923
|
} else {
|
|
25784
25924
|
const discoverDir = isRoot ? cachePath : join8(cachePath, subPath);
|
|
25785
25925
|
this.logger.debug(`No .prs found, trying auto-discovery: ${discoverDir}`);
|
|
@@ -26022,7 +26162,7 @@ var HttpRegistry = class {
|
|
|
26022
26162
|
* Sleep for specified milliseconds.
|
|
26023
26163
|
*/
|
|
26024
26164
|
sleep(ms) {
|
|
26025
|
-
return new Promise((
|
|
26165
|
+
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
26026
26166
|
}
|
|
26027
26167
|
/**
|
|
26028
26168
|
* Fetch with timeout.
|
|
@@ -26166,9 +26306,251 @@ function createHttpRegistry(options) {
|
|
|
26166
26306
|
// packages/resolver/src/vendor-registry.ts
|
|
26167
26307
|
init_src();
|
|
26168
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
|
+
|
|
26169
26544
|
// packages/resolver/src/index.ts
|
|
26170
26545
|
init_src();
|
|
26171
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
|
+
|
|
26172
26554
|
// packages/validator/src/validator.ts
|
|
26173
26555
|
init_src();
|
|
26174
26556
|
|
|
@@ -29621,7 +30003,7 @@ var Compiler = class _Compiler {
|
|
|
29621
30003
|
outputPathOwners.set(skillPath, `${formatter.name}:promptscript-skill`);
|
|
29622
30004
|
const skillOutput = {
|
|
29623
30005
|
path: skillPath,
|
|
29624
|
-
content: this.options.skillContent
|
|
30006
|
+
content: formatter.transformInjectedSkillContent ? formatter.transformInjectedSkillContent(this.options.skillContent) : this.options.skillContent
|
|
29625
30007
|
};
|
|
29626
30008
|
outputs.set(skillPath, addMarkerToOutput(skillOutput, sourceLabel, "promptscript"));
|
|
29627
30009
|
this.logger.verbose(` \u2192 ${skillPath} (auto-injected promptscript skill)`);
|
|
@@ -29702,12 +30084,12 @@ var Compiler = class _Compiler {
|
|
|
29702
30084
|
*/
|
|
29703
30085
|
async watch(entryPath, options = {}) {
|
|
29704
30086
|
const { default: chokidar2 } = await import("chokidar");
|
|
29705
|
-
const { dirname:
|
|
29706
|
-
const baseDir =
|
|
30087
|
+
const { dirname: dirname17, resolve: resolve22 } = await import("path");
|
|
30088
|
+
const baseDir = dirname17(resolve22(entryPath));
|
|
29707
30089
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
29708
30090
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
29709
30091
|
const debounceMs = options.debounce ?? 300;
|
|
29710
|
-
const watchPatterns = includePatterns.map((p) =>
|
|
30092
|
+
const watchPatterns = includePatterns.map((p) => resolve22(baseDir, p));
|
|
29711
30093
|
let debounceTimer = null;
|
|
29712
30094
|
let pendingChanges = [];
|
|
29713
30095
|
const handleChange = async (changedFiles) => {
|
|
@@ -29882,7 +30264,7 @@ var Pager = class {
|
|
|
29882
30264
|
}
|
|
29883
30265
|
return;
|
|
29884
30266
|
}
|
|
29885
|
-
return new Promise((
|
|
30267
|
+
return new Promise((resolve22) => {
|
|
29886
30268
|
const pagerCmd = getPagerCommand();
|
|
29887
30269
|
const [cmd, ...args] = pagerCmd.split(" ");
|
|
29888
30270
|
if (cmd === "less" && !args.includes("-R")) {
|
|
@@ -29890,7 +30272,7 @@ var Pager = class {
|
|
|
29890
30272
|
}
|
|
29891
30273
|
if (!cmd) {
|
|
29892
30274
|
console.log(content);
|
|
29893
|
-
|
|
30275
|
+
resolve22();
|
|
29894
30276
|
return;
|
|
29895
30277
|
}
|
|
29896
30278
|
const pager = spawn(cmd, args, {
|
|
@@ -29903,17 +30285,17 @@ var Pager = class {
|
|
|
29903
30285
|
});
|
|
29904
30286
|
pager.on("error", (_err) => {
|
|
29905
30287
|
console.log(content);
|
|
29906
|
-
|
|
30288
|
+
resolve22();
|
|
29907
30289
|
});
|
|
29908
30290
|
pager.on("close", () => {
|
|
29909
|
-
|
|
30291
|
+
resolve22();
|
|
29910
30292
|
});
|
|
29911
30293
|
if (pager.stdin) {
|
|
29912
30294
|
pager.stdin.write(content);
|
|
29913
30295
|
pager.stdin.end();
|
|
29914
30296
|
} else {
|
|
29915
30297
|
console.log(content);
|
|
29916
|
-
|
|
30298
|
+
resolve22();
|
|
29917
30299
|
}
|
|
29918
30300
|
});
|
|
29919
30301
|
}
|
|
@@ -29926,7 +30308,7 @@ function createPager(enabled = true) {
|
|
|
29926
30308
|
init_services();
|
|
29927
30309
|
|
|
29928
30310
|
// packages/cli/src/utils/registry-resolver.ts
|
|
29929
|
-
import { join as
|
|
30311
|
+
import { join as join11 } from "path";
|
|
29930
30312
|
async function resolveRegistryPath(config) {
|
|
29931
30313
|
if (config.registry?.git) {
|
|
29932
30314
|
const gitConfig = config.registry.git;
|
|
@@ -29940,7 +30322,7 @@ async function resolveRegistryPath(config) {
|
|
|
29940
30322
|
if (isValid) {
|
|
29941
30323
|
const subPath2 = gitConfig.path ?? "";
|
|
29942
30324
|
return {
|
|
29943
|
-
path: subPath2 ?
|
|
30325
|
+
path: subPath2 ? join11(cachePath, subPath2) : cachePath,
|
|
29944
30326
|
isRemote: true,
|
|
29945
30327
|
source: "git"
|
|
29946
30328
|
};
|
|
@@ -29969,7 +30351,7 @@ async function resolveRegistryPath(config) {
|
|
|
29969
30351
|
}
|
|
29970
30352
|
const subPath = gitConfig.path ?? "";
|
|
29971
30353
|
return {
|
|
29972
|
-
path: subPath ?
|
|
30354
|
+
path: subPath ? join11(cachePath, subPath) : cachePath,
|
|
29973
30355
|
isRemote: true,
|
|
29974
30356
|
source: "git"
|
|
29975
30357
|
};
|
|
@@ -30019,17 +30401,17 @@ function detectOutputConflicts(targets) {
|
|
|
30019
30401
|
|
|
30020
30402
|
// packages/cli/src/commands/compile.ts
|
|
30021
30403
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
30022
|
-
var __dirname2 =
|
|
30404
|
+
var __dirname2 = dirname9(__filename2);
|
|
30023
30405
|
async function loadBundledSkillContent(logger) {
|
|
30024
30406
|
const skillRelPath = "skills/promptscript/SKILL.md";
|
|
30025
30407
|
const candidates = [
|
|
30026
|
-
|
|
30408
|
+
resolve8(__dirname2, skillRelPath),
|
|
30027
30409
|
// bundled: dist/packages/cli/skills/...
|
|
30028
|
-
|
|
30410
|
+
resolve8(__dirname2, "..", "..", skillRelPath)
|
|
30029
30411
|
// dev: packages/cli/skills/...
|
|
30030
30412
|
];
|
|
30031
30413
|
for (const candidate of candidates) {
|
|
30032
|
-
if (
|
|
30414
|
+
if (existsSync12(candidate)) {
|
|
30033
30415
|
try {
|
|
30034
30416
|
const content = await readFile12(candidate, "utf-8");
|
|
30035
30417
|
logger.debug(
|
|
@@ -30046,8 +30428,8 @@ async function loadBundledSkillContent(logger) {
|
|
|
30046
30428
|
}
|
|
30047
30429
|
function findConfigInDir(dir) {
|
|
30048
30430
|
for (const file of CONFIG_FILES) {
|
|
30049
|
-
const fullPath =
|
|
30050
|
-
if (
|
|
30431
|
+
const fullPath = resolve8(dir, file);
|
|
30432
|
+
if (existsSync12(fullPath)) {
|
|
30051
30433
|
return fullPath;
|
|
30052
30434
|
}
|
|
30053
30435
|
}
|
|
@@ -30103,7 +30485,7 @@ function getBuildProfile(config, buildName) {
|
|
|
30103
30485
|
}
|
|
30104
30486
|
function resolveOutputBase(projectRoot, output) {
|
|
30105
30487
|
if (!output) return projectRoot;
|
|
30106
|
-
return isAbsolute5(output) ? output :
|
|
30488
|
+
return isAbsolute5(output) ? output : resolve8(projectRoot, output);
|
|
30107
30489
|
}
|
|
30108
30490
|
async function isPromptScriptGenerated2(filePath) {
|
|
30109
30491
|
try {
|
|
@@ -30147,13 +30529,13 @@ async function writeOutputs(outputs, options, _config, services) {
|
|
|
30147
30529
|
const targetErrors = [];
|
|
30148
30530
|
async function safeWrite(path, content) {
|
|
30149
30531
|
try {
|
|
30150
|
-
await mkdir4(
|
|
30532
|
+
await mkdir4(dirname9(path), { recursive: true });
|
|
30151
30533
|
await writeFile4(path, content, "utf-8");
|
|
30152
30534
|
return true;
|
|
30153
30535
|
} catch (err) {
|
|
30154
30536
|
const nodeErr = err;
|
|
30155
30537
|
if (nodeErr.code === "ENOTDIR") {
|
|
30156
|
-
const conflictPath = nodeErr.path ??
|
|
30538
|
+
const conflictPath = nodeErr.path ?? dirname9(path);
|
|
30157
30539
|
const msg = `Cannot create directory because '${conflictPath}' already exists as a file. Remove it or disable this target.`;
|
|
30158
30540
|
targetErrors.push(msg);
|
|
30159
30541
|
ConsoleOutput.error(msg);
|
|
@@ -30169,8 +30551,8 @@ async function writeOutputs(outputs, options, _config, services) {
|
|
|
30169
30551
|
}
|
|
30170
30552
|
}
|
|
30171
30553
|
for (const output of outputs.values()) {
|
|
30172
|
-
const outputPath = options.output ?
|
|
30173
|
-
const fileExists3 =
|
|
30554
|
+
const outputPath = options.output ? resolve8(options.output, output.path) : resolve8(output.path);
|
|
30555
|
+
const fileExists3 = existsSync12(outputPath);
|
|
30174
30556
|
if (options.dryRun) {
|
|
30175
30557
|
if (fileExists3) {
|
|
30176
30558
|
const isGenerated2 = await isPromptScriptGenerated2(outputPath);
|
|
@@ -30303,7 +30685,7 @@ async function compileCommand(options, services = createDefaultServices()) {
|
|
|
30303
30685
|
const spinner = createSpinner("Loading configuration...").start();
|
|
30304
30686
|
const logger = createCliLogger();
|
|
30305
30687
|
try {
|
|
30306
|
-
const projectRoot = options.cwd ?
|
|
30688
|
+
const projectRoot = options.cwd ? resolve8(options.cwd) : process.cwd();
|
|
30307
30689
|
logger.verbose("Loading configuration...");
|
|
30308
30690
|
const configPath = options.config ? options.config : options.cwd ? findConfigInDir(projectRoot) : void 0;
|
|
30309
30691
|
const config = await loadConfig(configPath);
|
|
@@ -30343,7 +30725,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30343
30725
|
}
|
|
30344
30726
|
}
|
|
30345
30727
|
let lockfile;
|
|
30346
|
-
const lockfilePath =
|
|
30728
|
+
const lockfilePath = resolve8(projectRoot, "promptscript.lock");
|
|
30347
30729
|
try {
|
|
30348
30730
|
const lockfileContent = await readFile12(lockfilePath, "utf-8");
|
|
30349
30731
|
const parsed = parseYaml5(lockfileContent, { maxAliasCount: 100 });
|
|
@@ -30363,7 +30745,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30363
30745
|
if (config.includePromptScriptSkill !== false) {
|
|
30364
30746
|
skillContent = await loadBundledSkillContent(logger);
|
|
30365
30747
|
}
|
|
30366
|
-
const localPath =
|
|
30748
|
+
const localPath = resolve8(projectRoot, ".promptscript");
|
|
30367
30749
|
const compiler = new Compiler({
|
|
30368
30750
|
resolver: {
|
|
30369
30751
|
registryPath,
|
|
@@ -30383,8 +30765,8 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30383
30765
|
ignoreHashes: options.ignoreHashes
|
|
30384
30766
|
});
|
|
30385
30767
|
const entry = buildProfile?.entry ?? config.input?.entry;
|
|
30386
|
-
const entryPath = entry ?
|
|
30387
|
-
if (!
|
|
30768
|
+
const entryPath = entry ? resolve8(projectRoot, entry) : resolve8(localPath, "project.prs");
|
|
30769
|
+
if (!existsSync12(entryPath)) {
|
|
30388
30770
|
spinner.fail("Entry file not found");
|
|
30389
30771
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
30390
30772
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -30409,6 +30791,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30409
30791
|
...options,
|
|
30410
30792
|
output: resolveOutputBase(projectRoot, configuredOutput)
|
|
30411
30793
|
};
|
|
30794
|
+
await postFormatWithPrettier(result.outputs, projectRoot, logger);
|
|
30412
30795
|
const writeResult = await writeOutputs(result.outputs, effectiveOptions, config, services);
|
|
30413
30796
|
if (writeResult.unchanged.length > 0) {
|
|
30414
30797
|
ConsoleOutput.muted(`Unchanged ${writeResult.unchanged.length} file(s)`);
|
|
@@ -30422,7 +30805,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30422
30805
|
ConsoleOutput.newline();
|
|
30423
30806
|
ConsoleOutput.info("Watching for changes... (Ctrl+C to stop)");
|
|
30424
30807
|
watchForChanges(
|
|
30425
|
-
|
|
30808
|
+
resolve8(projectRoot, ".promptscript"),
|
|
30426
30809
|
() => compileCommand({ ...options, watch: false }, services)
|
|
30427
30810
|
);
|
|
30428
30811
|
}
|
|
@@ -30473,8 +30856,8 @@ function watchForChanges(dir, callback) {
|
|
|
30473
30856
|
}
|
|
30474
30857
|
|
|
30475
30858
|
// packages/cli/src/commands/validate.ts
|
|
30476
|
-
import { resolve as
|
|
30477
|
-
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";
|
|
30478
30861
|
init_console();
|
|
30479
30862
|
init_src();
|
|
30480
30863
|
init_src2();
|
|
@@ -30583,7 +30966,7 @@ function discoverPrsFiles(dir) {
|
|
|
30583
30966
|
try {
|
|
30584
30967
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
30585
30968
|
for (const entry of entries) {
|
|
30586
|
-
const fullPath =
|
|
30969
|
+
const fullPath = join12(dir, entry.name);
|
|
30587
30970
|
if (entry.isDirectory()) {
|
|
30588
30971
|
results.push(...discoverPrsFiles(fullPath));
|
|
30589
30972
|
} else if (entry.name.endsWith(".prs")) {
|
|
@@ -30623,8 +31006,8 @@ async function validateCommand(options) {
|
|
|
30623
31006
|
formatters: []
|
|
30624
31007
|
// No formatters needed for validation only
|
|
30625
31008
|
});
|
|
30626
|
-
const entryPath =
|
|
30627
|
-
if (!
|
|
31009
|
+
const entryPath = resolve9("./.promptscript/project.prs");
|
|
31010
|
+
if (!existsSync13(entryPath)) {
|
|
30628
31011
|
handleEntryNotFound(entryPath, isJsonFormat, spinner);
|
|
30629
31012
|
return;
|
|
30630
31013
|
}
|
|
@@ -30706,8 +31089,8 @@ ${fixedCount} file(s) fixed.`);
|
|
|
30706
31089
|
|
|
30707
31090
|
// packages/cli/src/commands/pull.ts
|
|
30708
31091
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
30709
|
-
import { existsSync as
|
|
30710
|
-
import { resolve as
|
|
31092
|
+
import { existsSync as existsSync14 } from "fs";
|
|
31093
|
+
import { resolve as resolve10, dirname as dirname10 } from "path";
|
|
30711
31094
|
init_console();
|
|
30712
31095
|
async function pullCommand(options) {
|
|
30713
31096
|
const spinner = createSpinner("Loading configuration...").start();
|
|
@@ -30732,8 +31115,8 @@ async function pullCommand(options) {
|
|
|
30732
31115
|
}
|
|
30733
31116
|
spinner.text = `Fetching ${inheritPath}...`;
|
|
30734
31117
|
const content = await registry2.fetch(inheritPath);
|
|
30735
|
-
const destPath =
|
|
30736
|
-
if (
|
|
31118
|
+
const destPath = resolve10("./.promptscript/.inherited", inheritPath);
|
|
31119
|
+
if (existsSync14(destPath) && !options.force && !options.dryRun) {
|
|
30737
31120
|
spinner.warn("File already exists (use --force to overwrite)");
|
|
30738
31121
|
ConsoleOutput.muted(destPath);
|
|
30739
31122
|
return;
|
|
@@ -30743,12 +31126,12 @@ async function pullCommand(options) {
|
|
|
30743
31126
|
ConsoleOutput.newline();
|
|
30744
31127
|
ConsoleOutput.dryRun(`Would fetch: ${config.inherit}`);
|
|
30745
31128
|
ConsoleOutput.dryRun(` to: ${destPath}`);
|
|
30746
|
-
if (
|
|
31129
|
+
if (existsSync14(destPath)) {
|
|
30747
31130
|
ConsoleOutput.dryRun("(would overwrite existing file)");
|
|
30748
31131
|
}
|
|
30749
31132
|
return;
|
|
30750
31133
|
}
|
|
30751
|
-
await mkdir5(
|
|
31134
|
+
await mkdir5(dirname10(destPath), { recursive: true });
|
|
30752
31135
|
await writeFile5(destPath, content, "utf-8");
|
|
30753
31136
|
spinner.succeed("Pulled from registry");
|
|
30754
31137
|
ConsoleOutput.success(destPath);
|
|
@@ -30791,10 +31174,10 @@ async function createRegistry(config, options, spinner) {
|
|
|
30791
31174
|
}
|
|
30792
31175
|
const registryPath = config.registry?.path ?? "./registry";
|
|
30793
31176
|
spinner.text = `Using local registry: ${registryPath}...`;
|
|
30794
|
-
if (!
|
|
31177
|
+
if (!existsSync14(registryPath)) {
|
|
30795
31178
|
throw new Error(`Local registry path not found: ${registryPath}`);
|
|
30796
31179
|
}
|
|
30797
|
-
return createFileSystemRegistry(
|
|
31180
|
+
return createFileSystemRegistry(resolve10(registryPath));
|
|
30798
31181
|
}
|
|
30799
31182
|
function parseInheritPath(inheritPath) {
|
|
30800
31183
|
const versionIndex = inheritPath.lastIndexOf("@");
|
|
@@ -30841,9 +31224,9 @@ function handlePullError(error, spinner) {
|
|
|
30841
31224
|
}
|
|
30842
31225
|
|
|
30843
31226
|
// packages/cli/src/commands/diff.ts
|
|
30844
|
-
import { resolve as
|
|
31227
|
+
import { resolve as resolve11 } from "path";
|
|
30845
31228
|
import { readFile as readFile13 } from "fs/promises";
|
|
30846
|
-
import { existsSync as
|
|
31229
|
+
import { existsSync as existsSync15 } from "fs";
|
|
30847
31230
|
init_console();
|
|
30848
31231
|
import chalk2 from "chalk";
|
|
30849
31232
|
function configureColors(options) {
|
|
@@ -30878,9 +31261,9 @@ function printNewFilePreview(content, showFull, pager) {
|
|
|
30878
31261
|
}
|
|
30879
31262
|
}
|
|
30880
31263
|
async function compareOutput(_name, output, _config, showFull, pager) {
|
|
30881
|
-
const outputPath =
|
|
31264
|
+
const outputPath = resolve11(output.path);
|
|
30882
31265
|
const newContent = output.content;
|
|
30883
|
-
if (!
|
|
31266
|
+
if (!existsSync15(outputPath)) {
|
|
30884
31267
|
pager.write(chalk2.green(`+ ${outputPath} (new file)`));
|
|
30885
31268
|
pager.write("");
|
|
30886
31269
|
printNewFilePreview(newContent, showFull, pager);
|
|
@@ -30920,8 +31303,8 @@ async function diffCommand(options) {
|
|
|
30920
31303
|
formatters: targets,
|
|
30921
31304
|
customConventions: config.customConventions
|
|
30922
31305
|
});
|
|
30923
|
-
const entryPath =
|
|
30924
|
-
if (!
|
|
31306
|
+
const entryPath = resolve11("./.promptscript/project.prs");
|
|
31307
|
+
if (!existsSync15(entryPath)) {
|
|
30925
31308
|
spinner.fail("Entry file not found");
|
|
30926
31309
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
30927
31310
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -30989,8 +31372,8 @@ function printSimpleDiff(existingLines, newLines, showFull, pager) {
|
|
|
30989
31372
|
}
|
|
30990
31373
|
|
|
30991
31374
|
// packages/cli/src/commands/check.ts
|
|
30992
|
-
import { existsSync as
|
|
30993
|
-
import { resolve as
|
|
31375
|
+
import { existsSync as existsSync16 } from "fs";
|
|
31376
|
+
import { resolve as resolve12 } from "path";
|
|
30994
31377
|
init_console();
|
|
30995
31378
|
async function checkCommand(_options) {
|
|
30996
31379
|
const spinner = createSpinner("Checking project health...").start();
|
|
@@ -31053,7 +31436,7 @@ async function checkCommand(_options) {
|
|
|
31053
31436
|
});
|
|
31054
31437
|
}
|
|
31055
31438
|
const entryPath = config.input?.entry ?? ".promptscript/project.prs";
|
|
31056
|
-
if (
|
|
31439
|
+
if (existsSync16(entryPath)) {
|
|
31057
31440
|
results.push({
|
|
31058
31441
|
name: "Entry file",
|
|
31059
31442
|
status: "ok",
|
|
@@ -31068,8 +31451,8 @@ async function checkCommand(_options) {
|
|
|
31068
31451
|
hasErrors = true;
|
|
31069
31452
|
}
|
|
31070
31453
|
if (config.registry?.path) {
|
|
31071
|
-
const registryPath =
|
|
31072
|
-
if (
|
|
31454
|
+
const registryPath = resolve12(config.registry.path);
|
|
31455
|
+
if (existsSync16(registryPath)) {
|
|
31073
31456
|
results.push({
|
|
31074
31457
|
name: "Registry path",
|
|
31075
31458
|
status: "ok",
|
|
@@ -31154,21 +31537,21 @@ function printResults(results) {
|
|
|
31154
31537
|
init_src();
|
|
31155
31538
|
init_console();
|
|
31156
31539
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
31157
|
-
import { dirname as
|
|
31540
|
+
import { dirname as dirname11 } from "path";
|
|
31158
31541
|
|
|
31159
31542
|
// packages/cli/src/utils/version-check.ts
|
|
31160
31543
|
init_console();
|
|
31161
31544
|
import { homedir as homedir3 } from "os";
|
|
31162
|
-
import { join as
|
|
31545
|
+
import { join as join13 } from "path";
|
|
31163
31546
|
import { readFile as readFile14, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
|
|
31164
31547
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@promptscript/cli/latest";
|
|
31165
31548
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
31166
31549
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
31167
31550
|
function getCacheDir() {
|
|
31168
|
-
return
|
|
31551
|
+
return join13(homedir3(), ".promptscript", ".cache");
|
|
31169
31552
|
}
|
|
31170
31553
|
function getCachePath() {
|
|
31171
|
-
return
|
|
31554
|
+
return join13(getCacheDir(), "version.json");
|
|
31172
31555
|
}
|
|
31173
31556
|
async function readCache() {
|
|
31174
31557
|
try {
|
|
@@ -31307,7 +31690,7 @@ function printUpdateNotification(info) {
|
|
|
31307
31690
|
|
|
31308
31691
|
// packages/cli/src/commands/update-check.ts
|
|
31309
31692
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
31310
|
-
var __dirname3 =
|
|
31693
|
+
var __dirname3 = dirname11(__filename3);
|
|
31311
31694
|
async function updateCheckCommand() {
|
|
31312
31695
|
const currentVersion = getPackageVersion(__dirname3, "./package.json");
|
|
31313
31696
|
console.log(`@promptscript/cli v${currentVersion}`);
|
|
@@ -31335,7 +31718,7 @@ init_services();
|
|
|
31335
31718
|
init_console();
|
|
31336
31719
|
|
|
31337
31720
|
// packages/cli/src/utils/registry-scaffolder.ts
|
|
31338
|
-
import { join as
|
|
31721
|
+
import { join as join14 } from "path";
|
|
31339
31722
|
var SEED_BASE = `@meta {
|
|
31340
31723
|
id: "@core/base"
|
|
31341
31724
|
syntax: "1.0.0"
|
|
@@ -31436,14 +31819,14 @@ async function scaffoldRegistry(options, services) {
|
|
|
31436
31819
|
const createdFiles = [];
|
|
31437
31820
|
await fs4.mkdir(directory, { recursive: true });
|
|
31438
31821
|
const manifest = generateManifest(name, description, namespaces, seed);
|
|
31439
|
-
const manifestPath =
|
|
31822
|
+
const manifestPath = join14(directory, "registry-manifest.yaml");
|
|
31440
31823
|
await fs4.writeFile(manifestPath, manifest, "utf-8");
|
|
31441
31824
|
createdFiles.push(manifestPath);
|
|
31442
31825
|
const readme = generateReadme(name, description, namespaces);
|
|
31443
|
-
const readmePath =
|
|
31826
|
+
const readmePath = join14(directory, "README.md");
|
|
31444
31827
|
await fs4.writeFile(readmePath, readme, "utf-8");
|
|
31445
31828
|
createdFiles.push(readmePath);
|
|
31446
|
-
const gitignorePath =
|
|
31829
|
+
const gitignorePath = join14(directory, ".gitignore");
|
|
31447
31830
|
await fs4.writeFile(
|
|
31448
31831
|
gitignorePath,
|
|
31449
31832
|
".DS_Store\nnode_modules/\n*.log\n*.swp\n*.bak\n.env*\n",
|
|
@@ -31451,20 +31834,20 @@ async function scaffoldRegistry(options, services) {
|
|
|
31451
31834
|
);
|
|
31452
31835
|
createdFiles.push(gitignorePath);
|
|
31453
31836
|
for (const ns of namespaces) {
|
|
31454
|
-
const nsDir =
|
|
31837
|
+
const nsDir = join14(directory, ns);
|
|
31455
31838
|
await fs4.mkdir(nsDir, { recursive: true });
|
|
31456
31839
|
if (seed && ns === "@core") {
|
|
31457
|
-
const basePath =
|
|
31840
|
+
const basePath = join14(nsDir, "base.prs");
|
|
31458
31841
|
await fs4.writeFile(basePath, SEED_BASE, "utf-8");
|
|
31459
31842
|
createdFiles.push(basePath);
|
|
31460
|
-
const qualityPath =
|
|
31843
|
+
const qualityPath = join14(nsDir, "quality.prs");
|
|
31461
31844
|
await fs4.writeFile(qualityPath, SEED_QUALITY, "utf-8");
|
|
31462
31845
|
createdFiles.push(qualityPath);
|
|
31463
|
-
const securityPath =
|
|
31846
|
+
const securityPath = join14(nsDir, "security.prs");
|
|
31464
31847
|
await fs4.writeFile(securityPath, SEED_SECURITY, "utf-8");
|
|
31465
31848
|
createdFiles.push(securityPath);
|
|
31466
31849
|
} else {
|
|
31467
|
-
const gitkeepPath =
|
|
31850
|
+
const gitkeepPath = join14(nsDir, ".gitkeep");
|
|
31468
31851
|
await fs4.writeFile(gitkeepPath, "", "utf-8");
|
|
31469
31852
|
createdFiles.push(gitkeepPath);
|
|
31470
31853
|
}
|
|
@@ -31573,7 +31956,7 @@ Then reference configs with \`@inherit\` or \`@use\`:
|
|
|
31573
31956
|
}
|
|
31574
31957
|
|
|
31575
31958
|
// packages/cli/src/utils/resolve-target-directory.ts
|
|
31576
|
-
import { join as
|
|
31959
|
+
import { join as join15, resolve as resolve13 } from "path";
|
|
31577
31960
|
|
|
31578
31961
|
// packages/cli/src/utils/slugify.ts
|
|
31579
31962
|
function slugify(name) {
|
|
@@ -31584,7 +31967,7 @@ function slugify(name) {
|
|
|
31584
31967
|
async function resolveTargetDirectory(options, services) {
|
|
31585
31968
|
const { cwd, directoryArg, registryName, nonInteractive } = options;
|
|
31586
31969
|
if (directoryArg) {
|
|
31587
|
-
return
|
|
31970
|
+
return resolve13(directoryArg);
|
|
31588
31971
|
}
|
|
31589
31972
|
const empty = await isDirectoryEmpty(cwd, services.fs);
|
|
31590
31973
|
if (empty && nonInteractive) {
|
|
@@ -31598,9 +31981,9 @@ async function resolveTargetDirectory(options, services) {
|
|
|
31598
31981
|
{ name: `Subdirectory (./${slugify(registryName)})`, value: "subdirectory" }
|
|
31599
31982
|
]
|
|
31600
31983
|
});
|
|
31601
|
-
return choice === "here" ? cwd :
|
|
31984
|
+
return choice === "here" ? cwd : join15(cwd, slugify(registryName));
|
|
31602
31985
|
}
|
|
31603
|
-
return
|
|
31986
|
+
return join15(cwd, slugify(registryName));
|
|
31604
31987
|
}
|
|
31605
31988
|
async function isDirectoryEmpty(dir, fs4) {
|
|
31606
31989
|
const entries = await fs4.readdir(dir);
|
|
@@ -31691,15 +32074,15 @@ async function registryInitCommand(directory, options, services = createDefaultS
|
|
|
31691
32074
|
// packages/cli/src/commands/registry/validate.ts
|
|
31692
32075
|
init_services();
|
|
31693
32076
|
init_console();
|
|
31694
|
-
import { resolve as
|
|
32077
|
+
import { resolve as resolve14 } from "path";
|
|
31695
32078
|
|
|
31696
32079
|
// packages/cli/src/utils/registry-validator.ts
|
|
31697
|
-
import { join as
|
|
32080
|
+
import { join as join16 } from "path";
|
|
31698
32081
|
import { parse as parseYaml6 } from "yaml";
|
|
31699
32082
|
async function validateRegistry(registryPath, services) {
|
|
31700
32083
|
const { fs: fs4 } = services;
|
|
31701
32084
|
const issues = [];
|
|
31702
|
-
const manifestPath =
|
|
32085
|
+
const manifestPath = join16(registryPath, "registry-manifest.yaml");
|
|
31703
32086
|
if (!fs4.existsSync(manifestPath)) {
|
|
31704
32087
|
return {
|
|
31705
32088
|
valid: false,
|
|
@@ -31791,7 +32174,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31791
32174
|
});
|
|
31792
32175
|
}
|
|
31793
32176
|
if (entry.path) {
|
|
31794
|
-
const prsPath =
|
|
32177
|
+
const prsPath = join16(registryPath, entry.path);
|
|
31795
32178
|
if (!fs4.existsSync(prsPath)) {
|
|
31796
32179
|
issues.push({
|
|
31797
32180
|
severity: "error",
|
|
@@ -31826,7 +32209,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31826
32209
|
});
|
|
31827
32210
|
}
|
|
31828
32211
|
for (const ns of namespaceNames) {
|
|
31829
|
-
const nsDir =
|
|
32212
|
+
const nsDir = join16(registryPath, ns);
|
|
31830
32213
|
if (fs4.existsSync(nsDir)) {
|
|
31831
32214
|
try {
|
|
31832
32215
|
const files = await fs4.readdir(nsDir);
|
|
@@ -31840,7 +32223,7 @@ async function validateRegistry(registryPath, services) {
|
|
|
31840
32223
|
issues.push({
|
|
31841
32224
|
severity: "warning",
|
|
31842
32225
|
message: `Orphaned .prs file not in catalog: ${relativePath}`,
|
|
31843
|
-
path:
|
|
32226
|
+
path: join16(nsDir, file)
|
|
31844
32227
|
});
|
|
31845
32228
|
}
|
|
31846
32229
|
}
|
|
@@ -31891,7 +32274,7 @@ function detectCircularDependencies(catalog) {
|
|
|
31891
32274
|
|
|
31892
32275
|
// packages/cli/src/commands/registry/validate.ts
|
|
31893
32276
|
async function registryValidateCommand(path, options, services = createDefaultServices()) {
|
|
31894
|
-
const registryPath =
|
|
32277
|
+
const registryPath = resolve14(path ?? ".");
|
|
31895
32278
|
const spinner = createSpinner("Validating registry...").start();
|
|
31896
32279
|
try {
|
|
31897
32280
|
const result = await validateRegistry(registryPath, services);
|
|
@@ -31943,10 +32326,10 @@ async function registryValidateCommand(path, options, services = createDefaultSe
|
|
|
31943
32326
|
// packages/cli/src/commands/registry/publish.ts
|
|
31944
32327
|
init_services();
|
|
31945
32328
|
init_console();
|
|
31946
|
-
import { resolve as
|
|
32329
|
+
import { resolve as resolve15, join as join17 } from "path";
|
|
31947
32330
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
31948
32331
|
async function registryPublishCommand(path, options, services = createDefaultServices()) {
|
|
31949
|
-
const registryPath =
|
|
32332
|
+
const registryPath = resolve15(path ?? ".");
|
|
31950
32333
|
try {
|
|
31951
32334
|
if (!options.force) {
|
|
31952
32335
|
const spinner2 = createSpinner("Validating registry...").start();
|
|
@@ -31966,7 +32349,7 @@ async function registryPublishCommand(path, options, services = createDefaultSer
|
|
|
31966
32349
|
`Registry valid (${result.stats.catalogEntries} entries, ${result.stats.prsFiles} files)`
|
|
31967
32350
|
);
|
|
31968
32351
|
}
|
|
31969
|
-
const manifestPath =
|
|
32352
|
+
const manifestPath = join17(registryPath, "registry-manifest.yaml");
|
|
31970
32353
|
if (services.fs.existsSync(manifestPath)) {
|
|
31971
32354
|
const content = await services.fs.readFile(manifestPath, "utf-8");
|
|
31972
32355
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -32094,8 +32477,8 @@ async function registryListCommand() {
|
|
|
32094
32477
|
// packages/cli/src/commands/registry/add.ts
|
|
32095
32478
|
init_console();
|
|
32096
32479
|
import { readFile as readFile16, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
32097
|
-
import { existsSync as
|
|
32098
|
-
import { dirname as
|
|
32480
|
+
import { existsSync as existsSync17 } from "fs";
|
|
32481
|
+
import { dirname as dirname12 } from "path";
|
|
32099
32482
|
import { parse as parseYaml8, stringify as stringifyYaml } from "yaml";
|
|
32100
32483
|
init_user_config();
|
|
32101
32484
|
async function registryAddCommand(alias, url, options) {
|
|
@@ -32125,12 +32508,12 @@ async function registryAddCommand(alias, url, options) {
|
|
|
32125
32508
|
}
|
|
32126
32509
|
}
|
|
32127
32510
|
async function addToGlobalConfig(alias, url) {
|
|
32128
|
-
const configDir =
|
|
32129
|
-
if (!
|
|
32511
|
+
const configDir = dirname12(USER_CONFIG_PATH);
|
|
32512
|
+
if (!existsSync17(configDir)) {
|
|
32130
32513
|
await mkdir7(configDir, { recursive: true });
|
|
32131
32514
|
}
|
|
32132
32515
|
let config = { version: "1" };
|
|
32133
|
-
if (
|
|
32516
|
+
if (existsSync17(USER_CONFIG_PATH)) {
|
|
32134
32517
|
const content = await readFile16(USER_CONFIG_PATH, "utf-8");
|
|
32135
32518
|
const parsed = parseYaml8(content);
|
|
32136
32519
|
if (parsed && typeof parsed === "object") {
|
|
@@ -32180,8 +32563,8 @@ function registerRegistryCommands(registry2) {
|
|
|
32180
32563
|
|
|
32181
32564
|
// packages/cli/src/commands/lock.ts
|
|
32182
32565
|
import { writeFile as writeFile8, readFile as readFile18 } from "fs/promises";
|
|
32183
|
-
import { existsSync as
|
|
32184
|
-
import { resolve as
|
|
32566
|
+
import { existsSync as existsSync19 } from "fs";
|
|
32567
|
+
import { resolve as resolve16 } from "path";
|
|
32185
32568
|
import { parse as parseYaml9, stringify as stringifyYaml2 } from "yaml";
|
|
32186
32569
|
init_console();
|
|
32187
32570
|
init_src();
|
|
@@ -32189,9 +32572,9 @@ init_src();
|
|
|
32189
32572
|
// packages/cli/src/commands/lock-scanner.ts
|
|
32190
32573
|
init_src2();
|
|
32191
32574
|
import { readFile as readFile17 } from "fs/promises";
|
|
32192
|
-
import { existsSync as
|
|
32575
|
+
import { existsSync as existsSync18 } from "fs";
|
|
32193
32576
|
async function collectRemoteImports(entryPath, options) {
|
|
32194
|
-
if (!
|
|
32577
|
+
if (!existsSync18(entryPath)) {
|
|
32195
32578
|
return [];
|
|
32196
32579
|
}
|
|
32197
32580
|
const loader = new FileLoader({
|
|
@@ -32228,7 +32611,7 @@ async function collectRemoteImports(entryPath, options) {
|
|
|
32228
32611
|
results.push(marker);
|
|
32229
32612
|
}
|
|
32230
32613
|
} else {
|
|
32231
|
-
if (
|
|
32614
|
+
if (existsSync18(resolved)) {
|
|
32232
32615
|
await scan(resolved);
|
|
32233
32616
|
}
|
|
32234
32617
|
}
|
|
@@ -32254,8 +32637,8 @@ async function lockCommand(options) {
|
|
|
32254
32637
|
const aliases = config.registries ?? {};
|
|
32255
32638
|
const aliasEntries = Object.entries(aliases);
|
|
32256
32639
|
const projectRoot = process.cwd();
|
|
32257
|
-
const localPath =
|
|
32258
|
-
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");
|
|
32259
32642
|
const scannedImports = await collectRemoteImports(entryPath, {
|
|
32260
32643
|
localPath,
|
|
32261
32644
|
registries: config.registries
|
|
@@ -32266,7 +32649,7 @@ async function lockCommand(options) {
|
|
|
32266
32649
|
return;
|
|
32267
32650
|
}
|
|
32268
32651
|
let existing = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
32269
|
-
if (
|
|
32652
|
+
if (existsSync19(LOCKFILE_PATH)) {
|
|
32270
32653
|
try {
|
|
32271
32654
|
const raw = await readFile18(LOCKFILE_PATH, "utf-8");
|
|
32272
32655
|
const parsed = parseYaml9(raw, { maxAliasCount: 100 });
|
|
@@ -32335,7 +32718,7 @@ async function lockCommand(options) {
|
|
|
32335
32718
|
|
|
32336
32719
|
// packages/cli/src/commands/update.ts
|
|
32337
32720
|
import { writeFile as writeFile9, readFile as readFile19 } from "fs/promises";
|
|
32338
|
-
import { existsSync as
|
|
32721
|
+
import { existsSync as existsSync20 } from "fs";
|
|
32339
32722
|
import { parse as parseYaml10, stringify as stringifyYaml3 } from "yaml";
|
|
32340
32723
|
init_console();
|
|
32341
32724
|
init_src();
|
|
@@ -32358,7 +32741,7 @@ async function updateCommand(packageArg, options) {
|
|
|
32358
32741
|
return;
|
|
32359
32742
|
}
|
|
32360
32743
|
let existing = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
32361
|
-
if (
|
|
32744
|
+
if (existsSync20(LOCKFILE_PATH)) {
|
|
32362
32745
|
try {
|
|
32363
32746
|
const raw = await readFile19(LOCKFILE_PATH, "utf-8");
|
|
32364
32747
|
const parsed = parseYaml10(raw, { maxAliasCount: 100 });
|
|
@@ -32422,12 +32805,12 @@ async function updateCommand(packageArg, options) {
|
|
|
32422
32805
|
init_console();
|
|
32423
32806
|
init_src();
|
|
32424
32807
|
import { readFile as readFile20, writeFile as writeFile10, mkdir as mkdir8, readdir as readdir5 } from "fs/promises";
|
|
32425
|
-
import { existsSync as
|
|
32426
|
-
import { join as
|
|
32808
|
+
import { existsSync as existsSync21 } from "fs";
|
|
32809
|
+
import { join as join18, resolve as resolve17 } from "path";
|
|
32427
32810
|
import { homedir as homedir4 } from "os";
|
|
32428
32811
|
import { parse as parseYaml11 } from "yaml";
|
|
32429
32812
|
var VENDOR_DIR = ".promptscript/vendor";
|
|
32430
|
-
var CACHE_BASE =
|
|
32813
|
+
var CACHE_BASE = join18(homedir4(), ".promptscript", "cache", "registries");
|
|
32431
32814
|
async function vendorSyncCommand(options) {
|
|
32432
32815
|
const spinner = createSpinner("Syncing vendor directory...").start();
|
|
32433
32816
|
try {
|
|
@@ -32445,13 +32828,13 @@ async function vendorSyncCommand(options) {
|
|
|
32445
32828
|
}
|
|
32446
32829
|
const results = [];
|
|
32447
32830
|
for (const [repoUrl, dep] of deps) {
|
|
32448
|
-
const cacheDir =
|
|
32449
|
-
if (!
|
|
32831
|
+
const cacheDir = join18(CACHE_BASE, repoUrl.replace(/[/:]/g, "_"), dep.version);
|
|
32832
|
+
if (!existsSync21(cacheDir)) {
|
|
32450
32833
|
results.push({ repoUrl, status: "missing" });
|
|
32451
32834
|
continue;
|
|
32452
32835
|
}
|
|
32453
32836
|
if (!options.dryRun) {
|
|
32454
|
-
const vendorTarget =
|
|
32837
|
+
const vendorTarget = resolve17(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32455
32838
|
await mkdir8(vendorTarget, { recursive: true });
|
|
32456
32839
|
await copyDirectory(cacheDir, vendorTarget);
|
|
32457
32840
|
}
|
|
@@ -32497,7 +32880,7 @@ async function vendorCheckCommand(_options) {
|
|
|
32497
32880
|
spinner.warn("No dependencies in lockfile");
|
|
32498
32881
|
return;
|
|
32499
32882
|
}
|
|
32500
|
-
if (!
|
|
32883
|
+
if (!existsSync21(VENDOR_DIR)) {
|
|
32501
32884
|
spinner.fail("Vendor directory does not exist");
|
|
32502
32885
|
ConsoleOutput.muted("Run: prs vendor sync");
|
|
32503
32886
|
process.exitCode = 1;
|
|
@@ -32505,8 +32888,8 @@ async function vendorCheckCommand(_options) {
|
|
|
32505
32888
|
}
|
|
32506
32889
|
const issues = [];
|
|
32507
32890
|
for (const [repoUrl] of deps) {
|
|
32508
|
-
const vendorTarget =
|
|
32509
|
-
if (!
|
|
32891
|
+
const vendorTarget = resolve17(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32892
|
+
if (!existsSync21(vendorTarget)) {
|
|
32510
32893
|
issues.push({ repoUrl, issue: "missing from vendor directory" });
|
|
32511
32894
|
}
|
|
32512
32895
|
}
|
|
@@ -32529,7 +32912,7 @@ async function vendorCheckCommand(_options) {
|
|
|
32529
32912
|
}
|
|
32530
32913
|
}
|
|
32531
32914
|
async function loadLockfile() {
|
|
32532
|
-
if (!
|
|
32915
|
+
if (!existsSync21(LOCKFILE_PATH)) {
|
|
32533
32916
|
return null;
|
|
32534
32917
|
}
|
|
32535
32918
|
try {
|
|
@@ -32543,8 +32926,8 @@ async function loadLockfile() {
|
|
|
32543
32926
|
async function copyDirectory(src, dest) {
|
|
32544
32927
|
const entries = await readdir5(src, { withFileTypes: true });
|
|
32545
32928
|
for (const entry of entries) {
|
|
32546
|
-
const srcPath =
|
|
32547
|
-
const destPath =
|
|
32929
|
+
const srcPath = join18(src, entry.name);
|
|
32930
|
+
const destPath = join18(dest, entry.name);
|
|
32548
32931
|
if (entry.isDirectory()) {
|
|
32549
32932
|
await mkdir8(destPath, { recursive: true });
|
|
32550
32933
|
await copyDirectory(srcPath, destPath);
|
|
@@ -32556,12 +32939,12 @@ async function copyDirectory(src, dest) {
|
|
|
32556
32939
|
}
|
|
32557
32940
|
|
|
32558
32941
|
// packages/cli/src/commands/resolve-cmd.ts
|
|
32559
|
-
import { existsSync as
|
|
32560
|
-
import { join as
|
|
32942
|
+
import { existsSync as existsSync22 } from "fs";
|
|
32943
|
+
import { join as join19 } from "path";
|
|
32561
32944
|
import { homedir as homedir5 } from "os";
|
|
32562
32945
|
init_user_config();
|
|
32563
32946
|
init_console();
|
|
32564
|
-
var CACHE_BASE2 =
|
|
32947
|
+
var CACHE_BASE2 = join19(homedir5(), ".promptscript", "cache", "registries");
|
|
32565
32948
|
async function resolveCommand(importPath, _options) {
|
|
32566
32949
|
try {
|
|
32567
32950
|
const configFile = findConfigFile();
|
|
@@ -32603,11 +32986,11 @@ async function resolveCommand(importPath, _options) {
|
|
|
32603
32986
|
}
|
|
32604
32987
|
const { repoUrl, path, version } = expanded;
|
|
32605
32988
|
const cacheVersion = version ?? "latest";
|
|
32606
|
-
const cacheDir =
|
|
32607
|
-
const cacheExists =
|
|
32989
|
+
const cacheDir = join19(CACHE_BASE2, repoUrl.replace(/[/:]/g, "_"), cacheVersion);
|
|
32990
|
+
const cacheExists = existsSync22(cacheDir);
|
|
32608
32991
|
const filePath = path.endsWith(".prs") ? path : `${path}.prs`;
|
|
32609
|
-
const cachedFile =
|
|
32610
|
-
const fileExists3 = cacheExists &&
|
|
32992
|
+
const cachedFile = join19(cacheDir, filePath);
|
|
32993
|
+
const fileExists3 = cacheExists && existsSync22(cachedFile);
|
|
32611
32994
|
ConsoleOutput.newline();
|
|
32612
32995
|
console.log(` Alias: ${aliasName} \u2192 ${repoUrl}`);
|
|
32613
32996
|
console.log(` Repo: ${repoUrl}`);
|
|
@@ -32624,7 +33007,7 @@ async function resolveCommand(importPath, _options) {
|
|
|
32624
33007
|
ConsoleOutput.newline();
|
|
32625
33008
|
} else {
|
|
32626
33009
|
const resolvedPath = importPath.endsWith(".prs") ? importPath : `${importPath}.prs`;
|
|
32627
|
-
const exists =
|
|
33010
|
+
const exists = existsSync22(resolvedPath);
|
|
32628
33011
|
ConsoleOutput.newline();
|
|
32629
33012
|
console.log(` Import: ${importPath}`);
|
|
32630
33013
|
console.log(` Type: local file`);
|
|
@@ -32641,8 +33024,8 @@ async function resolveCommand(importPath, _options) {
|
|
|
32641
33024
|
}
|
|
32642
33025
|
|
|
32643
33026
|
// packages/cli/src/commands/inspect.ts
|
|
32644
|
-
import { existsSync as
|
|
32645
|
-
import { resolve as
|
|
33027
|
+
import { existsSync as existsSync23 } from "fs";
|
|
33028
|
+
import { resolve as resolve18, basename as basename13 } from "path";
|
|
32646
33029
|
init_console();
|
|
32647
33030
|
async function inspectCommand(skillName, options) {
|
|
32648
33031
|
const isJson = options.format === "json";
|
|
@@ -32655,8 +33038,8 @@ async function inspectCommand(skillName, options) {
|
|
|
32655
33038
|
localPath: "./.promptscript",
|
|
32656
33039
|
registries: config.registries
|
|
32657
33040
|
});
|
|
32658
|
-
const entryPath =
|
|
32659
|
-
if (!
|
|
33041
|
+
const entryPath = resolve18("./.promptscript/project.prs");
|
|
33042
|
+
if (!existsSync23(entryPath)) {
|
|
32660
33043
|
spinner.stop();
|
|
32661
33044
|
ConsoleOutput.error(`Entry file not found: ${entryPath}`);
|
|
32662
33045
|
process.exitCode = 1;
|
|
@@ -32728,7 +33111,7 @@ function summarizeValue(val) {
|
|
|
32728
33111
|
return String(val);
|
|
32729
33112
|
}
|
|
32730
33113
|
function shortPath(source) {
|
|
32731
|
-
return
|
|
33114
|
+
return basename13(source);
|
|
32732
33115
|
}
|
|
32733
33116
|
function getPropertySource(propName, trace, baseSource) {
|
|
32734
33117
|
for (let i = trace.length - 1; i >= 0; i--) {
|
|
@@ -32836,8 +33219,8 @@ init_console();
|
|
|
32836
33219
|
// packages/cli/src/commands/import.ts
|
|
32837
33220
|
init_src3();
|
|
32838
33221
|
init_console();
|
|
32839
|
-
import { resolve as
|
|
32840
|
-
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";
|
|
32841
33224
|
import { stat as stat2, readdir as readdir6, readFile as readFile21, writeFile as writeFile11, mkdir as mkdir9 } from "fs/promises";
|
|
32842
33225
|
function parseInstructionFrontmatter(content) {
|
|
32843
33226
|
const match = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/.exec(content);
|
|
@@ -32865,10 +33248,10 @@ async function importDirectory(dirPath) {
|
|
|
32865
33248
|
}
|
|
32866
33249
|
const lines = ["@meta {", ' version: "1.0"', "}", "", "@guards {"];
|
|
32867
33250
|
for (const filename of instructionFiles) {
|
|
32868
|
-
const filePath =
|
|
33251
|
+
const filePath = join20(dirPath, filename);
|
|
32869
33252
|
const content = await readFile21(filePath, "utf-8");
|
|
32870
33253
|
const frontmatter = parseInstructionFrontmatter(content);
|
|
32871
|
-
const entryName =
|
|
33254
|
+
const entryName = basename14(filename).replace(/\.instructions\.md$/i, "");
|
|
32872
33255
|
if (frontmatter) {
|
|
32873
33256
|
const globPatterns = frontmatter.applyTo.map((p) => `"${p}"`).join(", ");
|
|
32874
33257
|
lines.push(` ${entryName}(${globPatterns}) {`);
|
|
@@ -32891,7 +33274,7 @@ async function importDirectory(dirPath) {
|
|
|
32891
33274
|
return lines.join("\n");
|
|
32892
33275
|
}
|
|
32893
33276
|
async function importCommand(file, options) {
|
|
32894
|
-
const filepath =
|
|
33277
|
+
const filepath = resolve19(file);
|
|
32895
33278
|
const inputStat = await stat2(filepath).catch(() => null);
|
|
32896
33279
|
if (inputStat?.isDirectory()) {
|
|
32897
33280
|
const prsContent = await importDirectory(filepath);
|
|
@@ -32901,7 +33284,7 @@ async function importCommand(file, options) {
|
|
|
32901
33284
|
}
|
|
32902
33285
|
const outputDir = options.output ?? ".promptscript";
|
|
32903
33286
|
await mkdir9(outputDir, { recursive: true });
|
|
32904
|
-
const outputPath =
|
|
33287
|
+
const outputPath = join20(outputDir, "imported.prs");
|
|
32905
33288
|
await writeFile11(outputPath, prsContent);
|
|
32906
33289
|
console.log(`\u2714 Imported directory to ${outputPath}`);
|
|
32907
33290
|
return;
|
|
@@ -32923,11 +33306,11 @@ async function importCommand(file, options) {
|
|
|
32923
33306
|
console.log(result.prsContent);
|
|
32924
33307
|
return;
|
|
32925
33308
|
}
|
|
32926
|
-
const outputDir =
|
|
32927
|
-
if (!
|
|
33309
|
+
const outputDir = resolve19(options.output ?? ".promptscript");
|
|
33310
|
+
if (!existsSync24(outputDir)) {
|
|
32928
33311
|
mkdirSync(outputDir, { recursive: true });
|
|
32929
33312
|
}
|
|
32930
|
-
const outputPath =
|
|
33313
|
+
const outputPath = resolve19(outputDir, "imported.prs");
|
|
32931
33314
|
writeFileSync2(outputPath, result.prsContent, "utf-8");
|
|
32932
33315
|
ConsoleOutput.success(`Written to ${outputPath}`);
|
|
32933
33316
|
if (options.validate) {
|
|
@@ -33042,18 +33425,18 @@ async function detectMarker(filePath) {
|
|
|
33042
33425
|
}
|
|
33043
33426
|
|
|
33044
33427
|
// packages/cli/src/hooks/debounce-lock.ts
|
|
33045
|
-
import { createHash as
|
|
33046
|
-
import { existsSync as
|
|
33428
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
33429
|
+
import { existsSync as existsSync25, writeFileSync as writeFileSync4, unlinkSync, statSync } from "node:fs";
|
|
33047
33430
|
import { tmpdir } from "node:os";
|
|
33048
|
-
import { join as
|
|
33431
|
+
import { join as join21 } from "node:path";
|
|
33049
33432
|
var STALE_THRESHOLD_MS = 3e4;
|
|
33050
33433
|
function getLockPath(projectDir) {
|
|
33051
|
-
const hash =
|
|
33052
|
-
return
|
|
33434
|
+
const hash = createHash3("md5").update(projectDir).digest("hex").slice(0, 12);
|
|
33435
|
+
return join21(tmpdir(), `prs-compile-${hash}.lock`);
|
|
33053
33436
|
}
|
|
33054
33437
|
function acquireLock(projectDir) {
|
|
33055
33438
|
const lockPath = getLockPath(projectDir);
|
|
33056
|
-
if (
|
|
33439
|
+
if (existsSync25(lockPath)) {
|
|
33057
33440
|
try {
|
|
33058
33441
|
const stat4 = statSync(lockPath);
|
|
33059
33442
|
const age = Date.now() - stat4.mtimeMs;
|
|
@@ -33161,9 +33544,10 @@ Usage: echo '{"file_path":"..."}' | prs hook ${action}
|
|
|
33161
33544
|
init_hooks();
|
|
33162
33545
|
|
|
33163
33546
|
// packages/cli/src/commands/skills.ts
|
|
33164
|
-
import { writeFile as writeFile12, readFile as readFile23, readdir as readdir7 } from "fs/promises";
|
|
33165
|
-
import { resolve as
|
|
33166
|
-
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";
|
|
33167
33551
|
import { parse as parseYaml12, stringify as stringifyYaml4 } from "yaml";
|
|
33168
33552
|
init_console();
|
|
33169
33553
|
init_src();
|
|
@@ -33183,6 +33567,77 @@ function normalizeSkillSource(input2) {
|
|
|
33183
33567
|
}
|
|
33184
33568
|
return source;
|
|
33185
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
|
+
}
|
|
33186
33641
|
var HEADER_DIRECTIVES = ["@use ", "@inherit ", "@meta "];
|
|
33187
33642
|
function extractRepoUrl(source) {
|
|
33188
33643
|
const parts = source.replace(/^https?:\/\//, "").split("/");
|
|
@@ -33210,8 +33665,8 @@ function validateRemoteSource(source) {
|
|
|
33210
33665
|
}
|
|
33211
33666
|
async function resolveEntryFile(fileFlag) {
|
|
33212
33667
|
if (fileFlag) {
|
|
33213
|
-
const resolved =
|
|
33214
|
-
if (!
|
|
33668
|
+
const resolved = resolve20(fileFlag);
|
|
33669
|
+
if (!existsSync26(resolved)) {
|
|
33215
33670
|
throw new Error(`File not found: ${resolved}`);
|
|
33216
33671
|
}
|
|
33217
33672
|
return resolved;
|
|
@@ -33221,24 +33676,24 @@ async function resolveEntryFile(fileFlag) {
|
|
|
33221
33676
|
try {
|
|
33222
33677
|
const config = await loadConfig();
|
|
33223
33678
|
if (config.input?.entry) {
|
|
33224
|
-
const entryPath =
|
|
33225
|
-
if (
|
|
33679
|
+
const entryPath = resolve20(config.input.entry);
|
|
33680
|
+
if (existsSync26(entryPath)) {
|
|
33226
33681
|
return entryPath;
|
|
33227
33682
|
}
|
|
33228
33683
|
}
|
|
33229
33684
|
} catch {
|
|
33230
33685
|
}
|
|
33231
33686
|
}
|
|
33232
|
-
const promptscriptDir =
|
|
33233
|
-
if (
|
|
33687
|
+
const promptscriptDir = resolve20(".promptscript");
|
|
33688
|
+
if (existsSync26(promptscriptDir)) {
|
|
33234
33689
|
const entries = await readdir7(promptscriptDir);
|
|
33235
33690
|
const prsFiles = entries.filter((f) => f.endsWith(".prs"));
|
|
33236
33691
|
if (prsFiles.length === 1) {
|
|
33237
|
-
return
|
|
33692
|
+
return resolve20(promptscriptDir, prsFiles[0]);
|
|
33238
33693
|
}
|
|
33239
33694
|
if (prsFiles.length > 1) {
|
|
33240
33695
|
if (prsFiles.includes("project.prs")) {
|
|
33241
|
-
return
|
|
33696
|
+
return resolve20(promptscriptDir, "project.prs");
|
|
33242
33697
|
}
|
|
33243
33698
|
throw new Error(
|
|
33244
33699
|
`Multiple .prs files found in .promptscript/. Use --file to specify which one.`
|
|
@@ -33282,7 +33737,7 @@ function extractUsePath(line) {
|
|
|
33282
33737
|
}
|
|
33283
33738
|
async function loadLockfile2() {
|
|
33284
33739
|
const defaultLockfile = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
33285
|
-
if (!
|
|
33740
|
+
if (!existsSync26(LOCKFILE_PATH)) {
|
|
33286
33741
|
return defaultLockfile;
|
|
33287
33742
|
}
|
|
33288
33743
|
try {
|
|
@@ -33301,6 +33756,14 @@ async function saveLockfile(lockfile) {
|
|
|
33301
33756
|
async function skillsAddCommand(rawSource, options) {
|
|
33302
33757
|
const spinner = createSpinner("Adding skill...").start();
|
|
33303
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
|
+
}
|
|
33304
33767
|
const source = normalizeSkillSource(rawSource);
|
|
33305
33768
|
const sourceError = validateRemoteSource(source);
|
|
33306
33769
|
if (sourceError) {
|
|
@@ -33329,15 +33792,52 @@ async function skillsAddCommand(rawSource, options) {
|
|
|
33329
33792
|
process.exitCode = 1;
|
|
33330
33793
|
return;
|
|
33331
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;
|
|
33332
33833
|
const insertionPoint = findInsertionPoint(lines);
|
|
33333
33834
|
const newLine = `@use ${source}`;
|
|
33334
33835
|
lines.splice(insertionPoint, 0, newLine);
|
|
33335
33836
|
const updatedContent = lines.join("\n");
|
|
33336
|
-
const lockfile = await loadLockfile2();
|
|
33337
33837
|
const lockEntry = {
|
|
33338
33838
|
version: "latest",
|
|
33339
33839
|
commit: validation.headCommit ?? "0000000000000000000000000000000000000000",
|
|
33340
|
-
integrity
|
|
33840
|
+
integrity,
|
|
33341
33841
|
source: "md"
|
|
33342
33842
|
};
|
|
33343
33843
|
lockfile.dependencies[source] = lockEntry;
|
|
@@ -33465,10 +33965,39 @@ async function skillsUpdateCommand(name, options) {
|
|
|
33465
33965
|
});
|
|
33466
33966
|
continue;
|
|
33467
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
|
+
}
|
|
33468
33997
|
lockfile.dependencies[key] = {
|
|
33469
33998
|
version: dep.version ?? "latest",
|
|
33470
33999
|
commit: validation.headCommit,
|
|
33471
|
-
integrity
|
|
34000
|
+
integrity,
|
|
33472
34001
|
source: "md",
|
|
33473
34002
|
fetchedAt
|
|
33474
34003
|
};
|
|
@@ -33515,7 +34044,7 @@ async function skillsUpdateCommand(name, options) {
|
|
|
33515
34044
|
|
|
33516
34045
|
// packages/cli/src/cli.ts
|
|
33517
34046
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
33518
|
-
var __dirname4 =
|
|
34047
|
+
var __dirname4 = dirname16(__filename4);
|
|
33519
34048
|
var program = new Command();
|
|
33520
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) => {
|
|
33521
34050
|
const opts = thisCommand.opts();
|
|
@@ -33574,10 +34103,10 @@ program.command("resolve <import>").description("Show full resolution chain for
|
|
|
33574
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);
|
|
33575
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);
|
|
33576
34105
|
var skills = program.command("skills").description("Manage PromptScript skills");
|
|
33577
|
-
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));
|
|
33578
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));
|
|
33579
34108
|
skills.command("list").description("List skills imported in the current project").action(() => skillsListCommand());
|
|
33580
|
-
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));
|
|
33581
34110
|
var registry = program.command("registry").description("Manage PromptScript registries");
|
|
33582
34111
|
registerRegistryCommands(registry);
|
|
33583
34112
|
function run(args = process.argv) {
|