@promptscript/cli 1.16.0 → 1.17.1
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 +1 -1
- package/index.js +1666 -221
- package/package.json +3 -3
- package/src/cli.d.ts +1 -1
- package/src/cli.d.ts.map +1 -1
- package/src/commands/init.d.ts +4 -0
- package/src/commands/init.d.ts.map +1 -1
- package/src/commands/telemetry.d.ts +3 -0
- package/src/commands/telemetry.d.ts.map +1 -0
- package/src/commands/vendor.d.ts.map +1 -1
- package/src/config/env-config.d.ts +1 -0
- package/src/config/env-config.d.ts.map +1 -1
- package/src/config/merge-config.d.ts.map +1 -1
- package/src/telemetry/config.d.ts +10 -0
- package/src/telemetry/config.d.ts.map +1 -0
- package/src/telemetry/session.d.ts +14 -0
- package/src/telemetry/session.d.ts.map +1 -0
package/index.js
CHANGED
|
@@ -4437,20 +4437,20 @@ var init_services = __esm({
|
|
|
4437
4437
|
existsSync,
|
|
4438
4438
|
readFileSync: readFileSync2,
|
|
4439
4439
|
rename: async (...args) => {
|
|
4440
|
-
const { rename:
|
|
4441
|
-
return
|
|
4440
|
+
const { rename: rename3 } = await import("node:fs/promises");
|
|
4441
|
+
return rename3(...args);
|
|
4442
4442
|
},
|
|
4443
4443
|
rm: async (...args) => {
|
|
4444
4444
|
const { rm: rm3 } = await import("node:fs/promises");
|
|
4445
4445
|
return rm3(...args);
|
|
4446
4446
|
},
|
|
4447
4447
|
lstat: async (path2) => {
|
|
4448
|
-
const { lstat:
|
|
4449
|
-
return
|
|
4448
|
+
const { lstat: lstat10 } = await import("node:fs/promises");
|
|
4449
|
+
return lstat10(path2);
|
|
4450
4450
|
},
|
|
4451
4451
|
realpath: async (path2) => {
|
|
4452
|
-
const { realpath:
|
|
4453
|
-
return
|
|
4452
|
+
const { realpath: realpath7 } = await import("node:fs/promises");
|
|
4453
|
+
return realpath7(path2);
|
|
4454
4454
|
}
|
|
4455
4455
|
};
|
|
4456
4456
|
defaultPrompts = {
|
|
@@ -18437,8 +18437,8 @@ ${f.content}`
|
|
|
18437
18437
|
if (project) sections.push(project);
|
|
18438
18438
|
const techStack = this.techStack(ast, renderer);
|
|
18439
18439
|
if (techStack) sections.push(techStack);
|
|
18440
|
-
const
|
|
18441
|
-
if (
|
|
18440
|
+
const architecture2 = this.architecture(ast, renderer);
|
|
18441
|
+
if (architecture2) sections.push(architecture2);
|
|
18442
18442
|
const contextSection = this.contextSection(ast, renderer);
|
|
18443
18443
|
if (contextSection) sections.push(contextSection);
|
|
18444
18444
|
const codeStandards = this.codeStandards(ast, renderer);
|
|
@@ -20437,8 +20437,8 @@ ${content}`);
|
|
|
20437
20437
|
if (intro) sections.push(intro);
|
|
20438
20438
|
const techStack = this.techStack(ast);
|
|
20439
20439
|
if (techStack) sections.push(techStack);
|
|
20440
|
-
const
|
|
20441
|
-
if (
|
|
20440
|
+
const architecture2 = this.architecture(ast);
|
|
20441
|
+
if (architecture2) sections.push(architecture2);
|
|
20442
20442
|
const context = this.contextSection(ast);
|
|
20443
20443
|
if (context) sections.push(context);
|
|
20444
20444
|
const codeStyle = this.codeStyle(ast);
|
|
@@ -21021,8 +21021,8 @@ ${content}`);
|
|
|
21021
21021
|
if (identity) sections.push(identity);
|
|
21022
21022
|
const techStack = this.techStack(ast, renderer);
|
|
21023
21023
|
if (techStack) sections.push(techStack);
|
|
21024
|
-
const
|
|
21025
|
-
if (
|
|
21024
|
+
const architecture2 = this.architecture(ast, renderer);
|
|
21025
|
+
if (architecture2) sections.push(architecture2);
|
|
21026
21026
|
const contextSection = this.contextSection(ast, renderer);
|
|
21027
21027
|
if (contextSection) sections.push(contextSection);
|
|
21028
21028
|
const codeStandards = this.codeStandards(ast, renderer);
|
|
@@ -26597,8 +26597,20 @@ function loadEnvOverrides() {
|
|
|
26597
26597
|
const registryUrl = process.env["PROMPTSCRIPT_REGISTRY_URL"];
|
|
26598
26598
|
const cacheTtl = process.env["PROMPTSCRIPT_CACHE_TTL"];
|
|
26599
26599
|
const cacheEnabled = process.env["PROMPTSCRIPT_CACHE_ENABLED"];
|
|
26600
|
+
const telemetry = process.env["PROMPTSCRIPT_TELEMETRY"];
|
|
26600
26601
|
const hasCache = cacheTtl || cacheEnabled;
|
|
26601
26602
|
const hasRegistry = gitUrl || gitRef || registryUrl || hasCache;
|
|
26603
|
+
if (!hasRegistry && telemetry === void 0) {
|
|
26604
|
+
return overrides;
|
|
26605
|
+
}
|
|
26606
|
+
if (telemetry !== void 0) {
|
|
26607
|
+
const normalized = telemetry.trim().toLowerCase();
|
|
26608
|
+
if (["1", "true", "yes", "on"].includes(normalized)) {
|
|
26609
|
+
overrides.telemetry = true;
|
|
26610
|
+
} else if (["0", "false", "no", "off"].includes(normalized)) {
|
|
26611
|
+
overrides.telemetry = false;
|
|
26612
|
+
}
|
|
26613
|
+
}
|
|
26602
26614
|
if (!hasRegistry) {
|
|
26603
26615
|
return overrides;
|
|
26604
26616
|
}
|
|
@@ -26677,6 +26689,22 @@ function userConfigToProjectRegistry(userRegistry) {
|
|
|
26677
26689
|
}
|
|
26678
26690
|
function mergeConfigs(userConfig, projectConfig, envOverrides, cliFlags) {
|
|
26679
26691
|
const merged = { ...projectConfig };
|
|
26692
|
+
const telemetryValues = [
|
|
26693
|
+
userConfig.telemetry,
|
|
26694
|
+
projectConfig.telemetry,
|
|
26695
|
+
envOverrides.telemetry,
|
|
26696
|
+
cliFlags?.telemetry
|
|
26697
|
+
];
|
|
26698
|
+
if (telemetryValues.includes(false)) {
|
|
26699
|
+
merged.telemetry = false;
|
|
26700
|
+
} else {
|
|
26701
|
+
const explicitTelemetry = telemetryValues.find(
|
|
26702
|
+
(value) => value !== void 0
|
|
26703
|
+
);
|
|
26704
|
+
if (explicitTelemetry !== void 0) {
|
|
26705
|
+
merged.telemetry = explicitTelemetry;
|
|
26706
|
+
}
|
|
26707
|
+
}
|
|
26680
26708
|
if (userConfig.registry) {
|
|
26681
26709
|
const userRegistry = userConfigToProjectRegistry(userConfig.registry);
|
|
26682
26710
|
merged.registry = deepMergeRegistry(userRegistry, merged.registry);
|
|
@@ -27416,13 +27444,7 @@ function getSkillWrites(targets) {
|
|
|
27416
27444
|
const skillSource = resolve7(BUNDLED_SKILLS_DIR, skillName, "SKILL.md");
|
|
27417
27445
|
try {
|
|
27418
27446
|
const rawSkillContent = readFileSync3(skillSource, "utf-8");
|
|
27419
|
-
|
|
27420
|
-
const hasMarker = rawSkillContent.includes("<!-- PromptScript") || rawSkillContent.includes("# promptscript-generated:");
|
|
27421
|
-
if (!hasMarker && rawSkillContent.startsWith("---")) {
|
|
27422
|
-
const yamlMarker = "# promptscript-generated: true";
|
|
27423
|
-
skillContent = `---
|
|
27424
|
-
${yamlMarker}${rawSkillContent.slice(3)}`;
|
|
27425
|
-
}
|
|
27447
|
+
const skillContent = addPromptScriptMarker(rawSkillContent);
|
|
27426
27448
|
writes.push({
|
|
27427
27449
|
path: `.promptscript/skills/${skillName}/SKILL.md`,
|
|
27428
27450
|
content: skillContent
|
|
@@ -27430,7 +27452,14 @@ ${yamlMarker}${rawSkillContent.slice(3)}`;
|
|
|
27430
27452
|
for (const target of targets) {
|
|
27431
27453
|
const targetSkillDir = getTargetSkillDir(target, skillName);
|
|
27432
27454
|
if (targetSkillDir && !writes.some((write) => write.path === targetSkillDir.path)) {
|
|
27433
|
-
|
|
27455
|
+
const formatter = FormatterRegistry.get(target);
|
|
27456
|
+
let targetContent = skillContent;
|
|
27457
|
+
if (formatter?.transformInjectedSkillContent) {
|
|
27458
|
+
targetContent = addPromptScriptMarker(
|
|
27459
|
+
formatter.transformInjectedSkillContent(rawSkillContent)
|
|
27460
|
+
);
|
|
27461
|
+
}
|
|
27462
|
+
writes.push({ path: targetSkillDir.path, content: targetContent });
|
|
27434
27463
|
}
|
|
27435
27464
|
}
|
|
27436
27465
|
} catch {
|
|
@@ -27438,6 +27467,11 @@ ${yamlMarker}${rawSkillContent.slice(3)}`;
|
|
|
27438
27467
|
}
|
|
27439
27468
|
return writes;
|
|
27440
27469
|
}
|
|
27470
|
+
function addPromptScriptMarker(content) {
|
|
27471
|
+
const hasMarker = content.includes("<!-- PromptScript") || content.includes("# promptscript-generated:");
|
|
27472
|
+
return !hasMarker && content.startsWith("---") ? `---
|
|
27473
|
+
# promptscript-generated: true${content.slice(3)}` : content;
|
|
27474
|
+
}
|
|
27441
27475
|
async function resolveConfig(options, projectInfo, aiToolsDetection, prettierConfigPath, manifest, services) {
|
|
27442
27476
|
if (options.yes) {
|
|
27443
27477
|
const userConfig = await loadUserConfig();
|
|
@@ -28009,13 +28043,13 @@ var require_ipv4 = __commonJS({
|
|
|
28009
28043
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28010
28044
|
exports.Address4 = void 0;
|
|
28011
28045
|
var common = __importStar(require_common());
|
|
28012
|
-
var
|
|
28046
|
+
var constants4 = __importStar(require_constants());
|
|
28013
28047
|
var address_error_1 = require_address_error();
|
|
28014
|
-
var isCorrect4 = common.isCorrect(
|
|
28048
|
+
var isCorrect4 = common.isCorrect(constants4.BITS);
|
|
28015
28049
|
var Address4 = class _Address4 {
|
|
28016
28050
|
constructor(address) {
|
|
28017
28051
|
this.addressMinusSuffix = "";
|
|
28018
|
-
this.groups =
|
|
28052
|
+
this.groups = constants4.GROUPS;
|
|
28019
28053
|
this.parsedAddress = [];
|
|
28020
28054
|
this.parsedSubnet = "";
|
|
28021
28055
|
this.subnet = "/32";
|
|
@@ -28025,15 +28059,15 @@ var require_ipv4 = __commonJS({
|
|
|
28025
28059
|
this.isInSubnet = common.isInSubnet;
|
|
28026
28060
|
this.isHostInSubnet = common.isHostInSubnet;
|
|
28027
28061
|
this.address = address;
|
|
28028
|
-
const subnet =
|
|
28062
|
+
const subnet = constants4.RE_SUBNET_STRING.exec(address);
|
|
28029
28063
|
if (subnet) {
|
|
28030
28064
|
this.parsedSubnet = subnet[0].replace("/", "");
|
|
28031
28065
|
this.subnetMask = parseInt(this.parsedSubnet, 10);
|
|
28032
28066
|
this.subnet = `/${this.subnetMask}`;
|
|
28033
|
-
if (this.subnetMask < 0 || this.subnetMask >
|
|
28067
|
+
if (this.subnetMask < 0 || this.subnetMask > constants4.BITS) {
|
|
28034
28068
|
throw new address_error_1.AddressError("Invalid subnet mask.");
|
|
28035
28069
|
}
|
|
28036
|
-
address = address.replace(
|
|
28070
|
+
address = address.replace(constants4.RE_SUBNET_STRING, "");
|
|
28037
28071
|
}
|
|
28038
28072
|
this.addressMinusSuffix = address;
|
|
28039
28073
|
this.parsedAddress = this.parse(address);
|
|
@@ -28064,7 +28098,7 @@ var require_ipv4 = __commonJS({
|
|
|
28064
28098
|
if (groups.some((group) => /^0\d/.test(group))) {
|
|
28065
28099
|
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.");
|
|
28066
28100
|
}
|
|
28067
|
-
if (!address.match(
|
|
28101
|
+
if (!address.match(constants4.RE_ADDRESS)) {
|
|
28068
28102
|
throw new address_error_1.AddressError("Invalid IPv4 address.");
|
|
28069
28103
|
}
|
|
28070
28104
|
return groups;
|
|
@@ -28087,7 +28121,7 @@ var require_ipv4 = __commonJS({
|
|
|
28087
28121
|
* address.subnetMask; // 24
|
|
28088
28122
|
*/
|
|
28089
28123
|
static fromAddressAndMask(address, mask) {
|
|
28090
|
-
const bits = common.prefixLengthFromMask(new _Address4(mask).bigInt(),
|
|
28124
|
+
const bits = common.prefixLengthFromMask(new _Address4(mask).bigInt(), constants4.BITS);
|
|
28091
28125
|
return new _Address4(`${address}/${bits}`);
|
|
28092
28126
|
}
|
|
28093
28127
|
/**
|
|
@@ -28101,9 +28135,9 @@ var require_ipv4 = __commonJS({
|
|
|
28101
28135
|
*/
|
|
28102
28136
|
static fromAddressAndWildcardMask(address, wildcardMask) {
|
|
28103
28137
|
const wildcard = new _Address4(wildcardMask).bigInt();
|
|
28104
|
-
const allOnes = (BigInt(1) << BigInt(
|
|
28138
|
+
const allOnes = (BigInt(1) << BigInt(constants4.BITS)) - BigInt(1);
|
|
28105
28139
|
const mask = wildcard ^ allOnes;
|
|
28106
|
-
const bits = common.prefixLengthFromMask(mask,
|
|
28140
|
+
const bits = common.prefixLengthFromMask(mask, constants4.BITS);
|
|
28107
28141
|
return new _Address4(`${address}/${bits}`);
|
|
28108
28142
|
}
|
|
28109
28143
|
/**
|
|
@@ -28121,7 +28155,7 @@ var require_ipv4 = __commonJS({
|
|
|
28121
28155
|
*/
|
|
28122
28156
|
static fromWildcard(input2) {
|
|
28123
28157
|
const groups = input2.split(".");
|
|
28124
|
-
if (groups.length !==
|
|
28158
|
+
if (groups.length !== constants4.GROUPS) {
|
|
28125
28159
|
throw new address_error_1.AddressError("Wildcard pattern must have 4 octets");
|
|
28126
28160
|
}
|
|
28127
28161
|
let firstWildcard = -1;
|
|
@@ -28136,7 +28170,7 @@ var require_ipv4 = __commonJS({
|
|
|
28136
28170
|
}
|
|
28137
28171
|
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
|
|
28138
28172
|
const replaced = groups.map((g) => g === "*" ? "0" : g);
|
|
28139
|
-
const subnetBits =
|
|
28173
|
+
const subnetBits = constants4.BITS - trailing * 8;
|
|
28140
28174
|
return new _Address4(`${replaced.join(".")}/${subnetBits}`);
|
|
28141
28175
|
}
|
|
28142
28176
|
/**
|
|
@@ -28206,7 +28240,7 @@ var require_ipv4 = __commonJS({
|
|
|
28206
28240
|
toGroup6() {
|
|
28207
28241
|
const output = [];
|
|
28208
28242
|
let i;
|
|
28209
|
-
for (i = 0; i <
|
|
28243
|
+
for (i = 0; i < constants4.GROUPS; i += 2) {
|
|
28210
28244
|
output.push(`${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(this.parsedAddress[i + 1])}`);
|
|
28211
28245
|
}
|
|
28212
28246
|
return output.join(":");
|
|
@@ -28223,7 +28257,7 @@ var require_ipv4 = __commonJS({
|
|
|
28223
28257
|
* @returns {bigint}
|
|
28224
28258
|
*/
|
|
28225
28259
|
_startAddress() {
|
|
28226
|
-
return BigInt(`0b${this.mask() + "0".repeat(
|
|
28260
|
+
return BigInt(`0b${this.mask() + "0".repeat(constants4.BITS - this.subnetMask)}`);
|
|
28227
28261
|
}
|
|
28228
28262
|
/**
|
|
28229
28263
|
* The first address in the range given by this address' subnet.
|
|
@@ -28247,7 +28281,7 @@ var require_ipv4 = __commonJS({
|
|
|
28247
28281
|
* @returns {bigint}
|
|
28248
28282
|
*/
|
|
28249
28283
|
_endAddress() {
|
|
28250
|
-
return BigInt(`0b${this.mask() + "1".repeat(
|
|
28284
|
+
return BigInt(`0b${this.mask() + "1".repeat(constants4.BITS - this.subnetMask)}`);
|
|
28251
28285
|
}
|
|
28252
28286
|
/**
|
|
28253
28287
|
* The last address in the range given by this address' subnet
|
|
@@ -28272,7 +28306,7 @@ var require_ipv4 = __commonJS({
|
|
|
28272
28306
|
* @returns {Address4}
|
|
28273
28307
|
*/
|
|
28274
28308
|
subnetMaskAddress() {
|
|
28275
|
-
return _Address4.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(
|
|
28309
|
+
return _Address4.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(constants4.BITS - this.subnetMask)}`));
|
|
28276
28310
|
}
|
|
28277
28311
|
/**
|
|
28278
28312
|
* The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
|
|
@@ -28281,7 +28315,7 @@ var require_ipv4 = __commonJS({
|
|
|
28281
28315
|
* @returns {Address4}
|
|
28282
28316
|
*/
|
|
28283
28317
|
wildcardMask() {
|
|
28284
|
-
return _Address4.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(
|
|
28318
|
+
return _Address4.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(constants4.BITS - this.subnetMask)}`));
|
|
28285
28319
|
}
|
|
28286
28320
|
/**
|
|
28287
28321
|
* The network address in CIDR string form, e.g. `192.168.1.0/24` for
|
|
@@ -28416,7 +28450,7 @@ var require_ipv4 = __commonJS({
|
|
|
28416
28450
|
*/
|
|
28417
28451
|
binaryZeroPad() {
|
|
28418
28452
|
if (this._binaryZeroPad === void 0) {
|
|
28419
|
-
this._binaryZeroPad = this.bigInt().toString(2).padStart(
|
|
28453
|
+
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants4.BITS, "0");
|
|
28420
28454
|
}
|
|
28421
28455
|
return this._binaryZeroPad;
|
|
28422
28456
|
}
|
|
@@ -28426,7 +28460,7 @@ var require_ipv4 = __commonJS({
|
|
|
28426
28460
|
*/
|
|
28427
28461
|
groupForV6() {
|
|
28428
28462
|
const segments = this.parsedAddress;
|
|
28429
|
-
return this.correctForm().replace(
|
|
28463
|
+
return this.correctForm().replace(constants4.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments.slice(0, 2).join(".")}</span>.<span class="hover-group group-v4 group-7">${segments.slice(2, 4).join(".")}</span>`);
|
|
28430
28464
|
}
|
|
28431
28465
|
};
|
|
28432
28466
|
exports.Address4 = Address4;
|
|
@@ -31082,9 +31116,9 @@ var require_rate_limit = __commonJS({
|
|
|
31082
31116
|
throw new Error("The configured rate-limit store does not implement a `read` method, which is required to use `{ increment: false }`");
|
|
31083
31117
|
}
|
|
31084
31118
|
try {
|
|
31085
|
-
const res = await new Promise((
|
|
31119
|
+
const res = await new Promise((resolve38, reject) => {
|
|
31086
31120
|
store[storeMethod](key, (err, res2) => {
|
|
31087
|
-
err ? reject(err) :
|
|
31121
|
+
err ? reject(err) : resolve38(res2);
|
|
31088
31122
|
}, timeWindow, max);
|
|
31089
31123
|
});
|
|
31090
31124
|
current = res.current;
|
|
@@ -31191,13 +31225,13 @@ var init_health = __esm({
|
|
|
31191
31225
|
});
|
|
31192
31226
|
|
|
31193
31227
|
// packages/server/src/source-dirs.ts
|
|
31194
|
-
import { readFile as
|
|
31195
|
-
import { join as
|
|
31228
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
31229
|
+
import { join as join31, dirname as dirname23 } from "path";
|
|
31196
31230
|
import { parse as parseYaml16 } from "yaml";
|
|
31197
31231
|
async function readProjectConfig(workspace) {
|
|
31198
31232
|
for (const filename of CONFIG_FILENAMES) {
|
|
31199
31233
|
try {
|
|
31200
|
-
const raw = await
|
|
31234
|
+
const raw = await readFile29(join31(workspace, filename), "utf-8");
|
|
31201
31235
|
const config = parseYaml16(raw);
|
|
31202
31236
|
if (config) return config;
|
|
31203
31237
|
} catch {
|
|
@@ -31208,10 +31242,10 @@ async function readProjectConfig(workspace) {
|
|
|
31208
31242
|
async function resolveSourceDir(workspace) {
|
|
31209
31243
|
for (const filename of CONFIG_FILENAMES) {
|
|
31210
31244
|
try {
|
|
31211
|
-
const raw = await
|
|
31245
|
+
const raw = await readFile29(join31(workspace, filename), "utf-8");
|
|
31212
31246
|
const config = parseYaml16(raw);
|
|
31213
31247
|
if (config?.input?.entry) {
|
|
31214
|
-
return
|
|
31248
|
+
return dirname23(config.input.entry);
|
|
31215
31249
|
}
|
|
31216
31250
|
} catch {
|
|
31217
31251
|
}
|
|
@@ -31225,9 +31259,9 @@ async function resolveFileGlobs(workspace) {
|
|
|
31225
31259
|
async function resolveWatchPaths(workspace) {
|
|
31226
31260
|
const sourceDir = await resolveSourceDir(workspace);
|
|
31227
31261
|
return [
|
|
31228
|
-
|
|
31229
|
-
|
|
31230
|
-
|
|
31262
|
+
join31(workspace, sourceDir),
|
|
31263
|
+
join31(workspace, "promptscript.yaml"),
|
|
31264
|
+
join31(workspace, "promptscript.yml")
|
|
31231
31265
|
];
|
|
31232
31266
|
}
|
|
31233
31267
|
var DEFAULT_SOURCE_DIR, CONFIG_FILENAMES;
|
|
@@ -31254,32 +31288,32 @@ var init_config2 = __esm({
|
|
|
31254
31288
|
});
|
|
31255
31289
|
|
|
31256
31290
|
// packages/server/src/path-guard.ts
|
|
31257
|
-
import { resolve as
|
|
31258
|
-
import { realpath as
|
|
31291
|
+
import { resolve as resolve36, relative as relative16, isAbsolute as isAbsolute15, dirname as dirname24, basename as basename18 } from "path";
|
|
31292
|
+
import { realpath as realpath6 } from "fs/promises";
|
|
31259
31293
|
async function resolveSafePath(workspace, requestedPath) {
|
|
31260
31294
|
const decoded = decodeURIComponent(requestedPath);
|
|
31261
31295
|
if (isAbsolute15(decoded)) {
|
|
31262
31296
|
throw new PathTraversalError(requestedPath);
|
|
31263
31297
|
}
|
|
31264
|
-
const resolved =
|
|
31298
|
+
const resolved = resolve36(workspace, decoded);
|
|
31265
31299
|
const rel = relative16(workspace, resolved);
|
|
31266
31300
|
if (rel.startsWith("..") || isAbsolute15(rel)) {
|
|
31267
31301
|
throw new PathTraversalError(requestedPath);
|
|
31268
31302
|
}
|
|
31269
31303
|
let realWorkspace;
|
|
31270
31304
|
try {
|
|
31271
|
-
realWorkspace = await
|
|
31305
|
+
realWorkspace = await realpath6(workspace);
|
|
31272
31306
|
} catch {
|
|
31273
31307
|
realWorkspace = workspace;
|
|
31274
31308
|
}
|
|
31275
31309
|
let real;
|
|
31276
31310
|
try {
|
|
31277
|
-
real = await
|
|
31311
|
+
real = await realpath6(resolved);
|
|
31278
31312
|
} catch (err) {
|
|
31279
31313
|
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
31280
31314
|
try {
|
|
31281
|
-
const realParent = await
|
|
31282
|
-
real =
|
|
31315
|
+
const realParent = await realpath6(dirname24(resolved));
|
|
31316
|
+
real = resolve36(realParent, basename18(resolved));
|
|
31283
31317
|
} catch {
|
|
31284
31318
|
return resolved;
|
|
31285
31319
|
}
|
|
@@ -31307,8 +31341,8 @@ var init_path_guard = __esm({
|
|
|
31307
31341
|
});
|
|
31308
31342
|
|
|
31309
31343
|
// packages/server/src/routes/files.ts
|
|
31310
|
-
import { readFile as
|
|
31311
|
-
import { dirname as
|
|
31344
|
+
import { readFile as readFile30, writeFile as writeFile13, unlink as unlink3, stat as stat3, mkdir as mkdir12 } from "fs/promises";
|
|
31345
|
+
import { dirname as dirname25 } from "path";
|
|
31312
31346
|
import fg from "fast-glob";
|
|
31313
31347
|
function registerRoutes(app, workspace, readOnly) {
|
|
31314
31348
|
app.get("/api/files", async () => {
|
|
@@ -31328,7 +31362,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
31328
31362
|
const filePath = request.params["*"];
|
|
31329
31363
|
try {
|
|
31330
31364
|
const resolved = await resolveSafePath(workspace, filePath);
|
|
31331
|
-
const content = await
|
|
31365
|
+
const content = await readFile30(resolved, "utf-8");
|
|
31332
31366
|
return { path: filePath, content };
|
|
31333
31367
|
} catch (err) {
|
|
31334
31368
|
if (err instanceof PathTraversalError) {
|
|
@@ -31345,7 +31379,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
31345
31379
|
const filePath = request.params["*"];
|
|
31346
31380
|
try {
|
|
31347
31381
|
const resolved = await resolveSafePath(workspace, filePath);
|
|
31348
|
-
await
|
|
31382
|
+
await writeFile13(resolved, request.body.content, "utf-8");
|
|
31349
31383
|
return { path: filePath, status: "updated" };
|
|
31350
31384
|
} catch (err) {
|
|
31351
31385
|
if (err instanceof PathTraversalError) {
|
|
@@ -31368,8 +31402,8 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
31368
31402
|
return reply.status(409).send({ error: "File already exists" });
|
|
31369
31403
|
} catch {
|
|
31370
31404
|
}
|
|
31371
|
-
await
|
|
31372
|
-
await
|
|
31405
|
+
await mkdir12(dirname25(resolved), { recursive: true });
|
|
31406
|
+
await writeFile13(resolved, request.body.content, "utf-8");
|
|
31373
31407
|
return reply.status(201).send({ path: filePath, status: "created" });
|
|
31374
31408
|
} catch (err) {
|
|
31375
31409
|
if (err instanceof PathTraversalError) {
|
|
@@ -31597,7 +31631,7 @@ var migrate_exports = {};
|
|
|
31597
31631
|
__export(migrate_exports, {
|
|
31598
31632
|
migrateCommand: () => migrateCommand
|
|
31599
31633
|
});
|
|
31600
|
-
import { dirname as
|
|
31634
|
+
import { dirname as dirname26, relative as relative18, resolve as resolve37 } from "path";
|
|
31601
31635
|
import { parse as parseYaml17 } from "yaml";
|
|
31602
31636
|
async function migrateCommand(options, services = createDefaultServices()) {
|
|
31603
31637
|
const previousOutputStream = getContext().outputStream;
|
|
@@ -31617,7 +31651,7 @@ async function runMigrateCommand(options, services) {
|
|
|
31617
31651
|
ConsoleOutput.info("No migration candidates found. No files changed.");
|
|
31618
31652
|
return;
|
|
31619
31653
|
}
|
|
31620
|
-
const configPath =
|
|
31654
|
+
const configPath = findProjectConfig2(services);
|
|
31621
31655
|
if (!configPath) {
|
|
31622
31656
|
await initCommand(
|
|
31623
31657
|
{
|
|
@@ -31730,7 +31764,7 @@ function validateOptions(options) {
|
|
|
31730
31764
|
throw new Error("--static and --llm cannot be used together");
|
|
31731
31765
|
}
|
|
31732
31766
|
}
|
|
31733
|
-
function
|
|
31767
|
+
function findProjectConfig2(services) {
|
|
31734
31768
|
const envConfig = process.env["PROMPTSCRIPT_CONFIG"];
|
|
31735
31769
|
if (envConfig && services.fs.existsSync(envConfig)) {
|
|
31736
31770
|
return envConfig;
|
|
@@ -31781,7 +31815,7 @@ function extractTargetNames(targets) {
|
|
|
31781
31815
|
}
|
|
31782
31816
|
async function createStaticMigrationWrites(candidates, config, services) {
|
|
31783
31817
|
const result = await importMultipleFiles(
|
|
31784
|
-
candidates.map((candidate) =>
|
|
31818
|
+
candidates.map((candidate) => resolve37(services.cwd, candidate.path)),
|
|
31785
31819
|
{
|
|
31786
31820
|
projectName: config.id,
|
|
31787
31821
|
syntaxVersion: config.syntax || getLatestSyntaxVersion()
|
|
@@ -31873,7 +31907,7 @@ ${content}`;
|
|
|
31873
31907
|
}
|
|
31874
31908
|
function toUsePath(entryPath, targetPath) {
|
|
31875
31909
|
const withoutExtension = targetPath.replace(/\.prs$/, "");
|
|
31876
|
-
const path2 = relative18(
|
|
31910
|
+
const path2 = relative18(dirname26(entryPath), withoutExtension).replace(/\\/g, "/");
|
|
31877
31911
|
return path2.startsWith(".") ? path2 : `./${path2}`;
|
|
31878
31912
|
}
|
|
31879
31913
|
function validateProjectPath(path2) {
|
|
@@ -31933,16 +31967,16 @@ init_src();
|
|
|
31933
31967
|
init_init();
|
|
31934
31968
|
import { Command } from "commander";
|
|
31935
31969
|
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
|
|
31936
|
-
import { dirname as
|
|
31970
|
+
import { dirname as dirname27 } from "path";
|
|
31937
31971
|
|
|
31938
31972
|
// packages/cli/src/commands/compile.ts
|
|
31939
|
-
import { resolve as resolve19, dirname as dirname15, isAbsolute as
|
|
31973
|
+
import { resolve as resolve19, dirname as dirname15, isAbsolute as isAbsolute12, relative as relative13 } from "path";
|
|
31940
31974
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
31941
31975
|
import { chmod, writeFile as writeFile4, mkdir as mkdir5, readFile as readFile15 } from "fs/promises";
|
|
31942
31976
|
import { existsSync as existsSync13 } from "fs";
|
|
31943
31977
|
import chokidar from "chokidar";
|
|
31944
31978
|
|
|
31945
|
-
// node_modules/.pnpm/balanced-match@4.0.
|
|
31979
|
+
// node_modules/.pnpm/balanced-match@4.0.3/node_modules/balanced-match/dist/esm/index.js
|
|
31946
31980
|
var balanced = (a, b, str) => {
|
|
31947
31981
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
|
31948
31982
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
|
@@ -33722,10 +33756,10 @@ var Minimatch = class {
|
|
|
33722
33756
|
}
|
|
33723
33757
|
return filtered.join("/");
|
|
33724
33758
|
}).join("|");
|
|
33725
|
-
const [
|
|
33726
|
-
re = "^" +
|
|
33759
|
+
const [open4, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
33760
|
+
re = "^" + open4 + re + close + "$";
|
|
33727
33761
|
if (this.partial) {
|
|
33728
|
-
re = "^(?:\\/|" +
|
|
33762
|
+
re = "^(?:\\/|" + open4 + re.slice(1, -1) + close + ")$";
|
|
33729
33763
|
}
|
|
33730
33764
|
if (this.negate)
|
|
33731
33765
|
re = "^(?!" + re + ").+$";
|
|
@@ -38017,14 +38051,66 @@ async function discoverNativeContent(dir) {
|
|
|
38017
38051
|
|
|
38018
38052
|
// packages/resolver/src/vendor-manifest.ts
|
|
38019
38053
|
import { createHash as createHash3 } from "crypto";
|
|
38020
|
-
import { execFile } from "child_process";
|
|
38021
|
-
import {
|
|
38022
|
-
import {
|
|
38054
|
+
import { execFile, spawn } from "child_process";
|
|
38055
|
+
import { constants as constants2 } from "fs";
|
|
38056
|
+
import { lstat as lstat5, open as open2, readFile as readFile12, readdir as readdir4, readlink, realpath as realpath3 } from "fs/promises";
|
|
38057
|
+
import { basename as basename10, dirname as dirname9, join as join9, posix as posix2, relative as relative7, sep as sep5 } from "path";
|
|
38023
38058
|
import { promisify } from "util";
|
|
38024
38059
|
var VENDOR_MANIFEST_FILE = ".vendor-manifest.json";
|
|
38025
38060
|
var VENDOR_GIT_DIR = ".promptscript-git";
|
|
38026
38061
|
var execFileAsync = promisify(execFile);
|
|
38027
38062
|
var NULL_DEVICE = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
38063
|
+
var MAX_GIT_STDERR_BYTES = 64 * 1024;
|
|
38064
|
+
var MAX_GIT_TREE_RECORD_BYTES = 1024 * 1024;
|
|
38065
|
+
var MAX_GIT_CONFIG_BYTES = 1024 * 1024;
|
|
38066
|
+
function hashGitBlob(content) {
|
|
38067
|
+
return createHash3("sha1").update(`blob ${content.length}\0`).update(content).digest("hex");
|
|
38068
|
+
}
|
|
38069
|
+
async function readBoundedRegularFile(filePath, maxBytes, description) {
|
|
38070
|
+
const flags = constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0);
|
|
38071
|
+
const handle = await open2(filePath, flags);
|
|
38072
|
+
try {
|
|
38073
|
+
const metadata = await handle.stat();
|
|
38074
|
+
if (!metadata.isFile()) {
|
|
38075
|
+
throw new Error(`${description} is not a regular file: ${filePath}`);
|
|
38076
|
+
}
|
|
38077
|
+
const content = Buffer.alloc(maxBytes + 1);
|
|
38078
|
+
let offset = 0;
|
|
38079
|
+
while (offset < content.length) {
|
|
38080
|
+
const { bytesRead } = await handle.read(content, offset, content.length - offset, null);
|
|
38081
|
+
if (bytesRead === 0) {
|
|
38082
|
+
break;
|
|
38083
|
+
}
|
|
38084
|
+
offset += bytesRead;
|
|
38085
|
+
}
|
|
38086
|
+
if (offset > maxBytes) {
|
|
38087
|
+
throw new Error(`${description} exceeds ${maxBytes} bytes: ${filePath}`);
|
|
38088
|
+
}
|
|
38089
|
+
return content.subarray(0, offset);
|
|
38090
|
+
} finally {
|
|
38091
|
+
await handle.close();
|
|
38092
|
+
}
|
|
38093
|
+
}
|
|
38094
|
+
async function resolveSafeRepositorySymlink(symlinkPath, repositoryRoot, gitMetadataRoot) {
|
|
38095
|
+
let targetPath;
|
|
38096
|
+
try {
|
|
38097
|
+
targetPath = await realpath3(symlinkPath);
|
|
38098
|
+
} catch (error) {
|
|
38099
|
+
throw new Error(`Symbolic links must resolve inside vendor repositories: ${symlinkPath}`, {
|
|
38100
|
+
cause: error
|
|
38101
|
+
});
|
|
38102
|
+
}
|
|
38103
|
+
if (targetPath === repositoryRoot || !isInsideCachePath(targetPath, repositoryRoot) || isInsideCachePath(targetPath, gitMetadataRoot)) {
|
|
38104
|
+
throw new Error(`Symbolic links must resolve inside vendor repositories: ${symlinkPath}`);
|
|
38105
|
+
}
|
|
38106
|
+
const targetMetadata = await lstat5(targetPath);
|
|
38107
|
+
if (!targetMetadata.isFile()) {
|
|
38108
|
+
throw new Error(
|
|
38109
|
+
`Symbolic links must resolve to regular files in vendor repositories: ${symlinkPath}`
|
|
38110
|
+
);
|
|
38111
|
+
}
|
|
38112
|
+
return targetPath;
|
|
38113
|
+
}
|
|
38028
38114
|
function getVendorRepositoryRelativePath(repoUrl) {
|
|
38029
38115
|
const sshMatch = /^git@([^:]+):(.+)$/.exec(repoUrl);
|
|
38030
38116
|
const candidate = sshMatch ? `https://${sshMatch[1]}/${sshMatch[2]}` : /^[a-z][a-z\d+.-]*:\/\//i.test(repoUrl) ? repoUrl : `https://${repoUrl}`;
|
|
@@ -38062,6 +38148,8 @@ function isValidVendorManifest(value) {
|
|
|
38062
38148
|
}
|
|
38063
38149
|
async function hashVendorRepository(directory) {
|
|
38064
38150
|
const hash = createHash3("sha256");
|
|
38151
|
+
const repositoryRoot = await realpath3(directory);
|
|
38152
|
+
const gitMetadataRoot = join9(repositoryRoot, VENDOR_GIT_DIR);
|
|
38065
38153
|
async function visit(currentDirectory, prefix) {
|
|
38066
38154
|
const entries = await readdir4(currentDirectory, { withFileTypes: true });
|
|
38067
38155
|
entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
@@ -38077,9 +38165,11 @@ async function hashVendorRepository(directory) {
|
|
|
38077
38165
|
const entryPath = join9(currentDirectory, entry.name);
|
|
38078
38166
|
const relativePath = posix2.join(prefix, entry.name);
|
|
38079
38167
|
if (entry.isSymbolicLink()) {
|
|
38080
|
-
|
|
38081
|
-
|
|
38082
|
-
|
|
38168
|
+
await resolveSafeRepositorySymlink(entryPath, repositoryRoot, gitMetadataRoot);
|
|
38169
|
+
hash.update(`symlink:${relativePath}\0`);
|
|
38170
|
+
hash.update(await readlink(entryPath, { encoding: "buffer" }));
|
|
38171
|
+
hash.update("\0");
|
|
38172
|
+
} else if (entry.isDirectory()) {
|
|
38083
38173
|
hash.update(`directory:${relativePath}\0`);
|
|
38084
38174
|
await visit(entryPath, relativePath);
|
|
38085
38175
|
} else if (entry.isFile()) {
|
|
@@ -38107,23 +38197,43 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38107
38197
|
}
|
|
38108
38198
|
}
|
|
38109
38199
|
}
|
|
38200
|
+
async function rejectMetadataPath(relativePath, message) {
|
|
38201
|
+
try {
|
|
38202
|
+
await lstat5(join9(gitDir, ...relativePath.split("/")));
|
|
38203
|
+
throw new Error(`${message}: ${gitDir}`);
|
|
38204
|
+
} catch (error) {
|
|
38205
|
+
if (!(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")) {
|
|
38206
|
+
throw error;
|
|
38207
|
+
}
|
|
38208
|
+
}
|
|
38209
|
+
}
|
|
38110
38210
|
const gitMetadata = await lstat5(gitDir);
|
|
38111
38211
|
if (!gitMetadata.isDirectory() || gitMetadata.isSymbolicLink()) {
|
|
38112
38212
|
throw new Error(`Invalid vendor Git metadata directory: ${gitDir}`);
|
|
38113
38213
|
}
|
|
38114
38214
|
await rejectMetadataSymlinks(gitDir);
|
|
38115
|
-
const
|
|
38116
|
-
|
|
38215
|
+
const [repositoryRoot, gitMetadataRoot] = await Promise.all([
|
|
38216
|
+
realpath3(directory),
|
|
38217
|
+
realpath3(gitDir)
|
|
38218
|
+
]);
|
|
38219
|
+
const localConfigContent = await readBoundedRegularFile(
|
|
38220
|
+
join9(gitDir, "config"),
|
|
38221
|
+
MAX_GIT_CONFIG_BYTES,
|
|
38222
|
+
"Vendor Git config"
|
|
38223
|
+
);
|
|
38224
|
+
const localConfig = localConfigContent.toString("utf-8");
|
|
38225
|
+
if (/^[ \t]*\[(?:include|includeif)\b/im.test(localConfig) || /\bpromisor\s*=\s*true\b/i.test(localConfig) || /\bpartialclone/i.test(localConfig) || /\bworktreeconfig\s*=\s*true\b/i.test(localConfig)) {
|
|
38117
38226
|
throw new Error(`External or partial Git object sources are not allowed: ${gitDir}`);
|
|
38118
38227
|
}
|
|
38119
|
-
|
|
38120
|
-
|
|
38121
|
-
|
|
38122
|
-
|
|
38123
|
-
|
|
38124
|
-
|
|
38125
|
-
|
|
38126
|
-
|
|
38228
|
+
await rejectMetadataPath("commondir", "Git common directories are not allowed");
|
|
38229
|
+
await rejectMetadataPath(
|
|
38230
|
+
"objects/info/alternates",
|
|
38231
|
+
"Git object alternates are not allowed in vendor metadata"
|
|
38232
|
+
);
|
|
38233
|
+
await rejectMetadataPath(
|
|
38234
|
+
"objects/info/http-alternates",
|
|
38235
|
+
"Git HTTP alternates are not allowed in vendor metadata"
|
|
38236
|
+
);
|
|
38127
38237
|
const commonArgs = [`--git-dir=${gitDir}`, `--work-tree=${directory}`];
|
|
38128
38238
|
const environment = {
|
|
38129
38239
|
PATH: process.env["PATH"],
|
|
@@ -38141,27 +38251,96 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38141
38251
|
if (head.stdout.trim().toLowerCase() !== expectedCommit.toLowerCase()) {
|
|
38142
38252
|
throw new Error(`Vendored repository commit does not match the lockfile: ${directory}`);
|
|
38143
38253
|
}
|
|
38144
|
-
const tree = await execFileAsync("git", [...commonArgs, "ls-tree", "-r", "-z", expectedCommit], {
|
|
38145
|
-
env: environment
|
|
38146
|
-
});
|
|
38147
38254
|
const trackedFiles = /* @__PURE__ */ new Map();
|
|
38148
|
-
|
|
38149
|
-
|
|
38150
|
-
|
|
38151
|
-
|
|
38152
|
-
|
|
38153
|
-
|
|
38154
|
-
|
|
38155
|
-
|
|
38156
|
-
|
|
38157
|
-
throw new Error(`Unsupported Git tree mode in vendored repository: ${path2}`);
|
|
38158
|
-
}
|
|
38159
|
-
trackedFiles.set(path2, {
|
|
38160
|
-
objectId: metadata[2],
|
|
38161
|
-
executable: mode === "100755"
|
|
38255
|
+
const treeProcess = spawn("git", [...commonArgs, "ls-tree", "-r", "-z", expectedCommit], {
|
|
38256
|
+
env: environment,
|
|
38257
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
38258
|
+
});
|
|
38259
|
+
let processError = null;
|
|
38260
|
+
const processCompletion = new Promise((resolveProcess) => {
|
|
38261
|
+
treeProcess.once("error", (error) => {
|
|
38262
|
+
processError = new Error(`Failed to run git ls-tree: ${error.message}`, { cause: error });
|
|
38263
|
+
resolveProcess({ code: null, signal: null });
|
|
38162
38264
|
});
|
|
38163
|
-
|
|
38164
|
-
|
|
38265
|
+
treeProcess.once("close", (code2, signal2) => {
|
|
38266
|
+
resolveProcess({ code: code2, signal: signal2 });
|
|
38267
|
+
});
|
|
38268
|
+
});
|
|
38269
|
+
const stderrChunks = [];
|
|
38270
|
+
let stderrBytes = 0;
|
|
38271
|
+
let stderrTruncated = false;
|
|
38272
|
+
const stderrCompletion = (async () => {
|
|
38273
|
+
for await (const chunk of treeProcess.stderr) {
|
|
38274
|
+
const remaining = MAX_GIT_STDERR_BYTES - stderrBytes;
|
|
38275
|
+
if (remaining > 0) {
|
|
38276
|
+
const captured = chunk.subarray(0, remaining);
|
|
38277
|
+
stderrChunks.push(Buffer.from(captured));
|
|
38278
|
+
stderrBytes += captured.length;
|
|
38279
|
+
}
|
|
38280
|
+
if (chunk.length > remaining) {
|
|
38281
|
+
stderrTruncated = true;
|
|
38282
|
+
}
|
|
38283
|
+
}
|
|
38284
|
+
})();
|
|
38285
|
+
let pendingRecord = Buffer.alloc(0);
|
|
38286
|
+
let stdoutError = null;
|
|
38287
|
+
try {
|
|
38288
|
+
for await (const chunk of treeProcess.stdout) {
|
|
38289
|
+
const output = pendingRecord.length > 0 ? Buffer.concat([pendingRecord, chunk]) : chunk;
|
|
38290
|
+
let recordStart = 0;
|
|
38291
|
+
let separator = output.indexOf(0, recordStart);
|
|
38292
|
+
while (separator >= 0) {
|
|
38293
|
+
if (separator > recordStart) {
|
|
38294
|
+
const row = output.toString("utf8", recordStart, separator);
|
|
38295
|
+
const metadataSeparator = row.indexOf(" ");
|
|
38296
|
+
const metadata = row.slice(0, metadataSeparator).split(" ");
|
|
38297
|
+
const path2 = row.slice(metadataSeparator + 1);
|
|
38298
|
+
const [mode, entryType, objectId, ...extraFields] = metadata;
|
|
38299
|
+
if (metadataSeparator < 0 || entryType !== "blob" || extraFields.length > 0 || mode === void 0 || objectId === void 0) {
|
|
38300
|
+
throw new Error(`Unsupported Git tree entry in vendored repository: ${path2}`);
|
|
38301
|
+
}
|
|
38302
|
+
if (mode !== "100644" && mode !== "100755" && mode !== "120000") {
|
|
38303
|
+
throw new Error(`Unsupported Git tree mode in vendored repository: ${path2}`);
|
|
38304
|
+
}
|
|
38305
|
+
trackedFiles.set(path2, {
|
|
38306
|
+
objectId,
|
|
38307
|
+
executable: mode === "100755",
|
|
38308
|
+
symbolicLink: mode === "120000"
|
|
38309
|
+
});
|
|
38310
|
+
}
|
|
38311
|
+
recordStart = separator + 1;
|
|
38312
|
+
separator = output.indexOf(0, recordStart);
|
|
38313
|
+
}
|
|
38314
|
+
pendingRecord = recordStart < output.length ? Buffer.from(output.subarray(recordStart)) : Buffer.alloc(0);
|
|
38315
|
+
if (pendingRecord.length > MAX_GIT_TREE_RECORD_BYTES) {
|
|
38316
|
+
throw new Error(`Git ls-tree record exceeds ${MAX_GIT_TREE_RECORD_BYTES} bytes`);
|
|
38317
|
+
}
|
|
38318
|
+
}
|
|
38319
|
+
} catch (error) {
|
|
38320
|
+
stdoutError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
38321
|
+
treeProcess.kill();
|
|
38322
|
+
}
|
|
38323
|
+
const [{ code, signal }] = await Promise.all([processCompletion, stderrCompletion]);
|
|
38324
|
+
if (processError) {
|
|
38325
|
+
throw processError;
|
|
38326
|
+
}
|
|
38327
|
+
if (stdoutError) {
|
|
38328
|
+
throw stdoutError;
|
|
38329
|
+
}
|
|
38330
|
+
if (code !== 0) {
|
|
38331
|
+
const stderrOutput = Buffer.concat(stderrChunks, stderrBytes).toString("utf8");
|
|
38332
|
+
const stderrDetails = stderrTruncated ? `${stderrOutput}
|
|
38333
|
+
[stderr truncated]` : stderrOutput;
|
|
38334
|
+
const details = stderrDetails.trim();
|
|
38335
|
+
const status = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
38336
|
+
throw new Error(`Git ls-tree failed with ${status}${details ? `: ${details}` : ""}`);
|
|
38337
|
+
}
|
|
38338
|
+
if (pendingRecord.length > 0) {
|
|
38339
|
+
throw new Error("Git ls-tree output ended with an unterminated record");
|
|
38340
|
+
}
|
|
38341
|
+
let worktreeFileCount = 0;
|
|
38342
|
+
const regularFiles = [];
|
|
38343
|
+
const worktreeSymlinks = /* @__PURE__ */ new Map();
|
|
38165
38344
|
async function collectFiles(currentDirectory, prefix) {
|
|
38166
38345
|
const entries = await readdir4(currentDirectory, { withFileTypes: true });
|
|
38167
38346
|
for (const entry of entries) {
|
|
@@ -38171,13 +38350,32 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38171
38350
|
const entryPath = join9(currentDirectory, entry.name);
|
|
38172
38351
|
const relativePath = posix2.join(prefix, entry.name);
|
|
38173
38352
|
if (entry.isSymbolicLink()) {
|
|
38174
|
-
|
|
38175
|
-
|
|
38176
|
-
|
|
38353
|
+
const tracked = trackedFiles.get(relativePath);
|
|
38354
|
+
if (!tracked?.symbolicLink) {
|
|
38355
|
+
throw new Error(`Symbolic links are not allowed for regular files: ${entryPath}`);
|
|
38356
|
+
}
|
|
38357
|
+
const targetPath = await resolveSafeRepositorySymlink(
|
|
38358
|
+
entryPath,
|
|
38359
|
+
repositoryRoot,
|
|
38360
|
+
gitMetadataRoot
|
|
38361
|
+
);
|
|
38362
|
+
const targetRelativePath = relative7(repositoryRoot, targetPath).split(sep5).join("/");
|
|
38363
|
+
const trackedTarget = trackedFiles.get(targetRelativePath);
|
|
38364
|
+
if (!trackedTarget || trackedTarget.symbolicLink) {
|
|
38365
|
+
throw new Error(`Symbolic links must target tracked regular files: ${entryPath}`);
|
|
38366
|
+
}
|
|
38367
|
+
worktreeFileCount += 1;
|
|
38368
|
+
worktreeSymlinks.set(relativePath, await readlink(entryPath, { encoding: "buffer" }));
|
|
38369
|
+
} else if (entry.isDirectory()) {
|
|
38177
38370
|
await collectFiles(entryPath, relativePath);
|
|
38178
38371
|
} else if (entry.isFile()) {
|
|
38179
38372
|
if (!allowedUntrackedFiles.has(relativePath)) {
|
|
38180
38373
|
const tracked = trackedFiles.get(relativePath);
|
|
38374
|
+
if (tracked?.symbolicLink) {
|
|
38375
|
+
throw new Error(
|
|
38376
|
+
`Vendored repository symbolic links do not match commit ${expectedCommit}`
|
|
38377
|
+
);
|
|
38378
|
+
}
|
|
38181
38379
|
if (tracked && process.platform !== "win32") {
|
|
38182
38380
|
const metadata = await lstat5(entryPath);
|
|
38183
38381
|
if (Boolean(metadata.mode & 73) !== tracked.executable) {
|
|
@@ -38186,7 +38384,8 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38186
38384
|
);
|
|
38187
38385
|
}
|
|
38188
38386
|
}
|
|
38189
|
-
|
|
38387
|
+
worktreeFileCount += 1;
|
|
38388
|
+
regularFiles.push(relativePath);
|
|
38190
38389
|
}
|
|
38191
38390
|
} else {
|
|
38192
38391
|
throw new Error(`Unsupported vendor repository entry: ${entryPath}`);
|
|
@@ -38194,12 +38393,12 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38194
38393
|
}
|
|
38195
38394
|
}
|
|
38196
38395
|
await collectFiles(directory, "");
|
|
38197
|
-
if (
|
|
38396
|
+
if (worktreeFileCount !== trackedFiles.size || regularFiles.some((path2) => !trackedFiles.has(path2))) {
|
|
38198
38397
|
throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
|
|
38199
38398
|
}
|
|
38200
38399
|
const batchSize = 100;
|
|
38201
|
-
for (let index = 0; index <
|
|
38202
|
-
const paths =
|
|
38400
|
+
for (let index = 0; index < regularFiles.length; index += batchSize) {
|
|
38401
|
+
const paths = regularFiles.slice(index, index + batchSize);
|
|
38203
38402
|
const filePaths = paths.map((path2) => join9(directory, ...path2.split("/")));
|
|
38204
38403
|
const objects = await execFileAsync(
|
|
38205
38404
|
"git",
|
|
@@ -38211,6 +38410,12 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
38211
38410
|
throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
|
|
38212
38411
|
}
|
|
38213
38412
|
}
|
|
38413
|
+
for (const [path2, linkTarget] of worktreeSymlinks) {
|
|
38414
|
+
const tracked = trackedFiles.get(path2);
|
|
38415
|
+
if (!tracked || hashGitBlob(linkTarget) !== tracked.objectId) {
|
|
38416
|
+
throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
|
|
38417
|
+
}
|
|
38418
|
+
}
|
|
38214
38419
|
}
|
|
38215
38420
|
async function verifyVendoredGitRepository(directory, expectedCommit) {
|
|
38216
38421
|
await verifyGitRepositoryCheckout(directory, VENDOR_GIT_DIR, expectedCommit);
|
|
@@ -38276,8 +38481,7 @@ async function resolveVendoredRepository(vendorDir, repoUrl, expectedVersion, ex
|
|
|
38276
38481
|
realpath3(fullPath),
|
|
38277
38482
|
lstat5(fullPath)
|
|
38278
38483
|
]);
|
|
38279
|
-
|
|
38280
|
-
if (containment === ".." || containment.startsWith(`..${sep5}`) || isAbsolute8(containment) || repositoryRealPath === vendorRealPath) {
|
|
38484
|
+
if (!isInsideCachePath(repositoryRealPath, vendorRealPath) || repositoryRealPath === vendorRealPath) {
|
|
38281
38485
|
throw new Error(`Vendored dependency escapes the vendor directory: ${repoUrl}`);
|
|
38282
38486
|
}
|
|
38283
38487
|
if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
|
|
@@ -39380,7 +39584,7 @@ var HttpRegistry = class {
|
|
|
39380
39584
|
* Sleep for specified milliseconds.
|
|
39381
39585
|
*/
|
|
39382
39586
|
sleep(ms) {
|
|
39383
|
-
return new Promise((
|
|
39587
|
+
return new Promise((resolve38) => setTimeout(resolve38, ms));
|
|
39384
39588
|
}
|
|
39385
39589
|
/**
|
|
39386
39590
|
* Fetch with timeout.
|
|
@@ -39422,7 +39626,7 @@ var HttpRegistry = class {
|
|
|
39422
39626
|
*/
|
|
39423
39627
|
async fetchWithRetry(url) {
|
|
39424
39628
|
let lastError;
|
|
39425
|
-
let
|
|
39629
|
+
let delay2 = this.initialDelay;
|
|
39426
39630
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
39427
39631
|
try {
|
|
39428
39632
|
const response = await this.fetchWithTimeout(url, {
|
|
@@ -39441,8 +39645,8 @@ var HttpRegistry = class {
|
|
|
39441
39645
|
lastError = error;
|
|
39442
39646
|
}
|
|
39443
39647
|
if (attempt < this.maxRetries) {
|
|
39444
|
-
await this.sleep(
|
|
39445
|
-
|
|
39648
|
+
await this.sleep(delay2);
|
|
39649
|
+
delay2 *= 2;
|
|
39446
39650
|
}
|
|
39447
39651
|
}
|
|
39448
39652
|
throw lastError ?? new Error("Unknown fetch error");
|
|
@@ -41018,36 +41222,76 @@ var suspiciousUrls = {
|
|
|
41018
41222
|
// packages/validator/src/rules/authority-injection.ts
|
|
41019
41223
|
var AUTHORITY_PATTERNS = [
|
|
41020
41224
|
// Mandatory/strict mode indicators
|
|
41021
|
-
/\[?\s{0,10}
|
|
41225
|
+
/\[?\s{0,10}\bMANDATORY\b\s{0,10}(?:POLICY|UPDATE|FOOTER|INSTRUCTION|DIRECTIVE)\b\s{0,10}\]?/i,
|
|
41022
41226
|
/\[\s{0,10}OVERRIDE\s{0,10}\]/i,
|
|
41023
|
-
/\[?\s{0,10}
|
|
41024
|
-
/\[?\s{0,10}
|
|
41025
|
-
/\[?\s{0,10}
|
|
41026
|
-
/\[?\s{0,10}
|
|
41027
|
-
/\[?\s{0,10}
|
|
41028
|
-
/\[?\s{0,10}
|
|
41227
|
+
/\[?\s{0,10}\bSTRICT[_\s]{0,10}MODE\b\s{0,10}[:\s]{1,10}ON\b\s{0,10}\]?/i,
|
|
41228
|
+
/\[?\s{0,10}\bSYSTEM\b\s{0,10}(?:OVERRIDE|UPDATE|DIRECTIVE)\b\s{0,10}\]?/i,
|
|
41229
|
+
/\[?\s{0,10}\bADMIN(?:ISTRATOR)?\b\s{0,10}(?:MODE|OVERRIDE|ACCESS)\b\s{0,10}\]?/i,
|
|
41230
|
+
/\[?\s{0,10}\bROOT\b\s{0,10}(?:ACCESS|MODE|OVERRIDE)\b\s{0,10}\]?/i,
|
|
41231
|
+
/\[?\s{0,10}\bPRIORITY\b\s{0,10}(?:OVERRIDE|ONE|ALPHA)\b\s{0,10}\]?/i,
|
|
41232
|
+
/\[?\s{0,10}\bEMERGENCY\b\s{0,10}(?:PROTOCOL|OVERRIDE|MODE)\b\s{0,10}\]?/i,
|
|
41029
41233
|
// Warning suppression patterns
|
|
41030
41234
|
// Removed because it triggers false positives on valid agent instructions (e.g., "do not notify user")
|
|
41031
41235
|
// /(?:DO\s{1,10}NOT|NEVER|DON'?T)\s{1,10}(?:WARN|ALERT|NOTIFY|FLAG|REPORT)/i,
|
|
41032
|
-
|
|
41033
|
-
|
|
41034
|
-
|
|
41035
|
-
|
|
41036
|
-
/(
|
|
41236
|
+
/\b(?:DO\s{1,10}NOT|NEVER|DON'?T)\b\s{1,10}(?:PROVIDE|SHOW|DISPLAY|INCLUDE)\b\s{1,10}(?:SECURITY\s{1,10})?WARNINGS?\b/i,
|
|
41237
|
+
/\b(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\b\s{1,10}(?:ALL\s{1,10})?WARNINGS?\b/i,
|
|
41238
|
+
/\b(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\b\s{1,10}(?:ALL\s{1,10})?(?:SECURITY\s{1,10})?(?:ALERTS?|NOTIFICATIONS?)\b/i,
|
|
41239
|
+
/\bIGNORE\b\s{1,10}(?:ALL\s{1,10})?(?:SAFETY\s{1,10})?WARNINGS?\b/i,
|
|
41240
|
+
/(?:^|[.!?:;]\s{0,10})\s{0,10}(?:[-*]\s{1,10})?(?:PLEASE\s{1,10})?\b(?:SKIP|BYPASS)\b\s{1,10}(?:CHECKS?|VALIDATION)\b/im,
|
|
41241
|
+
/\b(?:SKIP|BYPASS)\b\s{1,10}(?:(?:ALL\s{1,10})(?:SAFETY\s{1,10})?|SAFETY\s{1,10})(?:CHECKS?|VALIDATION)\b/i,
|
|
41037
41242
|
// Execute/follow verbatim patterns
|
|
41038
|
-
|
|
41039
|
-
|
|
41040
|
-
|
|
41041
|
-
|
|
41042
|
-
|
|
41243
|
+
/\bEXECUTE\b\s{1,10}(?:THIS\s{1,10})?VERBATIM\b/i,
|
|
41244
|
+
/\bFOLLOW\b\s{1,10}(?:THESE?\s{1,10})?INSTRUCTIONS?\s{1,10}(?:EXACTLY|PRECISELY|LITERALLY)\b/i,
|
|
41245
|
+
/\b(?:MUST|SHALL|WILL)\b\s{1,10}(?:ALWAYS\s{1,10})?COMPLY\b/i,
|
|
41246
|
+
/\b(?:ABSOLUTE|UNCONDITIONAL)\b\s{1,10}(?:COMPLIANCE|OBEDIENCE)\b/i,
|
|
41247
|
+
/\bNO\b\s{1,10}(?:EXCEPTIONS?|DEVIATIONS?)\s{1,10}(?:ALLOWED|PERMITTED)\b/i,
|
|
41043
41248
|
// Authority assertion patterns
|
|
41044
|
-
|
|
41045
|
-
|
|
41046
|
-
|
|
41047
|
-
|
|
41249
|
+
/\bTHIS\b\s{1,10}(?:OVERRIDES?|SUPERSEDES?|REPLACES?)\s{1,10}(?:ALL\s{1,10})?(?:PREVIOUS|PRIOR|OTHER)\b/i,
|
|
41250
|
+
/\b(?:HIGHEST|TOP|MAXIMUM)\b\s{1,10}PRIORITY\s{1,10}(?:INSTRUCTION|DIRECTIVE|ORDER)\b/i,
|
|
41251
|
+
/\b(?:CORE|FUNDAMENTAL|BASE)\b\s{1,10}(?:DIRECTIVE|INSTRUCTION)\s{1,10}(?:UPDATE|OVERRIDE)\b/i,
|
|
41252
|
+
/\bNEW\b\s{1,10}(?:SYSTEM|CORE|BASE)\s{1,10}(?:INSTRUCTIONS?|DIRECTIVES?|RULES?)\b/i
|
|
41048
41253
|
];
|
|
41049
41254
|
function stripFencedCodeBlocks2(text) {
|
|
41050
|
-
|
|
41255
|
+
const lines = text.split("\n");
|
|
41256
|
+
const output = [];
|
|
41257
|
+
let pendingFence = [];
|
|
41258
|
+
let insideFence = false;
|
|
41259
|
+
let fenceCharacter = "";
|
|
41260
|
+
let fenceLength = 0;
|
|
41261
|
+
for (let index = 0; index < lines.length; index++) {
|
|
41262
|
+
const line = lines[index];
|
|
41263
|
+
const renderedLine = index < lines.length - 1 ? `${line}
|
|
41264
|
+
` : line;
|
|
41265
|
+
const trimmedLine = line.trimStart();
|
|
41266
|
+
const currentCharacter = trimmedLine[0];
|
|
41267
|
+
let currentLength = 0;
|
|
41268
|
+
if (currentCharacter === "`" || currentCharacter === "~") {
|
|
41269
|
+
while (trimmedLine[currentLength] === currentCharacter) {
|
|
41270
|
+
currentLength += 1;
|
|
41271
|
+
}
|
|
41272
|
+
}
|
|
41273
|
+
const closesFence = insideFence && currentCharacter === fenceCharacter && currentLength >= fenceLength && trimmedLine.slice(currentLength).trim() === "";
|
|
41274
|
+
const opensFence = !insideFence && currentLength >= 3;
|
|
41275
|
+
if (closesFence) {
|
|
41276
|
+
insideFence = false;
|
|
41277
|
+
pendingFence = [];
|
|
41278
|
+
fenceCharacter = "";
|
|
41279
|
+
fenceLength = 0;
|
|
41280
|
+
} else if (opensFence) {
|
|
41281
|
+
insideFence = true;
|
|
41282
|
+
fenceCharacter = currentCharacter;
|
|
41283
|
+
fenceLength = currentLength;
|
|
41284
|
+
pendingFence.push(renderedLine);
|
|
41285
|
+
} else if (insideFence) {
|
|
41286
|
+
pendingFence.push(renderedLine);
|
|
41287
|
+
} else {
|
|
41288
|
+
output.push(renderedLine);
|
|
41289
|
+
}
|
|
41290
|
+
}
|
|
41291
|
+
if (insideFence) {
|
|
41292
|
+
output.push(...pendingFence);
|
|
41293
|
+
}
|
|
41294
|
+
return output.join("");
|
|
41051
41295
|
}
|
|
41052
41296
|
var authorityInjection = {
|
|
41053
41297
|
id: "PS011",
|
|
@@ -41059,8 +41303,9 @@ var authorityInjection = {
|
|
|
41059
41303
|
ctx.ast,
|
|
41060
41304
|
(text, loc) => {
|
|
41061
41305
|
const strippedText = stripFencedCodeBlocks2(text);
|
|
41306
|
+
const normalizedText = strippedText.replace(/\s+/g, " ");
|
|
41062
41307
|
for (const pattern of AUTHORITY_PATTERNS) {
|
|
41063
|
-
if (pattern.test(strippedText)) {
|
|
41308
|
+
if (pattern.test(strippedText) || pattern.test(normalizedText)) {
|
|
41064
41309
|
ctx.report({
|
|
41065
41310
|
message: `Authority injection pattern detected: ${pattern.source}`,
|
|
41066
41311
|
location: loc,
|
|
@@ -44157,15 +44402,15 @@ var SECURITY_STRICT_MULTILINGUAL = {
|
|
|
44157
44402
|
};
|
|
44158
44403
|
|
|
44159
44404
|
// packages/compiler/src/compiler.ts
|
|
44160
|
-
import { dirname as dirname13, isAbsolute as
|
|
44405
|
+
import { dirname as dirname13, isAbsolute as isAbsolute9, join as join13, relative as relative10, resolve as resolve16, sep as sep7 } from "path";
|
|
44161
44406
|
|
|
44162
44407
|
// packages/compiler/src/hook-script-validator.ts
|
|
44163
44408
|
init_src4();
|
|
44164
44409
|
import { lstat as lstat7, realpath as realpath4 } from "fs/promises";
|
|
44165
|
-
import { dirname as dirname12, isAbsolute as
|
|
44410
|
+
import { dirname as dirname12, isAbsolute as isAbsolute8, relative as relative9, resolve as resolve15, sep as sep6 } from "path";
|
|
44166
44411
|
function isInside(root, candidate) {
|
|
44167
44412
|
const relation = relative9(root, candidate);
|
|
44168
|
-
return relation === "" || !relation.startsWith(`..${sep6}`) && relation !== ".." && !
|
|
44413
|
+
return relation === "" || !relation.startsWith(`..${sep6}`) && relation !== ".." && !isAbsolute8(relation);
|
|
44169
44414
|
}
|
|
44170
44415
|
function inferProjectRoot(localPath, configuredProjectRoot, entryPath) {
|
|
44171
44416
|
if (configuredProjectRoot) return resolve15(configuredProjectRoot);
|
|
@@ -44310,7 +44555,7 @@ var Compiler = class _Compiler {
|
|
|
44310
44555
|
formatTime: 0,
|
|
44311
44556
|
totalTime: 0
|
|
44312
44557
|
};
|
|
44313
|
-
const sourceLabel =
|
|
44558
|
+
const sourceLabel = isAbsolute9(entryPath) ? relative10(process.cwd(), entryPath) : entryPath;
|
|
44314
44559
|
this.logger.verbose("=== Stage 1: Resolve ===");
|
|
44315
44560
|
const startResolve = Date.now();
|
|
44316
44561
|
let resolved;
|
|
@@ -44395,7 +44640,7 @@ var Compiler = class _Compiler {
|
|
|
44395
44640
|
const sourceFile = block.loc.file;
|
|
44396
44641
|
const referenceRoot = sourceFile ? referenceRoots.find((root) => {
|
|
44397
44642
|
const relation = relative10(resolve16(root.path), resolve16(sourceFile));
|
|
44398
|
-
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep7}`) && !
|
|
44643
|
+
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute9(relation);
|
|
44399
44644
|
}) : void 0;
|
|
44400
44645
|
for (const [, skillValue] of Object.entries(block.content.properties)) {
|
|
44401
44646
|
if (typeof skillValue !== "object" || skillValue === null || !("references" in skillValue))
|
|
@@ -44408,7 +44653,7 @@ var Compiler = class _Compiler {
|
|
|
44408
44653
|
if (sourceFile && referenceRoot) {
|
|
44409
44654
|
const resolvedReference = resolve16(dirname13(sourceFile), ref);
|
|
44410
44655
|
const relation = relative10(resolve16(referenceRoot.path), resolvedReference);
|
|
44411
|
-
if (relation !== "" && relation !== ".." && !relation.startsWith(`..${sep7}`) && !
|
|
44656
|
+
if (relation !== "" && relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute9(relation)) {
|
|
44412
44657
|
const sourceReferences = registryReferencePaths.get(sourceFile) ?? /* @__PURE__ */ new Map();
|
|
44413
44658
|
const relativePath = relation.replaceAll("\\", "/");
|
|
44414
44659
|
const referenceKey = `${referenceRoot.repoUrl}\0${relativePath}\0${referenceRoot.version}`;
|
|
@@ -44700,12 +44945,12 @@ var Compiler = class _Compiler {
|
|
|
44700
44945
|
*/
|
|
44701
44946
|
async watch(entryPath, options = {}) {
|
|
44702
44947
|
const { default: chokidar2 } = await import("chokidar");
|
|
44703
|
-
const { dirname:
|
|
44704
|
-
const baseDir =
|
|
44948
|
+
const { dirname: dirname28, resolve: resolve38 } = await import("path");
|
|
44949
|
+
const baseDir = dirname28(resolve38(entryPath));
|
|
44705
44950
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
44706
44951
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
44707
44952
|
const debounceMs = options.debounce ?? 300;
|
|
44708
|
-
const watchPatterns = includePatterns.map((p) =>
|
|
44953
|
+
const watchPatterns = includePatterns.map((p) => resolve38(baseDir, p));
|
|
44709
44954
|
let debounceTimer = null;
|
|
44710
44955
|
let pendingChanges = [];
|
|
44711
44956
|
const handleChange = async (changedFiles) => {
|
|
@@ -44843,7 +45088,7 @@ var Compiler = class _Compiler {
|
|
|
44843
45088
|
};
|
|
44844
45089
|
|
|
44845
45090
|
// packages/cli/src/output/pager.ts
|
|
44846
|
-
import { spawn } from "child_process";
|
|
45091
|
+
import { spawn as spawn2 } from "child_process";
|
|
44847
45092
|
function isTTY() {
|
|
44848
45093
|
return process.stdout.isTTY === true;
|
|
44849
45094
|
}
|
|
@@ -44880,7 +45125,7 @@ var Pager = class {
|
|
|
44880
45125
|
}
|
|
44881
45126
|
return;
|
|
44882
45127
|
}
|
|
44883
|
-
return new Promise((
|
|
45128
|
+
return new Promise((resolve38) => {
|
|
44884
45129
|
const pagerCmd = getPagerCommand();
|
|
44885
45130
|
const [cmd, ...args] = pagerCmd.split(" ");
|
|
44886
45131
|
if (cmd === "less" && !args.includes("-R")) {
|
|
@@ -44888,10 +45133,10 @@ var Pager = class {
|
|
|
44888
45133
|
}
|
|
44889
45134
|
if (!cmd) {
|
|
44890
45135
|
console.log(content);
|
|
44891
|
-
|
|
45136
|
+
resolve38();
|
|
44892
45137
|
return;
|
|
44893
45138
|
}
|
|
44894
|
-
const pager =
|
|
45139
|
+
const pager = spawn2(cmd, args, {
|
|
44895
45140
|
stdio: ["pipe", "inherit", "inherit"],
|
|
44896
45141
|
env: {
|
|
44897
45142
|
...process.env,
|
|
@@ -44901,17 +45146,17 @@ var Pager = class {
|
|
|
44901
45146
|
});
|
|
44902
45147
|
pager.on("error", (_err) => {
|
|
44903
45148
|
console.log(content);
|
|
44904
|
-
|
|
45149
|
+
resolve38();
|
|
44905
45150
|
});
|
|
44906
45151
|
pager.on("close", () => {
|
|
44907
|
-
|
|
45152
|
+
resolve38();
|
|
44908
45153
|
});
|
|
44909
45154
|
if (pager.stdin) {
|
|
44910
45155
|
pager.stdin.write(content);
|
|
44911
45156
|
pager.stdin.end();
|
|
44912
45157
|
} else {
|
|
44913
45158
|
console.log(content);
|
|
44914
|
-
|
|
45159
|
+
resolve38();
|
|
44915
45160
|
}
|
|
44916
45161
|
});
|
|
44917
45162
|
}
|
|
@@ -44925,14 +45170,14 @@ init_services();
|
|
|
44925
45170
|
|
|
44926
45171
|
// packages/cli/src/utils/registry-resolver.ts
|
|
44927
45172
|
import { existsSync as existsSync12 } from "fs";
|
|
44928
|
-
import { isAbsolute as
|
|
45173
|
+
import { isAbsolute as isAbsolute10, join as join14, relative as relative11, resolve as resolve17, sep as sep8 } from "path";
|
|
44929
45174
|
async function resolveRegistrySubPath(repositoryPath, subPath) {
|
|
44930
45175
|
if (!subPath) {
|
|
44931
45176
|
return repositoryPath;
|
|
44932
45177
|
}
|
|
44933
45178
|
const result = resolve17(repositoryPath, subPath);
|
|
44934
45179
|
const relation = relative11(resolve17(repositoryPath), result);
|
|
44935
|
-
if (relation === ".." || relation.startsWith(`..${sep8}`) ||
|
|
45180
|
+
if (relation === ".." || relation.startsWith(`..${sep8}`) || isAbsolute10(relation)) {
|
|
44936
45181
|
throw new Error(`Registry path escapes its repository: ${subPath}`);
|
|
44937
45182
|
}
|
|
44938
45183
|
if (existsSync12(result) && !await isRealPathInside(result, repositoryPath)) {
|
|
@@ -45097,19 +45342,19 @@ function detectOutputConflicts(targets) {
|
|
|
45097
45342
|
}
|
|
45098
45343
|
|
|
45099
45344
|
// packages/cli/src/utils/managed-output-cleanup.ts
|
|
45100
|
-
import { constants as
|
|
45101
|
-
import { execFile as execFile2, spawn as
|
|
45345
|
+
import { constants as constants3 } from "node:fs";
|
|
45346
|
+
import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
|
|
45102
45347
|
import { createHash as createHash4 } from "node:crypto";
|
|
45103
45348
|
import {
|
|
45104
45349
|
lstat as lstat8,
|
|
45105
45350
|
mkdir as mkdir4,
|
|
45106
|
-
open as
|
|
45351
|
+
open as open3,
|
|
45107
45352
|
readFile as readFile14,
|
|
45108
45353
|
readdir as readdir6,
|
|
45109
45354
|
rmdir,
|
|
45110
45355
|
unlink as unlink2
|
|
45111
45356
|
} from "node:fs/promises";
|
|
45112
|
-
import { basename as basename13, dirname as dirname14, isAbsolute as
|
|
45357
|
+
import { basename as basename13, dirname as dirname14, isAbsolute as isAbsolute11, relative as relative12, resolve as resolve18 } from "node:path";
|
|
45113
45358
|
import { promisify as promisify2 } from "node:util";
|
|
45114
45359
|
var execFileAsync2 = promisify2(execFile2);
|
|
45115
45360
|
var PROMPTSCRIPT_MARKER_PATTERNS = [
|
|
@@ -45437,7 +45682,7 @@ function collectManagedDirectories(outputs, outputRoot) {
|
|
|
45437
45682
|
for (const output of outputs.values()) {
|
|
45438
45683
|
for (const directory of output.managedOutputDirectories ?? []) {
|
|
45439
45684
|
const normalized = directory.replace(/\\/g, "/");
|
|
45440
|
-
if (!normalized ||
|
|
45685
|
+
if (!normalized || isAbsolute11(normalized)) continue;
|
|
45441
45686
|
if (normalized.split("/").some((segment) => segment === "..")) continue;
|
|
45442
45687
|
const absolutePath = resolve18(outputRoot, normalized);
|
|
45443
45688
|
if (isWithin(outputRoot, absolutePath)) directories.add(absolutePath);
|
|
@@ -45458,7 +45703,7 @@ function collectManagedFiles(outputs, outputRoot) {
|
|
|
45458
45703
|
for (const output of outputs.values()) {
|
|
45459
45704
|
for (const file of output.managedOutputFiles ?? []) {
|
|
45460
45705
|
const normalized = file.replace(/\\/g, "/");
|
|
45461
|
-
if (!normalized ||
|
|
45706
|
+
if (!normalized || isAbsolute11(normalized)) continue;
|
|
45462
45707
|
if (normalized.split("/").some((segment) => segment === "..")) continue;
|
|
45463
45708
|
const absolutePath = resolve18(outputRoot, normalized);
|
|
45464
45709
|
if (isWithin(outputRoot, absolutePath)) files.add(absolutePath);
|
|
@@ -45565,7 +45810,7 @@ async function removeHookOutputIfUnchanged(file, outputRoot, expectedContent) {
|
|
|
45565
45810
|
async function guardedRewrite(directory, name, directoryStat, fileStat, expectedContent, content) {
|
|
45566
45811
|
const expectedHash = createHash4("sha256").update(expectedContent).digest("hex");
|
|
45567
45812
|
return new Promise((resolveResult) => {
|
|
45568
|
-
const child =
|
|
45813
|
+
const child = spawn3(
|
|
45569
45814
|
process.execPath,
|
|
45570
45815
|
[
|
|
45571
45816
|
"-e",
|
|
@@ -45603,7 +45848,7 @@ async function guardedRewrite(directory, name, directoryStat, fileStat, expected
|
|
|
45603
45848
|
}
|
|
45604
45849
|
async function guardedCreate(directory, name, directoryStat, content, mode) {
|
|
45605
45850
|
return new Promise((resolveResult) => {
|
|
45606
|
-
const child =
|
|
45851
|
+
const child = spawn3(
|
|
45607
45852
|
process.execPath,
|
|
45608
45853
|
[
|
|
45609
45854
|
"-e",
|
|
@@ -45739,7 +45984,7 @@ async function openAncestorDirectories(root, directory) {
|
|
|
45739
45984
|
}
|
|
45740
45985
|
async function openOrCreateAncestorDirectories(root, file) {
|
|
45741
45986
|
const relativePath = relative12(root, file);
|
|
45742
|
-
if (relativePath.startsWith("..") ||
|
|
45987
|
+
if (relativePath.startsWith("..") || isAbsolute11(relativePath)) {
|
|
45743
45988
|
return void 0;
|
|
45744
45989
|
}
|
|
45745
45990
|
await mkdir4(root, { recursive: true });
|
|
@@ -45799,7 +46044,7 @@ async function closeDirectoryGuards(guards) {
|
|
|
45799
46044
|
}
|
|
45800
46045
|
async function safeOpenDirectory(path2) {
|
|
45801
46046
|
try {
|
|
45802
|
-
return await
|
|
46047
|
+
return await open3(path2, constants3.O_RDONLY | constants3.O_DIRECTORY | constants3.O_NOFOLLOW);
|
|
45803
46048
|
} catch (error) {
|
|
45804
46049
|
if (isNodeError(error) && (error.code === "ENOENT" || error.code === "ENOTDIR" || error.code === "ELOOP")) {
|
|
45805
46050
|
return void 0;
|
|
@@ -46172,7 +46417,7 @@ function scanHookOwnership(value) {
|
|
|
46172
46417
|
}
|
|
46173
46418
|
function isWithin(root, candidate) {
|
|
46174
46419
|
const relativePath = relative12(root, candidate);
|
|
46175
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
46420
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute11(relativePath);
|
|
46176
46421
|
}
|
|
46177
46422
|
function isNodeError(error) {
|
|
46178
46423
|
return error instanceof Error && "code" in error;
|
|
@@ -46302,10 +46547,10 @@ function getBuildProfile(config, buildName) {
|
|
|
46302
46547
|
}
|
|
46303
46548
|
function resolveOutputBase(projectRoot, output) {
|
|
46304
46549
|
if (!output) return projectRoot;
|
|
46305
|
-
return
|
|
46550
|
+
return isAbsolute12(output) ? output : resolve19(projectRoot, output);
|
|
46306
46551
|
}
|
|
46307
46552
|
function resolveProjectPath(projectRoot, path2) {
|
|
46308
|
-
return
|
|
46553
|
+
return isAbsolute12(path2) ? path2 : resolve19(projectRoot, path2);
|
|
46309
46554
|
}
|
|
46310
46555
|
function resolveCompileConfigPath(projectRoot, options) {
|
|
46311
46556
|
if (options.config) {
|
|
@@ -49253,7 +49498,7 @@ import { resolve as resolve28, join as join22 } from "path";
|
|
|
49253
49498
|
|
|
49254
49499
|
// packages/cli/src/commands/lock-reference-scanner.ts
|
|
49255
49500
|
import { readFile as readFile22 } from "fs/promises";
|
|
49256
|
-
import { dirname as dirname19, isAbsolute as
|
|
49501
|
+
import { dirname as dirname19, isAbsolute as isAbsolute13, relative as relative15, resolve as resolve27, sep as sep9 } from "path";
|
|
49257
49502
|
async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
49258
49503
|
const references = {};
|
|
49259
49504
|
const sortedRoots = [...roots].sort(
|
|
@@ -49271,7 +49516,7 @@ async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (
|
|
|
49271
49516
|
if (!Array.isArray(refs)) continue;
|
|
49272
49517
|
for (const ref of refs) {
|
|
49273
49518
|
if (typeof ref !== "string") continue;
|
|
49274
|
-
const referencePath =
|
|
49519
|
+
const referencePath = isAbsolute13(ref) ? resolve27(ref) : resolve27(dirname19(block.loc.file), ref);
|
|
49275
49520
|
const root = sortedRoots.find(
|
|
49276
49521
|
(candidate) => isInsideCachePath(referencePath, candidate.cachePath)
|
|
49277
49522
|
);
|
|
@@ -49601,7 +49846,17 @@ async function updateCommand(packageArg, options) {
|
|
|
49601
49846
|
init_loader2();
|
|
49602
49847
|
init_console();
|
|
49603
49848
|
init_src();
|
|
49604
|
-
import {
|
|
49849
|
+
import {
|
|
49850
|
+
lstat as lstat9,
|
|
49851
|
+
mkdir as mkdir9,
|
|
49852
|
+
mkdtemp,
|
|
49853
|
+
readFile as readFile24,
|
|
49854
|
+
readdir as readdir7,
|
|
49855
|
+
realpath as realpath5,
|
|
49856
|
+
rename,
|
|
49857
|
+
rm,
|
|
49858
|
+
writeFile as writeFile9
|
|
49859
|
+
} from "fs/promises";
|
|
49605
49860
|
import { existsSync as existsSync21 } from "fs";
|
|
49606
49861
|
import { basename as basename14, dirname as dirname20, join as join23, resolve as resolve30 } from "path";
|
|
49607
49862
|
import { parse as parseYaml13 } from "yaml";
|
|
@@ -49625,11 +49880,11 @@ async function vendorSyncCommand(options) {
|
|
|
49625
49880
|
return;
|
|
49626
49881
|
}
|
|
49627
49882
|
const vendorDir = resolve30(VENDOR_DIR);
|
|
49883
|
+
await validateVendorParentDirectory(vendorDir, true);
|
|
49628
49884
|
const recoveredBackup = await recoverVendorDirectory(vendorDir);
|
|
49629
49885
|
if (recoveredBackup) {
|
|
49630
49886
|
ConsoleOutput.warn(`Recovered interrupted vendor update: ${recoveredBackup}`);
|
|
49631
49887
|
}
|
|
49632
|
-
await mkdir9(dirname20(vendorDir), { recursive: true });
|
|
49633
49888
|
const stagingDir = await mkdtemp(join23(dirname20(vendorDir), ".vendor-stage-"));
|
|
49634
49889
|
try {
|
|
49635
49890
|
const manifest = { version: 1, dependencies: {} };
|
|
@@ -49698,6 +49953,7 @@ async function vendorCheckCommand(_options) {
|
|
|
49698
49953
|
const deps = getRepositoryDependencies(lockfile);
|
|
49699
49954
|
validateDependencyPaths(deps);
|
|
49700
49955
|
const vendorDir = resolve30(VENDOR_DIR);
|
|
49956
|
+
await validateVendorParentDirectory(vendorDir, false);
|
|
49701
49957
|
const recoveredBackup = await recoverVendorDirectory(vendorDir);
|
|
49702
49958
|
if (recoveredBackup) {
|
|
49703
49959
|
ConsoleOutput.warn(`Recovered interrupted vendor update: ${recoveredBackup}`);
|
|
@@ -49805,6 +50061,24 @@ function validateDependencyPaths(dependencies) {
|
|
|
49805
50061
|
function toCloneUrl(repoUrl) {
|
|
49806
50062
|
return /^[a-z][a-z\d+.-]*:\/\//i.test(repoUrl) || repoUrl.startsWith("git@") ? repoUrl : `https://${repoUrl}`;
|
|
49807
50063
|
}
|
|
50064
|
+
async function validateVendorParentDirectory(vendorDir, createIfMissing) {
|
|
50065
|
+
const projectRoot = await realpath5(".");
|
|
50066
|
+
const parentDir = dirname20(vendorDir);
|
|
50067
|
+
if (createIfMissing) {
|
|
50068
|
+
await mkdir9(parentDir, { recursive: true });
|
|
50069
|
+
}
|
|
50070
|
+
try {
|
|
50071
|
+
const [metadata, parentRealPath] = await Promise.all([lstat9(parentDir), realpath5(parentDir)]);
|
|
50072
|
+
if (metadata.isSymbolicLink() || !metadata.isDirectory() || parentRealPath === projectRoot || !isInsideCachePath(parentRealPath, projectRoot)) {
|
|
50073
|
+
throw new Error(`Unsafe vendor parent directory: ${parentDir}`);
|
|
50074
|
+
}
|
|
50075
|
+
} catch (error) {
|
|
50076
|
+
if (!createIfMissing && typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
50077
|
+
return;
|
|
50078
|
+
}
|
|
50079
|
+
throw error;
|
|
50080
|
+
}
|
|
50081
|
+
}
|
|
49808
50082
|
async function replaceVendorDirectory(stagingDir, vendorDir) {
|
|
49809
50083
|
if (!existsSync21(vendorDir)) {
|
|
49810
50084
|
await rename(stagingDir, vendorDir);
|
|
@@ -50741,14 +51015,1169 @@ Usage: echo '{"file_path":"..."}' | prs hook ${action}
|
|
|
50741
51015
|
// packages/cli/src/cli.ts
|
|
50742
51016
|
init_hooks();
|
|
50743
51017
|
|
|
51018
|
+
// packages/cli/src/commands/telemetry.ts
|
|
51019
|
+
init_console();
|
|
51020
|
+
|
|
51021
|
+
// packages/cli/src/telemetry/config.ts
|
|
51022
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
51023
|
+
import { mkdir as mkdir11, readFile as readFile27, rename as rename2, writeFile as writeFile11 } from "node:fs/promises";
|
|
51024
|
+
import { dirname as dirname21, isAbsolute as isAbsolute14, join as join29, resolve as resolve34 } from "node:path";
|
|
51025
|
+
import { parseDocument } from "yaml";
|
|
51026
|
+
|
|
51027
|
+
// packages/telemetry/src/config.ts
|
|
51028
|
+
import { homedir as homedir6 } from "node:os";
|
|
51029
|
+
import { join as join27 } from "node:path";
|
|
51030
|
+
var DEFAULT_TELEMETRY_ENDPOINT = "https://telemetry.guziak.net/v1/events";
|
|
51031
|
+
function isDisabled(value) {
|
|
51032
|
+
if (value === void 0) {
|
|
51033
|
+
return false;
|
|
51034
|
+
}
|
|
51035
|
+
return ["0", "false", "no", "off"].includes(value.trim().toLowerCase());
|
|
51036
|
+
}
|
|
51037
|
+
function isDoNotTrackEnabled(value) {
|
|
51038
|
+
if (value === void 0) {
|
|
51039
|
+
return false;
|
|
51040
|
+
}
|
|
51041
|
+
const normalized = value.trim();
|
|
51042
|
+
return normalized !== "" && normalized !== "0";
|
|
51043
|
+
}
|
|
51044
|
+
function isSecureEndpoint(value) {
|
|
51045
|
+
try {
|
|
51046
|
+
const url = new URL(value);
|
|
51047
|
+
return url.protocol === "https:" && url.username === "" && url.password === "";
|
|
51048
|
+
} catch {
|
|
51049
|
+
return false;
|
|
51050
|
+
}
|
|
51051
|
+
}
|
|
51052
|
+
function resolveTelemetryConfig(input2 = {}) {
|
|
51053
|
+
const environment = input2.environment ?? process.env;
|
|
51054
|
+
const endpoint = input2.endpoint ?? environment["PROMPTSCRIPT_TELEMETRY_ENDPOINT"] ?? DEFAULT_TELEMETRY_ENDPOINT;
|
|
51055
|
+
const vetoes = [];
|
|
51056
|
+
if (isDoNotTrackEnabled(environment["DO_NOT_TRACK"])) {
|
|
51057
|
+
vetoes.push("DO_NOT_TRACK");
|
|
51058
|
+
}
|
|
51059
|
+
if (isDisabled(environment["PROMPTSCRIPT_TELEMETRY"])) {
|
|
51060
|
+
vetoes.push("PROMPTSCRIPT_TELEMETRY");
|
|
51061
|
+
}
|
|
51062
|
+
if (input2.userEnabled === false) {
|
|
51063
|
+
vetoes.push("user config");
|
|
51064
|
+
}
|
|
51065
|
+
if (input2.projectEnabled === false) {
|
|
51066
|
+
vetoes.push("project config");
|
|
51067
|
+
}
|
|
51068
|
+
if (input2.configurationValid === false) {
|
|
51069
|
+
vetoes.push("configuration unavailable");
|
|
51070
|
+
}
|
|
51071
|
+
if (!isSecureEndpoint(endpoint)) {
|
|
51072
|
+
vetoes.push("insecure endpoint");
|
|
51073
|
+
}
|
|
51074
|
+
return {
|
|
51075
|
+
enabled: vetoes.length === 0,
|
|
51076
|
+
endpoint,
|
|
51077
|
+
cacheDirectory: input2.cacheDirectory ?? join27(homedir6(), ".promptscript", ".cache"),
|
|
51078
|
+
vetoes
|
|
51079
|
+
};
|
|
51080
|
+
}
|
|
51081
|
+
|
|
51082
|
+
// packages/telemetry/telemetry-schema/promptscript-v1.json
|
|
51083
|
+
var promptscript_v1_default = {
|
|
51084
|
+
eventSchema: 1,
|
|
51085
|
+
commands: [
|
|
51086
|
+
"init",
|
|
51087
|
+
"compile",
|
|
51088
|
+
"build",
|
|
51089
|
+
"validate",
|
|
51090
|
+
"inspect",
|
|
51091
|
+
"pull",
|
|
51092
|
+
"diff",
|
|
51093
|
+
"check",
|
|
51094
|
+
"update-check",
|
|
51095
|
+
"serve",
|
|
51096
|
+
"import",
|
|
51097
|
+
"migrate",
|
|
51098
|
+
"upgrade",
|
|
51099
|
+
"lock",
|
|
51100
|
+
"update",
|
|
51101
|
+
"vendor-sync",
|
|
51102
|
+
"vendor-check",
|
|
51103
|
+
"resolve",
|
|
51104
|
+
"hooks",
|
|
51105
|
+
"skills-add",
|
|
51106
|
+
"skills-remove",
|
|
51107
|
+
"skills-list",
|
|
51108
|
+
"skills-update",
|
|
51109
|
+
"registry",
|
|
51110
|
+
"other"
|
|
51111
|
+
],
|
|
51112
|
+
outcomes: ["success", "error", "cancelled"],
|
|
51113
|
+
features: ["dry_run", "watch", "strict", "ci", "build_profile"],
|
|
51114
|
+
targets: [
|
|
51115
|
+
"github",
|
|
51116
|
+
"claude",
|
|
51117
|
+
"cursor",
|
|
51118
|
+
"antigravity",
|
|
51119
|
+
"factory",
|
|
51120
|
+
"opencode",
|
|
51121
|
+
"gemini",
|
|
51122
|
+
"windsurf",
|
|
51123
|
+
"cline",
|
|
51124
|
+
"roo",
|
|
51125
|
+
"codex",
|
|
51126
|
+
"continue",
|
|
51127
|
+
"augment",
|
|
51128
|
+
"goose",
|
|
51129
|
+
"kilo",
|
|
51130
|
+
"amp",
|
|
51131
|
+
"trae",
|
|
51132
|
+
"junie",
|
|
51133
|
+
"kiro",
|
|
51134
|
+
"cortex",
|
|
51135
|
+
"crush",
|
|
51136
|
+
"command-code",
|
|
51137
|
+
"kode",
|
|
51138
|
+
"mcpjam",
|
|
51139
|
+
"mistral-vibe",
|
|
51140
|
+
"mux",
|
|
51141
|
+
"openhands",
|
|
51142
|
+
"pi",
|
|
51143
|
+
"qoder",
|
|
51144
|
+
"qwen-code",
|
|
51145
|
+
"zencoder",
|
|
51146
|
+
"neovate",
|
|
51147
|
+
"pochi",
|
|
51148
|
+
"adal",
|
|
51149
|
+
"iflow",
|
|
51150
|
+
"openclaw",
|
|
51151
|
+
"codebuddy",
|
|
51152
|
+
"aider",
|
|
51153
|
+
"amazon-q",
|
|
51154
|
+
"warp",
|
|
51155
|
+
"zed",
|
|
51156
|
+
"jules",
|
|
51157
|
+
"devin",
|
|
51158
|
+
"grok",
|
|
51159
|
+
"kimi",
|
|
51160
|
+
"mimo",
|
|
51161
|
+
"deep-agents",
|
|
51162
|
+
"forgecode"
|
|
51163
|
+
],
|
|
51164
|
+
limits: {
|
|
51165
|
+
maxEvents: 25,
|
|
51166
|
+
maxCount: 1e6,
|
|
51167
|
+
maxDurationSumMs: 1e12
|
|
51168
|
+
}
|
|
51169
|
+
};
|
|
51170
|
+
|
|
51171
|
+
// packages/telemetry/src/schema.ts
|
|
51172
|
+
var TELEMETRY_EVENT_SCHEMA = promptscript_v1_default.eventSchema;
|
|
51173
|
+
var MAX_EVENTS_PER_BATCH = promptscript_v1_default.limits.maxEvents;
|
|
51174
|
+
var MAX_EVENT_COUNT = promptscript_v1_default.limits.maxCount;
|
|
51175
|
+
var MAX_DURATION_SUM_MS = promptscript_v1_default.limits.maxDurationSumMs;
|
|
51176
|
+
var COMMANDS = new Set(promptscript_v1_default.commands);
|
|
51177
|
+
var OUTCOMES = new Set(promptscript_v1_default.outcomes);
|
|
51178
|
+
var FEATURES = new Set(promptscript_v1_default.features);
|
|
51179
|
+
var TARGETS = new Set(promptscript_v1_default.targets);
|
|
51180
|
+
function sanitizeCommand(value) {
|
|
51181
|
+
return COMMANDS.has(value) ? value : "other";
|
|
51182
|
+
}
|
|
51183
|
+
function isTelemetryOutcome(value) {
|
|
51184
|
+
return OUTCOMES.has(value);
|
|
51185
|
+
}
|
|
51186
|
+
function sanitizeFeature(value) {
|
|
51187
|
+
if (FEATURES.has(value)) {
|
|
51188
|
+
return value;
|
|
51189
|
+
}
|
|
51190
|
+
const parts = value.split(":");
|
|
51191
|
+
const target = parts[1];
|
|
51192
|
+
if (parts.length === 2 && parts[0] === "target" && target !== void 0 && TARGETS.has(target)) {
|
|
51193
|
+
return value;
|
|
51194
|
+
}
|
|
51195
|
+
return null;
|
|
51196
|
+
}
|
|
51197
|
+
function isExcludedCommand(value) {
|
|
51198
|
+
return value === "hook" || value === "telemetry" || value === "__telemetry-flush";
|
|
51199
|
+
}
|
|
51200
|
+
|
|
51201
|
+
// packages/telemetry/src/payload.ts
|
|
51202
|
+
function metadataKey(record) {
|
|
51203
|
+
return [record.app_version, record.runtime_version, record.os, record.arch].join(":");
|
|
51204
|
+
}
|
|
51205
|
+
function eventKey(event) {
|
|
51206
|
+
return event.name === "command" ? `${event.name}:${event.command}:${event.outcome}` : `${event.name}:${event.feature}`;
|
|
51207
|
+
}
|
|
51208
|
+
function copyEvent(event) {
|
|
51209
|
+
return event.name === "command" ? { ...event } : { ...event };
|
|
51210
|
+
}
|
|
51211
|
+
function canAggregate(target, source) {
|
|
51212
|
+
if (target.count + source.count > MAX_EVENT_COUNT) {
|
|
51213
|
+
return false;
|
|
51214
|
+
}
|
|
51215
|
+
if (target.name === "command" && source.name === "command") {
|
|
51216
|
+
return target.duration_ms_sum + source.duration_ms_sum <= MAX_DURATION_SUM_MS;
|
|
51217
|
+
}
|
|
51218
|
+
return true;
|
|
51219
|
+
}
|
|
51220
|
+
function addEvent(target, source) {
|
|
51221
|
+
target.count += source.count;
|
|
51222
|
+
if (target.name === "command" && source.name === "command") {
|
|
51223
|
+
target.duration_ms_sum += source.duration_ms_sum;
|
|
51224
|
+
}
|
|
51225
|
+
}
|
|
51226
|
+
function aggregateRecords(records) {
|
|
51227
|
+
const aggregates = [];
|
|
51228
|
+
records.forEach((record, index) => {
|
|
51229
|
+
const key = `${metadataKey(record)}:${eventKey(record.event)}`;
|
|
51230
|
+
const aggregate = aggregates.find(
|
|
51231
|
+
(candidate) => `${metadataKey(candidate.metadata)}:${eventKey(candidate.event)}` === key && canAggregate(candidate.event, record.event)
|
|
51232
|
+
);
|
|
51233
|
+
if (aggregate !== void 0) {
|
|
51234
|
+
addEvent(aggregate.event, record.event);
|
|
51235
|
+
aggregate.sourceIndexes.push(index);
|
|
51236
|
+
return;
|
|
51237
|
+
}
|
|
51238
|
+
aggregates.push({
|
|
51239
|
+
metadata: {
|
|
51240
|
+
app_version: record.app_version,
|
|
51241
|
+
runtime_version: record.runtime_version,
|
|
51242
|
+
os: record.os,
|
|
51243
|
+
arch: record.arch
|
|
51244
|
+
},
|
|
51245
|
+
event: copyEvent(record.event),
|
|
51246
|
+
sourceIndexes: [index]
|
|
51247
|
+
});
|
|
51248
|
+
});
|
|
51249
|
+
return aggregates;
|
|
51250
|
+
}
|
|
51251
|
+
function toPayload(batch) {
|
|
51252
|
+
return {
|
|
51253
|
+
schema: 1,
|
|
51254
|
+
app: "promptscript",
|
|
51255
|
+
event_schema: TELEMETRY_EVENT_SCHEMA,
|
|
51256
|
+
runtime: "node",
|
|
51257
|
+
...batch.metadata,
|
|
51258
|
+
events: batch.events
|
|
51259
|
+
};
|
|
51260
|
+
}
|
|
51261
|
+
function buildTelemetryBatches(records) {
|
|
51262
|
+
const builders = [];
|
|
51263
|
+
for (const aggregate of aggregateRecords(records)) {
|
|
51264
|
+
const key = eventKey(aggregate.event);
|
|
51265
|
+
let batch = builders.find(
|
|
51266
|
+
(candidate) => metadataKey(candidate.metadata) === metadataKey(aggregate.metadata) && candidate.events.length < MAX_EVENTS_PER_BATCH && !candidate.eventKeys.has(key)
|
|
51267
|
+
);
|
|
51268
|
+
if (batch === void 0) {
|
|
51269
|
+
batch = {
|
|
51270
|
+
metadata: aggregate.metadata,
|
|
51271
|
+
events: [],
|
|
51272
|
+
eventKeys: /* @__PURE__ */ new Set(),
|
|
51273
|
+
sourceIndexes: /* @__PURE__ */ new Set()
|
|
51274
|
+
};
|
|
51275
|
+
builders.push(batch);
|
|
51276
|
+
}
|
|
51277
|
+
batch.events.push(aggregate.event);
|
|
51278
|
+
batch.eventKeys.add(key);
|
|
51279
|
+
aggregate.sourceIndexes.forEach((index) => batch?.sourceIndexes.add(index));
|
|
51280
|
+
}
|
|
51281
|
+
return builders.map((batch) => ({
|
|
51282
|
+
payload: toPayload(batch),
|
|
51283
|
+
sourceIndexes: [...batch.sourceIndexes]
|
|
51284
|
+
}));
|
|
51285
|
+
}
|
|
51286
|
+
|
|
51287
|
+
// packages/telemetry/src/spool.ts
|
|
51288
|
+
import {
|
|
51289
|
+
appendFileSync,
|
|
51290
|
+
existsSync as existsSync26,
|
|
51291
|
+
mkdirSync as mkdirSync2,
|
|
51292
|
+
readFileSync as readFileSync7,
|
|
51293
|
+
readdirSync as readdirSync2,
|
|
51294
|
+
renameSync as renameSync2,
|
|
51295
|
+
rmSync,
|
|
51296
|
+
statSync as statSync3,
|
|
51297
|
+
unlinkSync as unlinkSync3,
|
|
51298
|
+
writeFileSync as writeFileSync5
|
|
51299
|
+
} from "node:fs";
|
|
51300
|
+
import { join as join28 } from "node:path";
|
|
51301
|
+
var ACTIVE_FILE = "telemetry.ndjson";
|
|
51302
|
+
var INFLIGHT_FILE = "telemetry.inflight.ndjson";
|
|
51303
|
+
var QUARANTINE_FILE = "telemetry-quarantine.ndjson";
|
|
51304
|
+
var STATE_FILE = "telemetry-state.json";
|
|
51305
|
+
var LOCK_DIRECTORY = "telemetry.lock";
|
|
51306
|
+
var FLUSH_LOCK_DIRECTORY = "telemetry-flush.lock";
|
|
51307
|
+
var SIDECAR_PATTERN = /^telemetry\.\d+\.\d+\.\d+\.ndjson$/;
|
|
51308
|
+
var MAX_SPOOL_BYTES = 64 * 1024;
|
|
51309
|
+
var MAX_SPOOL_RECORDS = 200;
|
|
51310
|
+
var STALE_LOCK_MS = 3e4;
|
|
51311
|
+
var sidecarSequence = 0;
|
|
51312
|
+
function pathFor(cacheDirectory, name) {
|
|
51313
|
+
return join28(cacheDirectory, name);
|
|
51314
|
+
}
|
|
51315
|
+
function isNodeError2(error, code) {
|
|
51316
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
51317
|
+
}
|
|
51318
|
+
function removeStaleLock(lockPath) {
|
|
51319
|
+
try {
|
|
51320
|
+
if (Date.now() - statSync3(lockPath).mtimeMs > STALE_LOCK_MS) {
|
|
51321
|
+
rmSync(lockPath, { recursive: true });
|
|
51322
|
+
}
|
|
51323
|
+
} catch {
|
|
51324
|
+
}
|
|
51325
|
+
}
|
|
51326
|
+
function acquireLock2(cacheDirectory, lockDirectory = LOCK_DIRECTORY) {
|
|
51327
|
+
mkdirSync2(cacheDirectory, { recursive: true });
|
|
51328
|
+
const lockPath = pathFor(cacheDirectory, lockDirectory);
|
|
51329
|
+
try {
|
|
51330
|
+
mkdirSync2(lockPath);
|
|
51331
|
+
return true;
|
|
51332
|
+
} catch (error) {
|
|
51333
|
+
if (!isNodeError2(error, "EEXIST")) {
|
|
51334
|
+
return false;
|
|
51335
|
+
}
|
|
51336
|
+
removeStaleLock(lockPath);
|
|
51337
|
+
try {
|
|
51338
|
+
mkdirSync2(lockPath);
|
|
51339
|
+
return true;
|
|
51340
|
+
} catch {
|
|
51341
|
+
return false;
|
|
51342
|
+
}
|
|
51343
|
+
}
|
|
51344
|
+
}
|
|
51345
|
+
function releaseLock2(cacheDirectory, lockDirectory = LOCK_DIRECTORY) {
|
|
51346
|
+
try {
|
|
51347
|
+
rmSync(pathFor(cacheDirectory, lockDirectory), { recursive: true });
|
|
51348
|
+
} catch {
|
|
51349
|
+
}
|
|
51350
|
+
}
|
|
51351
|
+
function compactLines(lines) {
|
|
51352
|
+
const selected = [];
|
|
51353
|
+
let bytes = 0;
|
|
51354
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
51355
|
+
const line = lines[index];
|
|
51356
|
+
const lineBytes = Buffer.byteLength(`${line}
|
|
51357
|
+
`);
|
|
51358
|
+
if (selected.length >= MAX_SPOOL_RECORDS || bytes + lineBytes > MAX_SPOOL_BYTES) {
|
|
51359
|
+
break;
|
|
51360
|
+
}
|
|
51361
|
+
selected.push(line);
|
|
51362
|
+
bytes += lineBytes;
|
|
51363
|
+
}
|
|
51364
|
+
return selected.reverse();
|
|
51365
|
+
}
|
|
51366
|
+
function readLines(filePath) {
|
|
51367
|
+
try {
|
|
51368
|
+
return readFileSync7(filePath, "utf8").split("\n").filter(Boolean);
|
|
51369
|
+
} catch {
|
|
51370
|
+
return [];
|
|
51371
|
+
}
|
|
51372
|
+
}
|
|
51373
|
+
function writeLines(filePath, lines) {
|
|
51374
|
+
if (lines.length === 0) {
|
|
51375
|
+
try {
|
|
51376
|
+
unlinkSync3(filePath);
|
|
51377
|
+
} catch (error) {
|
|
51378
|
+
if (!isNodeError2(error, "ENOENT")) {
|
|
51379
|
+
throw error;
|
|
51380
|
+
}
|
|
51381
|
+
}
|
|
51382
|
+
return;
|
|
51383
|
+
}
|
|
51384
|
+
const temporaryPath = `${filePath}.${process.pid}.tmp`;
|
|
51385
|
+
writeFileSync5(temporaryPath, `${lines.join("\n")}
|
|
51386
|
+
`, { encoding: "utf8", mode: 384 });
|
|
51387
|
+
renameSync2(temporaryPath, filePath);
|
|
51388
|
+
}
|
|
51389
|
+
function compactFile(filePath) {
|
|
51390
|
+
writeLines(filePath, compactLines(readLines(filePath)));
|
|
51391
|
+
}
|
|
51392
|
+
function parseTelemetryEvent(value) {
|
|
51393
|
+
if (typeof value !== "object" || value === null || !("name" in value)) {
|
|
51394
|
+
return null;
|
|
51395
|
+
}
|
|
51396
|
+
const event = value;
|
|
51397
|
+
if (!Number.isSafeInteger(event["count"]) || Number(event["count"]) < 1 || Number(event["count"]) > MAX_EVENT_COUNT) {
|
|
51398
|
+
return null;
|
|
51399
|
+
}
|
|
51400
|
+
const count = Number(event["count"]);
|
|
51401
|
+
if (event["name"] === "command") {
|
|
51402
|
+
if (typeof event["command"] === "string" && sanitizeCommand(event["command"]) === event["command"] && typeof event["outcome"] === "string" && isTelemetryOutcome(event["outcome"]) && typeof event["duration_ms_sum"] === "number" && Number.isSafeInteger(event["duration_ms_sum"]) && event["duration_ms_sum"] >= 0 && event["duration_ms_sum"] <= MAX_DURATION_SUM_MS) {
|
|
51403
|
+
return {
|
|
51404
|
+
name: "command",
|
|
51405
|
+
command: event["command"],
|
|
51406
|
+
outcome: event["outcome"],
|
|
51407
|
+
count,
|
|
51408
|
+
duration_ms_sum: event["duration_ms_sum"]
|
|
51409
|
+
};
|
|
51410
|
+
}
|
|
51411
|
+
return null;
|
|
51412
|
+
}
|
|
51413
|
+
if (event["name"] === "feature" && typeof event["feature"] === "string") {
|
|
51414
|
+
const feature = sanitizeFeature(event["feature"]);
|
|
51415
|
+
return feature === null ? null : { name: "feature", feature, count };
|
|
51416
|
+
}
|
|
51417
|
+
return null;
|
|
51418
|
+
}
|
|
51419
|
+
function parseRecord(line) {
|
|
51420
|
+
try {
|
|
51421
|
+
const value = JSON.parse(line);
|
|
51422
|
+
if (typeof value !== "object" || value === null || !("event" in value)) {
|
|
51423
|
+
return null;
|
|
51424
|
+
}
|
|
51425
|
+
const record = value;
|
|
51426
|
+
const event = parseTelemetryEvent(record["event"]);
|
|
51427
|
+
if (typeof record["app_version"] !== "string" || !/^\d{1,5}\.\d{1,5}\.\d{1,5}(?:[-+][0-9A-Za-z.-]{1,32})?$/.test(record["app_version"]) || typeof record["runtime_version"] !== "string" || !/^\d{1,3}$/.test(record["runtime_version"]) || !["darwin", "linux", "windows", "other"].includes(String(record["os"])) || !["arm64", "x86_64", "other"].includes(String(record["arch"])) || event === null) {
|
|
51428
|
+
return null;
|
|
51429
|
+
}
|
|
51430
|
+
return {
|
|
51431
|
+
app_version: record["app_version"],
|
|
51432
|
+
runtime_version: record["runtime_version"],
|
|
51433
|
+
os: record["os"],
|
|
51434
|
+
arch: record["arch"],
|
|
51435
|
+
event
|
|
51436
|
+
};
|
|
51437
|
+
} catch {
|
|
51438
|
+
return null;
|
|
51439
|
+
}
|
|
51440
|
+
}
|
|
51441
|
+
function parseLines(lines) {
|
|
51442
|
+
const records = [];
|
|
51443
|
+
let corruptLines = 0;
|
|
51444
|
+
for (const line of lines) {
|
|
51445
|
+
const record = parseRecord(line);
|
|
51446
|
+
if (record === null) {
|
|
51447
|
+
corruptLines += 1;
|
|
51448
|
+
} else {
|
|
51449
|
+
records.push(record);
|
|
51450
|
+
}
|
|
51451
|
+
}
|
|
51452
|
+
return { records, corruptLines };
|
|
51453
|
+
}
|
|
51454
|
+
function sidecarFiles(cacheDirectory) {
|
|
51455
|
+
try {
|
|
51456
|
+
return readdirSync2(cacheDirectory).filter((name) => SIDECAR_PATTERN.test(name)).map((name) => pathFor(cacheDirectory, name));
|
|
51457
|
+
} catch {
|
|
51458
|
+
return [];
|
|
51459
|
+
}
|
|
51460
|
+
}
|
|
51461
|
+
function mergeSidecars(cacheDirectory) {
|
|
51462
|
+
const activePath = pathFor(cacheDirectory, ACTIVE_FILE);
|
|
51463
|
+
for (const sidecarPath of sidecarFiles(cacheDirectory)) {
|
|
51464
|
+
for (const line of readLines(sidecarPath)) {
|
|
51465
|
+
appendFileSync(activePath, `${line}
|
|
51466
|
+
`, { encoding: "utf8", mode: 384 });
|
|
51467
|
+
}
|
|
51468
|
+
try {
|
|
51469
|
+
unlinkSync3(sidecarPath);
|
|
51470
|
+
} catch {
|
|
51471
|
+
}
|
|
51472
|
+
}
|
|
51473
|
+
compactFile(activePath);
|
|
51474
|
+
}
|
|
51475
|
+
function appendSpoolRecords(cacheDirectory, records) {
|
|
51476
|
+
if (records.length === 0) {
|
|
51477
|
+
return;
|
|
51478
|
+
}
|
|
51479
|
+
const lines = records.map((record) => JSON.stringify(record));
|
|
51480
|
+
try {
|
|
51481
|
+
if (acquireLock2(cacheDirectory)) {
|
|
51482
|
+
try {
|
|
51483
|
+
const activePath = pathFor(cacheDirectory, ACTIVE_FILE);
|
|
51484
|
+
appendFileSync(activePath, `${lines.join("\n")}
|
|
51485
|
+
`, {
|
|
51486
|
+
encoding: "utf8",
|
|
51487
|
+
mode: 384
|
|
51488
|
+
});
|
|
51489
|
+
compactFile(activePath);
|
|
51490
|
+
} finally {
|
|
51491
|
+
releaseLock2(cacheDirectory);
|
|
51492
|
+
}
|
|
51493
|
+
return;
|
|
51494
|
+
}
|
|
51495
|
+
mkdirSync2(cacheDirectory, { recursive: true });
|
|
51496
|
+
sidecarSequence += 1;
|
|
51497
|
+
const sidecarPath = pathFor(
|
|
51498
|
+
cacheDirectory,
|
|
51499
|
+
`telemetry.${process.pid}.${Date.now()}.${sidecarSequence}.ndjson`
|
|
51500
|
+
);
|
|
51501
|
+
const temporaryPath = `${sidecarPath}.tmp`;
|
|
51502
|
+
writeFileSync5(temporaryPath, `${lines.join("\n")}
|
|
51503
|
+
`, { encoding: "utf8", mode: 384 });
|
|
51504
|
+
renameSync2(temporaryPath, sidecarPath);
|
|
51505
|
+
} catch {
|
|
51506
|
+
}
|
|
51507
|
+
}
|
|
51508
|
+
function claimSpool(cacheDirectory) {
|
|
51509
|
+
if (!acquireLock2(cacheDirectory)) {
|
|
51510
|
+
return null;
|
|
51511
|
+
}
|
|
51512
|
+
try {
|
|
51513
|
+
const inflightPath = pathFor(cacheDirectory, INFLIGHT_FILE);
|
|
51514
|
+
if (existsSync26(inflightPath) && readLines(inflightPath).length === 0) {
|
|
51515
|
+
try {
|
|
51516
|
+
unlinkSync3(inflightPath);
|
|
51517
|
+
} catch {
|
|
51518
|
+
return null;
|
|
51519
|
+
}
|
|
51520
|
+
}
|
|
51521
|
+
if (!existsSync26(inflightPath)) {
|
|
51522
|
+
mergeSidecars(cacheDirectory);
|
|
51523
|
+
const activePath = pathFor(cacheDirectory, ACTIVE_FILE);
|
|
51524
|
+
if (existsSync26(activePath)) {
|
|
51525
|
+
renameSync2(activePath, inflightPath);
|
|
51526
|
+
}
|
|
51527
|
+
}
|
|
51528
|
+
const lines = readLines(inflightPath);
|
|
51529
|
+
return lines.length === 0 ? null : parseLines(lines);
|
|
51530
|
+
} finally {
|
|
51531
|
+
releaseLock2(cacheDirectory);
|
|
51532
|
+
}
|
|
51533
|
+
}
|
|
51534
|
+
function completeSpoolClaim(cacheDirectory, remainingRecords, rejectedRecords = []) {
|
|
51535
|
+
if (!acquireLock2(cacheDirectory)) {
|
|
51536
|
+
return false;
|
|
51537
|
+
}
|
|
51538
|
+
try {
|
|
51539
|
+
try {
|
|
51540
|
+
writeLines(
|
|
51541
|
+
pathFor(cacheDirectory, INFLIGHT_FILE),
|
|
51542
|
+
remainingRecords.map((record) => JSON.stringify(record))
|
|
51543
|
+
);
|
|
51544
|
+
if (rejectedRecords.length > 0) {
|
|
51545
|
+
const quarantinePath = pathFor(cacheDirectory, QUARANTINE_FILE);
|
|
51546
|
+
for (const record of rejectedRecords) {
|
|
51547
|
+
appendFileSync(quarantinePath, `${JSON.stringify(record)}
|
|
51548
|
+
`, {
|
|
51549
|
+
encoding: "utf8",
|
|
51550
|
+
mode: 384
|
|
51551
|
+
});
|
|
51552
|
+
}
|
|
51553
|
+
compactFile(quarantinePath);
|
|
51554
|
+
}
|
|
51555
|
+
return true;
|
|
51556
|
+
} catch {
|
|
51557
|
+
return false;
|
|
51558
|
+
}
|
|
51559
|
+
} finally {
|
|
51560
|
+
releaseLock2(cacheDirectory);
|
|
51561
|
+
}
|
|
51562
|
+
}
|
|
51563
|
+
function prepareSpoolAttempt(cacheDirectory, remainingRecords) {
|
|
51564
|
+
if (!acquireLock2(cacheDirectory)) {
|
|
51565
|
+
return false;
|
|
51566
|
+
}
|
|
51567
|
+
try {
|
|
51568
|
+
try {
|
|
51569
|
+
writeLines(
|
|
51570
|
+
pathFor(cacheDirectory, INFLIGHT_FILE),
|
|
51571
|
+
remainingRecords.map((record) => JSON.stringify(record))
|
|
51572
|
+
);
|
|
51573
|
+
return true;
|
|
51574
|
+
} catch {
|
|
51575
|
+
return false;
|
|
51576
|
+
}
|
|
51577
|
+
} finally {
|
|
51578
|
+
releaseLock2(cacheDirectory);
|
|
51579
|
+
}
|
|
51580
|
+
}
|
|
51581
|
+
function acquireFlushLease(cacheDirectory) {
|
|
51582
|
+
return acquireLock2(cacheDirectory, FLUSH_LOCK_DIRECTORY);
|
|
51583
|
+
}
|
|
51584
|
+
function releaseFlushLease(cacheDirectory) {
|
|
51585
|
+
releaseLock2(cacheDirectory, FLUSH_LOCK_DIRECTORY);
|
|
51586
|
+
}
|
|
51587
|
+
function getSpoolInfo(cacheDirectory) {
|
|
51588
|
+
const files = [
|
|
51589
|
+
pathFor(cacheDirectory, ACTIVE_FILE),
|
|
51590
|
+
pathFor(cacheDirectory, INFLIGHT_FILE),
|
|
51591
|
+
...sidecarFiles(cacheDirectory)
|
|
51592
|
+
];
|
|
51593
|
+
let records = 0;
|
|
51594
|
+
let bytes = 0;
|
|
51595
|
+
for (const file of files) {
|
|
51596
|
+
const lines = readLines(file);
|
|
51597
|
+
records += lines.length;
|
|
51598
|
+
try {
|
|
51599
|
+
bytes += statSync3(file).size;
|
|
51600
|
+
} catch {
|
|
51601
|
+
}
|
|
51602
|
+
}
|
|
51603
|
+
return { records, bytes };
|
|
51604
|
+
}
|
|
51605
|
+
function readFlushState(cacheDirectory) {
|
|
51606
|
+
try {
|
|
51607
|
+
const value = JSON.parse(readFileSync7(pathFor(cacheDirectory, STATE_FILE), "utf8"));
|
|
51608
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
51609
|
+
} catch {
|
|
51610
|
+
return {};
|
|
51611
|
+
}
|
|
51612
|
+
}
|
|
51613
|
+
function writeFlushState(cacheDirectory, state) {
|
|
51614
|
+
try {
|
|
51615
|
+
mkdirSync2(cacheDirectory, { recursive: true });
|
|
51616
|
+
const statePath = pathFor(cacheDirectory, STATE_FILE);
|
|
51617
|
+
const temporaryPath = `${statePath}.${process.pid}.tmp`;
|
|
51618
|
+
writeFileSync5(temporaryPath, `${JSON.stringify(state, null, 2)}
|
|
51619
|
+
`, {
|
|
51620
|
+
encoding: "utf8",
|
|
51621
|
+
mode: 384
|
|
51622
|
+
});
|
|
51623
|
+
renameSync2(temporaryPath, statePath);
|
|
51624
|
+
} catch {
|
|
51625
|
+
}
|
|
51626
|
+
}
|
|
51627
|
+
|
|
51628
|
+
// packages/telemetry/src/transport.ts
|
|
51629
|
+
function isSecureEndpoint2(endpoint) {
|
|
51630
|
+
try {
|
|
51631
|
+
const url = new URL(endpoint);
|
|
51632
|
+
return url.protocol === "https:" && url.username === "" && url.password === "";
|
|
51633
|
+
} catch {
|
|
51634
|
+
return false;
|
|
51635
|
+
}
|
|
51636
|
+
}
|
|
51637
|
+
async function postTelemetry(endpoint, payload, timeoutMs, fetchImplementation = fetch) {
|
|
51638
|
+
if (!isSecureEndpoint2(endpoint)) {
|
|
51639
|
+
return "rejected";
|
|
51640
|
+
}
|
|
51641
|
+
const controller = new AbortController();
|
|
51642
|
+
const timeout = setTimeout(
|
|
51643
|
+
() => {
|
|
51644
|
+
controller.abort();
|
|
51645
|
+
},
|
|
51646
|
+
Math.max(0, timeoutMs)
|
|
51647
|
+
);
|
|
51648
|
+
try {
|
|
51649
|
+
const response = await fetchImplementation(endpoint, {
|
|
51650
|
+
method: "POST",
|
|
51651
|
+
redirect: "manual",
|
|
51652
|
+
signal: controller.signal,
|
|
51653
|
+
headers: {
|
|
51654
|
+
"Content-Type": "application/json",
|
|
51655
|
+
"User-Agent": "promptscript-telemetry/1"
|
|
51656
|
+
},
|
|
51657
|
+
body: JSON.stringify(payload)
|
|
51658
|
+
});
|
|
51659
|
+
if (response.ok) {
|
|
51660
|
+
return "sent";
|
|
51661
|
+
}
|
|
51662
|
+
if (response.status >= 300 && response.status < 400) {
|
|
51663
|
+
return "rejected";
|
|
51664
|
+
}
|
|
51665
|
+
if (response.status === 429 || response.status >= 500) {
|
|
51666
|
+
return "retryable";
|
|
51667
|
+
}
|
|
51668
|
+
if (response.status >= 400 && response.status < 500) {
|
|
51669
|
+
return "rejected";
|
|
51670
|
+
}
|
|
51671
|
+
return "retryable";
|
|
51672
|
+
} catch {
|
|
51673
|
+
return "unknown";
|
|
51674
|
+
} finally {
|
|
51675
|
+
clearTimeout(timeout);
|
|
51676
|
+
}
|
|
51677
|
+
}
|
|
51678
|
+
|
|
51679
|
+
// packages/telemetry/src/flush.ts
|
|
51680
|
+
var FLUSH_BUDGET_MS = 5e3;
|
|
51681
|
+
var MAX_BATCHES_PER_FLUSH = 3;
|
|
51682
|
+
var COMPLETION_RETRIES = 20;
|
|
51683
|
+
function delay(milliseconds) {
|
|
51684
|
+
return new Promise((resolve38) => setTimeout(resolve38, milliseconds));
|
|
51685
|
+
}
|
|
51686
|
+
async function persistCompletion(cacheDirectory, remainingRecords, rejectedRecords) {
|
|
51687
|
+
for (let attempt = 0; attempt < COMPLETION_RETRIES; attempt += 1) {
|
|
51688
|
+
if (completeSpoolClaim(cacheDirectory, remainingRecords, rejectedRecords)) {
|
|
51689
|
+
return true;
|
|
51690
|
+
}
|
|
51691
|
+
await delay(10);
|
|
51692
|
+
}
|
|
51693
|
+
return false;
|
|
51694
|
+
}
|
|
51695
|
+
async function persistAttempt(cacheDirectory, remainingRecords) {
|
|
51696
|
+
for (let attempt = 0; attempt < COMPLETION_RETRIES; attempt += 1) {
|
|
51697
|
+
if (prepareSpoolAttempt(cacheDirectory, remainingRecords)) {
|
|
51698
|
+
return true;
|
|
51699
|
+
}
|
|
51700
|
+
await delay(10);
|
|
51701
|
+
}
|
|
51702
|
+
return false;
|
|
51703
|
+
}
|
|
51704
|
+
async function runFlush(config, fetchImplementation = fetch) {
|
|
51705
|
+
const emptyResult = {
|
|
51706
|
+
attempted: false,
|
|
51707
|
+
deliveredRecords: 0,
|
|
51708
|
+
rejectedRecords: 0,
|
|
51709
|
+
remainingRecords: 0
|
|
51710
|
+
};
|
|
51711
|
+
if (!config.enabled || !acquireFlushLease(config.cacheDirectory)) {
|
|
51712
|
+
return emptyResult;
|
|
51713
|
+
}
|
|
51714
|
+
try {
|
|
51715
|
+
const claim = claimSpool(config.cacheDirectory);
|
|
51716
|
+
if (claim === null) {
|
|
51717
|
+
return emptyResult;
|
|
51718
|
+
}
|
|
51719
|
+
const state = readFlushState(config.cacheDirectory);
|
|
51720
|
+
const startedAt = Date.now();
|
|
51721
|
+
writeFlushState(config.cacheDirectory, {
|
|
51722
|
+
...state,
|
|
51723
|
+
lastAttempt: new Date(startedAt).toISOString(),
|
|
51724
|
+
...claim.corruptLines > 0 ? { lastError: `Skipped ${claim.corruptLines} corrupt spool record(s)` } : {}
|
|
51725
|
+
});
|
|
51726
|
+
const remainingIndexes = new Set(claim.records.map((_record, index) => index));
|
|
51727
|
+
const rejectedIndexes = /* @__PURE__ */ new Set();
|
|
51728
|
+
const batches = buildTelemetryBatches(claim.records).slice(0, MAX_BATCHES_PER_FLUSH);
|
|
51729
|
+
let deliveredRecords = 0;
|
|
51730
|
+
let stoppedForRetry = false;
|
|
51731
|
+
for (const batch of batches) {
|
|
51732
|
+
let remainingBudget = FLUSH_BUDGET_MS - (Date.now() - startedAt);
|
|
51733
|
+
if (remainingBudget <= 0) {
|
|
51734
|
+
stoppedForRetry = true;
|
|
51735
|
+
break;
|
|
51736
|
+
}
|
|
51737
|
+
const pendingRecords = claim.records.filter(
|
|
51738
|
+
(_record, index) => remainingIndexes.has(index) && !batch.sourceIndexes.includes(index)
|
|
51739
|
+
);
|
|
51740
|
+
if (!await persistAttempt(config.cacheDirectory, pendingRecords)) {
|
|
51741
|
+
stoppedForRetry = true;
|
|
51742
|
+
break;
|
|
51743
|
+
}
|
|
51744
|
+
for (const index of batch.sourceIndexes) {
|
|
51745
|
+
remainingIndexes.delete(index);
|
|
51746
|
+
}
|
|
51747
|
+
remainingBudget = FLUSH_BUDGET_MS - (Date.now() - startedAt);
|
|
51748
|
+
if (remainingBudget <= 0) {
|
|
51749
|
+
for (const index of batch.sourceIndexes) {
|
|
51750
|
+
remainingIndexes.add(index);
|
|
51751
|
+
}
|
|
51752
|
+
stoppedForRetry = true;
|
|
51753
|
+
break;
|
|
51754
|
+
}
|
|
51755
|
+
const result = await postTelemetry(
|
|
51756
|
+
config.endpoint,
|
|
51757
|
+
batch.payload,
|
|
51758
|
+
remainingBudget,
|
|
51759
|
+
fetchImplementation
|
|
51760
|
+
);
|
|
51761
|
+
if (result === "sent" || result === "unknown") {
|
|
51762
|
+
deliveredRecords += batch.sourceIndexes.length;
|
|
51763
|
+
if (result === "unknown") {
|
|
51764
|
+
break;
|
|
51765
|
+
}
|
|
51766
|
+
continue;
|
|
51767
|
+
}
|
|
51768
|
+
if (result === "rejected") {
|
|
51769
|
+
for (const index of batch.sourceIndexes) {
|
|
51770
|
+
rejectedIndexes.add(index);
|
|
51771
|
+
}
|
|
51772
|
+
continue;
|
|
51773
|
+
}
|
|
51774
|
+
for (const index of batch.sourceIndexes) {
|
|
51775
|
+
remainingIndexes.add(index);
|
|
51776
|
+
}
|
|
51777
|
+
stoppedForRetry = true;
|
|
51778
|
+
break;
|
|
51779
|
+
}
|
|
51780
|
+
const remainingRecords = claim.records.filter((_record, index) => remainingIndexes.has(index));
|
|
51781
|
+
const rejectedRecords = claim.records.filter((_record, index) => rejectedIndexes.has(index));
|
|
51782
|
+
const persisted = await persistCompletion(
|
|
51783
|
+
config.cacheDirectory,
|
|
51784
|
+
remainingRecords,
|
|
51785
|
+
rejectedRecords
|
|
51786
|
+
);
|
|
51787
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
51788
|
+
const lastError = stoppedForRetry ? "Delivery deferred after retryable failure" : rejectedRecords.length > 0 ? `Collector rejected ${rejectedRecords.length} record(s)` : !persisted ? "Could not finalize telemetry spool" : claim.corruptLines > 0 ? `Skipped ${claim.corruptLines} corrupt spool record(s)` : void 0;
|
|
51789
|
+
writeFlushState(config.cacheDirectory, {
|
|
51790
|
+
...readFlushState(config.cacheDirectory),
|
|
51791
|
+
...remainingRecords.length === 0 && persisted ? { lastSuccess: finishedAt } : {},
|
|
51792
|
+
lastError
|
|
51793
|
+
});
|
|
51794
|
+
return {
|
|
51795
|
+
attempted: batches.length > 0,
|
|
51796
|
+
deliveredRecords,
|
|
51797
|
+
rejectedRecords: rejectedRecords.length,
|
|
51798
|
+
remainingRecords: remainingRecords.length
|
|
51799
|
+
};
|
|
51800
|
+
} finally {
|
|
51801
|
+
releaseFlushLease(config.cacheDirectory);
|
|
51802
|
+
}
|
|
51803
|
+
}
|
|
51804
|
+
|
|
51805
|
+
// packages/telemetry/src/reporter.ts
|
|
51806
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
51807
|
+
import { performance } from "node:perf_hooks";
|
|
51808
|
+
var FLUSH_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
51809
|
+
var FLUSH_RECORD_THRESHOLD = 50;
|
|
51810
|
+
var TelemetrySession = class {
|
|
51811
|
+
config;
|
|
51812
|
+
metadata;
|
|
51813
|
+
command;
|
|
51814
|
+
features;
|
|
51815
|
+
startTime;
|
|
51816
|
+
excluded;
|
|
51817
|
+
finished = false;
|
|
51818
|
+
constructor(options) {
|
|
51819
|
+
this.config = options.config;
|
|
51820
|
+
this.metadata = options.metadata;
|
|
51821
|
+
this.excluded = isExcludedCommand(options.command);
|
|
51822
|
+
this.command = sanitizeCommand(options.command);
|
|
51823
|
+
this.features = (options.features ?? []).map((feature) => sanitizeFeature(feature)).filter((feature) => feature !== null);
|
|
51824
|
+
this.startTime = options.startTime ?? performance.now();
|
|
51825
|
+
}
|
|
51826
|
+
finish(outcome) {
|
|
51827
|
+
if (this.finished || !this.config.enabled || this.excluded) {
|
|
51828
|
+
return;
|
|
51829
|
+
}
|
|
51830
|
+
this.finished = true;
|
|
51831
|
+
const duration = Math.max(0, Math.round(performance.now() - this.startTime));
|
|
51832
|
+
const records = [
|
|
51833
|
+
{
|
|
51834
|
+
...this.metadata,
|
|
51835
|
+
event: {
|
|
51836
|
+
name: "command",
|
|
51837
|
+
command: this.command,
|
|
51838
|
+
outcome,
|
|
51839
|
+
count: 1,
|
|
51840
|
+
duration_ms_sum: duration
|
|
51841
|
+
}
|
|
51842
|
+
},
|
|
51843
|
+
...this.features.map((feature) => ({
|
|
51844
|
+
...this.metadata,
|
|
51845
|
+
event: { name: "feature", feature, count: 1 }
|
|
51846
|
+
}))
|
|
51847
|
+
];
|
|
51848
|
+
appendSpoolRecords(this.config.cacheDirectory, records);
|
|
51849
|
+
}
|
|
51850
|
+
};
|
|
51851
|
+
function shouldFlush(config, now) {
|
|
51852
|
+
const spool = getSpoolInfo(config.cacheDirectory);
|
|
51853
|
+
if (spool.records === 0) {
|
|
51854
|
+
return false;
|
|
51855
|
+
}
|
|
51856
|
+
if (spool.records >= FLUSH_RECORD_THRESHOLD) {
|
|
51857
|
+
return true;
|
|
51858
|
+
}
|
|
51859
|
+
const lastAttempt = readFlushState(config.cacheDirectory).lastAttempt;
|
|
51860
|
+
if (lastAttempt === void 0) {
|
|
51861
|
+
return true;
|
|
51862
|
+
}
|
|
51863
|
+
const timestamp = Date.parse(lastAttempt);
|
|
51864
|
+
return !Number.isFinite(timestamp) || now - timestamp >= FLUSH_INTERVAL_MS;
|
|
51865
|
+
}
|
|
51866
|
+
function maybeSpawnFlush(config, options = {}) {
|
|
51867
|
+
const environment = options.environment ?? process.env;
|
|
51868
|
+
const entrypoint = options.entrypoint ?? process.argv[1];
|
|
51869
|
+
if (!config.enabled || environment["PROMPTSCRIPT_TELEMETRY_FLUSH"] === "1" || entrypoint === void 0 || !shouldFlush(config, options.now ?? Date.now())) {
|
|
51870
|
+
return false;
|
|
51871
|
+
}
|
|
51872
|
+
try {
|
|
51873
|
+
const child = (options.spawn ?? spawn4)(
|
|
51874
|
+
options.executable ?? process.execPath,
|
|
51875
|
+
[entrypoint, "__telemetry-flush"],
|
|
51876
|
+
{
|
|
51877
|
+
detached: true,
|
|
51878
|
+
stdio: "ignore",
|
|
51879
|
+
env: {
|
|
51880
|
+
...environment,
|
|
51881
|
+
PROMPTSCRIPT_TELEMETRY_FLUSH: "1",
|
|
51882
|
+
PROMPTSCRIPT_NO_UPDATE_CHECK: "1"
|
|
51883
|
+
}
|
|
51884
|
+
}
|
|
51885
|
+
);
|
|
51886
|
+
child.unref();
|
|
51887
|
+
return true;
|
|
51888
|
+
} catch {
|
|
51889
|
+
return false;
|
|
51890
|
+
}
|
|
51891
|
+
}
|
|
51892
|
+
|
|
51893
|
+
// packages/telemetry/src/runtime.ts
|
|
51894
|
+
function operatingSystem(platform) {
|
|
51895
|
+
switch (platform) {
|
|
51896
|
+
case "darwin":
|
|
51897
|
+
return "darwin";
|
|
51898
|
+
case "linux":
|
|
51899
|
+
return "linux";
|
|
51900
|
+
case "win32":
|
|
51901
|
+
return "windows";
|
|
51902
|
+
default:
|
|
51903
|
+
return "other";
|
|
51904
|
+
}
|
|
51905
|
+
}
|
|
51906
|
+
function architecture(value) {
|
|
51907
|
+
switch (value) {
|
|
51908
|
+
case "arm64":
|
|
51909
|
+
return "arm64";
|
|
51910
|
+
case "x64":
|
|
51911
|
+
return "x86_64";
|
|
51912
|
+
default:
|
|
51913
|
+
return "other";
|
|
51914
|
+
}
|
|
51915
|
+
}
|
|
51916
|
+
function runtimeMetadata(appVersion, input2 = {}) {
|
|
51917
|
+
return {
|
|
51918
|
+
app_version: appVersion,
|
|
51919
|
+
runtime_version: (input2.nodeVersion ?? process.versions.node).split(".")[0] ?? "0",
|
|
51920
|
+
os: operatingSystem(input2.platform ?? process.platform),
|
|
51921
|
+
arch: architecture(input2.architecture ?? process.arch)
|
|
51922
|
+
};
|
|
51923
|
+
}
|
|
51924
|
+
|
|
51925
|
+
// packages/cli/src/telemetry/config.ts
|
|
51926
|
+
init_loader2();
|
|
51927
|
+
init_user_config();
|
|
51928
|
+
function resolveFrom(baseDirectory, value) {
|
|
51929
|
+
return isAbsolute14(value) ? value : resolve34(baseDirectory, value);
|
|
51930
|
+
}
|
|
51931
|
+
function findProjectConfig(cwd, customPath) {
|
|
51932
|
+
if (customPath !== void 0) {
|
|
51933
|
+
const path2 = resolveFrom(cwd, customPath);
|
|
51934
|
+
return existsSync27(path2) ? path2 : null;
|
|
51935
|
+
}
|
|
51936
|
+
const environmentPath = process.env["PROMPTSCRIPT_CONFIG"];
|
|
51937
|
+
if (environmentPath !== void 0 && environmentPath !== "") {
|
|
51938
|
+
const path2 = resolveFrom(cwd, environmentPath);
|
|
51939
|
+
return existsSync27(path2) ? path2 : null;
|
|
51940
|
+
}
|
|
51941
|
+
for (const file of CONFIG_FILES) {
|
|
51942
|
+
const path2 = join29(cwd, file);
|
|
51943
|
+
if (existsSync27(path2)) {
|
|
51944
|
+
return path2;
|
|
51945
|
+
}
|
|
51946
|
+
}
|
|
51947
|
+
return null;
|
|
51948
|
+
}
|
|
51949
|
+
function isNodeError3(error, code) {
|
|
51950
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
51951
|
+
}
|
|
51952
|
+
async function readUserTelemetrySetting(configPath) {
|
|
51953
|
+
let source;
|
|
51954
|
+
try {
|
|
51955
|
+
source = await readFile27(configPath, "utf8");
|
|
51956
|
+
} catch (error) {
|
|
51957
|
+
return isNodeError3(error, "ENOENT") ? { valid: true } : { valid: false };
|
|
51958
|
+
}
|
|
51959
|
+
try {
|
|
51960
|
+
const document = parseDocument(source);
|
|
51961
|
+
if (document.errors.length > 0) {
|
|
51962
|
+
return { valid: false };
|
|
51963
|
+
}
|
|
51964
|
+
const value = document.get("telemetry");
|
|
51965
|
+
if (value === void 0) {
|
|
51966
|
+
return { valid: true };
|
|
51967
|
+
}
|
|
51968
|
+
return typeof value === "boolean" ? { enabled: value, valid: true } : { valid: false };
|
|
51969
|
+
} catch {
|
|
51970
|
+
return { valid: false };
|
|
51971
|
+
}
|
|
51972
|
+
}
|
|
51973
|
+
async function resolveCliTelemetryConfig(options = {}) {
|
|
51974
|
+
const cwd = options.cwd === void 0 ? process.cwd() : resolve34(process.cwd(), options.cwd);
|
|
51975
|
+
const userSetting = await readUserTelemetrySetting(options.userConfigPath ?? USER_CONFIG_PATH);
|
|
51976
|
+
const projectPath = findProjectConfig(cwd, options.config);
|
|
51977
|
+
const environmentConfig = process.env["PROMPTSCRIPT_CONFIG"];
|
|
51978
|
+
const projectConfigRequested = options.config !== void 0 || environmentConfig !== void 0 && environmentConfig !== "";
|
|
51979
|
+
let projectEnabled;
|
|
51980
|
+
let configurationValid = userSetting.valid;
|
|
51981
|
+
if (projectConfigRequested && projectPath === null) {
|
|
51982
|
+
configurationValid = false;
|
|
51983
|
+
} else if (projectPath !== null) {
|
|
51984
|
+
try {
|
|
51985
|
+
const value = (await loadConfig(projectPath)).telemetry;
|
|
51986
|
+
if (value === void 0 || typeof value === "boolean") {
|
|
51987
|
+
projectEnabled = value;
|
|
51988
|
+
} else {
|
|
51989
|
+
configurationValid = false;
|
|
51990
|
+
}
|
|
51991
|
+
} catch {
|
|
51992
|
+
configurationValid = false;
|
|
51993
|
+
}
|
|
51994
|
+
}
|
|
51995
|
+
return resolveTelemetryConfig({
|
|
51996
|
+
environment: process.env,
|
|
51997
|
+
userEnabled: userSetting.enabled,
|
|
51998
|
+
projectEnabled,
|
|
51999
|
+
configurationValid,
|
|
52000
|
+
...options.cacheDirectory === void 0 ? {} : { cacheDirectory: options.cacheDirectory }
|
|
52001
|
+
});
|
|
52002
|
+
}
|
|
52003
|
+
async function setUserTelemetryEnabled(enabled, configPath = USER_CONFIG_PATH) {
|
|
52004
|
+
let source = "version: '1'\n";
|
|
52005
|
+
try {
|
|
52006
|
+
source = await readFile27(configPath, "utf8");
|
|
52007
|
+
} catch (error) {
|
|
52008
|
+
if (!isNodeError3(error, "ENOENT")) {
|
|
52009
|
+
throw error;
|
|
52010
|
+
}
|
|
52011
|
+
}
|
|
52012
|
+
const document = parseDocument(source);
|
|
52013
|
+
if (document.errors.length > 0) {
|
|
52014
|
+
throw new Error(`Cannot update invalid YAML user config: ${configPath}`);
|
|
52015
|
+
}
|
|
52016
|
+
document.set("telemetry", enabled);
|
|
52017
|
+
await mkdir11(dirname21(configPath), { recursive: true });
|
|
52018
|
+
const temporaryPath = `${configPath}.${process.pid}.tmp`;
|
|
52019
|
+
await writeFile11(temporaryPath, document.toString(), { encoding: "utf8", mode: 384 });
|
|
52020
|
+
await rename2(temporaryPath, configPath);
|
|
52021
|
+
}
|
|
52022
|
+
|
|
52023
|
+
// packages/cli/src/telemetry/session.ts
|
|
52024
|
+
var activeSession = null;
|
|
52025
|
+
var exitHandlerInstalled = false;
|
|
52026
|
+
function normalizedCommandName(command) {
|
|
52027
|
+
const name = command.name();
|
|
52028
|
+
const parentName = command.parent?.name();
|
|
52029
|
+
if (parentName === "vendor" || parentName === "skills") {
|
|
52030
|
+
return `${parentName}-${name}`;
|
|
52031
|
+
}
|
|
52032
|
+
if (parentName === "registry") {
|
|
52033
|
+
return "registry";
|
|
52034
|
+
}
|
|
52035
|
+
return name;
|
|
52036
|
+
}
|
|
52037
|
+
function stringValues(value) {
|
|
52038
|
+
if (typeof value === "string") {
|
|
52039
|
+
return [value];
|
|
52040
|
+
}
|
|
52041
|
+
if (Array.isArray(value)) {
|
|
52042
|
+
return value.filter((item) => typeof item === "string");
|
|
52043
|
+
}
|
|
52044
|
+
return [];
|
|
52045
|
+
}
|
|
52046
|
+
function commandFeatures(command) {
|
|
52047
|
+
const options = command.opts();
|
|
52048
|
+
const features = /* @__PURE__ */ new Set();
|
|
52049
|
+
const targetValues = [...stringValues(options["target"]), ...stringValues(options["targets"])];
|
|
52050
|
+
for (const target of targetValues) {
|
|
52051
|
+
const feature = sanitizeFeature(`target:${target}`);
|
|
52052
|
+
if (feature !== null) {
|
|
52053
|
+
features.add(feature);
|
|
52054
|
+
}
|
|
52055
|
+
}
|
|
52056
|
+
if (options["dryRun"] === true) {
|
|
52057
|
+
features.add("dry_run");
|
|
52058
|
+
}
|
|
52059
|
+
if (options["watch"] === true) {
|
|
52060
|
+
features.add("watch");
|
|
52061
|
+
}
|
|
52062
|
+
if (options["strict"] === true) {
|
|
52063
|
+
features.add("strict");
|
|
52064
|
+
}
|
|
52065
|
+
if (options["build"] !== void 0 || command.name() === "build") {
|
|
52066
|
+
features.add("build_profile");
|
|
52067
|
+
}
|
|
52068
|
+
if (process.env["CI"] !== void 0) {
|
|
52069
|
+
features.add("ci");
|
|
52070
|
+
}
|
|
52071
|
+
return [...features];
|
|
52072
|
+
}
|
|
52073
|
+
function exitOutcome(code) {
|
|
52074
|
+
if (code === 130 || code === 143) {
|
|
52075
|
+
return "cancelled";
|
|
52076
|
+
}
|
|
52077
|
+
return code === 0 ? "success" : "error";
|
|
52078
|
+
}
|
|
52079
|
+
function installExitHandler() {
|
|
52080
|
+
if (exitHandlerInstalled) {
|
|
52081
|
+
return;
|
|
52082
|
+
}
|
|
52083
|
+
process.on("exit", (code) => {
|
|
52084
|
+
finishCliTelemetry(exitOutcome(code));
|
|
52085
|
+
});
|
|
52086
|
+
for (const [signal, fallbackCode] of [
|
|
52087
|
+
["SIGINT", 130],
|
|
52088
|
+
["SIGTERM", 143]
|
|
52089
|
+
]) {
|
|
52090
|
+
process.once(signal, () => {
|
|
52091
|
+
finishCliTelemetry("cancelled");
|
|
52092
|
+
if (process.listenerCount(signal) > 0) {
|
|
52093
|
+
return;
|
|
52094
|
+
}
|
|
52095
|
+
try {
|
|
52096
|
+
process.kill(process.pid, signal);
|
|
52097
|
+
} catch {
|
|
52098
|
+
process.exit(fallbackCode);
|
|
52099
|
+
}
|
|
52100
|
+
});
|
|
52101
|
+
}
|
|
52102
|
+
exitHandlerInstalled = true;
|
|
52103
|
+
}
|
|
52104
|
+
async function prepareCliTelemetry(command, appVersion) {
|
|
52105
|
+
const name = normalizedCommandName(command);
|
|
52106
|
+
if (isExcludedCommand(name) || process.env["PROMPTSCRIPT_TELEMETRY_FLUSH"] === "1") {
|
|
52107
|
+
return;
|
|
52108
|
+
}
|
|
52109
|
+
const options = command.opts();
|
|
52110
|
+
const config = await resolveCliTelemetryConfig({
|
|
52111
|
+
...typeof options["cwd"] === "string" ? { cwd: options["cwd"] } : {},
|
|
52112
|
+
...typeof options["config"] === "string" ? { config: options["config"] } : {}
|
|
52113
|
+
});
|
|
52114
|
+
maybeSpawnFlush(config);
|
|
52115
|
+
activeSession = new TelemetrySession({
|
|
52116
|
+
config,
|
|
52117
|
+
metadata: runtimeMetadata(appVersion),
|
|
52118
|
+
command: name,
|
|
52119
|
+
features: commandFeatures(command)
|
|
52120
|
+
});
|
|
52121
|
+
installExitHandler();
|
|
52122
|
+
}
|
|
52123
|
+
function finishCliTelemetry(outcome) {
|
|
52124
|
+
const session = activeSession;
|
|
52125
|
+
activeSession = null;
|
|
52126
|
+
session?.finish(
|
|
52127
|
+
outcome ?? (process.exitCode === void 0 || process.exitCode === 0 ? "success" : "error")
|
|
52128
|
+
);
|
|
52129
|
+
}
|
|
52130
|
+
async function flushCliTelemetry() {
|
|
52131
|
+
const config = await resolveCliTelemetryConfig();
|
|
52132
|
+
await runFlush(config);
|
|
52133
|
+
}
|
|
52134
|
+
async function telemetryStatus() {
|
|
52135
|
+
const config = await resolveCliTelemetryConfig();
|
|
52136
|
+
return {
|
|
52137
|
+
config,
|
|
52138
|
+
spool: getSpoolInfo(config.cacheDirectory),
|
|
52139
|
+
state: readFlushState(config.cacheDirectory)
|
|
52140
|
+
};
|
|
52141
|
+
}
|
|
52142
|
+
|
|
52143
|
+
// packages/cli/src/commands/telemetry.ts
|
|
52144
|
+
async function telemetryCommand(action) {
|
|
52145
|
+
if (action === "enable") {
|
|
52146
|
+
await setUserTelemetryEnabled(true);
|
|
52147
|
+
ConsoleOutput.success("Anonymous usage telemetry enabled in user config");
|
|
52148
|
+
return;
|
|
52149
|
+
}
|
|
52150
|
+
if (action === "disable") {
|
|
52151
|
+
await setUserTelemetryEnabled(false);
|
|
52152
|
+
ConsoleOutput.success("Anonymous usage telemetry disabled in user config");
|
|
52153
|
+
return;
|
|
52154
|
+
}
|
|
52155
|
+
if (action !== "status") {
|
|
52156
|
+
ConsoleOutput.error("Action must be status, enable, or disable");
|
|
52157
|
+
process.exitCode = 1;
|
|
52158
|
+
return;
|
|
52159
|
+
}
|
|
52160
|
+
const { config, spool, state } = await telemetryStatus();
|
|
52161
|
+
console.log(`Enabled: ${config.enabled ? "yes" : "no"}`);
|
|
52162
|
+
console.log(`Endpoint: ${config.endpoint}`);
|
|
52163
|
+
console.log(`Spool records: ${spool.records}`);
|
|
52164
|
+
console.log(`Spool bytes: ${spool.bytes}`);
|
|
52165
|
+
console.log(`Last attempt: ${state.lastAttempt ?? "never"}`);
|
|
52166
|
+
console.log(`Last success: ${state.lastSuccess ?? "never"}`);
|
|
52167
|
+
console.log(`Last error: ${state.lastError ?? "none"}`);
|
|
52168
|
+
if (config.vetoes.length > 0) {
|
|
52169
|
+
console.log(`Disabled by: ${config.vetoes.join(", ")}`);
|
|
52170
|
+
}
|
|
52171
|
+
}
|
|
52172
|
+
|
|
50744
52173
|
// packages/cli/src/commands/skills.ts
|
|
50745
52174
|
init_src2();
|
|
50746
52175
|
init_loader2();
|
|
50747
52176
|
init_console();
|
|
50748
52177
|
init_src();
|
|
50749
|
-
import { writeFile as
|
|
50750
|
-
import { resolve as
|
|
50751
|
-
import { existsSync as
|
|
52178
|
+
import { writeFile as writeFile12, readFile as readFile28, readdir as readdir9, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
52179
|
+
import { resolve as resolve35, join as join30, basename as basename17, dirname as dirname22 } from "path";
|
|
52180
|
+
import { existsSync as existsSync28 } from "fs";
|
|
50752
52181
|
import { tmpdir as tmpdir3 } from "os";
|
|
50753
52182
|
import { parse as parseYaml15, stringify as stringifyYaml4 } from "yaml";
|
|
50754
52183
|
var REMOTE_SOURCE_PATTERN = /^[a-zA-Z0-9][\w.-]*\.[a-zA-Z]{2,}\/.+/;
|
|
@@ -50796,32 +52225,32 @@ async function collectProjectRemoteImports(entryFile) {
|
|
|
50796
52225
|
const projectRoot = process.cwd();
|
|
50797
52226
|
const entryFiles = /* @__PURE__ */ new Set();
|
|
50798
52227
|
if (entryFile) {
|
|
50799
|
-
entryFiles.add(
|
|
52228
|
+
entryFiles.add(resolve35(entryFile));
|
|
50800
52229
|
}
|
|
50801
52230
|
if (config) {
|
|
50802
52231
|
if (config.input?.entry) {
|
|
50803
|
-
entryFiles.add(
|
|
52232
|
+
entryFiles.add(resolve35(projectRoot, config.input.entry));
|
|
50804
52233
|
}
|
|
50805
52234
|
for (const build of Object.values(config.builds ?? {})) {
|
|
50806
52235
|
if (build.entry) {
|
|
50807
|
-
entryFiles.add(
|
|
52236
|
+
entryFiles.add(resolve35(projectRoot, build.entry));
|
|
50808
52237
|
}
|
|
50809
52238
|
}
|
|
50810
|
-
const defaultEntry =
|
|
50811
|
-
if (!config.input?.entry && (
|
|
52239
|
+
const defaultEntry = resolve35(projectRoot, ".promptscript/project.prs");
|
|
52240
|
+
if (!config.input?.entry && (existsSync28(defaultEntry) || entryFiles.size === 0)) {
|
|
50812
52241
|
entryFiles.add(defaultEntry);
|
|
50813
52242
|
}
|
|
50814
52243
|
} else if (!entryFile) {
|
|
50815
|
-
const defaultEntry =
|
|
50816
|
-
if (
|
|
52244
|
+
const defaultEntry = resolve35(projectRoot, ".promptscript/project.prs");
|
|
52245
|
+
if (existsSync28(defaultEntry)) {
|
|
50817
52246
|
entryFiles.add(defaultEntry);
|
|
50818
52247
|
} else {
|
|
50819
|
-
const promptscriptDir =
|
|
50820
|
-
if (
|
|
52248
|
+
const promptscriptDir = resolve35(projectRoot, ".promptscript");
|
|
52249
|
+
if (existsSync28(promptscriptDir)) {
|
|
50821
52250
|
const entries = await readdir9(promptscriptDir);
|
|
50822
52251
|
const prsFiles = entries.filter((entry) => entry.endsWith(".prs"));
|
|
50823
52252
|
if (prsFiles.length === 1) {
|
|
50824
|
-
entryFiles.add(
|
|
52253
|
+
entryFiles.add(resolve35(promptscriptDir, prsFiles[0]));
|
|
50825
52254
|
}
|
|
50826
52255
|
}
|
|
50827
52256
|
}
|
|
@@ -50830,7 +52259,7 @@ async function collectProjectRemoteImports(entryFile) {
|
|
|
50830
52259
|
for (const projectEntry of entryFiles) {
|
|
50831
52260
|
imports.push(
|
|
50832
52261
|
...await collectRemoteImports(projectEntry, {
|
|
50833
|
-
localPath:
|
|
52262
|
+
localPath: resolve35(projectRoot, ".promptscript"),
|
|
50834
52263
|
registries: config?.registries,
|
|
50835
52264
|
strict: true,
|
|
50836
52265
|
deduplicate: false,
|
|
@@ -50880,7 +52309,7 @@ function deriveSkillFolderName(source) {
|
|
|
50880
52309
|
const subPath = extractSubPath(source);
|
|
50881
52310
|
if (!subPath) return basename17(parseSkillSource(source).path);
|
|
50882
52311
|
if (!subPath.toLowerCase().endsWith(".md")) return basename17(subPath);
|
|
50883
|
-
const parent =
|
|
52312
|
+
const parent = dirname22(subPath);
|
|
50884
52313
|
if (parent === "." || parent === "") return basename17(parseSkillSource(source).path);
|
|
50885
52314
|
return basename17(parent);
|
|
50886
52315
|
}
|
|
@@ -50897,16 +52326,16 @@ function collectExistingSkillNames(lockfile, exclude) {
|
|
|
50897
52326
|
async function fetchAndValidateRemoteSkill(source, options) {
|
|
50898
52327
|
const skillFilePath = extractSkillFilePath(source);
|
|
50899
52328
|
const repoUrl = options.gitUrl ?? extractRepoUrl(source);
|
|
50900
|
-
const tmp = await mkdtemp2(
|
|
52329
|
+
const tmp = await mkdtemp2(join30(tmpdir3(), "prs-skill-validate-"));
|
|
50901
52330
|
const repoName = basename17(parseSkillSource(source).path.split("/")[2]);
|
|
50902
|
-
const cloneDir = !skillFilePath.includes("/") ?
|
|
52331
|
+
const cloneDir = !skillFilePath.includes("/") ? join30(tmp, repoName) : tmp;
|
|
50903
52332
|
try {
|
|
50904
52333
|
const gitRegistry = createGitRegistry({ url: repoUrl });
|
|
50905
52334
|
const cloneRef = options.version === "latest" || /^[0-9a-f]{40}$/i.test(options.version) ? void 0 : options.version;
|
|
50906
52335
|
await gitRegistry.cloneAtTag(repoUrl, cloneRef, cloneDir);
|
|
50907
52336
|
await gitRegistry.checkoutCommit(cloneDir, options.commit);
|
|
50908
52337
|
const subPath = extractSubPath(source);
|
|
50909
|
-
if (!subPath.toLowerCase().endsWith(".md") &&
|
|
52338
|
+
if (!subPath.toLowerCase().endsWith(".md") && existsSync28(join30(cloneDir, `${subPath}.prs`))) {
|
|
50910
52339
|
return {
|
|
50911
52340
|
content: "",
|
|
50912
52341
|
integrity: "",
|
|
@@ -50920,10 +52349,10 @@ async function fetchAndValidateRemoteSkill(source, options) {
|
|
|
50920
52349
|
]
|
|
50921
52350
|
};
|
|
50922
52351
|
}
|
|
50923
|
-
const filePath =
|
|
52352
|
+
const filePath = join30(cloneDir, skillFilePath);
|
|
50924
52353
|
let content;
|
|
50925
52354
|
try {
|
|
50926
|
-
content = await
|
|
52355
|
+
content = await readFile28(filePath, "utf-8");
|
|
50927
52356
|
} catch {
|
|
50928
52357
|
return {
|
|
50929
52358
|
content: "",
|
|
@@ -50999,8 +52428,8 @@ function validateRemoteSource(source) {
|
|
|
50999
52428
|
}
|
|
51000
52429
|
async function resolveEntryFile(fileFlag) {
|
|
51001
52430
|
if (fileFlag) {
|
|
51002
|
-
const resolved =
|
|
51003
|
-
if (!
|
|
52431
|
+
const resolved = resolve35(fileFlag);
|
|
52432
|
+
if (!existsSync28(resolved)) {
|
|
51004
52433
|
throw new Error(`File not found: ${resolved}`);
|
|
51005
52434
|
}
|
|
51006
52435
|
return resolved;
|
|
@@ -51010,24 +52439,24 @@ async function resolveEntryFile(fileFlag) {
|
|
|
51010
52439
|
try {
|
|
51011
52440
|
const config = await loadConfig();
|
|
51012
52441
|
if (config.input?.entry) {
|
|
51013
|
-
const entryPath =
|
|
51014
|
-
if (
|
|
52442
|
+
const entryPath = resolve35(config.input.entry);
|
|
52443
|
+
if (existsSync28(entryPath)) {
|
|
51015
52444
|
return entryPath;
|
|
51016
52445
|
}
|
|
51017
52446
|
}
|
|
51018
52447
|
} catch {
|
|
51019
52448
|
}
|
|
51020
52449
|
}
|
|
51021
|
-
const promptscriptDir =
|
|
51022
|
-
if (
|
|
52450
|
+
const promptscriptDir = resolve35(".promptscript");
|
|
52451
|
+
if (existsSync28(promptscriptDir)) {
|
|
51023
52452
|
const entries = await readdir9(promptscriptDir);
|
|
51024
52453
|
const prsFiles = entries.filter((f) => f.endsWith(".prs"));
|
|
51025
52454
|
if (prsFiles.length === 1) {
|
|
51026
|
-
return
|
|
52455
|
+
return resolve35(promptscriptDir, prsFiles[0]);
|
|
51027
52456
|
}
|
|
51028
52457
|
if (prsFiles.length > 1) {
|
|
51029
52458
|
if (prsFiles.includes("project.prs")) {
|
|
51030
|
-
return
|
|
52459
|
+
return resolve35(promptscriptDir, "project.prs");
|
|
51031
52460
|
}
|
|
51032
52461
|
throw new Error(
|
|
51033
52462
|
`Multiple .prs files found in .promptscript/. Use --file to specify which one.`
|
|
@@ -51128,12 +52557,12 @@ function findUseEndLine(lines, startLine) {
|
|
|
51128
52557
|
}
|
|
51129
52558
|
async function loadLockfile3() {
|
|
51130
52559
|
const defaultLockfile = { version: LOCKFILE_VERSION, dependencies: {} };
|
|
51131
|
-
if (!
|
|
52560
|
+
if (!existsSync28(LOCKFILE_PATH)) {
|
|
51132
52561
|
return defaultLockfile;
|
|
51133
52562
|
}
|
|
51134
52563
|
let parsed;
|
|
51135
52564
|
try {
|
|
51136
|
-
const raw = await
|
|
52565
|
+
const raw = await readFile28(LOCKFILE_PATH, "utf-8");
|
|
51137
52566
|
parsed = parseYaml15(raw, { maxAliasCount: 100 });
|
|
51138
52567
|
} catch (error) {
|
|
51139
52568
|
throw new Error(
|
|
@@ -51147,7 +52576,7 @@ async function loadLockfile3() {
|
|
|
51147
52576
|
return parsed;
|
|
51148
52577
|
}
|
|
51149
52578
|
async function saveLockfile(lockfile) {
|
|
51150
|
-
await
|
|
52579
|
+
await writeFile12(LOCKFILE_PATH, stringifyYaml4(lockfile), "utf-8");
|
|
51151
52580
|
}
|
|
51152
52581
|
async function skillsAddCommand(rawSource, options) {
|
|
51153
52582
|
const spinner = createSpinner("Adding skill...").start();
|
|
@@ -51170,7 +52599,7 @@ async function skillsAddCommand(rawSource, options) {
|
|
|
51170
52599
|
}
|
|
51171
52600
|
spinner.text = "Resolving entry file...";
|
|
51172
52601
|
const entryFile = await resolveEntryFile(options.file);
|
|
51173
|
-
const content = await
|
|
52602
|
+
const content = await readFile28(entryFile, "utf-8");
|
|
51174
52603
|
const lines = content.split("\n");
|
|
51175
52604
|
const alreadyImported = lines.some((line) => {
|
|
51176
52605
|
const usePath = extractUsePath(line);
|
|
@@ -51282,7 +52711,7 @@ async function skillsAddCommand(rawSource, options) {
|
|
|
51282
52711
|
ConsoleOutput.dryRun(`Would update ${LOCKFILE_PATH}`);
|
|
51283
52712
|
return;
|
|
51284
52713
|
}
|
|
51285
|
-
await
|
|
52714
|
+
await writeFile12(entryFile, updatedContent, "utf-8");
|
|
51286
52715
|
await saveLockfile(lockfile);
|
|
51287
52716
|
spinner.succeed("Skill added");
|
|
51288
52717
|
ConsoleOutput.newline();
|
|
@@ -51298,7 +52727,7 @@ async function skillsRemoveCommand(name, options) {
|
|
|
51298
52727
|
const spinner = createSpinner("Removing skill...").start();
|
|
51299
52728
|
try {
|
|
51300
52729
|
const entryFile = await resolveEntryFile();
|
|
51301
|
-
const content = await
|
|
52730
|
+
const content = await readFile28(entryFile, "utf-8");
|
|
51302
52731
|
const lines = content.split("\n");
|
|
51303
52732
|
const parsed = parse(content, { filename: entryFile, tolerant: true });
|
|
51304
52733
|
if (!parsed.ast || parsed.errors.length > 0) {
|
|
@@ -51378,7 +52807,7 @@ async function skillsRemoveCommand(name, options) {
|
|
|
51378
52807
|
return;
|
|
51379
52808
|
}
|
|
51380
52809
|
lines.splice(lineIndex, candidate.endIndex - lineIndex + 1);
|
|
51381
|
-
await
|
|
52810
|
+
await writeFile12(entryFile, lines.join("\n"), "utf-8");
|
|
51382
52811
|
if (removedPath in lockfile.dependencies && !hasSameImportRemaining) {
|
|
51383
52812
|
delete lockfile.dependencies[removedPath];
|
|
51384
52813
|
}
|
|
@@ -51414,7 +52843,7 @@ async function skillsListCommand() {
|
|
|
51414
52843
|
const spinner = createSpinner("Loading skills...").start();
|
|
51415
52844
|
try {
|
|
51416
52845
|
const entryFile = await resolveEntryFile();
|
|
51417
|
-
const content = await
|
|
52846
|
+
const content = await readFile28(entryFile, "utf-8");
|
|
51418
52847
|
const lines = content.split("\n");
|
|
51419
52848
|
const skills2 = [];
|
|
51420
52849
|
for (const line of lines) {
|
|
@@ -51582,9 +53011,13 @@ async function skillsUpdateCommand(name, options) {
|
|
|
51582
53011
|
|
|
51583
53012
|
// packages/cli/src/cli.ts
|
|
51584
53013
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
51585
|
-
var __dirname4 =
|
|
53014
|
+
var __dirname4 = dirname27(__filename4);
|
|
53015
|
+
var CLI_VERSION = getPackageVersion(__dirname3, "./package.json");
|
|
51586
53016
|
var program = new Command();
|
|
51587
|
-
program.name("prs").description("PromptScript CLI - Standardize AI instructions").version(
|
|
53017
|
+
program.name("prs").description("PromptScript CLI - Standardize AI instructions").version(CLI_VERSION).option("--verbose", "Enable verbose output").option("--debug", "Enable debug output (includes verbose)").option("--quiet", "Suppress non-error output").hook("preAction", async (thisCommand, actionCommand) => {
|
|
53018
|
+
if (actionCommand.name() === "__telemetry-flush" && process.env["PROMPTSCRIPT_TELEMETRY_FLUSH"] === "1") {
|
|
53019
|
+
return;
|
|
53020
|
+
}
|
|
51588
53021
|
const opts = thisCommand.opts();
|
|
51589
53022
|
if (opts["quiet"]) {
|
|
51590
53023
|
setContext({ logLevel: 0 /* Quiet */ });
|
|
@@ -51598,7 +53031,8 @@ program.name("prs").description("PromptScript CLI - Standardize AI instructions"
|
|
|
51598
53031
|
} else if (process.env["PROMPTSCRIPT_VERBOSE"] === "1" || process.env["PROMPTSCRIPT_VERBOSE"] === "true") {
|
|
51599
53032
|
setContext({ logLevel: 2 /* Verbose */ });
|
|
51600
53033
|
}
|
|
51601
|
-
|
|
53034
|
+
await prepareCliTelemetry(actionCommand, CLI_VERSION);
|
|
53035
|
+
if (actionCommand.name() === "update-check" || actionCommand.name() === "telemetry" || actionCommand.name() === "__telemetry-flush") {
|
|
51602
53036
|
return;
|
|
51603
53037
|
}
|
|
51604
53038
|
const currentVersion = getPackageVersion(__dirname3, "./package.json");
|
|
@@ -51607,6 +53041,8 @@ program.name("prs").description("PromptScript CLI - Standardize AI instructions"
|
|
|
51607
53041
|
printUpdateNotification(updateInfo);
|
|
51608
53042
|
}
|
|
51609
53043
|
});
|
|
53044
|
+
}).hook("postAction", () => {
|
|
53045
|
+
finishCliTelemetry();
|
|
51610
53046
|
});
|
|
51611
53047
|
program.command("init").description("Initialize PromptScript in current directory").option("-n, --name <name>", "Project name (auto-detected from package.json, etc.)").option("-t, --team <team>", "Team namespace").option("--inherit <path>", "Inheritance path (e.g., @company/team)").option("--registry <path>", "Registry path").option("--targets <targets...>", "Target AI tools (for example: github, claude, cursor)").option("-i, --interactive", "Force interactive mode").option("-y, --yes", "Skip prompts; requires explicit, detected, or configured targets").option("-f, --force", "Force reinitialize even if already initialized").option("-m, --migrate", "Deprecated: run migration during initialization").option("--auto-import", "Automatically import existing instruction files (static)").option("--backup", "Create .prs-backup/ before replacing files").option("--dry-run", "Preview files without writing").option("--no-hooks", "Skip auto-compile hook installation for AI tools").action((opts) => {
|
|
51612
53048
|
if (opts.migrate) {
|
|
@@ -51628,6 +53064,8 @@ program.command("pull").description("Pull updates from registry").option("-f, --
|
|
|
51628
53064
|
program.command("diff").description("Show diff for compiled output").option("-t, --target <target>", "Specific target").option("-a, --all", "Show diff for all targets at once").option("--full", "Show full diff without truncation").option("--no-pager", "Disable pager output").option("--color", "Force colored output").option("--no-color", "Disable colored output").action(diffCommand);
|
|
51629
53065
|
program.command("check").description("Check configuration and dependencies health").action(checkCommand);
|
|
51630
53066
|
program.command("update-check").description("Check for CLI updates").action(updateCheckCommand);
|
|
53067
|
+
program.command("telemetry").argument("<action>", "Action: status, enable, or disable").description("Manage anonymous usage telemetry").action(telemetryCommand);
|
|
53068
|
+
program.command("__telemetry-flush", { hidden: true }).description("Flush queued anonymous telemetry").action(flushCliTelemetry);
|
|
51631
53069
|
program.command("serve").description("Start local development server for playground").option("-p, --port <port>", "Port to listen on", "3000").option("--host <host>", "Host to bind to", "127.0.0.1").option("--read-only", "Disable file modifications").option("--cors-origin <origin>", "Allowed CORS origin", "https://getpromptscript.dev").action(async (opts) => {
|
|
51632
53070
|
const { serveCommand: serveCommand2 } = await Promise.resolve().then(() => (init_serve(), serve_exports));
|
|
51633
53071
|
await serveCommand2(opts);
|
|
@@ -51653,11 +53091,18 @@ skills.command("list").description("List skills imported in the current project"
|
|
|
51653
53091
|
skills.command("update [name]").description("Update lock entries for markdown-sourced skills").option("--dry-run", "Preview changes without writing").option("--skip-validation", "Skip SKILL.md frontmatter validation (not recommended)").option("--strict", "Treat validation warnings as errors").action((name, opts) => skillsUpdateCommand(name, opts));
|
|
51654
53092
|
var registry = program.command("registry").description("Manage PromptScript registries");
|
|
51655
53093
|
registerRegistryCommands(registry);
|
|
51656
|
-
function run(args = process.argv) {
|
|
51657
|
-
|
|
53094
|
+
async function run(args = process.argv) {
|
|
53095
|
+
try {
|
|
53096
|
+
await program.parseAsync(args);
|
|
53097
|
+
} catch (error) {
|
|
53098
|
+
finishCliTelemetry("error");
|
|
53099
|
+
throw error;
|
|
53100
|
+
} finally {
|
|
53101
|
+
finishCliTelemetry();
|
|
53102
|
+
}
|
|
51658
53103
|
}
|
|
51659
53104
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
51660
|
-
run();
|
|
53105
|
+
await run();
|
|
51661
53106
|
}
|
|
51662
53107
|
|
|
51663
53108
|
// packages/cli/src/index.ts
|