@promptscript/cli 1.13.0 → 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/prs.js +3 -1
- package/index.js +680 -314
- package/package.json +4 -4
- package/src/commands/compile.d.ts.map +1 -1
- package/src/commands/hooks.d.ts +6 -0
- package/src/commands/hooks.d.ts.map +1 -1
- package/src/commands/registry/index.d.ts.map +1 -1
- package/src/commands/update.d.ts.map +1 -1
- package/src/types.d.ts +2 -0
- package/src/types.d.ts.map +1 -1
- package/src/utils/registry-scaffolder.d.ts +2 -0
- package/src/utils/registry-scaffolder.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -4,11 +4,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __esm = (fn, res) => function __init() {
|
|
8
|
-
|
|
7
|
+
var __esm = (fn, res, err) => function __init() {
|
|
8
|
+
if (err) throw err[0];
|
|
9
|
+
try {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
} catch (e) {
|
|
12
|
+
throw err = [e], e;
|
|
13
|
+
}
|
|
9
14
|
};
|
|
10
15
|
var __commonJS = (cb, mod) => function __require() {
|
|
11
|
-
|
|
16
|
+
try {
|
|
17
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
throw mod = 0, e;
|
|
20
|
+
}
|
|
12
21
|
};
|
|
13
22
|
var __export = (target, all) => {
|
|
14
23
|
for (var name in all)
|
|
@@ -1406,6 +1415,12 @@ var init_mapper = __esm({
|
|
|
1406
1415
|
});
|
|
1407
1416
|
|
|
1408
1417
|
// packages/importer/src/emitter.ts
|
|
1418
|
+
function resolveQuoteDelimiter(content) {
|
|
1419
|
+
const matches = content.match(/"+/g);
|
|
1420
|
+
if (!matches) return '"""';
|
|
1421
|
+
const maxRun = matches.reduce((max, m) => Math.max(max, m.length), 0);
|
|
1422
|
+
return '"'.repeat(Math.max(3, maxRun + 1));
|
|
1423
|
+
}
|
|
1409
1424
|
function emitPrs(sections, options) {
|
|
1410
1425
|
const lines = [];
|
|
1411
1426
|
lines.push("@meta {");
|
|
@@ -1431,11 +1446,12 @@ function emitPrs(sections, options) {
|
|
|
1431
1446
|
lines.push(` ${entryName}: {`);
|
|
1432
1447
|
lines.push(` applyTo: [${applyToStr}]`);
|
|
1433
1448
|
lines.push(` description: "${description}"`);
|
|
1434
|
-
|
|
1449
|
+
const contentDelimiter2 = resolveQuoteDelimiter(section.content);
|
|
1450
|
+
lines.push(` content: ${contentDelimiter2}`);
|
|
1435
1451
|
for (const contentLine of section.content.split("\n")) {
|
|
1436
1452
|
lines.push(` ${contentLine}`);
|
|
1437
1453
|
}
|
|
1438
|
-
lines.push(`
|
|
1454
|
+
lines.push(` ${contentDelimiter2}`);
|
|
1439
1455
|
lines.push(` }`);
|
|
1440
1456
|
}
|
|
1441
1457
|
lines.push(`}`);
|
|
@@ -1444,11 +1460,12 @@ function emitPrs(sections, options) {
|
|
|
1444
1460
|
}
|
|
1445
1461
|
lines.push(`@${block} {`);
|
|
1446
1462
|
const mergedContent = blockSections.map((s) => s.content).join("\n\n");
|
|
1447
|
-
|
|
1463
|
+
const contentDelimiter = resolveQuoteDelimiter(mergedContent);
|
|
1464
|
+
lines.push(` ${contentDelimiter}`);
|
|
1448
1465
|
for (const contentLine of mergedContent.split("\n")) {
|
|
1449
1466
|
lines.push(` ${contentLine}`);
|
|
1450
1467
|
}
|
|
1451
|
-
lines.push(`
|
|
1468
|
+
lines.push(` ${contentDelimiter}`);
|
|
1452
1469
|
lines.push("}");
|
|
1453
1470
|
}
|
|
1454
1471
|
lines.push("");
|
|
@@ -1488,11 +1505,12 @@ function emitModularFiles(blocks, options) {
|
|
|
1488
1505
|
lines.push("# REVIEW: low confidence -- verify this mapping");
|
|
1489
1506
|
}
|
|
1490
1507
|
lines.push(`@${block.targetBlock} {`);
|
|
1491
|
-
|
|
1508
|
+
const blockDelimiter = resolveQuoteDelimiter(block.content);
|
|
1509
|
+
lines.push(` ${blockDelimiter}`);
|
|
1492
1510
|
for (const contentLine of block.content.split("\n")) {
|
|
1493
1511
|
lines.push(` ${contentLine}`);
|
|
1494
1512
|
}
|
|
1495
|
-
lines.push(
|
|
1513
|
+
lines.push(` ${blockDelimiter}`);
|
|
1496
1514
|
lines.push("}");
|
|
1497
1515
|
lines.push("");
|
|
1498
1516
|
}
|
|
@@ -1516,11 +1534,12 @@ function emitModularFiles(blocks, options) {
|
|
|
1516
1534
|
projectLines.push(comment);
|
|
1517
1535
|
}
|
|
1518
1536
|
projectLines.push("@identity {");
|
|
1519
|
-
|
|
1537
|
+
const identityDelimiter = resolveQuoteDelimiter(identity.content);
|
|
1538
|
+
projectLines.push(` ${identityDelimiter}`);
|
|
1520
1539
|
for (const line of identity.content.split("\n")) {
|
|
1521
1540
|
projectLines.push(` ${line}`);
|
|
1522
1541
|
}
|
|
1523
|
-
projectLines.push(
|
|
1542
|
+
projectLines.push(` ${identityDelimiter}`);
|
|
1524
1543
|
projectLines.push("}");
|
|
1525
1544
|
}
|
|
1526
1545
|
projectLines.push("");
|
|
@@ -8913,6 +8932,7 @@ var init_parser2 = __esm({
|
|
|
8913
8932
|
{ ALT: () => this.SUBRULE(this.block) }
|
|
8914
8933
|
])
|
|
8915
8934
|
);
|
|
8935
|
+
this.CONSUME(EOF);
|
|
8916
8936
|
});
|
|
8917
8937
|
/**
|
|
8918
8938
|
* metaBlock
|
|
@@ -10084,6 +10104,12 @@ ${s.content}`);
|
|
|
10084
10104
|
reviewComments: []
|
|
10085
10105
|
};
|
|
10086
10106
|
}
|
|
10107
|
+
function isStructuralMarker(line) {
|
|
10108
|
+
const trimmed = line.trim();
|
|
10109
|
+
if (/^```[^\s`]*$/.test(trimmed)) return true;
|
|
10110
|
+
if (/^(---|\*\*\*|___)$/.test(trimmed)) return true;
|
|
10111
|
+
return false;
|
|
10112
|
+
}
|
|
10087
10113
|
function mergeUnion(sections) {
|
|
10088
10114
|
const seenLines = /* @__PURE__ */ new Set();
|
|
10089
10115
|
const uniqueLines = [];
|
|
@@ -10093,6 +10119,10 @@ function mergeUnion(sections) {
|
|
|
10093
10119
|
for (const line of lines) {
|
|
10094
10120
|
const normalized = line.trim().replace(/\s+/g, " ");
|
|
10095
10121
|
if (normalized.length === 0) continue;
|
|
10122
|
+
if (isStructuralMarker(line)) {
|
|
10123
|
+
uniqueLines.push(line);
|
|
10124
|
+
continue;
|
|
10125
|
+
}
|
|
10096
10126
|
if (seenLines.has(normalized)) {
|
|
10097
10127
|
deduped++;
|
|
10098
10128
|
continue;
|
|
@@ -11774,11 +11804,18 @@ var init_base_formatter = __esm({
|
|
|
11774
11804
|
referenceProvenance(sourcePath) {
|
|
11775
11805
|
return `<!-- from: ${sourcePath} -->`;
|
|
11776
11806
|
}
|
|
11807
|
+
/**
|
|
11808
|
+
* Check if a name is safe for use in file paths.
|
|
11809
|
+
* Rejects path traversal sequences and path separators.
|
|
11810
|
+
*/
|
|
11811
|
+
isSafeName(name) {
|
|
11812
|
+
return !name.includes("..") && !name.includes("/") && !name.includes("\\");
|
|
11813
|
+
}
|
|
11777
11814
|
/**
|
|
11778
11815
|
* Check if a skill name is safe for use in file paths.
|
|
11779
11816
|
*/
|
|
11780
11817
|
isSafeSkillName(name) {
|
|
11781
|
-
return
|
|
11818
|
+
return this.isSafeName(name);
|
|
11782
11819
|
}
|
|
11783
11820
|
/**
|
|
11784
11821
|
* Render content inside a code fence, using a longer fence if the content
|
|
@@ -11952,9 +11989,11 @@ var init_markdown_instruction_formatter = __esm({
|
|
|
11952
11989
|
if ("type" in value && value["type"] === "TextContent") {
|
|
11953
11990
|
const content = this.valueToString(value);
|
|
11954
11991
|
if (content.includes("\n")) {
|
|
11992
|
+
const cmdName = name.replace(/^\/+/, "");
|
|
11993
|
+
if (!this.isSafeName(cmdName)) continue;
|
|
11955
11994
|
commands.push({
|
|
11956
|
-
name:
|
|
11957
|
-
description:
|
|
11995
|
+
name: cmdName,
|
|
11996
|
+
description: cmdName,
|
|
11958
11997
|
content
|
|
11959
11998
|
});
|
|
11960
11999
|
}
|
|
@@ -11962,8 +12001,10 @@ var init_markdown_instruction_formatter = __esm({
|
|
|
11962
12001
|
}
|
|
11963
12002
|
const obj = value;
|
|
11964
12003
|
if (obj["prompt"] === true || obj["content"]) {
|
|
12004
|
+
const cmdName = name.replace(/^\/+/, "");
|
|
12005
|
+
if (!this.isSafeName(cmdName)) continue;
|
|
11965
12006
|
commands.push({
|
|
11966
|
-
name:
|
|
12007
|
+
name: cmdName,
|
|
11967
12008
|
description: obj["description"] ? this.valueToString(obj["description"]) : name,
|
|
11968
12009
|
argumentHint: obj["argumentHint"] ? this.valueToString(obj["argumentHint"]) : void 0,
|
|
11969
12010
|
content: obj["content"] ? this.valueToString(obj["content"]) : ""
|
|
@@ -18392,11 +18433,21 @@ function detectTools() {
|
|
|
18392
18433
|
);
|
|
18393
18434
|
}
|
|
18394
18435
|
async function readSettingsFile(path) {
|
|
18436
|
+
let content;
|
|
18437
|
+
try {
|
|
18438
|
+
content = await readFile4(path, "utf-8");
|
|
18439
|
+
} catch (err) {
|
|
18440
|
+
const nodeErr = err;
|
|
18441
|
+
if (nodeErr.code === "ENOENT") {
|
|
18442
|
+
return {};
|
|
18443
|
+
}
|
|
18444
|
+
throw err;
|
|
18445
|
+
}
|
|
18395
18446
|
try {
|
|
18396
|
-
const content = await readFile4(path, "utf-8");
|
|
18397
18447
|
return JSON.parse(content);
|
|
18398
|
-
} catch {
|
|
18399
|
-
|
|
18448
|
+
} catch (err) {
|
|
18449
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18450
|
+
throw new Error(`Failed to parse settings file ${path}: ${message}`, { cause: err });
|
|
18400
18451
|
}
|
|
18401
18452
|
}
|
|
18402
18453
|
async function writeSettingsFile(path, data) {
|
|
@@ -19889,9 +19940,9 @@ var require_dist = __commonJS({
|
|
|
19889
19940
|
}
|
|
19890
19941
|
});
|
|
19891
19942
|
|
|
19892
|
-
// node_modules/.pnpm/toad-cache@3.7.
|
|
19943
|
+
// node_modules/.pnpm/toad-cache@3.7.1/node_modules/toad-cache/dist/toad-cache.cjs
|
|
19893
19944
|
var require_toad_cache = __commonJS({
|
|
19894
|
-
"node_modules/.pnpm/toad-cache@3.7.
|
|
19945
|
+
"node_modules/.pnpm/toad-cache@3.7.1/node_modules/toad-cache/dist/toad-cache.cjs"(exports) {
|
|
19895
19946
|
"use strict";
|
|
19896
19947
|
var FifoMap = class {
|
|
19897
19948
|
constructor(max = 1e3, ttlInMsecs = 0) {
|
|
@@ -20002,6 +20053,155 @@ var require_toad_cache = __commonJS({
|
|
|
20002
20053
|
this.last = item;
|
|
20003
20054
|
}
|
|
20004
20055
|
};
|
|
20056
|
+
var FifoObject = class {
|
|
20057
|
+
constructor(max = 1e3, ttlInMsecs = 0) {
|
|
20058
|
+
if (isNaN(max) || max < 0) {
|
|
20059
|
+
throw new Error("Invalid max value");
|
|
20060
|
+
}
|
|
20061
|
+
if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
|
|
20062
|
+
throw new Error("Invalid ttl value");
|
|
20063
|
+
}
|
|
20064
|
+
this.first = null;
|
|
20065
|
+
this.items = /* @__PURE__ */ Object.create(null);
|
|
20066
|
+
this.last = null;
|
|
20067
|
+
this.size = 0;
|
|
20068
|
+
this.max = max;
|
|
20069
|
+
this.ttl = ttlInMsecs;
|
|
20070
|
+
}
|
|
20071
|
+
clear() {
|
|
20072
|
+
this.items = /* @__PURE__ */ Object.create(null);
|
|
20073
|
+
this.first = null;
|
|
20074
|
+
this.last = null;
|
|
20075
|
+
this.size = 0;
|
|
20076
|
+
}
|
|
20077
|
+
delete(key) {
|
|
20078
|
+
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20079
|
+
const deletedItem = this.items[key];
|
|
20080
|
+
delete this.items[key];
|
|
20081
|
+
this.size--;
|
|
20082
|
+
if (deletedItem.prev !== null) {
|
|
20083
|
+
deletedItem.prev.next = deletedItem.next;
|
|
20084
|
+
}
|
|
20085
|
+
if (deletedItem.next !== null) {
|
|
20086
|
+
deletedItem.next.prev = deletedItem.prev;
|
|
20087
|
+
}
|
|
20088
|
+
if (this.first === deletedItem) {
|
|
20089
|
+
this.first = deletedItem.next;
|
|
20090
|
+
}
|
|
20091
|
+
if (this.last === deletedItem) {
|
|
20092
|
+
this.last = deletedItem.prev;
|
|
20093
|
+
}
|
|
20094
|
+
}
|
|
20095
|
+
}
|
|
20096
|
+
deleteMany(keys) {
|
|
20097
|
+
for (var i = 0; i < keys.length; i++) {
|
|
20098
|
+
this.delete(keys[i]);
|
|
20099
|
+
}
|
|
20100
|
+
}
|
|
20101
|
+
evict() {
|
|
20102
|
+
if (this.size > 0) {
|
|
20103
|
+
const item = this.first;
|
|
20104
|
+
delete this.items[item.key];
|
|
20105
|
+
if (--this.size === 0) {
|
|
20106
|
+
this.first = null;
|
|
20107
|
+
this.last = null;
|
|
20108
|
+
} else {
|
|
20109
|
+
this.first = item.next;
|
|
20110
|
+
this.first.prev = null;
|
|
20111
|
+
}
|
|
20112
|
+
}
|
|
20113
|
+
}
|
|
20114
|
+
expiresAt(key) {
|
|
20115
|
+
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20116
|
+
return this.items[key].expiry;
|
|
20117
|
+
}
|
|
20118
|
+
}
|
|
20119
|
+
get(key) {
|
|
20120
|
+
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20121
|
+
const item = this.items[key];
|
|
20122
|
+
if (this.ttl > 0 && item.expiry <= Date.now()) {
|
|
20123
|
+
this.delete(key);
|
|
20124
|
+
return;
|
|
20125
|
+
}
|
|
20126
|
+
return item.value;
|
|
20127
|
+
}
|
|
20128
|
+
}
|
|
20129
|
+
getMany(keys) {
|
|
20130
|
+
const result = [];
|
|
20131
|
+
for (var i = 0; i < keys.length; i++) {
|
|
20132
|
+
result.push(this.get(keys[i]));
|
|
20133
|
+
}
|
|
20134
|
+
return result;
|
|
20135
|
+
}
|
|
20136
|
+
keys() {
|
|
20137
|
+
return Object.keys(this.items);
|
|
20138
|
+
}
|
|
20139
|
+
set(key, value) {
|
|
20140
|
+
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20141
|
+
const item2 = this.items[key];
|
|
20142
|
+
item2.value = value;
|
|
20143
|
+
item2.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
|
|
20144
|
+
return;
|
|
20145
|
+
}
|
|
20146
|
+
if (this.max > 0 && this.size === this.max) {
|
|
20147
|
+
this.evict();
|
|
20148
|
+
}
|
|
20149
|
+
const item = {
|
|
20150
|
+
expiry: this.ttl > 0 ? Date.now() + this.ttl : this.ttl,
|
|
20151
|
+
key,
|
|
20152
|
+
prev: this.last,
|
|
20153
|
+
next: null,
|
|
20154
|
+
value
|
|
20155
|
+
};
|
|
20156
|
+
this.items[key] = item;
|
|
20157
|
+
if (++this.size === 1) {
|
|
20158
|
+
this.first = item;
|
|
20159
|
+
} else {
|
|
20160
|
+
this.last.next = item;
|
|
20161
|
+
}
|
|
20162
|
+
this.last = item;
|
|
20163
|
+
}
|
|
20164
|
+
};
|
|
20165
|
+
var HitStatisticsRecord = class {
|
|
20166
|
+
constructor() {
|
|
20167
|
+
this.records = {};
|
|
20168
|
+
}
|
|
20169
|
+
initForCache(cacheId, currentTimeStamp) {
|
|
20170
|
+
this.records[cacheId] = {
|
|
20171
|
+
[currentTimeStamp]: {
|
|
20172
|
+
cacheSize: 0,
|
|
20173
|
+
hits: 0,
|
|
20174
|
+
falsyHits: 0,
|
|
20175
|
+
emptyHits: 0,
|
|
20176
|
+
misses: 0,
|
|
20177
|
+
expirations: 0,
|
|
20178
|
+
evictions: 0,
|
|
20179
|
+
invalidateOne: 0,
|
|
20180
|
+
invalidateAll: 0,
|
|
20181
|
+
sets: 0
|
|
20182
|
+
}
|
|
20183
|
+
};
|
|
20184
|
+
}
|
|
20185
|
+
resetForCache(cacheId) {
|
|
20186
|
+
for (let key of Object.keys(this.records[cacheId])) {
|
|
20187
|
+
this.records[cacheId][key] = {
|
|
20188
|
+
cacheSize: 0,
|
|
20189
|
+
hits: 0,
|
|
20190
|
+
falsyHits: 0,
|
|
20191
|
+
emptyHits: 0,
|
|
20192
|
+
misses: 0,
|
|
20193
|
+
expirations: 0,
|
|
20194
|
+
evictions: 0,
|
|
20195
|
+
invalidateOne: 0,
|
|
20196
|
+
invalidateAll: 0,
|
|
20197
|
+
sets: 0
|
|
20198
|
+
};
|
|
20199
|
+
}
|
|
20200
|
+
}
|
|
20201
|
+
getStatistics() {
|
|
20202
|
+
return this.records;
|
|
20203
|
+
}
|
|
20204
|
+
};
|
|
20005
20205
|
var LruMap = class {
|
|
20006
20206
|
constructor(max = 1e3, ttlInMsecs = 0) {
|
|
20007
20207
|
if (isNaN(max) || max < 0) {
|
|
@@ -20270,46 +20470,6 @@ var require_toad_cache = __commonJS({
|
|
|
20270
20470
|
this.last = item;
|
|
20271
20471
|
}
|
|
20272
20472
|
};
|
|
20273
|
-
var HitStatisticsRecord = class {
|
|
20274
|
-
constructor() {
|
|
20275
|
-
this.records = {};
|
|
20276
|
-
}
|
|
20277
|
-
initForCache(cacheId, currentTimeStamp) {
|
|
20278
|
-
this.records[cacheId] = {
|
|
20279
|
-
[currentTimeStamp]: {
|
|
20280
|
-
cacheSize: 0,
|
|
20281
|
-
hits: 0,
|
|
20282
|
-
falsyHits: 0,
|
|
20283
|
-
emptyHits: 0,
|
|
20284
|
-
misses: 0,
|
|
20285
|
-
expirations: 0,
|
|
20286
|
-
evictions: 0,
|
|
20287
|
-
invalidateOne: 0,
|
|
20288
|
-
invalidateAll: 0,
|
|
20289
|
-
sets: 0
|
|
20290
|
-
}
|
|
20291
|
-
};
|
|
20292
|
-
}
|
|
20293
|
-
resetForCache(cacheId) {
|
|
20294
|
-
for (let key of Object.keys(this.records[cacheId])) {
|
|
20295
|
-
this.records[cacheId][key] = {
|
|
20296
|
-
cacheSize: 0,
|
|
20297
|
-
hits: 0,
|
|
20298
|
-
falsyHits: 0,
|
|
20299
|
-
emptyHits: 0,
|
|
20300
|
-
misses: 0,
|
|
20301
|
-
expirations: 0,
|
|
20302
|
-
evictions: 0,
|
|
20303
|
-
invalidateOne: 0,
|
|
20304
|
-
invalidateAll: 0,
|
|
20305
|
-
sets: 0
|
|
20306
|
-
};
|
|
20307
|
-
}
|
|
20308
|
-
}
|
|
20309
|
-
getStatistics() {
|
|
20310
|
-
return this.records;
|
|
20311
|
-
}
|
|
20312
|
-
};
|
|
20313
20473
|
function getTimestamp(date) {
|
|
20314
20474
|
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
|
|
20315
20475
|
}
|
|
@@ -20451,115 +20611,6 @@ var require_toad_cache = __commonJS({
|
|
|
20451
20611
|
this.hitStatistics.addMiss();
|
|
20452
20612
|
}
|
|
20453
20613
|
};
|
|
20454
|
-
var FifoObject = class {
|
|
20455
|
-
constructor(max = 1e3, ttlInMsecs = 0) {
|
|
20456
|
-
if (isNaN(max) || max < 0) {
|
|
20457
|
-
throw new Error("Invalid max value");
|
|
20458
|
-
}
|
|
20459
|
-
if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
|
|
20460
|
-
throw new Error("Invalid ttl value");
|
|
20461
|
-
}
|
|
20462
|
-
this.first = null;
|
|
20463
|
-
this.items = /* @__PURE__ */ Object.create(null);
|
|
20464
|
-
this.last = null;
|
|
20465
|
-
this.size = 0;
|
|
20466
|
-
this.max = max;
|
|
20467
|
-
this.ttl = ttlInMsecs;
|
|
20468
|
-
}
|
|
20469
|
-
clear() {
|
|
20470
|
-
this.items = /* @__PURE__ */ Object.create(null);
|
|
20471
|
-
this.first = null;
|
|
20472
|
-
this.last = null;
|
|
20473
|
-
this.size = 0;
|
|
20474
|
-
}
|
|
20475
|
-
delete(key) {
|
|
20476
|
-
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20477
|
-
const deletedItem = this.items[key];
|
|
20478
|
-
delete this.items[key];
|
|
20479
|
-
this.size--;
|
|
20480
|
-
if (deletedItem.prev !== null) {
|
|
20481
|
-
deletedItem.prev.next = deletedItem.next;
|
|
20482
|
-
}
|
|
20483
|
-
if (deletedItem.next !== null) {
|
|
20484
|
-
deletedItem.next.prev = deletedItem.prev;
|
|
20485
|
-
}
|
|
20486
|
-
if (this.first === deletedItem) {
|
|
20487
|
-
this.first = deletedItem.next;
|
|
20488
|
-
}
|
|
20489
|
-
if (this.last === deletedItem) {
|
|
20490
|
-
this.last = deletedItem.prev;
|
|
20491
|
-
}
|
|
20492
|
-
}
|
|
20493
|
-
}
|
|
20494
|
-
deleteMany(keys) {
|
|
20495
|
-
for (var i = 0; i < keys.length; i++) {
|
|
20496
|
-
this.delete(keys[i]);
|
|
20497
|
-
}
|
|
20498
|
-
}
|
|
20499
|
-
evict() {
|
|
20500
|
-
if (this.size > 0) {
|
|
20501
|
-
const item = this.first;
|
|
20502
|
-
delete this.items[item.key];
|
|
20503
|
-
if (--this.size === 0) {
|
|
20504
|
-
this.first = null;
|
|
20505
|
-
this.last = null;
|
|
20506
|
-
} else {
|
|
20507
|
-
this.first = item.next;
|
|
20508
|
-
this.first.prev = null;
|
|
20509
|
-
}
|
|
20510
|
-
}
|
|
20511
|
-
}
|
|
20512
|
-
expiresAt(key) {
|
|
20513
|
-
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20514
|
-
return this.items[key].expiry;
|
|
20515
|
-
}
|
|
20516
|
-
}
|
|
20517
|
-
get(key) {
|
|
20518
|
-
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20519
|
-
const item = this.items[key];
|
|
20520
|
-
if (this.ttl > 0 && item.expiry <= Date.now()) {
|
|
20521
|
-
this.delete(key);
|
|
20522
|
-
return;
|
|
20523
|
-
}
|
|
20524
|
-
return item.value;
|
|
20525
|
-
}
|
|
20526
|
-
}
|
|
20527
|
-
getMany(keys) {
|
|
20528
|
-
const result = [];
|
|
20529
|
-
for (var i = 0; i < keys.length; i++) {
|
|
20530
|
-
result.push(this.get(keys[i]));
|
|
20531
|
-
}
|
|
20532
|
-
return result;
|
|
20533
|
-
}
|
|
20534
|
-
keys() {
|
|
20535
|
-
return Object.keys(this.items);
|
|
20536
|
-
}
|
|
20537
|
-
set(key, value) {
|
|
20538
|
-
if (Object.prototype.hasOwnProperty.call(this.items, key)) {
|
|
20539
|
-
const item2 = this.items[key];
|
|
20540
|
-
item2.value = value;
|
|
20541
|
-
item2.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
|
|
20542
|
-
return;
|
|
20543
|
-
}
|
|
20544
|
-
if (this.max > 0 && this.size === this.max) {
|
|
20545
|
-
this.evict();
|
|
20546
|
-
}
|
|
20547
|
-
const item = {
|
|
20548
|
-
expiry: this.ttl > 0 ? Date.now() + this.ttl : this.ttl,
|
|
20549
|
-
key,
|
|
20550
|
-
prev: this.last,
|
|
20551
|
-
next: null,
|
|
20552
|
-
value
|
|
20553
|
-
};
|
|
20554
|
-
this.items[key] = item;
|
|
20555
|
-
if (++this.size === 1) {
|
|
20556
|
-
this.first = item;
|
|
20557
|
-
} else {
|
|
20558
|
-
this.last.next = item;
|
|
20559
|
-
}
|
|
20560
|
-
this.last = item;
|
|
20561
|
-
}
|
|
20562
|
-
};
|
|
20563
20614
|
exports.Fifo = FifoObject;
|
|
20564
20615
|
exports.FifoMap = FifoMap;
|
|
20565
20616
|
exports.FifoObject = FifoObject;
|
|
@@ -20572,9 +20623,9 @@ var require_toad_cache = __commonJS({
|
|
|
20572
20623
|
}
|
|
20573
20624
|
});
|
|
20574
20625
|
|
|
20575
|
-
// node_modules/.pnpm/@fastify+rate-limit@
|
|
20626
|
+
// node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/store/LocalStore.js
|
|
20576
20627
|
var require_LocalStore = __commonJS({
|
|
20577
|
-
"node_modules/.pnpm/@fastify+rate-limit@
|
|
20628
|
+
"node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/store/LocalStore.js"(exports, module) {
|
|
20578
20629
|
"use strict";
|
|
20579
20630
|
var { LruMap: Lru } = require_toad_cache();
|
|
20580
20631
|
function LocalStore(continueExceeding, exponentialBackoff, cache = 5e3) {
|
|
@@ -20615,9 +20666,9 @@ var require_LocalStore = __commonJS({
|
|
|
20615
20666
|
}
|
|
20616
20667
|
});
|
|
20617
20668
|
|
|
20618
|
-
// node_modules/.pnpm/@fastify+rate-limit@
|
|
20669
|
+
// node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/store/RedisStore.js
|
|
20619
20670
|
var require_RedisStore = __commonJS({
|
|
20620
|
-
"node_modules/.pnpm/@fastify+rate-limit@
|
|
20671
|
+
"node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/store/RedisStore.js"(exports, module) {
|
|
20621
20672
|
"use strict";
|
|
20622
20673
|
var lua = `
|
|
20623
20674
|
-- Key to operate on
|
|
@@ -20673,9 +20724,9 @@ var require_RedisStore = __commonJS({
|
|
|
20673
20724
|
}
|
|
20674
20725
|
});
|
|
20675
20726
|
|
|
20676
|
-
// node_modules/.pnpm/@fastify+rate-limit@
|
|
20727
|
+
// node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/index.js
|
|
20677
20728
|
var require_rate_limit = __commonJS({
|
|
20678
|
-
"node_modules/.pnpm/@fastify+rate-limit@
|
|
20729
|
+
"node_modules/.pnpm/@fastify+rate-limit@11.0.0/node_modules/@fastify/rate-limit/index.js"(exports, module) {
|
|
20679
20730
|
"use strict";
|
|
20680
20731
|
var fp = require_plugin();
|
|
20681
20732
|
var { parse: parse2, format: format2 } = require_dist();
|
|
@@ -20743,7 +20794,7 @@ var require_rate_limit = __commonJS({
|
|
|
20743
20794
|
globalParams.timeWindow = defaultTimeWindow;
|
|
20744
20795
|
}
|
|
20745
20796
|
globalParams.hook = settings.hook || defaultHook;
|
|
20746
|
-
globalParams.allowList = settings.allowList ||
|
|
20797
|
+
globalParams.allowList = settings.allowList || null;
|
|
20747
20798
|
globalParams.ban = Number.isFinite(settings.ban) && settings.ban >= 0 ? Math.trunc(settings.ban) : -1;
|
|
20748
20799
|
globalParams.onBanReach = typeof settings.onBanReach === "function" ? settings.onBanReach : defaultOnFn;
|
|
20749
20800
|
globalParams.onExceeding = typeof settings.onExceeding === "function" ? settings.onExceeding : defaultOnFn;
|
|
@@ -20873,9 +20924,9 @@ var require_rate_limit = __commonJS({
|
|
|
20873
20924
|
let ttl = 0;
|
|
20874
20925
|
let ttlInSeconds = 0;
|
|
20875
20926
|
try {
|
|
20876
|
-
const res = await new Promise((
|
|
20927
|
+
const res = await new Promise((resolve24, reject) => {
|
|
20877
20928
|
store.incr(key, (err, res2) => {
|
|
20878
|
-
err ? reject(err) :
|
|
20929
|
+
err ? reject(err) : resolve24(res2);
|
|
20879
20930
|
}, timeWindow, max);
|
|
20880
20931
|
});
|
|
20881
20932
|
current = res.current;
|
|
@@ -21044,17 +21095,43 @@ var init_config2 = __esm({
|
|
|
21044
21095
|
});
|
|
21045
21096
|
|
|
21046
21097
|
// packages/server/src/path-guard.ts
|
|
21047
|
-
import { resolve as
|
|
21048
|
-
|
|
21098
|
+
import { resolve as resolve23, relative as relative6, isAbsolute as isAbsolute6, dirname as dirname15, basename as basename16 } from "path";
|
|
21099
|
+
import { realpath as realpath2 } from "fs/promises";
|
|
21100
|
+
async function resolveSafePath(workspace, requestedPath) {
|
|
21049
21101
|
const decoded = decodeURIComponent(requestedPath);
|
|
21050
21102
|
if (isAbsolute6(decoded)) {
|
|
21051
21103
|
throw new PathTraversalError(requestedPath);
|
|
21052
21104
|
}
|
|
21053
|
-
const resolved =
|
|
21054
|
-
const rel =
|
|
21105
|
+
const resolved = resolve23(workspace, decoded);
|
|
21106
|
+
const rel = relative6(workspace, resolved);
|
|
21055
21107
|
if (rel.startsWith("..") || isAbsolute6(rel)) {
|
|
21056
21108
|
throw new PathTraversalError(requestedPath);
|
|
21057
21109
|
}
|
|
21110
|
+
let realWorkspace;
|
|
21111
|
+
try {
|
|
21112
|
+
realWorkspace = await realpath2(workspace);
|
|
21113
|
+
} catch {
|
|
21114
|
+
realWorkspace = workspace;
|
|
21115
|
+
}
|
|
21116
|
+
let real;
|
|
21117
|
+
try {
|
|
21118
|
+
real = await realpath2(resolved);
|
|
21119
|
+
} catch (err) {
|
|
21120
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
21121
|
+
try {
|
|
21122
|
+
const realParent = await realpath2(dirname15(resolved));
|
|
21123
|
+
real = resolve23(realParent, basename16(resolved));
|
|
21124
|
+
} catch {
|
|
21125
|
+
return resolved;
|
|
21126
|
+
}
|
|
21127
|
+
} else {
|
|
21128
|
+
throw err;
|
|
21129
|
+
}
|
|
21130
|
+
}
|
|
21131
|
+
const realRel = relative6(realWorkspace, real);
|
|
21132
|
+
if (realRel.startsWith("..") || isAbsolute6(realRel)) {
|
|
21133
|
+
throw new PathTraversalError(requestedPath);
|
|
21134
|
+
}
|
|
21058
21135
|
return resolved;
|
|
21059
21136
|
}
|
|
21060
21137
|
var PathTraversalError;
|
|
@@ -21072,7 +21149,7 @@ var init_path_guard = __esm({
|
|
|
21072
21149
|
|
|
21073
21150
|
// packages/server/src/routes/files.ts
|
|
21074
21151
|
import { readFile as readFile25, writeFile as writeFile13, unlink as unlink2, stat as stat3, mkdir as mkdir10 } from "fs/promises";
|
|
21075
|
-
import { dirname as
|
|
21152
|
+
import { dirname as dirname16 } from "path";
|
|
21076
21153
|
import fg from "fast-glob";
|
|
21077
21154
|
function registerRoutes(app, workspace, readOnly) {
|
|
21078
21155
|
app.get("/api/files", async () => {
|
|
@@ -21091,7 +21168,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21091
21168
|
app.get("/api/files/*", async (request, reply) => {
|
|
21092
21169
|
const filePath = request.params["*"];
|
|
21093
21170
|
try {
|
|
21094
|
-
const resolved = resolveSafePath(workspace, filePath);
|
|
21171
|
+
const resolved = await resolveSafePath(workspace, filePath);
|
|
21095
21172
|
const content = await readFile25(resolved, "utf-8");
|
|
21096
21173
|
return { path: filePath, content };
|
|
21097
21174
|
} catch (err) {
|
|
@@ -21108,7 +21185,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21108
21185
|
if (readOnly) return reply.status(403).send({ error: "Read-only mode" });
|
|
21109
21186
|
const filePath = request.params["*"];
|
|
21110
21187
|
try {
|
|
21111
|
-
const resolved = resolveSafePath(workspace, filePath);
|
|
21188
|
+
const resolved = await resolveSafePath(workspace, filePath);
|
|
21112
21189
|
await writeFile13(resolved, request.body.content, "utf-8");
|
|
21113
21190
|
return { path: filePath, status: "updated" };
|
|
21114
21191
|
} catch (err) {
|
|
@@ -21126,13 +21203,13 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21126
21203
|
if (readOnly) return reply.status(403).send({ error: "Read-only mode" });
|
|
21127
21204
|
const filePath = request.params["*"];
|
|
21128
21205
|
try {
|
|
21129
|
-
const resolved = resolveSafePath(workspace, filePath);
|
|
21206
|
+
const resolved = await resolveSafePath(workspace, filePath);
|
|
21130
21207
|
try {
|
|
21131
21208
|
await stat3(resolved);
|
|
21132
21209
|
return reply.status(409).send({ error: "File already exists" });
|
|
21133
21210
|
} catch {
|
|
21134
21211
|
}
|
|
21135
|
-
await mkdir10(
|
|
21212
|
+
await mkdir10(dirname16(resolved), { recursive: true });
|
|
21136
21213
|
await writeFile13(resolved, request.body.content, "utf-8");
|
|
21137
21214
|
return reply.status(201).send({ path: filePath, status: "created" });
|
|
21138
21215
|
} catch (err) {
|
|
@@ -21147,7 +21224,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
21147
21224
|
if (readOnly) return reply.status(403).send({ error: "Read-only mode" });
|
|
21148
21225
|
const filePath = request.params["*"];
|
|
21149
21226
|
try {
|
|
21150
|
-
const resolved = resolveSafePath(workspace, filePath);
|
|
21227
|
+
const resolved = await resolveSafePath(workspace, filePath);
|
|
21151
21228
|
await unlink2(resolved);
|
|
21152
21229
|
return { path: filePath, status: "deleted" };
|
|
21153
21230
|
} catch (err) {
|
|
@@ -21170,7 +21247,7 @@ var init_files = __esm({
|
|
|
21170
21247
|
|
|
21171
21248
|
// packages/server/src/watcher.ts
|
|
21172
21249
|
import { watch } from "chokidar";
|
|
21173
|
-
import { relative as
|
|
21250
|
+
import { relative as relative7 } from "path";
|
|
21174
21251
|
function isWatchedFile(filePath) {
|
|
21175
21252
|
const base = filePath.split("/").pop() ?? "";
|
|
21176
21253
|
if (CONFIG_FILENAMES2.has(base)) return true;
|
|
@@ -21186,15 +21263,15 @@ function createFileWatcher(workspace, watchPaths, onEvent) {
|
|
|
21186
21263
|
});
|
|
21187
21264
|
watcher.on("add", (filePath) => {
|
|
21188
21265
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
21189
|
-
onEvent({ type: "file:created", path:
|
|
21266
|
+
onEvent({ type: "file:created", path: relative7(workspace, filePath) });
|
|
21190
21267
|
});
|
|
21191
21268
|
watcher.on("change", (filePath) => {
|
|
21192
21269
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
21193
|
-
onEvent({ type: "file:changed", path:
|
|
21270
|
+
onEvent({ type: "file:changed", path: relative7(workspace, filePath) });
|
|
21194
21271
|
});
|
|
21195
21272
|
watcher.on("unlink", (filePath) => {
|
|
21196
21273
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
21197
|
-
onEvent({ type: "file:deleted", path:
|
|
21274
|
+
onEvent({ type: "file:deleted", path: relative7(workspace, filePath) });
|
|
21198
21275
|
});
|
|
21199
21276
|
return watcher;
|
|
21200
21277
|
}
|
|
@@ -21216,7 +21293,20 @@ async function createServer(options) {
|
|
|
21216
21293
|
origin: options.corsOrigin
|
|
21217
21294
|
});
|
|
21218
21295
|
await app.register(import_rate_limit.default, { max: 1e3, timeWindow: "1 minute" });
|
|
21219
|
-
await app.register(fastifyWebsocket
|
|
21296
|
+
await app.register(fastifyWebsocket, {
|
|
21297
|
+
options: {
|
|
21298
|
+
// Validate Origin header to prevent cross-origin WebSocket connections.
|
|
21299
|
+
// Browser WebSockets don't enforce CORS, so we must check server-side.
|
|
21300
|
+
verifyClient: (info, callback) => {
|
|
21301
|
+
const origin = info.req.headers.origin;
|
|
21302
|
+
if (origin && origin !== options.corsOrigin && options.corsOrigin !== "*") {
|
|
21303
|
+
callback(false, 403, "Origin not allowed");
|
|
21304
|
+
return;
|
|
21305
|
+
}
|
|
21306
|
+
callback(true);
|
|
21307
|
+
}
|
|
21308
|
+
}
|
|
21309
|
+
});
|
|
21220
21310
|
registerHealthRoute(app);
|
|
21221
21311
|
registerConfigRoute(
|
|
21222
21312
|
app,
|
|
@@ -21357,12 +21447,12 @@ var init_migrate = __esm({
|
|
|
21357
21447
|
init_src();
|
|
21358
21448
|
init_init();
|
|
21359
21449
|
import { Command } from "commander";
|
|
21360
|
-
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
21361
|
-
import { dirname as
|
|
21450
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
|
|
21451
|
+
import { dirname as dirname17 } from "path";
|
|
21362
21452
|
|
|
21363
21453
|
// packages/cli/src/commands/compile.ts
|
|
21364
21454
|
init_src();
|
|
21365
|
-
import { resolve as
|
|
21455
|
+
import { resolve as resolve10, dirname as dirname9, isAbsolute as isAbsolute5 } from "path";
|
|
21366
21456
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21367
21457
|
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile12 } from "fs/promises";
|
|
21368
21458
|
import { existsSync as existsSync12 } from "fs";
|
|
@@ -21374,6 +21464,68 @@ init_env_config();
|
|
|
21374
21464
|
import { readFile as readFile6 } from "fs/promises";
|
|
21375
21465
|
import { existsSync as existsSync6 } from "fs";
|
|
21376
21466
|
import { parse as parseYaml4 } from "yaml";
|
|
21467
|
+
|
|
21468
|
+
// packages/cli/src/config/merge-config.ts
|
|
21469
|
+
function deepMergeRegistry(target, source) {
|
|
21470
|
+
if (!source) return target;
|
|
21471
|
+
if (!target) return source;
|
|
21472
|
+
const merged = { ...target };
|
|
21473
|
+
if (source.path !== void 0) merged.path = source.path;
|
|
21474
|
+
if (source.url !== void 0) merged.url = source.url;
|
|
21475
|
+
if (source.git) {
|
|
21476
|
+
const mergedAuth = source.git.auth ?? merged.git?.auth;
|
|
21477
|
+
merged.git = {
|
|
21478
|
+
...merged.git,
|
|
21479
|
+
...source.git,
|
|
21480
|
+
...mergedAuth ? { auth: mergedAuth } : {}
|
|
21481
|
+
};
|
|
21482
|
+
}
|
|
21483
|
+
if (source.cache) {
|
|
21484
|
+
merged.cache = { ...merged.cache, ...source.cache };
|
|
21485
|
+
}
|
|
21486
|
+
if (source.auth) {
|
|
21487
|
+
merged.auth = { ...merged.auth, ...source.auth };
|
|
21488
|
+
}
|
|
21489
|
+
return merged;
|
|
21490
|
+
}
|
|
21491
|
+
function userConfigToProjectRegistry(userRegistry) {
|
|
21492
|
+
const registry2 = {};
|
|
21493
|
+
if (userRegistry.git) {
|
|
21494
|
+
registry2.git = {
|
|
21495
|
+
url: userRegistry.git.url,
|
|
21496
|
+
...userRegistry.git.fallbackUrl ? { fallbackUrl: userRegistry.git.fallbackUrl } : {},
|
|
21497
|
+
...userRegistry.git.ref ? { ref: userRegistry.git.ref } : {},
|
|
21498
|
+
...userRegistry.git.path ? { path: userRegistry.git.path } : {},
|
|
21499
|
+
...userRegistry.git.auth ? { auth: userRegistry.git.auth } : {}
|
|
21500
|
+
};
|
|
21501
|
+
}
|
|
21502
|
+
if (userRegistry.url) {
|
|
21503
|
+
registry2.url = userRegistry.url;
|
|
21504
|
+
}
|
|
21505
|
+
if (userRegistry.cache) {
|
|
21506
|
+
registry2.cache = { ...userRegistry.cache };
|
|
21507
|
+
}
|
|
21508
|
+
return registry2;
|
|
21509
|
+
}
|
|
21510
|
+
function mergeConfigs(userConfig, projectConfig, envOverrides, cliFlags) {
|
|
21511
|
+
const merged = { ...projectConfig };
|
|
21512
|
+
if (userConfig.registry) {
|
|
21513
|
+
const userRegistry = userConfigToProjectRegistry(userConfig.registry);
|
|
21514
|
+
merged.registry = deepMergeRegistry(userRegistry, merged.registry);
|
|
21515
|
+
}
|
|
21516
|
+
if (envOverrides.registry) {
|
|
21517
|
+
merged.registry = deepMergeRegistry(merged.registry, envOverrides.registry);
|
|
21518
|
+
}
|
|
21519
|
+
if (cliFlags?.registry) {
|
|
21520
|
+
merged.registry = deepMergeRegistry(merged.registry, cliFlags.registry);
|
|
21521
|
+
}
|
|
21522
|
+
if (cliFlags?.targets) {
|
|
21523
|
+
merged.targets = cliFlags.targets;
|
|
21524
|
+
}
|
|
21525
|
+
return merged;
|
|
21526
|
+
}
|
|
21527
|
+
|
|
21528
|
+
// packages/cli/src/config/loader.ts
|
|
21377
21529
|
var CONFIG_FILES = [
|
|
21378
21530
|
"promptscript.yaml",
|
|
21379
21531
|
"promptscript.yml",
|
|
@@ -21426,6 +21578,12 @@ async function loadConfig(customPath) {
|
|
|
21426
21578
|
throw new Error(`Failed to parse ${configFile}: ${message}`, { cause: error });
|
|
21427
21579
|
}
|
|
21428
21580
|
}
|
|
21581
|
+
async function loadEffectiveConfig(customPath, cliFlags) {
|
|
21582
|
+
const userConfig = await loadUserConfig();
|
|
21583
|
+
const projectConfig = await loadConfig(customPath);
|
|
21584
|
+
const envOverrides = loadEnvOverrides();
|
|
21585
|
+
return mergeConfigs(userConfig, projectConfig, envOverrides, cliFlags);
|
|
21586
|
+
}
|
|
21429
21587
|
|
|
21430
21588
|
// packages/cli/src/commands/compile.ts
|
|
21431
21589
|
init_loader();
|
|
@@ -21489,8 +21647,8 @@ init_src4();
|
|
|
21489
21647
|
init_src2();
|
|
21490
21648
|
init_src();
|
|
21491
21649
|
import { existsSync as existsSync9 } from "fs";
|
|
21492
|
-
import { lstat as
|
|
21493
|
-
import { basename as basename11, dirname as dirname7, join as join8 } from "path";
|
|
21650
|
+
import { lstat as lstat4, readdir as readdir4, readFile as readFile11 } from "fs/promises";
|
|
21651
|
+
import { basename as basename11, dirname as dirname7, join as join8, relative as relative4, resolve as resolve9 } from "path";
|
|
21494
21652
|
|
|
21495
21653
|
// packages/resolver/src/loader.ts
|
|
21496
21654
|
init_src();
|
|
@@ -23033,10 +23191,10 @@ function parseSkillIgnore(content) {
|
|
|
23033
23191
|
return { patterns };
|
|
23034
23192
|
}
|
|
23035
23193
|
function isIgnoredByRules(relPath, rules) {
|
|
23036
|
-
const
|
|
23194
|
+
const basename17 = relPath.split("/").pop() ?? relPath;
|
|
23037
23195
|
let ignored = false;
|
|
23038
23196
|
for (const { regex, matchPath, negated } of rules.patterns) {
|
|
23039
|
-
const target = matchPath ? relPath :
|
|
23197
|
+
const target = matchPath ? relPath : basename17;
|
|
23040
23198
|
if (regex.test(target)) {
|
|
23041
23199
|
ignored = !negated;
|
|
23042
23200
|
}
|
|
@@ -24596,6 +24754,27 @@ var GitRegistry = class {
|
|
|
24596
24754
|
await this.cacheManager.remove(this.url, targetRef);
|
|
24597
24755
|
await this.ensureCloned(targetRef);
|
|
24598
24756
|
}
|
|
24757
|
+
/**
|
|
24758
|
+
* Checkout a specific commit in an already-cloned repository.
|
|
24759
|
+
* Used to enforce lockfile pinning: after cloning at a tag/branch,
|
|
24760
|
+
* checkout the exact commit recorded in the lockfile.
|
|
24761
|
+
*
|
|
24762
|
+
* @param targetDir - Path to the cloned repository
|
|
24763
|
+
* @param commit - Commit hash to checkout
|
|
24764
|
+
*/
|
|
24765
|
+
async checkoutCommit(targetDir, commit) {
|
|
24766
|
+
const git = this.createGit(targetDir);
|
|
24767
|
+
try {
|
|
24768
|
+
await git.fetch(["origin", commit, "--depth=1"]);
|
|
24769
|
+
} catch {
|
|
24770
|
+
try {
|
|
24771
|
+
await git.fetch(["--unshallow"]);
|
|
24772
|
+
} catch {
|
|
24773
|
+
await git.fetch(["origin"]);
|
|
24774
|
+
}
|
|
24775
|
+
}
|
|
24776
|
+
await git.checkout(commit);
|
|
24777
|
+
}
|
|
24599
24778
|
/**
|
|
24600
24779
|
* Get the current commit hash for a ref.
|
|
24601
24780
|
*
|
|
@@ -25125,8 +25304,16 @@ async function validateRemoteAccess(repoUrl) {
|
|
|
25125
25304
|
}
|
|
25126
25305
|
|
|
25127
25306
|
// packages/resolver/src/registry-cache.ts
|
|
25128
|
-
import { mkdir as mkdir3, stat, writeFile as writeFile3, readFile as readFile9 } from "fs/promises";
|
|
25129
|
-
import { join as join7 } from "path";
|
|
25307
|
+
import { mkdir as mkdir3, stat, writeFile as writeFile3, readFile as readFile9, lstat as lstat2 } from "fs/promises";
|
|
25308
|
+
import { join as join7, resolve as resolve7, relative as relative3 } from "path";
|
|
25309
|
+
function validatePathComponent(component, label) {
|
|
25310
|
+
if (component.includes("..")) {
|
|
25311
|
+
throw new Error(`Invalid ${label}: contains parent directory traversal (..)`);
|
|
25312
|
+
}
|
|
25313
|
+
if (component.startsWith("/")) {
|
|
25314
|
+
throw new Error(`Invalid ${label}: absolute paths are not allowed`);
|
|
25315
|
+
}
|
|
25316
|
+
}
|
|
25130
25317
|
var RegistryCache = class {
|
|
25131
25318
|
constructor(baseDir) {
|
|
25132
25319
|
this.baseDir = baseDir;
|
|
@@ -25134,7 +25321,13 @@ var RegistryCache = class {
|
|
|
25134
25321
|
baseDir;
|
|
25135
25322
|
getCachePath(repoUrl, version) {
|
|
25136
25323
|
const normalized = repoUrl.replace(/^(https?:\/\/|git@|git:\/\/)/, "").replace(":", "/");
|
|
25137
|
-
|
|
25324
|
+
validatePathComponent(version, "version");
|
|
25325
|
+
const result = join7(this.baseDir, "registries", normalized, version);
|
|
25326
|
+
const rel = relative3(resolve7(this.baseDir), resolve7(result));
|
|
25327
|
+
if (rel.startsWith("..")) {
|
|
25328
|
+
throw new Error(`Path traversal detected: version "${version}" escapes cache root`);
|
|
25329
|
+
}
|
|
25330
|
+
return result;
|
|
25138
25331
|
}
|
|
25139
25332
|
async has(repoUrl, version) {
|
|
25140
25333
|
try {
|
|
@@ -25148,8 +25341,19 @@ var RegistryCache = class {
|
|
|
25148
25341
|
async set(repoUrl, version, commit) {
|
|
25149
25342
|
const cachePath = this.getCachePath(repoUrl, version);
|
|
25150
25343
|
await mkdir3(cachePath, { recursive: true });
|
|
25344
|
+
const metaPath = join7(cachePath, ".prs-registry-meta.json");
|
|
25345
|
+
try {
|
|
25346
|
+
const statResult = await lstat2(metaPath);
|
|
25347
|
+
if (statResult.isSymbolicLink()) {
|
|
25348
|
+
throw new Error(
|
|
25349
|
+
`Refusing to write metadata: ${metaPath} is a symlink (possible supply-chain attack)`
|
|
25350
|
+
);
|
|
25351
|
+
}
|
|
25352
|
+
} catch (err) {
|
|
25353
|
+
if (err.code !== "ENOENT") throw err;
|
|
25354
|
+
}
|
|
25151
25355
|
const meta = { commit, cachedAt: Date.now() };
|
|
25152
|
-
await writeFile3(
|
|
25356
|
+
await writeFile3(metaPath, JSON.stringify(meta, null, 2));
|
|
25153
25357
|
return cachePath;
|
|
25154
25358
|
}
|
|
25155
25359
|
async isStale(repoUrl, version, ttlMs) {
|
|
@@ -25198,9 +25402,16 @@ var RegistryCache = class {
|
|
|
25198
25402
|
}
|
|
25199
25403
|
};
|
|
25200
25404
|
|
|
25405
|
+
// packages/resolver/src/reference-hasher.ts
|
|
25406
|
+
import { createHash as createHash2 } from "crypto";
|
|
25407
|
+
function hashContent(content) {
|
|
25408
|
+
const hex = createHash2("sha256").update(content).digest("hex");
|
|
25409
|
+
return `sha256-${hex}`;
|
|
25410
|
+
}
|
|
25411
|
+
|
|
25201
25412
|
// packages/resolver/src/auto-discovery.ts
|
|
25202
|
-
import { readFile as readFile10, readdir as readdir3, access as access2, lstat as
|
|
25203
|
-
import { resolve as
|
|
25413
|
+
import { readFile as readFile10, readdir as readdir3, access as access2, lstat as lstat3 } from "fs/promises";
|
|
25414
|
+
import { resolve as resolve8, basename as basename10 } from "path";
|
|
25204
25415
|
var CONTEXT_FILES = ["CLAUDE.md", ".clinerules", ".cursorrules"];
|
|
25205
25416
|
async function fileExists2(path) {
|
|
25206
25417
|
try {
|
|
@@ -25236,9 +25447,9 @@ async function discoverSkills(dir) {
|
|
|
25236
25447
|
const properties = {};
|
|
25237
25448
|
for (const entry of entries) {
|
|
25238
25449
|
if (!entry.isDirectory()) continue;
|
|
25239
|
-
let skillMdPath =
|
|
25450
|
+
let skillMdPath = resolve8(dir, entry.name, "SKILL.md");
|
|
25240
25451
|
if (!await fileExists2(skillMdPath)) {
|
|
25241
|
-
const dirnameMdPath =
|
|
25452
|
+
const dirnameMdPath = resolve8(dir, entry.name, `${entry.name}.md`);
|
|
25242
25453
|
if (await fileExists2(dirnameMdPath)) {
|
|
25243
25454
|
skillMdPath = dirnameMdPath;
|
|
25244
25455
|
} else {
|
|
@@ -25265,7 +25476,7 @@ async function discoverSkills(dir) {
|
|
|
25265
25476
|
return Object.keys(properties).length > 0 ? properties : null;
|
|
25266
25477
|
}
|
|
25267
25478
|
async function discoverRootSkill(dir) {
|
|
25268
|
-
const skillMdPath =
|
|
25479
|
+
const skillMdPath = resolve8(dir, "SKILL.md");
|
|
25269
25480
|
if (!await fileExists2(skillMdPath)) return null;
|
|
25270
25481
|
try {
|
|
25271
25482
|
const raw = await readFile10(skillMdPath, "utf-8");
|
|
@@ -25296,9 +25507,9 @@ async function discoverAgents(dir) {
|
|
|
25296
25507
|
const properties = {};
|
|
25297
25508
|
for (const entry of entries) {
|
|
25298
25509
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25299
|
-
const fullPath =
|
|
25510
|
+
const fullPath = resolve8(dir, entry.name);
|
|
25300
25511
|
try {
|
|
25301
|
-
const stat4 = await
|
|
25512
|
+
const stat4 = await lstat3(fullPath);
|
|
25302
25513
|
if (stat4.isSymbolicLink()) continue;
|
|
25303
25514
|
const raw = await readFile10(fullPath, "utf-8");
|
|
25304
25515
|
const fm = parseFrontmatter(raw);
|
|
@@ -25332,9 +25543,9 @@ async function discoverCommands(dir) {
|
|
|
25332
25543
|
for (const entry of entries) {
|
|
25333
25544
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
25334
25545
|
if (entry.name === "SKILL.md") continue;
|
|
25335
|
-
const fullPath =
|
|
25546
|
+
const fullPath = resolve8(dir, entry.name);
|
|
25336
25547
|
try {
|
|
25337
|
-
const stat4 = await
|
|
25548
|
+
const stat4 = await lstat3(fullPath);
|
|
25338
25549
|
if (stat4.isSymbolicLink()) continue;
|
|
25339
25550
|
const raw = await readFile10(fullPath, "utf-8");
|
|
25340
25551
|
const fm = parseFrontmatter(raw);
|
|
@@ -25349,7 +25560,7 @@ async function discoverCommands(dir) {
|
|
|
25349
25560
|
}
|
|
25350
25561
|
async function discoverContext(dir) {
|
|
25351
25562
|
for (const fileName of CONTEXT_FILES) {
|
|
25352
|
-
const fullPath =
|
|
25563
|
+
const fullPath = resolve8(dir, fileName);
|
|
25353
25564
|
if (!await fileExists2(fullPath)) continue;
|
|
25354
25565
|
try {
|
|
25355
25566
|
const content = await readFile10(fullPath, "utf-8");
|
|
@@ -25366,7 +25577,7 @@ var AGENT_WRAPPER_DIRS = ["agents"];
|
|
|
25366
25577
|
var COMMAND_WRAPPER_DIRS = ["commands"];
|
|
25367
25578
|
async function safeIsDirectory(dir) {
|
|
25368
25579
|
try {
|
|
25369
|
-
const stat4 = await
|
|
25580
|
+
const stat4 = await lstat3(dir);
|
|
25370
25581
|
return stat4.isDirectory();
|
|
25371
25582
|
} catch {
|
|
25372
25583
|
return false;
|
|
@@ -25379,7 +25590,7 @@ async function discoverNativeContent(dir) {
|
|
|
25379
25590
|
const subSkills = await discoverSkills(dir);
|
|
25380
25591
|
const wrappedSkillResults = await Promise.all(
|
|
25381
25592
|
SKILL_WRAPPER_DIRS.map(async (name) => {
|
|
25382
|
-
const candidate =
|
|
25593
|
+
const candidate = resolve8(dir, name);
|
|
25383
25594
|
if (!await safeIsDirectory(candidate)) return null;
|
|
25384
25595
|
return discoverSkills(candidate);
|
|
25385
25596
|
})
|
|
@@ -25400,7 +25611,7 @@ async function discoverNativeContent(dir) {
|
|
|
25400
25611
|
const rootAgents = await discoverAgents(dir) ?? {};
|
|
25401
25612
|
const wrappedAgents = {};
|
|
25402
25613
|
for (const name of AGENT_WRAPPER_DIRS) {
|
|
25403
|
-
const candidate =
|
|
25614
|
+
const candidate = resolve8(dir, name);
|
|
25404
25615
|
if (await safeIsDirectory(candidate)) {
|
|
25405
25616
|
const found = await discoverAgents(candidate);
|
|
25406
25617
|
if (found) Object.assign(wrappedAgents, found);
|
|
@@ -25413,7 +25624,7 @@ async function discoverNativeContent(dir) {
|
|
|
25413
25624
|
const rootCommands = await discoverCommands(dir) ?? {};
|
|
25414
25625
|
const wrappedCommands = {};
|
|
25415
25626
|
for (const name of COMMAND_WRAPPER_DIRS) {
|
|
25416
|
-
const candidate =
|
|
25627
|
+
const candidate = resolve8(dir, name);
|
|
25417
25628
|
if (await safeIsDirectory(candidate)) {
|
|
25418
25629
|
const found = await discoverCommands(candidate);
|
|
25419
25630
|
if (found) Object.assign(wrappedCommands, found);
|
|
@@ -25880,23 +26091,56 @@ var Resolver = class {
|
|
|
25880
26091
|
const lockEntry = this.options.lockfile?.dependencies[repoUrl];
|
|
25881
26092
|
const pinnedTag = lockEntry?.version ?? (version || void 0);
|
|
25882
26093
|
const tag = pinnedTag ?? "main";
|
|
26094
|
+
const lockedCommit = lockEntry?.commit && /^[0-9a-f]{40}$/.test(lockEntry.commit) && !/^0{40}$/.test(lockEntry.commit) ? lockEntry.commit : null;
|
|
25883
26095
|
const hasCached = await this.registryCache.has(repoUrl, effectiveVersion);
|
|
25884
26096
|
let cachePath;
|
|
25885
26097
|
if (hasCached) {
|
|
25886
26098
|
this.logger.debug(`Registry cache hit: ${repoUrl}@${effectiveVersion}`);
|
|
25887
26099
|
cachePath = this.registryCache.getCachePath(repoUrl, effectiveVersion);
|
|
26100
|
+
if (lockedCommit) {
|
|
26101
|
+
try {
|
|
26102
|
+
const cachedMeta = await this.registryCache.getMeta(repoUrl, effectiveVersion);
|
|
26103
|
+
if (cachedMeta && cachedMeta.commit !== lockedCommit) {
|
|
26104
|
+
this.logger.verbose(
|
|
26105
|
+
`Lockfile commit mismatch for ${repoUrl}: cached=${cachedMeta.commit}, locked=${lockedCommit}. Re-cloning.`
|
|
26106
|
+
);
|
|
26107
|
+
const fallbackRepoUrl = this.options.registries ? findFallbackUrl(repoUrl, this.options.registries) : void 0;
|
|
26108
|
+
await this.gitRegistry.cloneAtTag(repoUrl, tag, cachePath, fallbackRepoUrl);
|
|
26109
|
+
await this.gitRegistry.checkoutCommit(cachePath, lockedCommit);
|
|
26110
|
+
await this.registryCache.set(repoUrl, effectiveVersion, lockedCommit);
|
|
26111
|
+
}
|
|
26112
|
+
} catch (err) {
|
|
26113
|
+
this.logger.debug(`Lockfile commit verification failed: ${err}`);
|
|
26114
|
+
}
|
|
26115
|
+
}
|
|
25888
26116
|
} else {
|
|
25889
26117
|
this.logger.verbose(`Registry cache miss, cloning: ${repoUrl}@${tag}`);
|
|
25890
26118
|
cachePath = this.registryCache.getCachePath(repoUrl, effectiveVersion);
|
|
25891
26119
|
const fallbackRepoUrl = this.options.registries ? findFallbackUrl(repoUrl, this.options.registries) : void 0;
|
|
25892
26120
|
await this.gitRegistry.cloneAtTag(repoUrl, tag, cachePath, fallbackRepoUrl);
|
|
25893
|
-
|
|
26121
|
+
if (lockedCommit) {
|
|
26122
|
+
this.logger.verbose(`Checking out locked commit: ${lockedCommit}`);
|
|
26123
|
+
await this.gitRegistry.checkoutCommit(cachePath, lockedCommit);
|
|
26124
|
+
}
|
|
26125
|
+
const commitHash = lockedCommit ?? lockEntry?.commit ?? "unknown";
|
|
25894
26126
|
await this.registryCache.set(repoUrl, effectiveVersion, commitHash);
|
|
25895
26127
|
}
|
|
25896
26128
|
const isRoot = subPath === "";
|
|
25897
26129
|
const isMdPath = !isRoot && subPath.endsWith(".md");
|
|
25898
26130
|
const resolvedFileName = isRoot ? "" : isMdPath ? subPath : subPath.endsWith(".prs") ? subPath : `${subPath}.prs`;
|
|
25899
26131
|
const resolvedFullPath = isRoot ? "" : join8(cachePath, resolvedFileName);
|
|
26132
|
+
if (!isRoot) {
|
|
26133
|
+
const rel = relative4(resolve9(cachePath), resolve9(resolvedFullPath));
|
|
26134
|
+
if (rel.startsWith("..") || resolve9(resolvedFullPath) === resolve9(cachePath)) {
|
|
26135
|
+
errors.push(
|
|
26136
|
+
new ResolveError(
|
|
26137
|
+
`Path traversal detected: subpath '${subPath}' escapes repository cache boundary.`
|
|
26138
|
+
)
|
|
26139
|
+
);
|
|
26140
|
+
this.resolving.delete(marker);
|
|
26141
|
+
return { ast: null, sources: [marker], errors };
|
|
26142
|
+
}
|
|
26143
|
+
}
|
|
25900
26144
|
let resolvedAST = null;
|
|
25901
26145
|
if (!isRoot && existsSync9(resolvedFullPath) && isMdPath) {
|
|
25902
26146
|
this.logger.debug(`Found .md file: ${resolvedFullPath}`);
|
|
@@ -25922,16 +26166,43 @@ var Resolver = class {
|
|
|
25922
26166
|
);
|
|
25923
26167
|
} else {
|
|
25924
26168
|
const discoverDir = isRoot ? cachePath : join8(cachePath, subPath);
|
|
25925
|
-
|
|
25926
|
-
|
|
25927
|
-
|
|
25928
|
-
|
|
25929
|
-
|
|
26169
|
+
if (!isRoot) {
|
|
26170
|
+
const dirRel = relative4(resolve9(cachePath), resolve9(discoverDir));
|
|
26171
|
+
if (dirRel.startsWith("..")) {
|
|
26172
|
+
errors.push(
|
|
26173
|
+
new ResolveError(
|
|
26174
|
+
`Path traversal detected: subpath '${subPath}' escapes repository cache boundary.`
|
|
26175
|
+
)
|
|
26176
|
+
);
|
|
26177
|
+
this.resolving.delete(marker);
|
|
26178
|
+
return { ast: null, sources: [marker], errors };
|
|
26179
|
+
}
|
|
26180
|
+
}
|
|
26181
|
+
if (!isRoot && !existsSync9(discoverDir)) {
|
|
25930
26182
|
errors.push(
|
|
25931
26183
|
new ResolveError(
|
|
25932
|
-
`Cannot resolve registry import:
|
|
26184
|
+
`Cannot resolve registry import: path '${subPath}' does not exist in repository ${repoUrl}.`
|
|
25933
26185
|
)
|
|
25934
26186
|
);
|
|
26187
|
+
} else {
|
|
26188
|
+
this.logger.debug(
|
|
26189
|
+
`No .prs found, trying directory scan and auto-discovery: ${discoverDir}`
|
|
26190
|
+
);
|
|
26191
|
+
const dirResult = await this.tryDirectoryScan(discoverDir, [marker], []);
|
|
26192
|
+
if (dirResult?.ast) {
|
|
26193
|
+
resolvedAST = dirResult.ast;
|
|
26194
|
+
} else {
|
|
26195
|
+
resolvedAST = await discoverNativeContent(discoverDir);
|
|
26196
|
+
if (!resolvedAST) {
|
|
26197
|
+
const where = isRoot ? "<repository root>" : `'${subPath}'`;
|
|
26198
|
+
const hint = isRoot ? ` Specify a sub-path (e.g. ${repoUrl}/skills/<name>).` : "";
|
|
26199
|
+
errors.push(
|
|
26200
|
+
new ResolveError(
|
|
26201
|
+
`Cannot resolve registry import: no .prs file, .md file, or native content at ${where} in ${repoUrl}.${hint}`
|
|
26202
|
+
)
|
|
26203
|
+
);
|
|
26204
|
+
}
|
|
26205
|
+
}
|
|
25935
26206
|
}
|
|
25936
26207
|
}
|
|
25937
26208
|
const result = {
|
|
@@ -25961,7 +26232,7 @@ var Resolver = class {
|
|
|
25961
26232
|
async tryDirectoryScan(dirPath, sources, errors) {
|
|
25962
26233
|
let stat4;
|
|
25963
26234
|
try {
|
|
25964
|
-
stat4 = await
|
|
26235
|
+
stat4 = await lstat4(dirPath);
|
|
25965
26236
|
} catch {
|
|
25966
26237
|
return null;
|
|
25967
26238
|
}
|
|
@@ -26014,7 +26285,7 @@ var Resolver = class {
|
|
|
26014
26285
|
const subDir = join8(currentDir, entry.name);
|
|
26015
26286
|
let subStat;
|
|
26016
26287
|
try {
|
|
26017
|
-
subStat = await
|
|
26288
|
+
subStat = await lstat4(subDir);
|
|
26018
26289
|
} catch {
|
|
26019
26290
|
continue;
|
|
26020
26291
|
}
|
|
@@ -26069,6 +26340,41 @@ var Resolver = class {
|
|
|
26069
26340
|
clearCache() {
|
|
26070
26341
|
this.cache.clear();
|
|
26071
26342
|
}
|
|
26343
|
+
/**
|
|
26344
|
+
* Verify integrity hashes for registry reference files.
|
|
26345
|
+
* Reads each referenced file from the registry cache and compares its
|
|
26346
|
+
* hash against the lockfile entry.
|
|
26347
|
+
*
|
|
26348
|
+
* @param lockfile - Lockfile with reference hashes
|
|
26349
|
+
* @returns Array of errors for mismatched references
|
|
26350
|
+
*/
|
|
26351
|
+
async verifyReferenceHashes(lockfile) {
|
|
26352
|
+
if (!lockfile.references) return [];
|
|
26353
|
+
const errors = [];
|
|
26354
|
+
for (const [key, entry] of Object.entries(lockfile.references)) {
|
|
26355
|
+
const parts = key.split("\0");
|
|
26356
|
+
if (parts.length !== 3) continue;
|
|
26357
|
+
const [repoUrl, relativePath, version] = parts;
|
|
26358
|
+
try {
|
|
26359
|
+
const cachePath = this.registryCache.getCachePath(repoUrl, version);
|
|
26360
|
+
const fullPath = join8(cachePath, relativePath);
|
|
26361
|
+
if (!existsSync9(fullPath)) continue;
|
|
26362
|
+
const content = await readFile11(fullPath);
|
|
26363
|
+
const actualHash = hashContent(content);
|
|
26364
|
+
if (actualHash !== entry.hash) {
|
|
26365
|
+
errors.push(
|
|
26366
|
+
new ResolveError(
|
|
26367
|
+
`Reference file hash mismatch: ${relativePath} has changed since last lock. Run \`prs lock --update\` to accept changes.`,
|
|
26368
|
+
void 0,
|
|
26369
|
+
"PS2023" /* LOCKFILE_INTEGRITY */
|
|
26370
|
+
)
|
|
26371
|
+
);
|
|
26372
|
+
}
|
|
26373
|
+
} catch {
|
|
26374
|
+
}
|
|
26375
|
+
}
|
|
26376
|
+
return errors;
|
|
26377
|
+
}
|
|
26072
26378
|
/**
|
|
26073
26379
|
* Get the file loader.
|
|
26074
26380
|
*/
|
|
@@ -26162,7 +26468,7 @@ var HttpRegistry = class {
|
|
|
26162
26468
|
* Sleep for specified milliseconds.
|
|
26163
26469
|
*/
|
|
26164
26470
|
sleep(ms) {
|
|
26165
|
-
return new Promise((
|
|
26471
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
26166
26472
|
}
|
|
26167
26473
|
/**
|
|
26168
26474
|
* Fetch with timeout.
|
|
@@ -26544,13 +26850,6 @@ function formatSkillValidationIssues(issues) {
|
|
|
26544
26850
|
// packages/resolver/src/index.ts
|
|
26545
26851
|
init_src();
|
|
26546
26852
|
|
|
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
|
-
|
|
26554
26853
|
// packages/validator/src/validator.ts
|
|
26555
26854
|
init_src();
|
|
26556
26855
|
|
|
@@ -26767,10 +27066,10 @@ function walkValue(value, loc, callback, exclude) {
|
|
|
26767
27066
|
const typed = value;
|
|
26768
27067
|
if (typed.type === "TextContent" && typeof typed.value === "string") {
|
|
26769
27068
|
callback(typed.value, typed.loc ?? loc);
|
|
27069
|
+
return;
|
|
26770
27070
|
}
|
|
26771
|
-
} else {
|
|
26772
|
-
walkObjectProperties(value, loc, callback, exclude);
|
|
26773
27071
|
}
|
|
27072
|
+
walkObjectProperties(value, loc, callback, exclude);
|
|
26774
27073
|
}
|
|
26775
27074
|
}
|
|
26776
27075
|
function offsetLocation(baseLoc, text, charIndex) {
|
|
@@ -27715,7 +28014,8 @@ var AUTHORITY_PATTERNS = [
|
|
|
27715
28014
|
/\[?\s{0,10}PRIORITY\s{0,10}(?:OVERRIDE|ONE|ALPHA)\s{0,10}\]?/i,
|
|
27716
28015
|
/\[?\s{0,10}EMERGENCY\s{0,10}(?:PROTOCOL|OVERRIDE|MODE)\s{0,10}\]?/i,
|
|
27717
28016
|
// Warning suppression patterns
|
|
27718
|
-
|
|
28017
|
+
// Removed because it triggers false positives on valid agent instructions (e.g., "do not notify user")
|
|
28018
|
+
// /(?:DO\s{1,10}NOT|NEVER|DON'?T)\s{1,10}(?:WARN|ALERT|NOTIFY|FLAG|REPORT)/i,
|
|
27719
28019
|
/(?:DO\s{1,10}NOT|NEVER|DON'?T)\s{1,10}(?:PROVIDE|SHOW|DISPLAY|INCLUDE)\s{1,10}(?:SECURITY\s{1,10})?WARNINGS?/i,
|
|
27720
28020
|
/(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\s{1,10}(?:ALL\s{1,10})?WARNINGS?/i,
|
|
27721
28021
|
/(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\s{1,10}(?:ALL\s{1,10})?(?:SECURITY\s{1,10})?(?:ALERTS?|NOTIFICATIONS?)/i,
|
|
@@ -27858,7 +28158,10 @@ function decodeRawHex(hex) {
|
|
|
27858
28158
|
if (isNaN(byte)) return null;
|
|
27859
28159
|
bytes.push(byte);
|
|
27860
28160
|
}
|
|
27861
|
-
|
|
28161
|
+
let decoded = "";
|
|
28162
|
+
for (const byte of bytes) {
|
|
28163
|
+
decoded += String.fromCharCode(byte);
|
|
28164
|
+
}
|
|
27862
28165
|
if (/[\x00-\x08\x0E-\x1F]/.test(decoded)) {
|
|
27863
28166
|
return null;
|
|
27864
28167
|
}
|
|
@@ -29356,10 +29659,14 @@ function getComposedFrom(skill) {
|
|
|
29356
29659
|
return raw.filter(isComposedFromEntry);
|
|
29357
29660
|
}
|
|
29358
29661
|
function extractRegistry(source) {
|
|
29359
|
-
if (
|
|
29360
|
-
|
|
29361
|
-
|
|
29362
|
-
|
|
29662
|
+
if (source.startsWith("@")) {
|
|
29663
|
+
const slash = source.indexOf("/");
|
|
29664
|
+
if (slash === -1) return source;
|
|
29665
|
+
return source.slice(0, slash);
|
|
29666
|
+
}
|
|
29667
|
+
const match = /\/(@[a-zA-Z_][a-zA-Z0-9_-]*)\//.exec(source);
|
|
29668
|
+
if (match) return match[1] ?? null;
|
|
29669
|
+
return null;
|
|
29363
29670
|
}
|
|
29364
29671
|
function matchesTargetPattern(composedFrom, targetPattern) {
|
|
29365
29672
|
const registry2 = extractRegistry(targetPattern);
|
|
@@ -29621,6 +29928,17 @@ var Validator = class {
|
|
|
29621
29928
|
}
|
|
29622
29929
|
this.logger.debug(`Validator initialized with ${this.rules.length} rules`);
|
|
29623
29930
|
}
|
|
29931
|
+
/**
|
|
29932
|
+
* Update validator configuration after construction.
|
|
29933
|
+
* Allows the compiler to inject runtime data (registry references, lockfile, etc.)
|
|
29934
|
+
* that becomes available only after resolution.
|
|
29935
|
+
*/
|
|
29936
|
+
updateConfig(partial) {
|
|
29937
|
+
this.config = { ...this.config, ...partial };
|
|
29938
|
+
if (partial.disableRules) {
|
|
29939
|
+
this.disabledRules = new Set(partial.disableRules);
|
|
29940
|
+
}
|
|
29941
|
+
}
|
|
29624
29942
|
/**
|
|
29625
29943
|
* Validate an AST.
|
|
29626
29944
|
*
|
|
@@ -29751,7 +30069,7 @@ var SECURITY_STRICT_MULTILINGUAL = {
|
|
|
29751
30069
|
};
|
|
29752
30070
|
|
|
29753
30071
|
// packages/compiler/src/compiler.ts
|
|
29754
|
-
import { relative as
|
|
30072
|
+
import { relative as relative5, isAbsolute as isAbsolute4 } from "path";
|
|
29755
30073
|
function generateHtmlMarker(source, target) {
|
|
29756
30074
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
29757
30075
|
return `<!-- PromptScript ${timestamp} | source: ${source} | target: ${target} - do not edit -->`;
|
|
@@ -29827,7 +30145,7 @@ var Compiler = class _Compiler {
|
|
|
29827
30145
|
formatTime: 0,
|
|
29828
30146
|
totalTime: 0
|
|
29829
30147
|
};
|
|
29830
|
-
const sourceLabel = isAbsolute4(entryPath) ?
|
|
30148
|
+
const sourceLabel = isAbsolute4(entryPath) ? relative5(process.cwd(), entryPath) : entryPath;
|
|
29831
30149
|
this.logger.verbose("=== Stage 1: Resolve ===");
|
|
29832
30150
|
const startResolve = Date.now();
|
|
29833
30151
|
let resolved;
|
|
@@ -29861,6 +30179,7 @@ var Compiler = class _Compiler {
|
|
|
29861
30179
|
stats
|
|
29862
30180
|
};
|
|
29863
30181
|
}
|
|
30182
|
+
const compileErrors = [];
|
|
29864
30183
|
if (!this.options.ignoreHashes && this.options.resolver.lockfile?.references) {
|
|
29865
30184
|
this.logger.verbose("=== Stage 1.5: Reference Integrity ===");
|
|
29866
30185
|
const registryReferences = /* @__PURE__ */ new Set();
|
|
@@ -29877,17 +30196,29 @@ var Compiler = class _Compiler {
|
|
|
29877
30196
|
}
|
|
29878
30197
|
}
|
|
29879
30198
|
}
|
|
29880
|
-
|
|
29881
|
-
|
|
29882
|
-
|
|
29883
|
-
this.options.validator.ignoreHashes = this.options.ignoreHashes;
|
|
30199
|
+
const hashErrors = await this.resolver.verifyReferenceHashes(this.options.resolver.lockfile);
|
|
30200
|
+
for (const err of hashErrors) {
|
|
30201
|
+
compileErrors.push(this.toCompileError(err));
|
|
29884
30202
|
}
|
|
30203
|
+
this.validator.updateConfig({
|
|
30204
|
+
registryReferences,
|
|
30205
|
+
lockfile: this.options.resolver.lockfile,
|
|
30206
|
+
ignoreHashes: this.options.ignoreHashes
|
|
30207
|
+
});
|
|
29885
30208
|
} else if (this.options.ignoreHashes) {
|
|
29886
30209
|
this.logger.verbose("--ignore-hashes is set: reference integrity verification is disabled");
|
|
29887
30210
|
console.error("\u26A0 --ignore-hashes is set: reference integrity verification is disabled");
|
|
29888
|
-
|
|
29889
|
-
|
|
29890
|
-
|
|
30211
|
+
this.validator.updateConfig({ ignoreHashes: true });
|
|
30212
|
+
}
|
|
30213
|
+
if (compileErrors.length > 0) {
|
|
30214
|
+
stats.totalTime = Date.now() - startTotal;
|
|
30215
|
+
return {
|
|
30216
|
+
success: false,
|
|
30217
|
+
outputs: /* @__PURE__ */ new Map(),
|
|
30218
|
+
errors: compileErrors,
|
|
30219
|
+
warnings: [],
|
|
30220
|
+
stats
|
|
30221
|
+
};
|
|
29891
30222
|
}
|
|
29892
30223
|
this.logger.verbose("=== Stage 2: Validate ===");
|
|
29893
30224
|
const startValidate = Date.now();
|
|
@@ -30084,12 +30415,12 @@ var Compiler = class _Compiler {
|
|
|
30084
30415
|
*/
|
|
30085
30416
|
async watch(entryPath, options = {}) {
|
|
30086
30417
|
const { default: chokidar2 } = await import("chokidar");
|
|
30087
|
-
const { dirname:
|
|
30088
|
-
const baseDir =
|
|
30418
|
+
const { dirname: dirname18, resolve: resolve24 } = await import("path");
|
|
30419
|
+
const baseDir = dirname18(resolve24(entryPath));
|
|
30089
30420
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
30090
30421
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
30091
30422
|
const debounceMs = options.debounce ?? 300;
|
|
30092
|
-
const watchPatterns = includePatterns.map((p) =>
|
|
30423
|
+
const watchPatterns = includePatterns.map((p) => resolve24(baseDir, p));
|
|
30093
30424
|
let debounceTimer = null;
|
|
30094
30425
|
let pendingChanges = [];
|
|
30095
30426
|
const handleChange = async (changedFiles) => {
|
|
@@ -30264,7 +30595,7 @@ var Pager = class {
|
|
|
30264
30595
|
}
|
|
30265
30596
|
return;
|
|
30266
30597
|
}
|
|
30267
|
-
return new Promise((
|
|
30598
|
+
return new Promise((resolve24) => {
|
|
30268
30599
|
const pagerCmd = getPagerCommand();
|
|
30269
30600
|
const [cmd, ...args] = pagerCmd.split(" ");
|
|
30270
30601
|
if (cmd === "less" && !args.includes("-R")) {
|
|
@@ -30272,7 +30603,7 @@ var Pager = class {
|
|
|
30272
30603
|
}
|
|
30273
30604
|
if (!cmd) {
|
|
30274
30605
|
console.log(content);
|
|
30275
|
-
|
|
30606
|
+
resolve24();
|
|
30276
30607
|
return;
|
|
30277
30608
|
}
|
|
30278
30609
|
const pager = spawn(cmd, args, {
|
|
@@ -30285,17 +30616,17 @@ var Pager = class {
|
|
|
30285
30616
|
});
|
|
30286
30617
|
pager.on("error", (_err) => {
|
|
30287
30618
|
console.log(content);
|
|
30288
|
-
|
|
30619
|
+
resolve24();
|
|
30289
30620
|
});
|
|
30290
30621
|
pager.on("close", () => {
|
|
30291
|
-
|
|
30622
|
+
resolve24();
|
|
30292
30623
|
});
|
|
30293
30624
|
if (pager.stdin) {
|
|
30294
30625
|
pager.stdin.write(content);
|
|
30295
30626
|
pager.stdin.end();
|
|
30296
30627
|
} else {
|
|
30297
30628
|
console.log(content);
|
|
30298
|
-
|
|
30629
|
+
resolve24();
|
|
30299
30630
|
}
|
|
30300
30631
|
});
|
|
30301
30632
|
}
|
|
@@ -30405,9 +30736,9 @@ var __dirname2 = dirname9(__filename2);
|
|
|
30405
30736
|
async function loadBundledSkillContent(logger) {
|
|
30406
30737
|
const skillRelPath = "skills/promptscript/SKILL.md";
|
|
30407
30738
|
const candidates = [
|
|
30408
|
-
|
|
30739
|
+
resolve10(__dirname2, skillRelPath),
|
|
30409
30740
|
// bundled: dist/packages/cli/skills/...
|
|
30410
|
-
|
|
30741
|
+
resolve10(__dirname2, "..", "..", skillRelPath)
|
|
30411
30742
|
// dev: packages/cli/skills/...
|
|
30412
30743
|
];
|
|
30413
30744
|
for (const candidate of candidates) {
|
|
@@ -30428,7 +30759,7 @@ async function loadBundledSkillContent(logger) {
|
|
|
30428
30759
|
}
|
|
30429
30760
|
function findConfigInDir(dir) {
|
|
30430
30761
|
for (const file of CONFIG_FILES) {
|
|
30431
|
-
const fullPath =
|
|
30762
|
+
const fullPath = resolve10(dir, file);
|
|
30432
30763
|
if (existsSync12(fullPath)) {
|
|
30433
30764
|
return fullPath;
|
|
30434
30765
|
}
|
|
@@ -30485,7 +30816,7 @@ function getBuildProfile(config, buildName) {
|
|
|
30485
30816
|
}
|
|
30486
30817
|
function resolveOutputBase(projectRoot, output) {
|
|
30487
30818
|
if (!output) return projectRoot;
|
|
30488
|
-
return isAbsolute5(output) ? output :
|
|
30819
|
+
return isAbsolute5(output) ? output : resolve10(projectRoot, output);
|
|
30489
30820
|
}
|
|
30490
30821
|
async function isPromptScriptGenerated2(filePath) {
|
|
30491
30822
|
try {
|
|
@@ -30551,7 +30882,7 @@ async function writeOutputs(outputs, options, _config, services) {
|
|
|
30551
30882
|
}
|
|
30552
30883
|
}
|
|
30553
30884
|
for (const output of outputs.values()) {
|
|
30554
|
-
const outputPath = options.output ?
|
|
30885
|
+
const outputPath = options.output ? resolve10(options.output, output.path) : resolve10(output.path);
|
|
30555
30886
|
const fileExists3 = existsSync12(outputPath);
|
|
30556
30887
|
if (options.dryRun) {
|
|
30557
30888
|
if (fileExists3) {
|
|
@@ -30685,14 +31016,21 @@ async function compileCommand(options, services = createDefaultServices()) {
|
|
|
30685
31016
|
const spinner = createSpinner("Loading configuration...").start();
|
|
30686
31017
|
const logger = createCliLogger();
|
|
30687
31018
|
try {
|
|
30688
|
-
const projectRoot = options.cwd ?
|
|
31019
|
+
const projectRoot = options.cwd ? resolve10(options.cwd) : process.cwd();
|
|
30689
31020
|
logger.verbose("Loading configuration...");
|
|
30690
31021
|
const configPath = options.config ? options.config : options.cwd ? findConfigInDir(projectRoot) : void 0;
|
|
30691
|
-
const config = await
|
|
31022
|
+
const config = await loadEffectiveConfig(configPath);
|
|
30692
31023
|
const buildProfile = getBuildProfile(config, options.build);
|
|
30693
31024
|
const selectedTarget = options.target ?? options.format;
|
|
30694
31025
|
const targetEntries = buildProfile?.targets ?? config.targets;
|
|
30695
|
-
const
|
|
31026
|
+
const parsedTargets = parseTargets(targetEntries);
|
|
31027
|
+
let targets;
|
|
31028
|
+
if (selectedTarget) {
|
|
31029
|
+
const matched = parsedTargets.find((t) => t.name === selectedTarget);
|
|
31030
|
+
targets = matched ? [matched] : [{ name: selectedTarget }];
|
|
31031
|
+
} else {
|
|
31032
|
+
targets = parsedTargets;
|
|
31033
|
+
}
|
|
30696
31034
|
const conflicts = detectOutputConflicts(targets);
|
|
30697
31035
|
if (conflicts.size > 0) {
|
|
30698
31036
|
const lines = [...conflicts.entries()].map(
|
|
@@ -30725,7 +31063,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30725
31063
|
}
|
|
30726
31064
|
}
|
|
30727
31065
|
let lockfile;
|
|
30728
|
-
const lockfilePath =
|
|
31066
|
+
const lockfilePath = resolve10(projectRoot, "promptscript.lock");
|
|
30729
31067
|
try {
|
|
30730
31068
|
const lockfileContent = await readFile12(lockfilePath, "utf-8");
|
|
30731
31069
|
const parsed = parseYaml5(lockfileContent, { maxAliasCount: 100 });
|
|
@@ -30745,7 +31083,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30745
31083
|
if (config.includePromptScriptSkill !== false) {
|
|
30746
31084
|
skillContent = await loadBundledSkillContent(logger);
|
|
30747
31085
|
}
|
|
30748
|
-
const localPath =
|
|
31086
|
+
const localPath = resolve10(projectRoot, ".promptscript");
|
|
30749
31087
|
const compiler = new Compiler({
|
|
30750
31088
|
resolver: {
|
|
30751
31089
|
registryPath,
|
|
@@ -30765,7 +31103,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30765
31103
|
ignoreHashes: options.ignoreHashes
|
|
30766
31104
|
});
|
|
30767
31105
|
const entry = buildProfile?.entry ?? config.input?.entry;
|
|
30768
|
-
const entryPath = entry ?
|
|
31106
|
+
const entryPath = entry ? resolve10(projectRoot, entry) : resolve10(localPath, "project.prs");
|
|
30769
31107
|
if (!existsSync12(entryPath)) {
|
|
30770
31108
|
spinner.fail("Entry file not found");
|
|
30771
31109
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
@@ -30805,7 +31143,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
30805
31143
|
ConsoleOutput.newline();
|
|
30806
31144
|
ConsoleOutput.info("Watching for changes... (Ctrl+C to stop)");
|
|
30807
31145
|
watchForChanges(
|
|
30808
|
-
|
|
31146
|
+
resolve10(projectRoot, ".promptscript"),
|
|
30809
31147
|
() => compileCommand({ ...options, watch: false }, services)
|
|
30810
31148
|
);
|
|
30811
31149
|
}
|
|
@@ -30856,7 +31194,7 @@ function watchForChanges(dir, callback) {
|
|
|
30856
31194
|
}
|
|
30857
31195
|
|
|
30858
31196
|
// packages/cli/src/commands/validate.ts
|
|
30859
|
-
import { resolve as
|
|
31197
|
+
import { resolve as resolve11, join as join12 } from "path";
|
|
30860
31198
|
import { existsSync as existsSync13, readFileSync as readFileSync4, writeFileSync, readdirSync } from "fs";
|
|
30861
31199
|
init_console();
|
|
30862
31200
|
init_src();
|
|
@@ -31006,7 +31344,7 @@ async function validateCommand(options) {
|
|
|
31006
31344
|
formatters: []
|
|
31007
31345
|
// No formatters needed for validation only
|
|
31008
31346
|
});
|
|
31009
|
-
const entryPath =
|
|
31347
|
+
const entryPath = resolve11("./.promptscript/project.prs");
|
|
31010
31348
|
if (!existsSync13(entryPath)) {
|
|
31011
31349
|
handleEntryNotFound(entryPath, isJsonFormat, spinner);
|
|
31012
31350
|
return;
|
|
@@ -31090,7 +31428,7 @@ ${fixedCount} file(s) fixed.`);
|
|
|
31090
31428
|
// packages/cli/src/commands/pull.ts
|
|
31091
31429
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
31092
31430
|
import { existsSync as existsSync14 } from "fs";
|
|
31093
|
-
import { resolve as
|
|
31431
|
+
import { resolve as resolve12, dirname as dirname10 } from "path";
|
|
31094
31432
|
init_console();
|
|
31095
31433
|
async function pullCommand(options) {
|
|
31096
31434
|
const spinner = createSpinner("Loading configuration...").start();
|
|
@@ -31115,7 +31453,7 @@ async function pullCommand(options) {
|
|
|
31115
31453
|
}
|
|
31116
31454
|
spinner.text = `Fetching ${inheritPath}...`;
|
|
31117
31455
|
const content = await registry2.fetch(inheritPath);
|
|
31118
|
-
const destPath =
|
|
31456
|
+
const destPath = resolve12("./.promptscript/.inherited", inheritPath);
|
|
31119
31457
|
if (existsSync14(destPath) && !options.force && !options.dryRun) {
|
|
31120
31458
|
spinner.warn("File already exists (use --force to overwrite)");
|
|
31121
31459
|
ConsoleOutput.muted(destPath);
|
|
@@ -31177,7 +31515,7 @@ async function createRegistry(config, options, spinner) {
|
|
|
31177
31515
|
if (!existsSync14(registryPath)) {
|
|
31178
31516
|
throw new Error(`Local registry path not found: ${registryPath}`);
|
|
31179
31517
|
}
|
|
31180
|
-
return createFileSystemRegistry(
|
|
31518
|
+
return createFileSystemRegistry(resolve12(registryPath));
|
|
31181
31519
|
}
|
|
31182
31520
|
function parseInheritPath(inheritPath) {
|
|
31183
31521
|
const versionIndex = inheritPath.lastIndexOf("@");
|
|
@@ -31224,7 +31562,7 @@ function handlePullError(error, spinner) {
|
|
|
31224
31562
|
}
|
|
31225
31563
|
|
|
31226
31564
|
// packages/cli/src/commands/diff.ts
|
|
31227
|
-
import { resolve as
|
|
31565
|
+
import { resolve as resolve13 } from "path";
|
|
31228
31566
|
import { readFile as readFile13 } from "fs/promises";
|
|
31229
31567
|
import { existsSync as existsSync15 } from "fs";
|
|
31230
31568
|
init_console();
|
|
@@ -31261,7 +31599,7 @@ function printNewFilePreview(content, showFull, pager) {
|
|
|
31261
31599
|
}
|
|
31262
31600
|
}
|
|
31263
31601
|
async function compareOutput(_name, output, _config, showFull, pager) {
|
|
31264
|
-
const outputPath =
|
|
31602
|
+
const outputPath = resolve13(output.path);
|
|
31265
31603
|
const newContent = output.content;
|
|
31266
31604
|
if (!existsSync15(outputPath)) {
|
|
31267
31605
|
pager.write(chalk2.green(`+ ${outputPath} (new file)`));
|
|
@@ -31303,7 +31641,7 @@ async function diffCommand(options) {
|
|
|
31303
31641
|
formatters: targets,
|
|
31304
31642
|
customConventions: config.customConventions
|
|
31305
31643
|
});
|
|
31306
|
-
const entryPath =
|
|
31644
|
+
const entryPath = resolve13("./.promptscript/project.prs");
|
|
31307
31645
|
if (!existsSync15(entryPath)) {
|
|
31308
31646
|
spinner.fail("Entry file not found");
|
|
31309
31647
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
@@ -31373,7 +31711,7 @@ function printSimpleDiff(existingLines, newLines, showFull, pager) {
|
|
|
31373
31711
|
|
|
31374
31712
|
// packages/cli/src/commands/check.ts
|
|
31375
31713
|
import { existsSync as existsSync16 } from "fs";
|
|
31376
|
-
import { resolve as
|
|
31714
|
+
import { resolve as resolve14 } from "path";
|
|
31377
31715
|
init_console();
|
|
31378
31716
|
async function checkCommand(_options) {
|
|
31379
31717
|
const spinner = createSpinner("Checking project health...").start();
|
|
@@ -31451,7 +31789,7 @@ async function checkCommand(_options) {
|
|
|
31451
31789
|
hasErrors = true;
|
|
31452
31790
|
}
|
|
31453
31791
|
if (config.registry?.path) {
|
|
31454
|
-
const registryPath =
|
|
31792
|
+
const registryPath = resolve14(config.registry.path);
|
|
31455
31793
|
if (existsSync16(registryPath)) {
|
|
31456
31794
|
results.push({
|
|
31457
31795
|
name: "Registry path",
|
|
@@ -31815,8 +32153,32 @@ var SEED_SECURITY = `@meta {
|
|
|
31815
32153
|
`;
|
|
31816
32154
|
async function scaffoldRegistry(options, services) {
|
|
31817
32155
|
const { fs: fs4 } = services;
|
|
31818
|
-
const { directory, name, description, namespaces, seed } = options;
|
|
32156
|
+
const { directory, name, description, namespaces, seed, force } = options;
|
|
31819
32157
|
const createdFiles = [];
|
|
32158
|
+
const existingManifestPath = join14(directory, "registry-manifest.yaml");
|
|
32159
|
+
if (fs4.existsSync(existingManifestPath) && !force) {
|
|
32160
|
+
throw new Error(
|
|
32161
|
+
`Directory already contains a registry-manifest.yaml. Use --force to overwrite.`
|
|
32162
|
+
);
|
|
32163
|
+
}
|
|
32164
|
+
if (!force) {
|
|
32165
|
+
let entries;
|
|
32166
|
+
try {
|
|
32167
|
+
entries = await fs4.readdir(directory);
|
|
32168
|
+
} catch (err) {
|
|
32169
|
+
const nodeErr = err;
|
|
32170
|
+
if (nodeErr.code !== "ENOENT") {
|
|
32171
|
+
throw err;
|
|
32172
|
+
}
|
|
32173
|
+
entries = [];
|
|
32174
|
+
}
|
|
32175
|
+
const visibleEntries = entries.filter((e) => !e.startsWith("."));
|
|
32176
|
+
if (visibleEntries.length > 0) {
|
|
32177
|
+
throw new Error(
|
|
32178
|
+
`Directory "${directory}" is not empty. Use --force to overwrite existing files.`
|
|
32179
|
+
);
|
|
32180
|
+
}
|
|
32181
|
+
}
|
|
31820
32182
|
await fs4.mkdir(directory, { recursive: true });
|
|
31821
32183
|
const manifest = generateManifest(name, description, namespaces, seed);
|
|
31822
32184
|
const manifestPath = join14(directory, "registry-manifest.yaml");
|
|
@@ -31956,7 +32318,7 @@ Then reference configs with \`@inherit\` or \`@use\`:
|
|
|
31956
32318
|
}
|
|
31957
32319
|
|
|
31958
32320
|
// packages/cli/src/utils/resolve-target-directory.ts
|
|
31959
|
-
import { join as join15, resolve as
|
|
32321
|
+
import { join as join15, resolve as resolve15 } from "path";
|
|
31960
32322
|
|
|
31961
32323
|
// packages/cli/src/utils/slugify.ts
|
|
31962
32324
|
function slugify(name) {
|
|
@@ -31967,7 +32329,7 @@ function slugify(name) {
|
|
|
31967
32329
|
async function resolveTargetDirectory(options, services) {
|
|
31968
32330
|
const { cwd, directoryArg, registryName, nonInteractive } = options;
|
|
31969
32331
|
if (directoryArg) {
|
|
31970
|
-
return
|
|
32332
|
+
return resolve15(directoryArg);
|
|
31971
32333
|
}
|
|
31972
32334
|
const empty = await isDirectoryEmpty(cwd, services.fs);
|
|
31973
32335
|
if (empty && nonInteractive) {
|
|
@@ -32043,7 +32405,7 @@ async function registryInitCommand(directory, options, services = createDefaultS
|
|
|
32043
32405
|
);
|
|
32044
32406
|
const spinner = createSpinner("Creating registry...").start();
|
|
32045
32407
|
const createdFiles = await scaffoldRegistry(
|
|
32046
|
-
{ directory: targetDir, name, description, namespaces, seed },
|
|
32408
|
+
{ directory: targetDir, name, description, namespaces, seed, force: options.force },
|
|
32047
32409
|
services
|
|
32048
32410
|
);
|
|
32049
32411
|
spinner.succeed("Registry created");
|
|
@@ -32074,7 +32436,7 @@ async function registryInitCommand(directory, options, services = createDefaultS
|
|
|
32074
32436
|
// packages/cli/src/commands/registry/validate.ts
|
|
32075
32437
|
init_services();
|
|
32076
32438
|
init_console();
|
|
32077
|
-
import { resolve as
|
|
32439
|
+
import { resolve as resolve16 } from "path";
|
|
32078
32440
|
|
|
32079
32441
|
// packages/cli/src/utils/registry-validator.ts
|
|
32080
32442
|
import { join as join16 } from "path";
|
|
@@ -32274,7 +32636,7 @@ function detectCircularDependencies(catalog) {
|
|
|
32274
32636
|
|
|
32275
32637
|
// packages/cli/src/commands/registry/validate.ts
|
|
32276
32638
|
async function registryValidateCommand(path, options, services = createDefaultServices()) {
|
|
32277
|
-
const registryPath =
|
|
32639
|
+
const registryPath = resolve16(path ?? ".");
|
|
32278
32640
|
const spinner = createSpinner("Validating registry...").start();
|
|
32279
32641
|
try {
|
|
32280
32642
|
const result = await validateRegistry(registryPath, services);
|
|
@@ -32326,10 +32688,10 @@ async function registryValidateCommand(path, options, services = createDefaultSe
|
|
|
32326
32688
|
// packages/cli/src/commands/registry/publish.ts
|
|
32327
32689
|
init_services();
|
|
32328
32690
|
init_console();
|
|
32329
|
-
import { resolve as
|
|
32691
|
+
import { resolve as resolve17, join as join17 } from "path";
|
|
32330
32692
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
32331
32693
|
async function registryPublishCommand(path, options, services = createDefaultServices()) {
|
|
32332
|
-
const registryPath =
|
|
32694
|
+
const registryPath = resolve17(path ?? ".");
|
|
32333
32695
|
try {
|
|
32334
32696
|
if (!options.force) {
|
|
32335
32697
|
const spinner2 = createSpinner("Validating registry...").start();
|
|
@@ -32554,7 +32916,7 @@ async function addToProjectConfig(alias, url) {
|
|
|
32554
32916
|
|
|
32555
32917
|
// packages/cli/src/commands/registry/index.ts
|
|
32556
32918
|
function registerRegistryCommands(registry2) {
|
|
32557
|
-
registry2.command("init [directory]").description("Create a new PromptScript registry").option("-n, --name <name>", "Registry name").option("-d, --description <desc>", "Registry description").option("--namespaces <ns...>", "Namespace names (e.g., @core @stacks)").option("-y, --yes", "Non-interactive mode with defaults").option("-o, --output <dir>", "Output directory").option("--no-seed", "Skip seed configurations").action((directory, opts) => registryInitCommand(directory, opts));
|
|
32919
|
+
registry2.command("init [directory]").description("Create a new PromptScript registry").option("-n, --name <name>", "Registry name").option("-d, --description <desc>", "Registry description").option("--namespaces <ns...>", "Namespace names (e.g., @core @stacks)").option("-y, --yes", "Non-interactive mode with defaults").option("-o, --output <dir>", "Output directory").option("--no-seed", "Skip seed configurations").option("-f, --force", "Force overwrite existing files").action((directory, opts) => registryInitCommand(directory, opts));
|
|
32558
32920
|
registry2.command("validate [path]").description("Validate registry structure and manifest").option("--strict", "Treat warnings as errors").option("--format <format>", "Output format (text, json)", "text").action((path, opts) => registryValidateCommand(path, opts));
|
|
32559
32921
|
registry2.command("publish [path]").description("Publish registry to remote").option("--dry-run", "Preview what would be published").option("-f, --force", "Skip validation").option("-m, --message <msg>", "Git commit message").option("--tag <tag>", "Git tag for release").action((path, opts) => registryPublishCommand(path, opts));
|
|
32560
32922
|
registry2.command("list").description("Show merged registry alias mappings from all config levels").action(() => registryListCommand());
|
|
@@ -32564,7 +32926,7 @@ function registerRegistryCommands(registry2) {
|
|
|
32564
32926
|
// packages/cli/src/commands/lock.ts
|
|
32565
32927
|
import { writeFile as writeFile8, readFile as readFile18 } from "fs/promises";
|
|
32566
32928
|
import { existsSync as existsSync19 } from "fs";
|
|
32567
|
-
import { resolve as
|
|
32929
|
+
import { resolve as resolve18 } from "path";
|
|
32568
32930
|
import { parse as parseYaml9, stringify as stringifyYaml2 } from "yaml";
|
|
32569
32931
|
init_console();
|
|
32570
32932
|
init_src();
|
|
@@ -32637,8 +32999,8 @@ async function lockCommand(options) {
|
|
|
32637
32999
|
const aliases = config.registries ?? {};
|
|
32638
33000
|
const aliasEntries = Object.entries(aliases);
|
|
32639
33001
|
const projectRoot = process.cwd();
|
|
32640
|
-
const localPath =
|
|
32641
|
-
const entryPath = config.input?.entry ?
|
|
33002
|
+
const localPath = resolve18(projectRoot, ".promptscript");
|
|
33003
|
+
const entryPath = config.input?.entry ? resolve18(projectRoot, config.input.entry) : resolve18(localPath, "project.prs");
|
|
32642
33004
|
const scannedImports = await collectRemoteImports(entryPath, {
|
|
32643
33005
|
localPath,
|
|
32644
33006
|
registries: config.registries
|
|
@@ -32765,10 +33127,12 @@ async function updateCommand(packageArg, options) {
|
|
|
32765
33127
|
const dependencies = { ...existing.dependencies };
|
|
32766
33128
|
for (const repoUrl of toUpdate) {
|
|
32767
33129
|
const before = existing.dependencies[repoUrl]?.version ?? "(none)";
|
|
33130
|
+
const existingDep = existing.dependencies[repoUrl];
|
|
33131
|
+
const validation = await validateRemoteAccess(repoUrl);
|
|
32768
33132
|
const updated = {
|
|
32769
33133
|
version: "latest",
|
|
32770
|
-
commit: "0000000000000000000000000000000000000000",
|
|
32771
|
-
integrity: "sha256-pending"
|
|
33134
|
+
commit: validation.headCommit ?? existingDep?.commit ?? "0000000000000000000000000000000000000000",
|
|
33135
|
+
integrity: existingDep?.integrity ?? "sha256-pending"
|
|
32772
33136
|
};
|
|
32773
33137
|
dependencies[repoUrl] = updated;
|
|
32774
33138
|
updates.push({ repoUrl, before, after: updated.version });
|
|
@@ -32806,7 +33170,7 @@ init_console();
|
|
|
32806
33170
|
init_src();
|
|
32807
33171
|
import { readFile as readFile20, writeFile as writeFile10, mkdir as mkdir8, readdir as readdir5 } from "fs/promises";
|
|
32808
33172
|
import { existsSync as existsSync21 } from "fs";
|
|
32809
|
-
import { join as join18, resolve as
|
|
33173
|
+
import { join as join18, resolve as resolve19 } from "path";
|
|
32810
33174
|
import { homedir as homedir4 } from "os";
|
|
32811
33175
|
import { parse as parseYaml11 } from "yaml";
|
|
32812
33176
|
var VENDOR_DIR = ".promptscript/vendor";
|
|
@@ -32834,7 +33198,7 @@ async function vendorSyncCommand(options) {
|
|
|
32834
33198
|
continue;
|
|
32835
33199
|
}
|
|
32836
33200
|
if (!options.dryRun) {
|
|
32837
|
-
const vendorTarget =
|
|
33201
|
+
const vendorTarget = resolve19(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32838
33202
|
await mkdir8(vendorTarget, { recursive: true });
|
|
32839
33203
|
await copyDirectory(cacheDir, vendorTarget);
|
|
32840
33204
|
}
|
|
@@ -32888,7 +33252,7 @@ async function vendorCheckCommand(_options) {
|
|
|
32888
33252
|
}
|
|
32889
33253
|
const issues = [];
|
|
32890
33254
|
for (const [repoUrl] of deps) {
|
|
32891
|
-
const vendorTarget =
|
|
33255
|
+
const vendorTarget = resolve19(VENDOR_DIR, repoUrl.replace(/[/:]/g, "_"));
|
|
32892
33256
|
if (!existsSync21(vendorTarget)) {
|
|
32893
33257
|
issues.push({ repoUrl, issue: "missing from vendor directory" });
|
|
32894
33258
|
}
|
|
@@ -33025,7 +33389,7 @@ async function resolveCommand(importPath, _options) {
|
|
|
33025
33389
|
|
|
33026
33390
|
// packages/cli/src/commands/inspect.ts
|
|
33027
33391
|
import { existsSync as existsSync23 } from "fs";
|
|
33028
|
-
import { resolve as
|
|
33392
|
+
import { resolve as resolve20, basename as basename13 } from "path";
|
|
33029
33393
|
init_console();
|
|
33030
33394
|
async function inspectCommand(skillName, options) {
|
|
33031
33395
|
const isJson = options.format === "json";
|
|
@@ -33038,7 +33402,7 @@ async function inspectCommand(skillName, options) {
|
|
|
33038
33402
|
localPath: "./.promptscript",
|
|
33039
33403
|
registries: config.registries
|
|
33040
33404
|
});
|
|
33041
|
-
const entryPath =
|
|
33405
|
+
const entryPath = resolve20("./.promptscript/project.prs");
|
|
33042
33406
|
if (!existsSync23(entryPath)) {
|
|
33043
33407
|
spinner.stop();
|
|
33044
33408
|
ConsoleOutput.error(`Entry file not found: ${entryPath}`);
|
|
@@ -33219,7 +33583,7 @@ init_console();
|
|
|
33219
33583
|
// packages/cli/src/commands/import.ts
|
|
33220
33584
|
init_src3();
|
|
33221
33585
|
init_console();
|
|
33222
|
-
import { resolve as
|
|
33586
|
+
import { resolve as resolve21, join as join20, basename as basename14 } from "path";
|
|
33223
33587
|
import { writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync24 } from "fs";
|
|
33224
33588
|
import { stat as stat2, readdir as readdir6, readFile as readFile21, writeFile as writeFile11, mkdir as mkdir9 } from "fs/promises";
|
|
33225
33589
|
function parseInstructionFrontmatter(content) {
|
|
@@ -33274,7 +33638,7 @@ async function importDirectory(dirPath) {
|
|
|
33274
33638
|
return lines.join("\n");
|
|
33275
33639
|
}
|
|
33276
33640
|
async function importCommand(file, options) {
|
|
33277
|
-
const filepath =
|
|
33641
|
+
const filepath = resolve21(file);
|
|
33278
33642
|
const inputStat = await stat2(filepath).catch(() => null);
|
|
33279
33643
|
if (inputStat?.isDirectory()) {
|
|
33280
33644
|
const prsContent = await importDirectory(filepath);
|
|
@@ -33306,11 +33670,11 @@ async function importCommand(file, options) {
|
|
|
33306
33670
|
console.log(result.prsContent);
|
|
33307
33671
|
return;
|
|
33308
33672
|
}
|
|
33309
|
-
const outputDir =
|
|
33673
|
+
const outputDir = resolve21(options.output ?? ".promptscript");
|
|
33310
33674
|
if (!existsSync24(outputDir)) {
|
|
33311
33675
|
mkdirSync(outputDir, { recursive: true });
|
|
33312
33676
|
}
|
|
33313
|
-
const outputPath =
|
|
33677
|
+
const outputPath = resolve21(outputDir, "imported.prs");
|
|
33314
33678
|
writeFileSync2(outputPath, result.prsContent, "utf-8");
|
|
33315
33679
|
ConsoleOutput.success(`Written to ${outputPath}`);
|
|
33316
33680
|
if (options.validate) {
|
|
@@ -33545,7 +33909,7 @@ init_hooks();
|
|
|
33545
33909
|
|
|
33546
33910
|
// packages/cli/src/commands/skills.ts
|
|
33547
33911
|
import { writeFile as writeFile12, readFile as readFile23, readdir as readdir7, mkdtemp, rm } from "fs/promises";
|
|
33548
|
-
import { resolve as
|
|
33912
|
+
import { resolve as resolve22, join as join22, basename as basename15, dirname as dirname13 } from "path";
|
|
33549
33913
|
import { existsSync as existsSync26 } from "fs";
|
|
33550
33914
|
import { tmpdir as tmpdir2 } from "os";
|
|
33551
33915
|
import { parse as parseYaml12, stringify as stringifyYaml4 } from "yaml";
|
|
@@ -33665,7 +34029,7 @@ function validateRemoteSource(source) {
|
|
|
33665
34029
|
}
|
|
33666
34030
|
async function resolveEntryFile(fileFlag) {
|
|
33667
34031
|
if (fileFlag) {
|
|
33668
|
-
const resolved =
|
|
34032
|
+
const resolved = resolve22(fileFlag);
|
|
33669
34033
|
if (!existsSync26(resolved)) {
|
|
33670
34034
|
throw new Error(`File not found: ${resolved}`);
|
|
33671
34035
|
}
|
|
@@ -33676,7 +34040,7 @@ async function resolveEntryFile(fileFlag) {
|
|
|
33676
34040
|
try {
|
|
33677
34041
|
const config = await loadConfig();
|
|
33678
34042
|
if (config.input?.entry) {
|
|
33679
|
-
const entryPath =
|
|
34043
|
+
const entryPath = resolve22(config.input.entry);
|
|
33680
34044
|
if (existsSync26(entryPath)) {
|
|
33681
34045
|
return entryPath;
|
|
33682
34046
|
}
|
|
@@ -33684,16 +34048,16 @@ async function resolveEntryFile(fileFlag) {
|
|
|
33684
34048
|
} catch {
|
|
33685
34049
|
}
|
|
33686
34050
|
}
|
|
33687
|
-
const promptscriptDir =
|
|
34051
|
+
const promptscriptDir = resolve22(".promptscript");
|
|
33688
34052
|
if (existsSync26(promptscriptDir)) {
|
|
33689
34053
|
const entries = await readdir7(promptscriptDir);
|
|
33690
34054
|
const prsFiles = entries.filter((f) => f.endsWith(".prs"));
|
|
33691
34055
|
if (prsFiles.length === 1) {
|
|
33692
|
-
return
|
|
34056
|
+
return resolve22(promptscriptDir, prsFiles[0]);
|
|
33693
34057
|
}
|
|
33694
34058
|
if (prsFiles.length > 1) {
|
|
33695
34059
|
if (prsFiles.includes("project.prs")) {
|
|
33696
|
-
return
|
|
34060
|
+
return resolve22(promptscriptDir, "project.prs");
|
|
33697
34061
|
}
|
|
33698
34062
|
throw new Error(
|
|
33699
34063
|
`Multiple .prs files found in .promptscript/. Use --file to specify which one.`
|
|
@@ -34044,7 +34408,7 @@ async function skillsUpdateCommand(name, options) {
|
|
|
34044
34408
|
|
|
34045
34409
|
// packages/cli/src/cli.ts
|
|
34046
34410
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
34047
|
-
var __dirname4 =
|
|
34411
|
+
var __dirname4 = dirname17(__filename4);
|
|
34048
34412
|
var program = new Command();
|
|
34049
34413
|
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) => {
|
|
34050
34414
|
const opts = thisCommand.opts();
|
|
@@ -34112,7 +34476,9 @@ registerRegistryCommands(registry);
|
|
|
34112
34476
|
function run(args = process.argv) {
|
|
34113
34477
|
program.parse(args);
|
|
34114
34478
|
}
|
|
34115
|
-
|
|
34479
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
34480
|
+
run();
|
|
34481
|
+
}
|
|
34116
34482
|
|
|
34117
34483
|
// packages/cli/src/index.ts
|
|
34118
34484
|
init_init();
|
|
@@ -34150,7 +34516,7 @@ toad-cache/dist/toad-cache.cjs:
|
|
|
34150
34516
|
(**
|
|
34151
34517
|
* toad-cache
|
|
34152
34518
|
*
|
|
34153
|
-
* @copyright
|
|
34519
|
+
* @copyright 2026 Igor Savin <kibertoad@gmail.com>
|
|
34154
34520
|
* @license MIT
|
|
34155
34521
|
* @version 3.7.0
|
|
34156
34522
|
*)
|