@promptscript/cli 1.18.1 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/index.js +1889 -466
- package/package.json +3 -3
- package/skills/promptscript/SKILL.md +12 -5
- package/src/cli.d.ts.map +1 -1
- package/src/commands/compile.d.ts.map +1 -1
- package/src/commands/init.d.ts.map +1 -1
- package/src/commands/lock.d.ts.map +1 -1
- package/src/commands/skills.d.ts +27 -5
- package/src/commands/skills.d.ts.map +1 -1
- package/src/config/merge-config.d.ts.map +1 -1
- package/src/types.d.ts +10 -0
- package/src/types.d.ts.map +1 -1
- package/src/utils/global-output-safety.d.ts +12 -0
- package/src/utils/global-output-safety.d.ts.map +1 -0
- package/src/utils/managed-output-cleanup.d.ts.map +1 -1
- package/src/utils/output-ownership.d.ts +1 -1
- package/src/utils/output-ownership.d.ts.map +1 -1
- package/src/utils/registry-resolver.d.ts.map +1 -1
- package/src/utils/resource-filter.d.ts +35 -0
- package/src/utils/resource-filter.d.ts.map +1 -0
package/index.js
CHANGED
|
@@ -113,7 +113,9 @@ var init_target_output_paths = __esm({
|
|
|
113
113
|
mimo: "AGENTS.md",
|
|
114
114
|
"deep-agents": "AGENTS.md",
|
|
115
115
|
forgecode: "AGENTS.md",
|
|
116
|
-
hermes: "AGENTS.md"
|
|
116
|
+
hermes: "AGENTS.md",
|
|
117
|
+
// GitLab Duo (Agent Platform)
|
|
118
|
+
"gitlab-duo": "AGENTS.md"
|
|
117
119
|
};
|
|
118
120
|
DEFAULT_OUTPUT_PATHS = DEFAULT_OUTPUT_PATH_VALUES;
|
|
119
121
|
}
|
|
@@ -184,7 +186,9 @@ var init_config = __esm({
|
|
|
184
186
|
"mimo",
|
|
185
187
|
"deep-agents",
|
|
186
188
|
"forgecode",
|
|
187
|
-
"hermes"
|
|
189
|
+
"hermes",
|
|
190
|
+
// GitLab Duo (Agent Platform)
|
|
191
|
+
"gitlab-duo"
|
|
188
192
|
];
|
|
189
193
|
}
|
|
190
194
|
});
|
|
@@ -914,10 +918,12 @@ var init_levenshtein = __esm({
|
|
|
914
918
|
|
|
915
919
|
// packages/core/src/utils/markers.ts
|
|
916
920
|
function stripPromptScriptMarkers(content) {
|
|
917
|
-
return content.replace(new RegExp(`${HTML_MARKER}\\n*`, "g"), "").replace(new RegExp(`${YAML_MARKER}[^\\n]+\\n*`, "g"), "");
|
|
921
|
+
return content.replace(new RegExp(`${HTML_MARKER}\\n*`, "g"), "").replace(new RegExp(`${TYPESCRIPT_MARKER}[^\\n]+\\n*`, "g"), "").replace(new RegExp(`${LEGACY_TYPESCRIPT_MARKER}\\n*`, "g"), "").replace(new RegExp(`${YAML_MARKER}[^\\n]+\\n*`, "g"), "");
|
|
918
922
|
}
|
|
919
923
|
function isGeneratedByPromptScript(content) {
|
|
920
|
-
const head = new RegExp(
|
|
924
|
+
const head = new RegExp(
|
|
925
|
+
`^\\s*(?:${YAML_MARKER}|${TYPESCRIPT_MARKER}|${LEGACY_TYPESCRIPT_MARKER}|${HTML_MARKER})`
|
|
926
|
+
);
|
|
921
927
|
return content.split("\n", 5).some((line) => head.test(line));
|
|
922
928
|
}
|
|
923
929
|
function stripFrontmatterMarkerLines(frontmatter) {
|
|
@@ -927,12 +933,14 @@ function stripFrontmatterMarkerLines(frontmatter) {
|
|
|
927
933
|
function stripLeadingHtmlMarker(body) {
|
|
928
934
|
return body.replace(new RegExp(`^\\s*${HTML_MARKER}\\n*`), "");
|
|
929
935
|
}
|
|
930
|
-
var HTML_MARKER, YAML_MARKER;
|
|
936
|
+
var HTML_MARKER, YAML_MARKER, TYPESCRIPT_MARKER, LEGACY_TYPESCRIPT_MARKER;
|
|
931
937
|
var init_markers = __esm({
|
|
932
938
|
"packages/core/src/utils/markers.ts"() {
|
|
933
939
|
"use strict";
|
|
934
940
|
HTML_MARKER = "<!--\\s*PromptScript [^>]+-->";
|
|
935
941
|
YAML_MARKER = "#\\s*promptscript-generated:";
|
|
942
|
+
TYPESCRIPT_MARKER = "//\\s*promptscript-generated:";
|
|
943
|
+
LEGACY_TYPESCRIPT_MARKER = "//\\s*Generated by PromptScript - do not edit\\.";
|
|
936
944
|
}
|
|
937
945
|
});
|
|
938
946
|
|
|
@@ -5092,10 +5100,21 @@ var init_hook_capabilities = __esm({
|
|
|
5092
5100
|
}
|
|
5093
5101
|
},
|
|
5094
5102
|
opencode: {
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5103
|
+
status: "native",
|
|
5104
|
+
configPath: ".opencode/plugins/promptscript.ts",
|
|
5105
|
+
events: ["pre-tool-use", "post-tool-use"],
|
|
5106
|
+
commandFormat: "generated TypeScript plugin with bounded JSON payloads",
|
|
5107
|
+
timeoutUnit: "milliseconds",
|
|
5108
|
+
projectRootStrategy: "plugin-context",
|
|
5109
|
+
platforms: ["unix"],
|
|
5110
|
+
nativeVersions: ["multifile", "full"],
|
|
5111
|
+
fallback: "Use OpenCode version 'multifile' or 'full'.",
|
|
5112
|
+
documentationUrl: "https://opencode.ai/docs/plugins/",
|
|
5113
|
+
terminal: {
|
|
5114
|
+
guarantee: "not-guaranteed",
|
|
5115
|
+
toolNames: [],
|
|
5116
|
+
notes: "OpenCode exposes tool.execute.before and tool.execute.after only; a dedicated terminal command event is not guaranteed, and MCP tool calls plus some subagent paths may not fire plugin hooks at all."
|
|
5117
|
+
}
|
|
5099
5118
|
},
|
|
5100
5119
|
gemini: {
|
|
5101
5120
|
status: "native",
|
|
@@ -5233,7 +5252,8 @@ var init_hook_capabilities = __esm({
|
|
|
5233
5252
|
mimo: UNSUPPORTED_CAPABILITY,
|
|
5234
5253
|
"deep-agents": UNSUPPORTED_CAPABILITY,
|
|
5235
5254
|
forgecode: UNSUPPORTED_CAPABILITY,
|
|
5236
|
-
hermes: UNSUPPORTED_CAPABILITY
|
|
5255
|
+
hermes: UNSUPPORTED_CAPABILITY,
|
|
5256
|
+
"gitlab-duo": UNSUPPORTED_CAPABILITY
|
|
5237
5257
|
};
|
|
5238
5258
|
VSCODE_HOOK_CAPABILITY = {
|
|
5239
5259
|
status: "compatible",
|
|
@@ -6122,12 +6142,12 @@ var init_target_capabilities = __esm({
|
|
|
6122
6142
|
simple: { name: "simple", description: "Single OPENCODE.md file", outputPath: "OPENCODE.md" },
|
|
6123
6143
|
multifile: {
|
|
6124
6144
|
name: "multifile",
|
|
6125
|
-
description: "OPENCODE.md + .opencode/commands/<name>.md (skills via full mode)",
|
|
6145
|
+
description: "OPENCODE.md + .opencode/commands/<name>.md + .opencode/plugins/promptscript.ts (skills via full mode)",
|
|
6126
6146
|
outputPath: "OPENCODE.md"
|
|
6127
6147
|
},
|
|
6128
6148
|
full: {
|
|
6129
6149
|
name: "full",
|
|
6130
|
-
description: "Multifile + .opencode/skills/<name>/SKILL.md + .opencode/commands/<name>.md + .opencode/agents/<name>.md",
|
|
6150
|
+
description: "Multifile + .opencode/skills/<name>/SKILL.md + .opencode/commands/<name>.md + .opencode/agents/<name>.md + .opencode/plugins/promptscript.ts",
|
|
6131
6151
|
outputPath: "OPENCODE.md"
|
|
6132
6152
|
}
|
|
6133
6153
|
}
|
|
@@ -6832,6 +6852,21 @@ var init_target_capabilities = __esm({
|
|
|
6832
6852
|
},
|
|
6833
6853
|
full: { name: "full", description: "Single AGENTS.md file", outputPath: "AGENTS.md" }
|
|
6834
6854
|
}
|
|
6855
|
+
},
|
|
6856
|
+
"gitlab-duo": {
|
|
6857
|
+
versions: {
|
|
6858
|
+
simple: { name: "simple", description: "Single AGENTS.md file", outputPath: "AGENTS.md" },
|
|
6859
|
+
multifile: {
|
|
6860
|
+
name: "multifile",
|
|
6861
|
+
description: "Single AGENTS.md file (skills via full mode)",
|
|
6862
|
+
outputPath: "AGENTS.md"
|
|
6863
|
+
},
|
|
6864
|
+
full: {
|
|
6865
|
+
name: "full",
|
|
6866
|
+
description: "Multifile + skills/<name>/SKILL.md",
|
|
6867
|
+
outputPath: "AGENTS.md"
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6835
6870
|
}
|
|
6836
6871
|
};
|
|
6837
6872
|
}
|
|
@@ -7383,6 +7418,22 @@ var init_target_catalog = __esm({
|
|
|
7383
7418
|
hasCommands: false
|
|
7384
7419
|
}
|
|
7385
7420
|
},
|
|
7421
|
+
// GitLab Duo (Agent Platform)
|
|
7422
|
+
"gitlab-duo": {
|
|
7423
|
+
name: "gitlab-duo",
|
|
7424
|
+
outputPath: DEFAULT_OUTPUT_PATHS["gitlab-duo"],
|
|
7425
|
+
family: "simple",
|
|
7426
|
+
// Duo reads Agent Skills from a repository-root `skills/` directory,
|
|
7427
|
+
// so the dot-directory skill layout does not apply to this target.
|
|
7428
|
+
features: {
|
|
7429
|
+
defaultEnabled: false,
|
|
7430
|
+
defaultVersion: "full",
|
|
7431
|
+
hasSkills: true,
|
|
7432
|
+
hasAgents: false,
|
|
7433
|
+
hasCommands: false
|
|
7434
|
+
},
|
|
7435
|
+
skillPath: { basePath: "skills", fileName: "SKILL.md" }
|
|
7436
|
+
},
|
|
7386
7437
|
// AGENTS.md-only targets
|
|
7387
7438
|
aider: {
|
|
7388
7439
|
name: "aider",
|
|
@@ -7557,6 +7608,89 @@ var init_target_catalog = __esm({
|
|
|
7557
7608
|
}
|
|
7558
7609
|
});
|
|
7559
7610
|
|
|
7611
|
+
// packages/core/src/agent-capabilities.ts
|
|
7612
|
+
function fieldStatus(groups, target) {
|
|
7613
|
+
if (groups.emitted?.includes(target)) return "emitted";
|
|
7614
|
+
if (groups.transformed?.includes(target)) return "transformed";
|
|
7615
|
+
return "not-supported";
|
|
7616
|
+
}
|
|
7617
|
+
function getAgentFieldStatus(target, field) {
|
|
7618
|
+
return fieldStatus(AGENT_FIELD_STATUS_GROUPS[field], target);
|
|
7619
|
+
}
|
|
7620
|
+
function listAgentFieldSupportTargets(field) {
|
|
7621
|
+
const groups = AGENT_FIELD_STATUS_GROUPS[field];
|
|
7622
|
+
return { emitted: groups.emitted ?? [], transformed: groups.transformed ?? [] };
|
|
7623
|
+
}
|
|
7624
|
+
var CANONICAL_AGENT_FIELDS, ALL_NATIVE_AGENT_TARGETS, CLAUDE_CONTRACT_TARGETS, MARKDOWN_CONTRACT_TARGETS, AGENT_FIELD_STATUS_GROUPS;
|
|
7625
|
+
var init_agent_capabilities = __esm({
|
|
7626
|
+
"packages/core/src/agent-capabilities.ts"() {
|
|
7627
|
+
"use strict";
|
|
7628
|
+
init_target_catalog();
|
|
7629
|
+
CANONICAL_AGENT_FIELDS = [
|
|
7630
|
+
"description",
|
|
7631
|
+
"content",
|
|
7632
|
+
"tools",
|
|
7633
|
+
"model",
|
|
7634
|
+
"reasoningEffort",
|
|
7635
|
+
"specModel",
|
|
7636
|
+
"specReasoningEffort",
|
|
7637
|
+
"disallowedTools",
|
|
7638
|
+
"permissionMode",
|
|
7639
|
+
"skills",
|
|
7640
|
+
"mcpServers",
|
|
7641
|
+
"sandboxMode",
|
|
7642
|
+
"nicknameCandidates",
|
|
7643
|
+
"handoffs",
|
|
7644
|
+
"maxTurns",
|
|
7645
|
+
"memory",
|
|
7646
|
+
"background",
|
|
7647
|
+
"isolation"
|
|
7648
|
+
];
|
|
7649
|
+
ALL_NATIVE_AGENT_TARGETS = [
|
|
7650
|
+
"github",
|
|
7651
|
+
"claude",
|
|
7652
|
+
"cursor",
|
|
7653
|
+
"factory",
|
|
7654
|
+
"codex",
|
|
7655
|
+
"opencode",
|
|
7656
|
+
"augment",
|
|
7657
|
+
"amp",
|
|
7658
|
+
"grok"
|
|
7659
|
+
];
|
|
7660
|
+
CLAUDE_CONTRACT_TARGETS = ["claude", "grok"];
|
|
7661
|
+
MARKDOWN_CONTRACT_TARGETS = ["opencode", "augment", "amp"];
|
|
7662
|
+
AGENT_FIELD_STATUS_GROUPS = {
|
|
7663
|
+
description: { emitted: ALL_NATIVE_AGENT_TARGETS },
|
|
7664
|
+
content: {
|
|
7665
|
+
emitted: [...MARKDOWN_CONTRACT_TARGETS, "github", "claude", "cursor", "factory", "grok"],
|
|
7666
|
+
transformed: ["codex"]
|
|
7667
|
+
},
|
|
7668
|
+
tools: { emitted: [...CLAUDE_CONTRACT_TARGETS, "factory"], transformed: ["github"] },
|
|
7669
|
+
model: {
|
|
7670
|
+
emitted: [...CLAUDE_CONTRACT_TARGETS, "cursor", "factory", "codex"],
|
|
7671
|
+
transformed: ["github"]
|
|
7672
|
+
},
|
|
7673
|
+
reasoningEffort: { emitted: ["factory"], transformed: ["codex"] },
|
|
7674
|
+
specModel: { emitted: ["factory"], transformed: ["github"] },
|
|
7675
|
+
specReasoningEffort: { emitted: ["factory"] },
|
|
7676
|
+
disallowedTools: { emitted: CLAUDE_CONTRACT_TARGETS },
|
|
7677
|
+
permissionMode: { emitted: CLAUDE_CONTRACT_TARGETS },
|
|
7678
|
+
skills: { emitted: CLAUDE_CONTRACT_TARGETS, transformed: ["codex"] },
|
|
7679
|
+
mcpServers: {
|
|
7680
|
+
emitted: [...CLAUDE_CONTRACT_TARGETS, "cursor", "factory"],
|
|
7681
|
+
transformed: ["github", "codex"]
|
|
7682
|
+
},
|
|
7683
|
+
sandboxMode: { transformed: ["codex"] },
|
|
7684
|
+
nicknameCandidates: { transformed: ["codex"] },
|
|
7685
|
+
handoffs: { emitted: ["github"] },
|
|
7686
|
+
maxTurns: { emitted: CLAUDE_CONTRACT_TARGETS },
|
|
7687
|
+
memory: { emitted: CLAUDE_CONTRACT_TARGETS },
|
|
7688
|
+
background: { emitted: CLAUDE_CONTRACT_TARGETS },
|
|
7689
|
+
isolation: { emitted: CLAUDE_CONTRACT_TARGETS }
|
|
7690
|
+
};
|
|
7691
|
+
}
|
|
7692
|
+
});
|
|
7693
|
+
|
|
7560
7694
|
// packages/core/src/git-timeout.ts
|
|
7561
7695
|
function isGitTimeoutError(error) {
|
|
7562
7696
|
const errorWithCode = error;
|
|
@@ -7795,6 +7929,80 @@ var init_output_plan = __esm({
|
|
|
7795
7929
|
}
|
|
7796
7930
|
});
|
|
7797
7931
|
|
|
7932
|
+
// packages/core/src/output-resources.ts
|
|
7933
|
+
function isOutputResourceKind(value) {
|
|
7934
|
+
return OUTPUT_RESOURCE_KINDS.includes(value);
|
|
7935
|
+
}
|
|
7936
|
+
function keepBestMatch(current, next) {
|
|
7937
|
+
return current && current.specificity >= next.specificity ? current : next;
|
|
7938
|
+
}
|
|
7939
|
+
function matchResourcePath(resourcePath, normalizedPath) {
|
|
7940
|
+
const nameIndex = resourcePath.indexOf("<name>");
|
|
7941
|
+
if (nameIndex >= 0) {
|
|
7942
|
+
const prefix = resourcePath.slice(0, nameIndex);
|
|
7943
|
+
return normalizedPath.startsWith(prefix) ? prefix.length : 0;
|
|
7944
|
+
}
|
|
7945
|
+
return resourcePath === normalizedPath ? resourcePath.length + 2 : 0;
|
|
7946
|
+
}
|
|
7947
|
+
function normalizeBaseDir(dir) {
|
|
7948
|
+
return dir.replaceAll("\\", "/").split("/").filter(Boolean).join("/");
|
|
7949
|
+
}
|
|
7950
|
+
function hooksSiblingSpecificity(resource, normalizedPath) {
|
|
7951
|
+
const directory = resource.path.slice(0, resource.path.lastIndexOf("/"));
|
|
7952
|
+
if (!directory.endsWith("/hooks")) return 0;
|
|
7953
|
+
if (!normalizedPath.startsWith(`${directory}/`)) return 0;
|
|
7954
|
+
if (normalizedPath.slice(directory.length + 1).includes("/")) return 0;
|
|
7955
|
+
return directory.length + 2;
|
|
7956
|
+
}
|
|
7957
|
+
function matchCatalogResource(target, normalizedPath) {
|
|
7958
|
+
let best;
|
|
7959
|
+
for (const resource of TARGET_CAPABILITIES[target].resources) {
|
|
7960
|
+
let next;
|
|
7961
|
+
if (resource.kind === "main") {
|
|
7962
|
+
const specificity = matchResourcePath(resource.path, normalizedPath);
|
|
7963
|
+
if (specificity > 0) {
|
|
7964
|
+
next = { kind: "main", specificity };
|
|
7965
|
+
}
|
|
7966
|
+
} else {
|
|
7967
|
+
const specificity = matchResourcePath(resource.path, normalizedPath) || (resource.kind === "hooks" ? hooksSiblingSpecificity(resource, normalizedPath) : 0);
|
|
7968
|
+
if (specificity > 0) {
|
|
7969
|
+
next = { kind: resource.kind, specificity };
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
if (next) {
|
|
7973
|
+
best = keepBestMatch(best, next);
|
|
7974
|
+
}
|
|
7975
|
+
}
|
|
7976
|
+
return best?.kind;
|
|
7977
|
+
}
|
|
7978
|
+
function classifyOutputResource(target, path2, skillBaseDir) {
|
|
7979
|
+
const normalizedPath = path2.replaceAll("\\", "/");
|
|
7980
|
+
const catalogKind = isKnownTarget(target) ? matchCatalogResource(target, normalizedPath) : void 0;
|
|
7981
|
+
if (catalogKind) return catalogKind;
|
|
7982
|
+
const baseDir = skillBaseDir ? normalizeBaseDir(skillBaseDir) : "";
|
|
7983
|
+
if (baseDir && (normalizedPath === baseDir || normalizedPath.startsWith(`${baseDir}/`))) {
|
|
7984
|
+
return "skills";
|
|
7985
|
+
}
|
|
7986
|
+
return "main";
|
|
7987
|
+
}
|
|
7988
|
+
var OUTPUT_RESOURCE_KINDS;
|
|
7989
|
+
var init_output_resources = __esm({
|
|
7990
|
+
"packages/core/src/output-resources.ts"() {
|
|
7991
|
+
"use strict";
|
|
7992
|
+
init_target_catalog();
|
|
7993
|
+
init_config();
|
|
7994
|
+
OUTPUT_RESOURCE_KINDS = [
|
|
7995
|
+
"agents",
|
|
7996
|
+
"skills",
|
|
7997
|
+
"commands",
|
|
7998
|
+
"mcp",
|
|
7999
|
+
"hooks",
|
|
8000
|
+
"plugins",
|
|
8001
|
+
"main"
|
|
8002
|
+
];
|
|
8003
|
+
}
|
|
8004
|
+
});
|
|
8005
|
+
|
|
7798
8006
|
// packages/core/src/index.ts
|
|
7799
8007
|
var init_src = __esm({
|
|
7800
8008
|
"packages/core/src/index.ts"() {
|
|
@@ -7818,10 +8026,12 @@ var init_src = __esm({
|
|
|
7818
8026
|
init_section_registry();
|
|
7819
8027
|
init_target_catalog();
|
|
7820
8028
|
init_target_capabilities();
|
|
8029
|
+
init_agent_capabilities();
|
|
7821
8030
|
init_hook_capabilities();
|
|
7822
8031
|
init_git_timeout();
|
|
7823
8032
|
init_structured_output();
|
|
7824
8033
|
init_output_plan();
|
|
8034
|
+
init_output_resources();
|
|
7825
8035
|
}
|
|
7826
8036
|
});
|
|
7827
8037
|
|
|
@@ -19160,9 +19370,12 @@ var init_base_formatter = __esm({
|
|
|
19160
19370
|
return `${skillBasePath}/${skillName}`;
|
|
19161
19371
|
}
|
|
19162
19372
|
const normalizedOutputDir = this.normalizeOutputDir(outputDir);
|
|
19373
|
+
if (!normalizedOutputDir) {
|
|
19374
|
+
return `${skillBasePath}/${skillName}`;
|
|
19375
|
+
}
|
|
19163
19376
|
if (!configuredBaseDir) {
|
|
19164
|
-
const targetRoot = defaultSkillBasePath.replace(
|
|
19165
|
-
return `${targetRoot}/${normalizedOutputDir}
|
|
19377
|
+
const targetRoot = defaultSkillBasePath.replace(/(?:^|\/)skills$/, "");
|
|
19378
|
+
return targetRoot ? `${targetRoot}/${normalizedOutputDir}` : normalizedOutputDir;
|
|
19166
19379
|
}
|
|
19167
19380
|
const outputSegments = normalizedOutputDir.split("/").filter((segment) => segment.length > 0);
|
|
19168
19381
|
const relativeOutputDir = outputSegments[0] === "skills" ? outputSegments.slice(1).join("/") : outputSegments.join("/");
|
|
@@ -19726,7 +19939,7 @@ function getEnabledHookScriptResources(hook) {
|
|
|
19726
19939
|
}
|
|
19727
19940
|
function mapEvent(event, target) {
|
|
19728
19941
|
if (target === "windsurf") return WINDSURF_EVENT_MAP[event][0] ?? null;
|
|
19729
|
-
const map = target
|
|
19942
|
+
const map = EVENT_MAPS[target] ?? CODEX_EVENT_MAP;
|
|
19730
19943
|
return map[event] || null;
|
|
19731
19944
|
}
|
|
19732
19945
|
function mapEvents(event) {
|
|
@@ -19743,6 +19956,7 @@ function getEffectiveMatcher(hook, target) {
|
|
|
19743
19956
|
function convertTimeout(timeoutMs, target) {
|
|
19744
19957
|
if (target === "gemini") return timeoutMs;
|
|
19745
19958
|
if (target === "windsurf") return timeoutMs;
|
|
19959
|
+
if (target === "opencode") return timeoutMs;
|
|
19746
19960
|
if (target === "claude" || target === "cursor" || target === "codex" || target === "factory" || target === "github" || target === "vscode" || target === "grok")
|
|
19747
19961
|
return Math.ceil(timeoutMs / 1e3);
|
|
19748
19962
|
return timeoutMs;
|
|
@@ -20022,7 +20236,37 @@ function generateCodexHookConfig(hooks) {
|
|
|
20022
20236
|
}
|
|
20023
20237
|
return result;
|
|
20024
20238
|
}
|
|
20025
|
-
|
|
20239
|
+
function buildOpenCodeHookRule(hook) {
|
|
20240
|
+
const nativeEvent = mapEvent(hook.event, "opencode");
|
|
20241
|
+
if (nativeEvent !== "tool.execute.before" && nativeEvent !== "tool.execute.after") return null;
|
|
20242
|
+
const command = hook.command ?? (hook.script ? [
|
|
20243
|
+
...getPosixInterpreter(hook.script.interpreter),
|
|
20244
|
+
getScriptPathFromNativeCwd(hook),
|
|
20245
|
+
...hook.script.args
|
|
20246
|
+
] : []);
|
|
20247
|
+
if (command.length === 0) return null;
|
|
20248
|
+
const rule = {
|
|
20249
|
+
id: hook.id.replace(/[^A-Za-z0-9._-]/g, "-"),
|
|
20250
|
+
event: nativeEvent,
|
|
20251
|
+
...hook.matcher !== void 0 ? { matcher: hook.matcher } : {},
|
|
20252
|
+
command,
|
|
20253
|
+
...hook.cwd !== void 0 && hook.cwd !== "project" ? { cwd: hook.cwd } : {},
|
|
20254
|
+
...hook.timeoutMs !== void 0 ? { timeoutMs: hook.timeoutMs } : {}
|
|
20255
|
+
};
|
|
20256
|
+
return rule;
|
|
20257
|
+
}
|
|
20258
|
+
function generateOpenCodePlugin(hooks) {
|
|
20259
|
+
const rules = [];
|
|
20260
|
+
for (const hook of applyHookTargetOverrides(hooks, "opencode")) {
|
|
20261
|
+
if (hook.enabled === false) continue;
|
|
20262
|
+
const rule = buildOpenCodeHookRule(hook);
|
|
20263
|
+
if (rule) rules.push(rule);
|
|
20264
|
+
}
|
|
20265
|
+
if (rules.length === 0) return null;
|
|
20266
|
+
const serializedRules = rules.map((rule) => JSON.stringify(rule));
|
|
20267
|
+
return "// promptscript-generated: opencode-plugin\n// Generated by PromptScript - do not edit.\n// Recompiling the .promptscript sources rewrites this file; manual edits are discarded.\n// Scope: OpenCode fires these hooks for local tool executions only. MCP tool calls,\n// some subagent paths, and failed tool calls have no dedicated plugin hook.\n// OpenCode tool hooks do not expose model or agent context; payloads omit those fields.\n\ninterface OpenCodeHookRule {\n id: string;\n event: 'tool.execute.before' | 'tool.execute.after';\n matcher?: string;\n command: string[];\n cwd?: string;\n timeoutMs?: number;\n}\n\nconst HOOK_RULES: readonly OpenCodeHookRule[] = [\n" + serializedRules.map((rule) => " " + rule).join(",\n") + "\n];\n" + OPENCODE_PLUGIN_RUNTIME;
|
|
20268
|
+
}
|
|
20269
|
+
var HOOK_OWNERSHIP_MARKER, SHELL_SAFE_ARGUMENT, HOST_CWD_STRATEGIES, CLAUDE_EVENT_MAP, CURSOR_EVENT_MAP, CODEX_EVENT_MAP, FACTORY_EVENT_MAP, GITHUB_EVENT_MAP, GEMINI_EVENT_MAP, GROK_EVENT_MAP, WINDSURF_EVENT_MAP, VSCODE_EVENT_MAP, OPENCODE_EVENT_MAP, EVENT_MAPS, GITHUB_MATCHER_EVENTS, OPENCODE_PLUGIN_PATH, OPENCODE_PLUGIN_RUNTIME;
|
|
20026
20270
|
var init_hook_adapters = __esm({
|
|
20027
20271
|
"packages/formatters/src/hook-adapters.ts"() {
|
|
20028
20272
|
"use strict";
|
|
@@ -20034,6 +20278,7 @@ var init_hook_adapters = __esm({
|
|
|
20034
20278
|
"git-root": false,
|
|
20035
20279
|
"native-cwd": true,
|
|
20036
20280
|
"workspace-cwd": true,
|
|
20281
|
+
"plugin-context": false,
|
|
20037
20282
|
none: false
|
|
20038
20283
|
};
|
|
20039
20284
|
CLAUDE_EVENT_MAP = {
|
|
@@ -20125,12 +20370,199 @@ var init_hook_adapters = __esm({
|
|
|
20125
20370
|
notification: "",
|
|
20126
20371
|
stop: "Stop"
|
|
20127
20372
|
};
|
|
20373
|
+
OPENCODE_EVENT_MAP = {
|
|
20374
|
+
"pre-terminal-command": "",
|
|
20375
|
+
"pre-tool-use": "tool.execute.before",
|
|
20376
|
+
"post-tool-use": "tool.execute.after",
|
|
20377
|
+
"session-start": "",
|
|
20378
|
+
setup: "",
|
|
20379
|
+
"subagent-start": "",
|
|
20380
|
+
notification: "",
|
|
20381
|
+
stop: ""
|
|
20382
|
+
};
|
|
20383
|
+
EVENT_MAPS = {
|
|
20384
|
+
claude: CLAUDE_EVENT_MAP,
|
|
20385
|
+
cursor: CURSOR_EVENT_MAP,
|
|
20386
|
+
factory: FACTORY_EVENT_MAP,
|
|
20387
|
+
github: GITHUB_EVENT_MAP,
|
|
20388
|
+
gemini: GEMINI_EVENT_MAP,
|
|
20389
|
+
grok: GROK_EVENT_MAP,
|
|
20390
|
+
vscode: VSCODE_EVENT_MAP,
|
|
20391
|
+
opencode: OPENCODE_EVENT_MAP
|
|
20392
|
+
};
|
|
20128
20393
|
GITHUB_MATCHER_EVENTS = /* @__PURE__ */ new Set([
|
|
20129
20394
|
"pre-tool-use",
|
|
20130
20395
|
"post-tool-use",
|
|
20131
20396
|
"subagent-start",
|
|
20132
20397
|
"notification"
|
|
20133
20398
|
]);
|
|
20399
|
+
OPENCODE_PLUGIN_PATH = ".opencode/plugins/promptscript.ts";
|
|
20400
|
+
OPENCODE_PLUGIN_RUNTIME = `
|
|
20401
|
+
const PAYLOAD_LIMIT_BYTES = 32768;
|
|
20402
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
20403
|
+
const KILL_GRACE_MS = 1000;
|
|
20404
|
+
|
|
20405
|
+
interface OpenCodePluginContext {
|
|
20406
|
+
directory: string;
|
|
20407
|
+
worktree?: string;
|
|
20408
|
+
}
|
|
20409
|
+
|
|
20410
|
+
interface OpenCodeToolInput {
|
|
20411
|
+
tool?: string;
|
|
20412
|
+
sessionID?: string;
|
|
20413
|
+
callID?: string;
|
|
20414
|
+
args?: unknown;
|
|
20415
|
+
}
|
|
20416
|
+
|
|
20417
|
+
interface OpenCodeToolOutput {
|
|
20418
|
+
args?: unknown;
|
|
20419
|
+
}
|
|
20420
|
+
|
|
20421
|
+
interface OpenCodeToolResult {
|
|
20422
|
+
title?: unknown;
|
|
20423
|
+
output?: unknown;
|
|
20424
|
+
metadata?: unknown;
|
|
20425
|
+
}
|
|
20426
|
+
|
|
20427
|
+
interface OpenCodeCompiledRule {
|
|
20428
|
+
rule: OpenCodeHookRule;
|
|
20429
|
+
matcher: RegExp | null;
|
|
20430
|
+
}
|
|
20431
|
+
|
|
20432
|
+
function safeStringify(value: unknown): string {
|
|
20433
|
+
try {
|
|
20434
|
+
return JSON.stringify(value);
|
|
20435
|
+
} catch {
|
|
20436
|
+
return '{}';
|
|
20437
|
+
}
|
|
20438
|
+
}
|
|
20439
|
+
|
|
20440
|
+
function payloadByteLength(value: string): number {
|
|
20441
|
+
return new TextEncoder().encode(value).byteLength;
|
|
20442
|
+
}
|
|
20443
|
+
|
|
20444
|
+
// Keep the payload bounded: drop oversized tool arguments first, then the
|
|
20445
|
+
// result object, so the command always receives parseable JSON.
|
|
20446
|
+
function boundedPayload(payload: Record<string, unknown>): string {
|
|
20447
|
+
const full = safeStringify(payload);
|
|
20448
|
+
if (payloadByteLength(full) <= PAYLOAD_LIMIT_BYTES) return full;
|
|
20449
|
+
const withoutArgs = { ...payload, args: '[truncated]' };
|
|
20450
|
+
const trimmed = safeStringify(withoutArgs);
|
|
20451
|
+
if (payloadByteLength(trimmed) <= PAYLOAD_LIMIT_BYTES) return trimmed;
|
|
20452
|
+
const withoutResult = safeStringify({ ...withoutArgs, result: '[truncated]' });
|
|
20453
|
+
if (payloadByteLength(withoutResult) <= PAYLOAD_LIMIT_BYTES) return withoutResult;
|
|
20454
|
+
return '{"target":"opencode","args":"[truncated]","result":"[truncated]"}';
|
|
20455
|
+
}
|
|
20456
|
+
|
|
20457
|
+
function buildPayload(
|
|
20458
|
+
rule: OpenCodeHookRule,
|
|
20459
|
+
input: OpenCodeToolInput,
|
|
20460
|
+
args: unknown,
|
|
20461
|
+
result?: unknown
|
|
20462
|
+
): Record<string, unknown> {
|
|
20463
|
+
const payload: Record<string, unknown> = {
|
|
20464
|
+
target: 'opencode',
|
|
20465
|
+
hook: rule.id,
|
|
20466
|
+
event: rule.event === 'tool.execute.before' ? 'pre-tool-use' : 'post-tool-use',
|
|
20467
|
+
tool: input.tool,
|
|
20468
|
+
args,
|
|
20469
|
+
sessionID: input.sessionID,
|
|
20470
|
+
callID: input.callID,
|
|
20471
|
+
timestamp: new Date().toISOString()
|
|
20472
|
+
};
|
|
20473
|
+
if (result !== undefined) payload.result = result;
|
|
20474
|
+
return payload;
|
|
20475
|
+
}
|
|
20476
|
+
|
|
20477
|
+
// Hooks observe tool execution asynchronously. Failures are logged, and every
|
|
20478
|
+
// process gets a bounded lifetime so a broken hook cannot disrupt the session.
|
|
20479
|
+
async function runRule(
|
|
20480
|
+
rule: OpenCodeHookRule,
|
|
20481
|
+
projectRoot: string,
|
|
20482
|
+
payload: string
|
|
20483
|
+
): Promise<void> {
|
|
20484
|
+
try {
|
|
20485
|
+
const cwd = rule.cwd ? projectRoot + '/' + rule.cwd : projectRoot;
|
|
20486
|
+
const proc = Bun.spawn({
|
|
20487
|
+
cmd: rule.command,
|
|
20488
|
+
cwd,
|
|
20489
|
+
stdin: 'pipe',
|
|
20490
|
+
stdout: 'inherit',
|
|
20491
|
+
stderr: 'inherit'
|
|
20492
|
+
});
|
|
20493
|
+
const timeoutMs = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
20494
|
+
let graceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
20495
|
+
const timer = setTimeout(() => {
|
|
20496
|
+
proc.kill('SIGTERM');
|
|
20497
|
+
graceTimer = setTimeout(() => proc.kill('SIGKILL'), KILL_GRACE_MS);
|
|
20498
|
+
}, timeoutMs);
|
|
20499
|
+
try {
|
|
20500
|
+
proc.stdin.write(payload);
|
|
20501
|
+
proc.stdin.end();
|
|
20502
|
+
const exitCode = await proc.exited;
|
|
20503
|
+
if (exitCode !== 0) {
|
|
20504
|
+
console.error(
|
|
20505
|
+
'[promptscript] opencode hook "' + rule.id + '" exited with code ' + exitCode
|
|
20506
|
+
);
|
|
20507
|
+
}
|
|
20508
|
+
} finally {
|
|
20509
|
+
clearTimeout(timer);
|
|
20510
|
+
if (graceTimer !== undefined) clearTimeout(graceTimer);
|
|
20511
|
+
}
|
|
20512
|
+
} catch (error: unknown) {
|
|
20513
|
+
console.error('[promptscript] opencode hook "' + rule.id + '" failed:', error);
|
|
20514
|
+
}
|
|
20515
|
+
}
|
|
20516
|
+
|
|
20517
|
+
export const PromptScriptHooks = async (context: OpenCodePluginContext) => {
|
|
20518
|
+
const projectRoot = context.worktree || context.directory;
|
|
20519
|
+
const compiled: OpenCodeCompiledRule[] = [];
|
|
20520
|
+
for (const rule of HOOK_RULES) {
|
|
20521
|
+
if (rule.matcher === undefined) {
|
|
20522
|
+
compiled.push({ rule, matcher: null });
|
|
20523
|
+
continue;
|
|
20524
|
+
}
|
|
20525
|
+
try {
|
|
20526
|
+
compiled.push({ rule, matcher: new RegExp(rule.matcher) });
|
|
20527
|
+
} catch (error: unknown) {
|
|
20528
|
+
console.error(
|
|
20529
|
+
'[promptscript] opencode hook "' + rule.id + '" has an invalid matcher:',
|
|
20530
|
+
rule.matcher
|
|
20531
|
+
);
|
|
20532
|
+
}
|
|
20533
|
+
}
|
|
20534
|
+
|
|
20535
|
+
return {
|
|
20536
|
+
'tool.execute.before': async (input: OpenCodeToolInput, output: OpenCodeToolOutput) => {
|
|
20537
|
+
for (const entry of compiled) {
|
|
20538
|
+
if (entry.rule.event !== 'tool.execute.before') continue;
|
|
20539
|
+
if (entry.matcher !== null && !entry.matcher.test(String(input.tool))) continue;
|
|
20540
|
+
void runRule(
|
|
20541
|
+
entry.rule,
|
|
20542
|
+
projectRoot,
|
|
20543
|
+
boundedPayload(buildPayload(entry.rule, input, output.args))
|
|
20544
|
+
);
|
|
20545
|
+
}
|
|
20546
|
+
},
|
|
20547
|
+
'tool.execute.after': async (input: OpenCodeToolInput, output: OpenCodeToolResult) => {
|
|
20548
|
+
for (const entry of compiled) {
|
|
20549
|
+
if (entry.rule.event !== 'tool.execute.after') continue;
|
|
20550
|
+
if (entry.matcher !== null && !entry.matcher.test(String(input.tool))) continue;
|
|
20551
|
+
const result = {
|
|
20552
|
+
title: output.title,
|
|
20553
|
+
output: output.output,
|
|
20554
|
+
metadata: output.metadata
|
|
20555
|
+
};
|
|
20556
|
+
void runRule(
|
|
20557
|
+
entry.rule,
|
|
20558
|
+
projectRoot,
|
|
20559
|
+
boundedPayload(buildPayload(entry.rule, input, input.args, result))
|
|
20560
|
+
);
|
|
20561
|
+
}
|
|
20562
|
+
}
|
|
20563
|
+
};
|
|
20564
|
+
};
|
|
20565
|
+
`;
|
|
20134
20566
|
}
|
|
20135
20567
|
});
|
|
20136
20568
|
|
|
@@ -20181,6 +20613,108 @@ var init_hook_capability_warnings = __esm({
|
|
|
20181
20613
|
}
|
|
20182
20614
|
});
|
|
20183
20615
|
|
|
20616
|
+
// packages/formatters/src/agent-capability-warnings.ts
|
|
20617
|
+
function collectAgentEntries(ast) {
|
|
20618
|
+
const agentsBlock = ast.blocks.find((block) => block.name === "agents");
|
|
20619
|
+
if (!agentsBlock) return null;
|
|
20620
|
+
const entries = [];
|
|
20621
|
+
if (agentsBlock.content.type === "ObjectContent" || agentsBlock.content.type === "MixedContent") {
|
|
20622
|
+
for (const [name, value] of Object.entries(agentsBlock.content.properties)) {
|
|
20623
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
20624
|
+
const fields = Object.fromEntries(
|
|
20625
|
+
Object.entries(value).filter(([key]) => !key.startsWith("__"))
|
|
20626
|
+
);
|
|
20627
|
+
entries.push({ name, fields });
|
|
20628
|
+
}
|
|
20629
|
+
}
|
|
20630
|
+
}
|
|
20631
|
+
return { location: agentsBlock.loc, entries };
|
|
20632
|
+
}
|
|
20633
|
+
function describeFieldSupport(field) {
|
|
20634
|
+
const support = listAgentFieldSupportTargets(field);
|
|
20635
|
+
const parts = [];
|
|
20636
|
+
if (support.emitted.length > 0) {
|
|
20637
|
+
parts.push(`emitted by ${support.emitted.join(", ")}`);
|
|
20638
|
+
}
|
|
20639
|
+
if (support.transformed.length > 0) {
|
|
20640
|
+
parts.push(`transformed by ${support.transformed.join(", ")}`);
|
|
20641
|
+
}
|
|
20642
|
+
return parts.length > 0 ? `Field support: ${parts.join("; ")}.` : "";
|
|
20643
|
+
}
|
|
20644
|
+
function describeBlockOmission(agentsResource, target, version, location, options) {
|
|
20645
|
+
if (!agentsResource) {
|
|
20646
|
+
if (options?.blockWarningHandled) return [];
|
|
20647
|
+
return [
|
|
20648
|
+
{
|
|
20649
|
+
code: AGENT_COMPATIBILITY_CODE,
|
|
20650
|
+
ruleName: "agent-compatibility",
|
|
20651
|
+
message: `Target "${target}" has no native agent output and will omit @agents.`,
|
|
20652
|
+
suggestion: "Compile a target with agent support or move agent guidance into instruction blocks.",
|
|
20653
|
+
location
|
|
20654
|
+
}
|
|
20655
|
+
];
|
|
20656
|
+
}
|
|
20657
|
+
return [
|
|
20658
|
+
{
|
|
20659
|
+
code: AGENT_COMPATIBILITY_CODE,
|
|
20660
|
+
ruleName: "agent-compatibility",
|
|
20661
|
+
message: `Target "${target}" version "${version}" cannot emit @agents and will omit it.`,
|
|
20662
|
+
suggestion: `Use a version that emits agents: ${agentsResource.versions.join(", ")}.`,
|
|
20663
|
+
location
|
|
20664
|
+
}
|
|
20665
|
+
];
|
|
20666
|
+
}
|
|
20667
|
+
function describeFieldLoss(agentName, field, target, location) {
|
|
20668
|
+
if (field === "description" || field === "content") return void 0;
|
|
20669
|
+
const isCanonical = CANONICAL_AGENT_FIELDS.includes(field);
|
|
20670
|
+
const status = isCanonical ? getAgentFieldStatus(target, field) : "not-supported";
|
|
20671
|
+
if (status !== "not-supported") return void 0;
|
|
20672
|
+
return {
|
|
20673
|
+
code: AGENT_COMPATIBILITY_CODE,
|
|
20674
|
+
ruleName: "agent-compatibility",
|
|
20675
|
+
message: `Agent "${agentName}": field "${field}" is not supported by target "${target}" and will be omitted.`,
|
|
20676
|
+
suggestion: isCanonical ? describeFieldSupport(field) : "Not a canonical @agents field; remove it or model it through a supported block.",
|
|
20677
|
+
location
|
|
20678
|
+
};
|
|
20679
|
+
}
|
|
20680
|
+
function collectEntryFieldWarnings(entry, target, location) {
|
|
20681
|
+
const warnings = [];
|
|
20682
|
+
for (const field of Object.keys(entry.fields)) {
|
|
20683
|
+
const warning = describeFieldLoss(entry.name, field, target, location);
|
|
20684
|
+
if (warning) warnings.push(warning);
|
|
20685
|
+
}
|
|
20686
|
+
return warnings;
|
|
20687
|
+
}
|
|
20688
|
+
function getAgentCapabilityWarnings(ast, target, version, options) {
|
|
20689
|
+
const agentsBlock = collectAgentEntries(ast);
|
|
20690
|
+
if (!agentsBlock || !isKnownTarget(target)) return [];
|
|
20691
|
+
const agentsResource = TARGET_CAPABILITIES[target].resources.find(
|
|
20692
|
+
(resource) => resource.kind === "agents"
|
|
20693
|
+
);
|
|
20694
|
+
if (!agentsResource?.versions.includes(version)) {
|
|
20695
|
+
return describeBlockOmission(agentsResource, target, version, agentsBlock.location, options);
|
|
20696
|
+
}
|
|
20697
|
+
return agentsBlock.entries.flatMap(
|
|
20698
|
+
(entry) => collectEntryFieldWarnings(entry, target, agentsBlock.location)
|
|
20699
|
+
);
|
|
20700
|
+
}
|
|
20701
|
+
function appendAgentCapabilityWarnings(output, ast, target, version, options) {
|
|
20702
|
+
const warnings = getAgentCapabilityWarnings(ast, target, version, options);
|
|
20703
|
+
if (warnings.length === 0) return output;
|
|
20704
|
+
return {
|
|
20705
|
+
...output,
|
|
20706
|
+
warnings: [...output.warnings ?? [], ...warnings]
|
|
20707
|
+
};
|
|
20708
|
+
}
|
|
20709
|
+
var AGENT_COMPATIBILITY_CODE;
|
|
20710
|
+
var init_agent_capability_warnings = __esm({
|
|
20711
|
+
"packages/formatters/src/agent-capability-warnings.ts"() {
|
|
20712
|
+
"use strict";
|
|
20713
|
+
init_src();
|
|
20714
|
+
AGENT_COMPATIBILITY_CODE = "PS4003";
|
|
20715
|
+
}
|
|
20716
|
+
});
|
|
20717
|
+
|
|
20184
20718
|
// packages/formatters/src/mcp-helpers.ts
|
|
20185
20719
|
function findMcpServersBlock(ast) {
|
|
20186
20720
|
return ast.blocks.find((b) => b.name === "mcpServers");
|
|
@@ -20410,6 +20944,7 @@ var init_markdown_instruction_formatter = __esm({
|
|
|
20410
20944
|
init_base_formatter();
|
|
20411
20945
|
init_hook_adapters();
|
|
20412
20946
|
init_hook_capability_warnings();
|
|
20947
|
+
init_agent_capability_warnings();
|
|
20413
20948
|
init_mcp_helpers();
|
|
20414
20949
|
init_section_title_resolver();
|
|
20415
20950
|
MarkdownInstructionFormatter = class extends BaseFormatter {
|
|
@@ -20428,7 +20963,7 @@ var init_markdown_instruction_formatter = __esm({
|
|
|
20428
20963
|
}
|
|
20429
20964
|
getSkillBasePath() {
|
|
20430
20965
|
if (!this.config.hasSkills) return null;
|
|
20431
|
-
return `${this.config.dotDir}/skills`;
|
|
20966
|
+
return this.config.skillsDir ?? `${this.config.dotDir}/skills`;
|
|
20432
20967
|
}
|
|
20433
20968
|
getSkillFileName() {
|
|
20434
20969
|
if (!this.config.hasSkills) return null;
|
|
@@ -20454,7 +20989,10 @@ var init_markdown_instruction_formatter = __esm({
|
|
|
20454
20989
|
hookWarnings.length > 0 || !hasEnabledHooks ? /* @__PURE__ */ new Set(["hooks"]) : void 0
|
|
20455
20990
|
);
|
|
20456
20991
|
const warnedOutput = unsupportedWarnings.length > 0 ? { ...output, warnings: [...output.warnings ?? [], ...unsupportedWarnings] } : output;
|
|
20457
|
-
|
|
20992
|
+
const agentOutput = appendAgentCapabilityWarnings(warnedOutput, ast, this.name, version, {
|
|
20993
|
+
blockWarningHandled: (this.config.unsupportedBlocks ?? []).includes("agents")
|
|
20994
|
+
});
|
|
20995
|
+
return appendTargetHookCapabilityWarnings(agentOutput, ast, this.name, version);
|
|
20458
20996
|
}
|
|
20459
20997
|
hasEnabledHooks(ast) {
|
|
20460
20998
|
const hooksBlock = ast.blocks.find((block) => block.name === "hooks");
|
|
@@ -21114,24 +21652,28 @@ ${list}` : list;
|
|
|
21114
21652
|
});
|
|
21115
21653
|
|
|
21116
21654
|
// packages/formatters/src/create-simple-formatter.ts
|
|
21117
|
-
function buildVersions(
|
|
21655
|
+
function buildVersions(inputs) {
|
|
21656
|
+
const { outputPath, dotDir, hasSkills, hasAgents, hasCommands } = inputs;
|
|
21657
|
+
const { skillFileName, skillsInMultifile, mcpConfigPath, skillsDir } = inputs;
|
|
21118
21658
|
const isNested = outputPath.startsWith(dotDir + "/");
|
|
21119
21659
|
const simpleDesc = `Single ${outputPath} file`;
|
|
21120
|
-
const
|
|
21660
|
+
const defaultSkillsDir = `${dotDir}/skills`;
|
|
21661
|
+
const resolvedSkillsDir = skillsDir ?? defaultSkillsDir;
|
|
21662
|
+
const skillPath = `${resolvedSkillsDir}/<name>/${skillFileName}`;
|
|
21121
21663
|
const commandPath = `${dotDir}/commands/<name>.md`;
|
|
21122
21664
|
const agentPath = `${dotDir}/agents/<name>.md`;
|
|
21123
|
-
const
|
|
21124
|
-
|
|
21665
|
+
const skillsFullModeOnly = hasSkills && !skillsInMultifile;
|
|
21666
|
+
const describeAdditionalFiles = (version, paths, fullModeSkillsOnly) => {
|
|
21667
|
+
if (paths.length === 0 && fullModeSkillsOnly) {
|
|
21125
21668
|
return `Single ${outputPath} file (skills via full mode)`;
|
|
21126
21669
|
}
|
|
21127
21670
|
if (paths.length === 0) return `Single ${outputPath} file`;
|
|
21128
21671
|
const prefix = !isNested && version === "full" && hasSkills ? "Multifile" : outputPath;
|
|
21129
|
-
const suffix =
|
|
21672
|
+
const suffix = fullModeSkillsOnly ? " (skills via full mode)" : "";
|
|
21130
21673
|
return `${prefix} + ${paths.join(" + ")}${suffix}`;
|
|
21131
21674
|
};
|
|
21132
21675
|
const multifilePaths = [];
|
|
21133
|
-
|
|
21134
|
-
if (hasSkills && !skillsInFullMode) multifilePaths.push(skillPath);
|
|
21676
|
+
if (hasSkills && skillsInMultifile) multifilePaths.push(skillPath);
|
|
21135
21677
|
if (hasCommands) multifilePaths.push(commandPath);
|
|
21136
21678
|
if (mcpConfigPath) multifilePaths.push(mcpConfigPath);
|
|
21137
21679
|
const fullPaths = [];
|
|
@@ -21139,7 +21681,7 @@ function buildVersions(outputPath, dotDir, hasSkills, hasAgents, hasCommands, sk
|
|
|
21139
21681
|
if (hasCommands) fullPaths.push(commandPath);
|
|
21140
21682
|
if (hasAgents) fullPaths.push(agentPath);
|
|
21141
21683
|
if (mcpConfigPath) fullPaths.push(mcpConfigPath);
|
|
21142
|
-
const multifileDesc = describeAdditionalFiles("multifile", multifilePaths,
|
|
21684
|
+
const multifileDesc = describeAdditionalFiles("multifile", multifilePaths, skillsFullModeOnly);
|
|
21143
21685
|
const fullDesc = describeAdditionalFiles("full", fullPaths, false);
|
|
21144
21686
|
return {
|
|
21145
21687
|
simple: { name: "simple", description: simpleDesc, outputPath },
|
|
@@ -21157,20 +21699,24 @@ function createSimpleMarkdownFormatter(opts) {
|
|
|
21157
21699
|
hasAgents = false,
|
|
21158
21700
|
hasCommands = false,
|
|
21159
21701
|
hasSkills = true,
|
|
21702
|
+
skillsInMultifile = false,
|
|
21160
21703
|
skillFileName = "SKILL.md",
|
|
21161
21704
|
mcpConfigPath,
|
|
21162
21705
|
mcpConfigFormat,
|
|
21163
|
-
unsupportedBlocks
|
|
21706
|
+
unsupportedBlocks,
|
|
21707
|
+
skillsDir
|
|
21164
21708
|
} = opts;
|
|
21165
|
-
const versions = buildVersions(
|
|
21709
|
+
const versions = buildVersions({
|
|
21166
21710
|
outputPath,
|
|
21167
21711
|
dotDir,
|
|
21168
21712
|
hasSkills,
|
|
21169
21713
|
hasAgents,
|
|
21170
21714
|
hasCommands,
|
|
21715
|
+
skillsInMultifile,
|
|
21171
21716
|
skillFileName,
|
|
21172
|
-
mcpConfigPath
|
|
21173
|
-
|
|
21717
|
+
...mcpConfigPath ? { mcpConfigPath } : {},
|
|
21718
|
+
...skillsDir ? { skillsDir } : {}
|
|
21719
|
+
});
|
|
21174
21720
|
class SimpleFormatter extends MarkdownInstructionFormatter {
|
|
21175
21721
|
constructor() {
|
|
21176
21722
|
super({
|
|
@@ -21184,6 +21730,8 @@ function createSimpleMarkdownFormatter(opts) {
|
|
|
21184
21730
|
hasAgents,
|
|
21185
21731
|
hasCommands,
|
|
21186
21732
|
hasSkills,
|
|
21733
|
+
skillsInMultifile,
|
|
21734
|
+
...skillsDir ? { skillsDir } : {},
|
|
21187
21735
|
...mcpConfigPath ? { mcpConfigPath } : {},
|
|
21188
21736
|
...mcpConfigFormat ? { mcpConfigFormat } : {},
|
|
21189
21737
|
...unsupportedBlocks ? { unsupportedBlocks } : {}
|
|
@@ -21703,6 +22251,7 @@ var init_github2 = __esm({
|
|
|
21703
22251
|
init_mcp_helpers();
|
|
21704
22252
|
init_hook_adapters();
|
|
21705
22253
|
init_hook_capability_warnings();
|
|
22254
|
+
init_agent_capability_warnings();
|
|
21706
22255
|
init_section_title_resolver();
|
|
21707
22256
|
GITHUB_VERSIONS = {
|
|
21708
22257
|
simple: {
|
|
@@ -21797,6 +22346,7 @@ var init_github2 = __esm({
|
|
|
21797
22346
|
output = this.formatSimple(ast, options);
|
|
21798
22347
|
}
|
|
21799
22348
|
output = appendTargetHookCapabilityWarnings(output, ast, this.name, version);
|
|
22349
|
+
output = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
21800
22350
|
const hooksBlock = ast.blocks.find((block) => block.name === "hooks");
|
|
21801
22351
|
const hooks = hooksBlock ? extractHooks(hooksBlock) : [];
|
|
21802
22352
|
const hookWarnings = hooksBlock && version !== "simple" ? [
|
|
@@ -22868,6 +23418,7 @@ var init_claude2 = __esm({
|
|
|
22868
23418
|
init_base_formatter();
|
|
22869
23419
|
init_hook_adapters();
|
|
22870
23420
|
init_hook_capability_warnings();
|
|
23421
|
+
init_agent_capability_warnings();
|
|
22871
23422
|
init_mcp_helpers();
|
|
22872
23423
|
init_section_title_resolver();
|
|
22873
23424
|
CLAUDE_VERSIONS = {
|
|
@@ -22918,6 +23469,7 @@ var init_claude2 = __esm({
|
|
|
22918
23469
|
output = this.formatSimple(ast, options);
|
|
22919
23470
|
}
|
|
22920
23471
|
output = appendTargetHookCapabilityWarnings(output, ast, this.name, version);
|
|
23472
|
+
output = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
22921
23473
|
output = {
|
|
22922
23474
|
...output,
|
|
22923
23475
|
managedOutputFiles: [
|
|
@@ -23964,6 +24516,7 @@ var init_cursor2 = __esm({
|
|
|
23964
24516
|
init_glob_categorizer();
|
|
23965
24517
|
init_hook_adapters();
|
|
23966
24518
|
init_hook_capability_warnings();
|
|
24519
|
+
init_agent_capability_warnings();
|
|
23967
24520
|
init_mcp_helpers();
|
|
23968
24521
|
init_plugin_helpers();
|
|
23969
24522
|
init_section_title_resolver();
|
|
@@ -24052,10 +24605,11 @@ var init_cursor2 = __esm({
|
|
|
24052
24605
|
const hooks = hooksBlock ? extractHooks(hooksBlock) : [];
|
|
24053
24606
|
const effectiveHooks = applyHookTargetOverrides(hooks, "cursor");
|
|
24054
24607
|
if (hooksBlock && effectiveHooks.some((hook) => hook.enabled !== false)) {
|
|
24608
|
+
const withAgentWarnings = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
24055
24609
|
return {
|
|
24056
|
-
...
|
|
24610
|
+
...withAgentWarnings,
|
|
24057
24611
|
warnings: [
|
|
24058
|
-
...
|
|
24612
|
+
...withAgentWarnings.warnings ?? [],
|
|
24059
24613
|
{
|
|
24060
24614
|
code: "PS4002",
|
|
24061
24615
|
message: `Cursor ${version} mode cannot emit @hooks and will omit them.`,
|
|
@@ -24070,6 +24624,7 @@ var init_cursor2 = __esm({
|
|
|
24070
24624
|
}
|
|
24071
24625
|
}
|
|
24072
24626
|
output = appendTargetHookCapabilityWarnings(output, ast, this.name, version);
|
|
24627
|
+
output = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
24073
24628
|
return {
|
|
24074
24629
|
...output,
|
|
24075
24630
|
managedOutputFiles: [
|
|
@@ -26721,20 +27276,115 @@ ${filteredFrontmatter}
|
|
|
26721
27276
|
});
|
|
26722
27277
|
|
|
26723
27278
|
// packages/formatters/src/formatters/opencode.ts
|
|
26724
|
-
var
|
|
27279
|
+
var OPENCODE_VERSIONS, OpenCodeFormatter;
|
|
26725
27280
|
var init_opencode = __esm({
|
|
26726
27281
|
"packages/formatters/src/formatters/opencode.ts"() {
|
|
26727
27282
|
"use strict";
|
|
26728
|
-
|
|
26729
|
-
(
|
|
26730
|
-
|
|
26731
|
-
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
|
|
27283
|
+
init_hook_adapters();
|
|
27284
|
+
init_markdown_instruction_formatter();
|
|
27285
|
+
OPENCODE_VERSIONS = {
|
|
27286
|
+
simple: {
|
|
27287
|
+
name: "simple",
|
|
27288
|
+
description: "Single OPENCODE.md file",
|
|
27289
|
+
outputPath: "OPENCODE.md"
|
|
27290
|
+
},
|
|
27291
|
+
multifile: {
|
|
27292
|
+
name: "multifile",
|
|
27293
|
+
description: "OPENCODE.md + .opencode/commands/<name>.md + .opencode/plugins/promptscript.ts (skills via full mode)",
|
|
27294
|
+
outputPath: "OPENCODE.md"
|
|
27295
|
+
},
|
|
27296
|
+
full: {
|
|
27297
|
+
name: "full",
|
|
27298
|
+
description: "Multifile + .opencode/skills/<name>/SKILL.md + .opencode/commands/<name>.md + .opencode/agents/<name>.md + .opencode/plugins/promptscript.ts",
|
|
27299
|
+
outputPath: "OPENCODE.md"
|
|
27300
|
+
}
|
|
27301
|
+
};
|
|
27302
|
+
OpenCodeFormatter = class extends MarkdownInstructionFormatter {
|
|
27303
|
+
constructor() {
|
|
27304
|
+
super({
|
|
27305
|
+
name: "opencode",
|
|
27306
|
+
outputPath: "OPENCODE.md",
|
|
27307
|
+
description: "OpenCode instructions (Markdown)",
|
|
27308
|
+
defaultConvention: "markdown",
|
|
27309
|
+
mainFileHeader: "# OPENCODE.md",
|
|
27310
|
+
dotDir: ".opencode",
|
|
27311
|
+
skillFileName: "SKILL.md",
|
|
27312
|
+
hasAgents: true,
|
|
27313
|
+
hasCommands: true,
|
|
27314
|
+
hasSkills: true
|
|
27315
|
+
});
|
|
27316
|
+
}
|
|
27317
|
+
/**
|
|
27318
|
+
* Return supported OpenCode output modes.
|
|
27319
|
+
*/
|
|
27320
|
+
static getSupportedVersions() {
|
|
27321
|
+
return OPENCODE_VERSIONS;
|
|
27322
|
+
}
|
|
27323
|
+
/**
|
|
27324
|
+
* Format single-file output while retaining stale-plugin cleanup metadata.
|
|
27325
|
+
*/
|
|
27326
|
+
formatSimple(ast, options) {
|
|
27327
|
+
const output = super.formatSimple(ast, options);
|
|
27328
|
+
return {
|
|
27329
|
+
...output,
|
|
27330
|
+
managedOutputFiles: [
|
|
27331
|
+
.../* @__PURE__ */ new Set([...output.managedOutputFiles ?? [], OPENCODE_PLUGIN_PATH])
|
|
27332
|
+
]
|
|
27333
|
+
};
|
|
27334
|
+
}
|
|
27335
|
+
/**
|
|
27336
|
+
* Format multifile output and attach the generated hook plugin.
|
|
27337
|
+
*/
|
|
27338
|
+
formatMultifile(ast, options) {
|
|
27339
|
+
return this.appendHookPlugin(ast, super.formatMultifile(ast, options));
|
|
27340
|
+
}
|
|
27341
|
+
/**
|
|
27342
|
+
* Format full output and attach the generated hook plugin.
|
|
27343
|
+
*/
|
|
27344
|
+
formatFull(ast, options) {
|
|
27345
|
+
return this.appendHookPlugin(ast, super.formatFull(ast, options));
|
|
27346
|
+
}
|
|
27347
|
+
/**
|
|
27348
|
+
* Attach the generated OpenCode plugin and its compatibility warnings.
|
|
27349
|
+
*
|
|
27350
|
+
* The plugin path is always registered as managed output so recompiles and
|
|
27351
|
+
* version downgrades remove only PromptScript-owned files; user plugins in
|
|
27352
|
+
* the same directory are never touched.
|
|
27353
|
+
*/
|
|
27354
|
+
appendHookPlugin(ast, output) {
|
|
27355
|
+
const managedFiles = [.../* @__PURE__ */ new Set([...output.managedOutputFiles ?? [], OPENCODE_PLUGIN_PATH])];
|
|
27356
|
+
const hooksBlock = ast.blocks.find((block) => block.name === "hooks");
|
|
27357
|
+
if (!hooksBlock) {
|
|
27358
|
+
return { ...output, managedOutputFiles: managedFiles };
|
|
27359
|
+
}
|
|
27360
|
+
const hooks = extractHooks(hooksBlock);
|
|
27361
|
+
const plugin = generateOpenCodePlugin(hooks);
|
|
27362
|
+
const warnings = [
|
|
27363
|
+
...getHookCompatibilityWarnings(hooks, "opencode"),
|
|
27364
|
+
...plugin !== null ? [
|
|
27365
|
+
{
|
|
27366
|
+
code: "PS4002",
|
|
27367
|
+
message: "OpenCode tool hooks do not expose model or agent context; the generated payload omits those fields.",
|
|
27368
|
+
suggestion: "Use sessionID and callID for attribution."
|
|
27369
|
+
}
|
|
27370
|
+
] : []
|
|
27371
|
+
].map((warning) => ({ ...warning, location: hooksBlock.loc }));
|
|
27372
|
+
return {
|
|
27373
|
+
...output,
|
|
27374
|
+
...plugin !== null ? {
|
|
27375
|
+
additionalFiles: [
|
|
27376
|
+
...output.additionalFiles ?? [],
|
|
27377
|
+
{ path: OPENCODE_PLUGIN_PATH, content: plugin }
|
|
27378
|
+
]
|
|
27379
|
+
} : {},
|
|
27380
|
+
...warnings.length > 0 ? { warnings: [...output.warnings ?? [], ...warnings] } : {},
|
|
27381
|
+
managedOutputFiles: managedFiles,
|
|
27382
|
+
managedOutputDirectories: [
|
|
27383
|
+
.../* @__PURE__ */ new Set([...output.managedOutputDirectories ?? [], ".opencode/plugins"])
|
|
27384
|
+
]
|
|
27385
|
+
};
|
|
27386
|
+
}
|
|
27387
|
+
};
|
|
26738
27388
|
}
|
|
26739
27389
|
});
|
|
26740
27390
|
|
|
@@ -27040,20 +27690,54 @@ ${escaped}"""`;
|
|
|
27040
27690
|
}
|
|
27041
27691
|
return '""';
|
|
27042
27692
|
}
|
|
27043
|
-
function
|
|
27693
|
+
function mcpServerTomlConfig(server) {
|
|
27694
|
+
const config = {};
|
|
27695
|
+
if (server.command) config["command"] = server.command;
|
|
27696
|
+
if (server.url) config["url"] = server.url;
|
|
27697
|
+
if (server.headers) config["headers"] = server.headers;
|
|
27698
|
+
if (server.env) config["env"] = server.env;
|
|
27699
|
+
return config;
|
|
27700
|
+
}
|
|
27701
|
+
function agentInstructionsLines(content) {
|
|
27702
|
+
if (content !== null && typeof content === "object" && content.type === "TextContent") {
|
|
27703
|
+
const textContent = content.value ?? "";
|
|
27704
|
+
return [`developer_instructions = ${serializeTomlValue(textContent)}`];
|
|
27705
|
+
}
|
|
27706
|
+
if (typeof content === "string") {
|
|
27707
|
+
return [`developer_instructions = ${serializeTomlValue(content)}`];
|
|
27708
|
+
}
|
|
27709
|
+
return [];
|
|
27710
|
+
}
|
|
27711
|
+
function mcpServerTomlTableHeader(serverName) {
|
|
27712
|
+
return /^[A-Za-z0-9_-]+$/.test(serverName) ? `[mcp_servers.${serverName}]` : `[mcp_servers."${escapeTomlString2(serverName)}"]`;
|
|
27713
|
+
}
|
|
27714
|
+
function mcpServerTableLines(serverName, config) {
|
|
27715
|
+
return [
|
|
27716
|
+
mcpServerTomlTableHeader(serverName),
|
|
27717
|
+
...Object.entries(config).map(([key, val]) => `${key} = ${serializeTomlValue(val)}`)
|
|
27718
|
+
];
|
|
27719
|
+
}
|
|
27720
|
+
function agentMcpServerLines(mcpServers, resolvedMcpServers) {
|
|
27721
|
+
if (mcpServers !== null && typeof mcpServers === "object" && !Array.isArray(mcpServers)) {
|
|
27722
|
+
const servers = mcpServers;
|
|
27723
|
+
return Object.entries(servers).filter(([, config]) => config !== null && typeof config === "object").flatMap(([name, config]) => mcpServerTableLines(name, config));
|
|
27724
|
+
}
|
|
27725
|
+
if (Array.isArray(mcpServers)) {
|
|
27726
|
+
return mcpServers.filter((serverName) => typeof serverName === "string").flatMap((serverName) => {
|
|
27727
|
+
const config = resolvedMcpServers?.get(serverName);
|
|
27728
|
+
return config ? mcpServerTableLines(serverName, config) : [];
|
|
27729
|
+
});
|
|
27730
|
+
}
|
|
27731
|
+
return [];
|
|
27732
|
+
}
|
|
27733
|
+
function serializeAgentToml(agentName, agent, resolvedMcpServers) {
|
|
27044
27734
|
const lines = [];
|
|
27045
27735
|
lines.push(`name = "${escapeTomlString2(agentName)}"`);
|
|
27046
27736
|
const description = agent["description"];
|
|
27047
27737
|
if (typeof description === "string") {
|
|
27048
27738
|
lines.push(`description = "${escapeTomlString2(description)}"`);
|
|
27049
27739
|
}
|
|
27050
|
-
|
|
27051
|
-
if (content !== null && typeof content === "object" && content.type === "TextContent") {
|
|
27052
|
-
const textContent = content.value ?? "";
|
|
27053
|
-
lines.push(`developer_instructions = ${serializeTomlValue(textContent)}`);
|
|
27054
|
-
} else if (typeof content === "string") {
|
|
27055
|
-
lines.push(`developer_instructions = ${serializeTomlValue(content)}`);
|
|
27056
|
-
}
|
|
27740
|
+
lines.push(...agentInstructionsLines(agent["content"]));
|
|
27057
27741
|
const model = agent["model"];
|
|
27058
27742
|
if (typeof model === "string") {
|
|
27059
27743
|
lines.push(`model = "${escapeTomlString2(model)}"`);
|
|
@@ -27071,30 +27755,14 @@ function serializeAgentToml(agentName, agent) {
|
|
|
27071
27755
|
const escaped = nicknameCandidates.filter((c) => typeof c === "string").map((c) => `"${escapeTomlString2(c)}"`);
|
|
27072
27756
|
lines.push(`nickname_candidates = [${escaped.join(", ")}]`);
|
|
27073
27757
|
}
|
|
27074
|
-
const
|
|
27075
|
-
if (
|
|
27076
|
-
|
|
27077
|
-
const serverEntries = Object.entries(servers);
|
|
27078
|
-
if (serverEntries.length > 0) {
|
|
27079
|
-
lines.push("");
|
|
27080
|
-
lines.push("[mcp_servers]");
|
|
27081
|
-
for (const [serverName, serverConfig] of serverEntries) {
|
|
27082
|
-
if (serverConfig !== null && typeof serverConfig === "object") {
|
|
27083
|
-
lines.push(`[mcp_servers.${serverName}]`);
|
|
27084
|
-
const config = serverConfig;
|
|
27085
|
-
for (const [key, val] of Object.entries(config)) {
|
|
27086
|
-
lines.push(`${key} = ${serializeTomlValue(val)}`);
|
|
27087
|
-
}
|
|
27088
|
-
}
|
|
27089
|
-
}
|
|
27090
|
-
}
|
|
27758
|
+
const serverTables = agentMcpServerLines(agent["mcpServers"], resolvedMcpServers);
|
|
27759
|
+
if (serverTables.length > 0) {
|
|
27760
|
+
lines.push("", "[mcp_servers]", ...serverTables);
|
|
27091
27761
|
}
|
|
27092
27762
|
const skills2 = agent["skills"];
|
|
27093
27763
|
if (Array.isArray(skills2)) {
|
|
27094
27764
|
const skillNames = skills2.filter((s) => typeof s === "string").map((s) => `"${escapeTomlString2(s)}"`);
|
|
27095
|
-
lines.push("");
|
|
27096
|
-
lines.push("[skills]");
|
|
27097
|
-
lines.push(`config = [${skillNames.join(", ")}]`);
|
|
27765
|
+
lines.push("", "[skills]", `config = [${skillNames.join(", ")}]`);
|
|
27098
27766
|
}
|
|
27099
27767
|
return lines.join("\n") + "\n";
|
|
27100
27768
|
}
|
|
@@ -27111,6 +27779,7 @@ var init_codex = __esm({
|
|
|
27111
27779
|
init_markdown_instruction_formatter();
|
|
27112
27780
|
init_hook_adapters();
|
|
27113
27781
|
init_hook_capability_warnings();
|
|
27782
|
+
init_agent_capability_warnings();
|
|
27114
27783
|
init_mcp_helpers();
|
|
27115
27784
|
init_plugin_helpers();
|
|
27116
27785
|
CODEX_VERSIONS = {
|
|
@@ -27209,12 +27878,13 @@ var init_codex = __esm({
|
|
|
27209
27878
|
format(ast, options) {
|
|
27210
27879
|
const version = this.resolveVersion(options?.version);
|
|
27211
27880
|
if (version === "simple") {
|
|
27212
|
-
|
|
27881
|
+
let output = appendTargetHookCapabilityWarnings(
|
|
27213
27882
|
this.formatSimple(ast, options),
|
|
27214
27883
|
ast,
|
|
27215
27884
|
this.name,
|
|
27216
27885
|
version
|
|
27217
27886
|
);
|
|
27887
|
+
output = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
27218
27888
|
return {
|
|
27219
27889
|
...output,
|
|
27220
27890
|
managedOutputFiles: [
|
|
@@ -27267,16 +27937,17 @@ var init_codex = __esm({
|
|
|
27267
27937
|
if (!managedDirs.includes(".codex")) managedDirs.push(".codex");
|
|
27268
27938
|
}
|
|
27269
27939
|
const mcpServersBlock = findMcpServersBlock(ast);
|
|
27270
|
-
|
|
27271
|
-
|
|
27272
|
-
|
|
27273
|
-
|
|
27274
|
-
|
|
27275
|
-
|
|
27276
|
-
|
|
27277
|
-
managedDirs.push(".codex");
|
|
27278
|
-
}
|
|
27940
|
+
const definedMcpServers = mcpServersBlock ? extractMcpServers(mcpServersBlock) : [];
|
|
27941
|
+
if (definedMcpServers.length > 0) {
|
|
27942
|
+
extraFiles.push({
|
|
27943
|
+
path: ".codex/mcp.json",
|
|
27944
|
+
content: serializeMcpServersToJsonString(definedMcpServers)
|
|
27945
|
+
});
|
|
27946
|
+
managedDirs.push(".codex");
|
|
27279
27947
|
}
|
|
27948
|
+
const resolvedMcpServers = new Map(
|
|
27949
|
+
definedMcpServers.map((server) => [server.name, mcpServerTomlConfig(server)])
|
|
27950
|
+
);
|
|
27280
27951
|
const pluginsBlock = findPluginsBlock(ast);
|
|
27281
27952
|
if (pluginsBlock) {
|
|
27282
27953
|
const plugins = extractPlugins(pluginsBlock);
|
|
@@ -27297,7 +27968,7 @@ var init_codex = __esm({
|
|
|
27297
27968
|
if (!isValidAgentName(agentName)) continue;
|
|
27298
27969
|
const agent = agentValue;
|
|
27299
27970
|
const nativeAgentName = nativeNames.get(agentName) ?? agentName;
|
|
27300
|
-
const toml = serializeAgentToml(nativeAgentName, agent);
|
|
27971
|
+
const toml = serializeAgentToml(nativeAgentName, agent, resolvedMcpServers);
|
|
27301
27972
|
extraFiles.push({
|
|
27302
27973
|
path: `.codex/agents/${nativeAgentName}.toml`,
|
|
27303
27974
|
content: toml
|
|
@@ -28051,6 +28722,7 @@ var init_grok = __esm({
|
|
|
28051
28722
|
init_plugin_helpers();
|
|
28052
28723
|
init_hook_adapters();
|
|
28053
28724
|
init_hook_capability_warnings();
|
|
28725
|
+
init_agent_capability_warnings();
|
|
28054
28726
|
GROK_VERSIONS = {
|
|
28055
28727
|
simple: {
|
|
28056
28728
|
name: "simple",
|
|
@@ -28097,6 +28769,7 @@ var init_grok = __esm({
|
|
|
28097
28769
|
output = this.formatFull(ast, options);
|
|
28098
28770
|
}
|
|
28099
28771
|
output = appendTargetHookCapabilityWarnings(output, ast, this.name, version);
|
|
28772
|
+
output = appendAgentCapabilityWarnings(output, ast, this.name, version);
|
|
28100
28773
|
return {
|
|
28101
28774
|
...output,
|
|
28102
28775
|
managedOutputFiles: [
|
|
@@ -28264,6 +28937,25 @@ var init_hermes = __esm({
|
|
|
28264
28937
|
}
|
|
28265
28938
|
});
|
|
28266
28939
|
|
|
28940
|
+
// packages/formatters/src/formatters/gitlab-duo.ts
|
|
28941
|
+
var GitlabDuoFormatter, GITLAB_DUO_VERSIONS;
|
|
28942
|
+
var init_gitlab_duo = __esm({
|
|
28943
|
+
"packages/formatters/src/formatters/gitlab-duo.ts"() {
|
|
28944
|
+
"use strict";
|
|
28945
|
+
init_create_simple_formatter();
|
|
28946
|
+
({ Formatter: GitlabDuoFormatter, VERSIONS: GITLAB_DUO_VERSIONS } = createSimpleMarkdownFormatter({
|
|
28947
|
+
name: "gitlab-duo",
|
|
28948
|
+
outputPath: "AGENTS.md",
|
|
28949
|
+
description: "GitLab Duo instructions (Markdown)",
|
|
28950
|
+
mainFileHeader: "# AGENTS.md",
|
|
28951
|
+
dotDir: ".gitlab-duo",
|
|
28952
|
+
hasSkills: true,
|
|
28953
|
+
skillsInMultifile: false,
|
|
28954
|
+
skillsDir: "skills"
|
|
28955
|
+
}));
|
|
28956
|
+
}
|
|
28957
|
+
});
|
|
28958
|
+
|
|
28267
28959
|
// packages/formatters/src/formatters/index.ts
|
|
28268
28960
|
var init_formatters = __esm({
|
|
28269
28961
|
"packages/formatters/src/formatters/index.ts"() {
|
|
@@ -28317,6 +29009,7 @@ var init_formatters = __esm({
|
|
|
28317
29009
|
init_deep_agents();
|
|
28318
29010
|
init_forgecode();
|
|
28319
29011
|
init_hermes();
|
|
29012
|
+
init_gitlab_duo();
|
|
28320
29013
|
}
|
|
28321
29014
|
});
|
|
28322
29015
|
|
|
@@ -28374,6 +29067,7 @@ var init_builtin_formatters = __esm({
|
|
|
28374
29067
|
init_deep_agents();
|
|
28375
29068
|
init_forgecode();
|
|
28376
29069
|
init_hermes();
|
|
29070
|
+
init_gitlab_duo();
|
|
28377
29071
|
BUILTIN_FORMATTERS = {
|
|
28378
29072
|
// Original 7
|
|
28379
29073
|
github: GitHubFormatter,
|
|
@@ -28429,7 +29123,9 @@ var init_builtin_formatters = __esm({
|
|
|
28429
29123
|
mimo: MimoFormatter,
|
|
28430
29124
|
"deep-agents": DeepAgentsFormatter,
|
|
28431
29125
|
forgecode: ForgecodeFormatter,
|
|
28432
|
-
hermes: HermesFormatter
|
|
29126
|
+
hermes: HermesFormatter,
|
|
29127
|
+
// GitLab Duo (Agent Platform)
|
|
29128
|
+
"gitlab-duo": GitlabDuoFormatter
|
|
28433
29129
|
};
|
|
28434
29130
|
}
|
|
28435
29131
|
});
|
|
@@ -30738,6 +31434,7 @@ function userConfigToProjectRegistry(userRegistry) {
|
|
|
30738
31434
|
...userRegistry.git.fallbackUrl ? { fallbackUrl: userRegistry.git.fallbackUrl } : {},
|
|
30739
31435
|
...userRegistry.git.ref ? { ref: userRegistry.git.ref } : {},
|
|
30740
31436
|
...userRegistry.git.path ? { path: userRegistry.git.path } : {},
|
|
31437
|
+
...userRegistry.git.timeout !== void 0 ? { timeout: userRegistry.git.timeout } : {},
|
|
30741
31438
|
...userRegistry.git.auth ? { auth: userRegistry.git.auth } : {}
|
|
30742
31439
|
};
|
|
30743
31440
|
}
|
|
@@ -31252,6 +31949,7 @@ async function runInitCommand(options, services) {
|
|
|
31252
31949
|
});
|
|
31253
31950
|
}
|
|
31254
31951
|
let migrationPrompt;
|
|
31952
|
+
let migrationPromptCopied = false;
|
|
31255
31953
|
if (migrationMode === "llm") {
|
|
31256
31954
|
migrationPrompt = prepareLlmMigration(aiToolsDetection.migrationCandidates, options);
|
|
31257
31955
|
writes.push({ path: ".promptscript/migration-prompt.md", content: migrationPrompt });
|
|
@@ -31286,7 +31984,7 @@ async function runInitCommand(options, services) {
|
|
|
31286
31984
|
return;
|
|
31287
31985
|
}
|
|
31288
31986
|
if (migrationPrompt) {
|
|
31289
|
-
deliverMigrationPrompt(migrationPrompt);
|
|
31987
|
+
migrationPromptCopied = deliverMigrationPrompt(migrationPrompt);
|
|
31290
31988
|
}
|
|
31291
31989
|
const installedHookTargets = [];
|
|
31292
31990
|
if (options.hooks !== false) {
|
|
@@ -31353,13 +32051,17 @@ async function runInitCommand(options, services) {
|
|
|
31353
32051
|
ConsoleOutput.newline();
|
|
31354
32052
|
ConsoleOutput.stats("Next steps:");
|
|
31355
32053
|
if (migrationMode === "llm") {
|
|
31356
|
-
ConsoleOutput.
|
|
31357
|
-
|
|
31358
|
-
|
|
31359
|
-
|
|
32054
|
+
ConsoleOutput.info("1. Start your AI agent in this project");
|
|
32055
|
+
if (migrationPromptCopied) {
|
|
32056
|
+
ConsoleOutput.info("2. Paste the migration prompt - it is already in your clipboard");
|
|
32057
|
+
} else {
|
|
32058
|
+
ConsoleOutput.info(
|
|
32059
|
+
"2. Copy the migration prompt from the terminal output and paste it into your agent"
|
|
32060
|
+
);
|
|
31360
32061
|
}
|
|
31361
|
-
ConsoleOutput.
|
|
31362
|
-
ConsoleOutput.
|
|
32062
|
+
ConsoleOutput.info("3. Let the agent migrate your instructions");
|
|
32063
|
+
ConsoleOutput.info("4. Review the generated files, then run: prs validate --strict");
|
|
32064
|
+
ConsoleOutput.info("5. Run: prs compile");
|
|
31363
32065
|
} else if (migrationMode === "static") {
|
|
31364
32066
|
ConsoleOutput.muted("1. Review imported .promptscript/ files");
|
|
31365
32067
|
ConsoleOutput.muted("2. Run: prs validate --strict");
|
|
@@ -31499,6 +32201,7 @@ function deliverMigrationPrompt(prompt) {
|
|
|
31499
32201
|
console.log(prompt);
|
|
31500
32202
|
}
|
|
31501
32203
|
ConsoleOutput.info("Saved to .promptscript/migration-prompt.md");
|
|
32204
|
+
return copied;
|
|
31502
32205
|
}
|
|
31503
32206
|
function getSkillWrites(targets) {
|
|
31504
32207
|
const writes = [];
|
|
@@ -31841,16 +32544,6 @@ function getTargetSkillDir(target, skillName) {
|
|
|
31841
32544
|
const dir = `${basePath}/${skillName}`;
|
|
31842
32545
|
return { dir, path: `${dir}/${fileName}` };
|
|
31843
32546
|
}
|
|
31844
|
-
function getSkillInvocationHints(targets) {
|
|
31845
|
-
const hints = [];
|
|
31846
|
-
for (const target of targets) {
|
|
31847
|
-
const formatter = FormatterRegistry.get(target);
|
|
31848
|
-
if (formatter && formatter.getSkillBasePath()) {
|
|
31849
|
-
hints.push(`${formatter.description}: /promptscript`);
|
|
31850
|
-
}
|
|
31851
|
-
}
|
|
31852
|
-
return hints;
|
|
31853
|
-
}
|
|
31854
32547
|
function generateConfig(config) {
|
|
31855
32548
|
const syntaxVersion = getLatestSyntaxVersion();
|
|
31856
32549
|
const output = {
|
|
@@ -35272,9 +35965,9 @@ var require_rate_limit = __commonJS({
|
|
|
35272
35965
|
throw new Error("The configured rate-limit store does not implement a `read` method, which is required to use `{ increment: false }`");
|
|
35273
35966
|
}
|
|
35274
35967
|
try {
|
|
35275
|
-
const res = await new Promise((
|
|
35968
|
+
const res = await new Promise((resolve43, reject) => {
|
|
35276
35969
|
store[storeMethod](key, (err, res2) => {
|
|
35277
|
-
err ? reject(err) :
|
|
35970
|
+
err ? reject(err) : resolve43(res2);
|
|
35278
35971
|
}, timeWindow, max);
|
|
35279
35972
|
});
|
|
35280
35973
|
current = res.current;
|
|
@@ -35444,16 +36137,16 @@ var init_config2 = __esm({
|
|
|
35444
36137
|
});
|
|
35445
36138
|
|
|
35446
36139
|
// packages/server/src/path-guard.ts
|
|
35447
|
-
import { resolve as
|
|
36140
|
+
import { resolve as resolve41, relative as relative21, isAbsolute as isAbsolute19, dirname as dirname25, basename as basename19 } from "path";
|
|
35448
36141
|
import { realpath as realpath6 } from "fs/promises";
|
|
35449
36142
|
async function resolveSafePath(workspace, requestedPath) {
|
|
35450
36143
|
const decoded = decodeURIComponent(requestedPath);
|
|
35451
|
-
if (
|
|
36144
|
+
if (isAbsolute19(decoded)) {
|
|
35452
36145
|
throw new PathTraversalError(requestedPath);
|
|
35453
36146
|
}
|
|
35454
|
-
const resolved =
|
|
35455
|
-
const rel =
|
|
35456
|
-
if (rel.startsWith("..") ||
|
|
36147
|
+
const resolved = resolve41(workspace, decoded);
|
|
36148
|
+
const rel = relative21(workspace, resolved);
|
|
36149
|
+
if (rel.startsWith("..") || isAbsolute19(rel)) {
|
|
35457
36150
|
throw new PathTraversalError(requestedPath);
|
|
35458
36151
|
}
|
|
35459
36152
|
let realWorkspace;
|
|
@@ -35469,7 +36162,7 @@ async function resolveSafePath(workspace, requestedPath) {
|
|
|
35469
36162
|
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
35470
36163
|
try {
|
|
35471
36164
|
const realParent = await realpath6(dirname25(resolved));
|
|
35472
|
-
real =
|
|
36165
|
+
real = resolve41(realParent, basename19(resolved));
|
|
35473
36166
|
} catch {
|
|
35474
36167
|
return resolved;
|
|
35475
36168
|
}
|
|
@@ -35477,8 +36170,8 @@ async function resolveSafePath(workspace, requestedPath) {
|
|
|
35477
36170
|
throw err;
|
|
35478
36171
|
}
|
|
35479
36172
|
}
|
|
35480
|
-
const realRel =
|
|
35481
|
-
if (realRel.startsWith("..") ||
|
|
36173
|
+
const realRel = relative21(realWorkspace, real);
|
|
36174
|
+
if (realRel.startsWith("..") || isAbsolute19(realRel)) {
|
|
35482
36175
|
throw new PathTraversalError(requestedPath);
|
|
35483
36176
|
}
|
|
35484
36177
|
return resolved;
|
|
@@ -35497,7 +36190,7 @@ var init_path_guard = __esm({
|
|
|
35497
36190
|
});
|
|
35498
36191
|
|
|
35499
36192
|
// packages/server/src/routes/files.ts
|
|
35500
|
-
import { readFile as readFile32, writeFile as writeFile12, unlink as unlink3, stat as stat4, mkdir as
|
|
36193
|
+
import { readFile as readFile32, writeFile as writeFile12, unlink as unlink3, stat as stat4, mkdir as mkdir12 } from "fs/promises";
|
|
35501
36194
|
import { dirname as dirname26 } from "path";
|
|
35502
36195
|
import fg from "fast-glob";
|
|
35503
36196
|
function registerRoutes(app, workspace, readOnly) {
|
|
@@ -35558,7 +36251,7 @@ function registerRoutes(app, workspace, readOnly) {
|
|
|
35558
36251
|
return reply.status(409).send({ error: "File already exists" });
|
|
35559
36252
|
} catch {
|
|
35560
36253
|
}
|
|
35561
|
-
await
|
|
36254
|
+
await mkdir12(dirname26(resolved), { recursive: true });
|
|
35562
36255
|
await writeFile12(resolved, request.body.content, "utf-8");
|
|
35563
36256
|
return reply.status(201).send({ path: filePath, status: "created" });
|
|
35564
36257
|
} catch (err) {
|
|
@@ -35596,7 +36289,7 @@ var init_files = __esm({
|
|
|
35596
36289
|
|
|
35597
36290
|
// packages/server/src/watcher.ts
|
|
35598
36291
|
import { watch } from "chokidar";
|
|
35599
|
-
import { relative as
|
|
36292
|
+
import { relative as relative22 } from "path";
|
|
35600
36293
|
function isWatchedFile(filePath) {
|
|
35601
36294
|
const base = filePath.split("/").pop() ?? "";
|
|
35602
36295
|
if (CONFIG_FILENAMES2.has(base)) return true;
|
|
@@ -35612,15 +36305,15 @@ function createFileWatcher(workspace, watchPaths, onEvent) {
|
|
|
35612
36305
|
});
|
|
35613
36306
|
watcher.on("add", (filePath) => {
|
|
35614
36307
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
35615
|
-
onEvent({ type: "file:created", path:
|
|
36308
|
+
onEvent({ type: "file:created", path: relative22(workspace, filePath) });
|
|
35616
36309
|
});
|
|
35617
36310
|
watcher.on("change", (filePath) => {
|
|
35618
36311
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
35619
|
-
onEvent({ type: "file:changed", path:
|
|
36312
|
+
onEvent({ type: "file:changed", path: relative22(workspace, filePath) });
|
|
35620
36313
|
});
|
|
35621
36314
|
watcher.on("unlink", (filePath) => {
|
|
35622
36315
|
if (!ready || !isWatchedFile(filePath)) return;
|
|
35623
|
-
onEvent({ type: "file:deleted", path:
|
|
36316
|
+
onEvent({ type: "file:deleted", path: relative22(workspace, filePath) });
|
|
35624
36317
|
});
|
|
35625
36318
|
return watcher;
|
|
35626
36319
|
}
|
|
@@ -35787,7 +36480,7 @@ var migrate_exports = {};
|
|
|
35787
36480
|
__export(migrate_exports, {
|
|
35788
36481
|
migrateCommand: () => migrateCommand
|
|
35789
36482
|
});
|
|
35790
|
-
import { dirname as dirname27, relative as
|
|
36483
|
+
import { dirname as dirname27, relative as relative23, resolve as resolve42 } from "path";
|
|
35791
36484
|
import { parse as parseYaml17 } from "yaml";
|
|
35792
36485
|
async function migrateCommand(options, services = createDefaultServices()) {
|
|
35793
36486
|
const previousOutputStream = getContext().outputStream;
|
|
@@ -36045,7 +36738,7 @@ function extractTargetNames(targets) {
|
|
|
36045
36738
|
}
|
|
36046
36739
|
async function createStaticMigrationWrites(candidates, config, entryPaths, services) {
|
|
36047
36740
|
const result = await importMultipleFiles(
|
|
36048
|
-
candidates.map((candidate) =>
|
|
36741
|
+
candidates.map((candidate) => resolve42(services.cwd, candidate.path)),
|
|
36049
36742
|
{
|
|
36050
36743
|
projectName: config.id,
|
|
36051
36744
|
syntaxVersion: config.syntax || getLatestSyntaxVersion()
|
|
@@ -36079,7 +36772,7 @@ async function createStaticMigrationWrites(candidates, config, entryPaths, servi
|
|
|
36079
36772
|
const migratedProjectPath = ".promptscript/migrated/project.prs";
|
|
36080
36773
|
writes.push({ path: migratedProjectPath, content: markMigrationOutput(importedProject) });
|
|
36081
36774
|
for (const entryPath of entryPaths) {
|
|
36082
|
-
const useLine = `@use ${
|
|
36775
|
+
const useLine = `@use ${toUsePath2(entryPath, migratedProjectPath)}`;
|
|
36083
36776
|
if (services.fs.existsSync(entryPath)) {
|
|
36084
36777
|
const existing = await services.fs.readFile(entryPath, "utf-8");
|
|
36085
36778
|
const hasUseLine = existing.split(/\r?\n/).some((line) => line.trim() === useLine);
|
|
@@ -36137,9 +36830,9 @@ function markMigrationOutput(content) {
|
|
|
36137
36830
|
return `# promptscript-generated: migration
|
|
36138
36831
|
${content}`;
|
|
36139
36832
|
}
|
|
36140
|
-
function
|
|
36833
|
+
function toUsePath2(entryPath, targetPath) {
|
|
36141
36834
|
const withoutExtension = targetPath.replace(/\.prs$/, "");
|
|
36142
|
-
const path2 =
|
|
36835
|
+
const path2 = relative23(dirname27(entryPath), withoutExtension).replace(/\\/g, "/");
|
|
36143
36836
|
return path2.startsWith("./") || path2.startsWith("../") ? path2 : `./${path2}`;
|
|
36144
36837
|
}
|
|
36145
36838
|
function validateProjectPath(path2) {
|
|
@@ -36204,12 +36897,13 @@ import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
|
|
|
36204
36897
|
import { dirname as dirname28 } from "path";
|
|
36205
36898
|
|
|
36206
36899
|
// packages/cli/src/commands/compile.ts
|
|
36207
|
-
import { resolve as
|
|
36208
|
-
import {
|
|
36209
|
-
import {
|
|
36900
|
+
import { resolve as resolve22, isAbsolute as isAbsolute14, relative as relative15 } from "node:path";
|
|
36901
|
+
import { homedir as homedir4 } from "node:os";
|
|
36902
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
36903
|
+
import { existsSync as existsSync14, lstatSync as lstatSync2 } from "node:fs";
|
|
36210
36904
|
import chokidar from "chokidar";
|
|
36211
36905
|
|
|
36212
|
-
// node_modules/.pnpm/balanced-match@4.0.
|
|
36906
|
+
// node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js
|
|
36213
36907
|
var balanced = (a, b, str) => {
|
|
36214
36908
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
|
36215
36909
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
|
@@ -38149,6 +38843,14 @@ function findFallbackUrl(repoUrl, registries) {
|
|
|
38149
38843
|
}
|
|
38150
38844
|
return void 0;
|
|
38151
38845
|
}
|
|
38846
|
+
function findRegistryEntry(repoUrl, registries) {
|
|
38847
|
+
for (const entry of Object.values(registries)) {
|
|
38848
|
+
if (typeof entry !== "string" && entry.url === repoUrl) {
|
|
38849
|
+
return entry;
|
|
38850
|
+
}
|
|
38851
|
+
}
|
|
38852
|
+
return void 0;
|
|
38853
|
+
}
|
|
38152
38854
|
|
|
38153
38855
|
// packages/resolver/src/loader.ts
|
|
38154
38856
|
var REGISTRY_MARKER_PREFIX = "__registry__:";
|
|
@@ -39169,7 +39871,8 @@ function parseSkillMd(content, sourceFile = "<skill>") {
|
|
|
39169
39871
|
sourceFile,
|
|
39170
39872
|
frontmatter.location,
|
|
39171
39873
|
yamlFrontmatter.fieldLocations,
|
|
39172
|
-
yamlFrontmatter.fieldItemLocations
|
|
39874
|
+
yamlFrontmatter.fieldItemLocations,
|
|
39875
|
+
yamlFrontmatter.fieldValueLocations
|
|
39173
39876
|
);
|
|
39174
39877
|
const bodyContent = stripLeadingHtmlMarker(frontmatter.body).trim();
|
|
39175
39878
|
const result = {
|
|
@@ -39294,11 +39997,11 @@ function parseYamlFrontmatter(frontmatter, sourceFile) {
|
|
|
39294
39997
|
}
|
|
39295
39998
|
rejectUnsafeYamlNodes(document.contents, sourceFile, frontmatter);
|
|
39296
39999
|
enforceFrontmatterLimits(document.contents, sourceFile, frontmatter);
|
|
39297
|
-
const {
|
|
39298
|
-
|
|
39299
|
-
|
|
39300
|
-
|
|
39301
|
-
);
|
|
40000
|
+
const {
|
|
40001
|
+
fields: fieldLocations,
|
|
40002
|
+
items: fieldItemLocations,
|
|
40003
|
+
values: fieldValueLocations
|
|
40004
|
+
} = getTopLevelFieldLocations(document.contents, sourceFile, frontmatter);
|
|
39302
40005
|
let value;
|
|
39303
40006
|
try {
|
|
39304
40007
|
value = document.toJS({ maxAliasCount: 0 });
|
|
@@ -39311,7 +40014,7 @@ function parseYamlFrontmatter(frontmatter, sourceFile) {
|
|
|
39311
40014
|
);
|
|
39312
40015
|
}
|
|
39313
40016
|
if (document.contents === null) {
|
|
39314
|
-
return { fields: {}, fieldLocations, fieldItemLocations };
|
|
40017
|
+
return { fields: {}, fieldLocations, fieldItemLocations, fieldValueLocations };
|
|
39315
40018
|
}
|
|
39316
40019
|
if (!isRecord5(value)) {
|
|
39317
40020
|
throw frontmatterError(
|
|
@@ -39320,7 +40023,7 @@ function parseYamlFrontmatter(frontmatter, sourceFile) {
|
|
|
39320
40023
|
frontmatter.location
|
|
39321
40024
|
);
|
|
39322
40025
|
}
|
|
39323
|
-
return { fields: value, fieldLocations, fieldItemLocations };
|
|
40026
|
+
return { fields: value, fieldLocations, fieldItemLocations, fieldValueLocations };
|
|
39324
40027
|
}
|
|
39325
40028
|
function getYamlLocation(frontmatter, sourceFile, offset) {
|
|
39326
40029
|
const source = frontmatter.raw;
|
|
@@ -39339,7 +40042,10 @@ function getYamlLocation(frontmatter, sourceFile, offset) {
|
|
|
39339
40042
|
function getTopLevelFieldLocations(node, sourceFile, frontmatter) {
|
|
39340
40043
|
const fieldLocations = /* @__PURE__ */ new Map();
|
|
39341
40044
|
const fieldItemLocations = /* @__PURE__ */ new Map();
|
|
39342
|
-
|
|
40045
|
+
const fieldValueLocations = /* @__PURE__ */ new Map();
|
|
40046
|
+
if (!isCollection(node)) {
|
|
40047
|
+
return { fields: fieldLocations, items: fieldItemLocations, values: fieldValueLocations };
|
|
40048
|
+
}
|
|
39343
40049
|
for (const item of node.items) {
|
|
39344
40050
|
if (!isPair(item)) continue;
|
|
39345
40051
|
const key = getScalarString(item.key);
|
|
@@ -39351,9 +40057,21 @@ function getTopLevelFieldLocations(node, sourceFile, frontmatter) {
|
|
|
39351
40057
|
key,
|
|
39352
40058
|
item.value.items.map((value) => getNodeLocation(value, sourceFile, frontmatter))
|
|
39353
40059
|
);
|
|
40060
|
+
fieldValueLocations.set(key, getNestedFieldLocations(item.value, sourceFile, frontmatter));
|
|
39354
40061
|
}
|
|
39355
40062
|
}
|
|
39356
|
-
return { fields: fieldLocations, items: fieldItemLocations };
|
|
40063
|
+
return { fields: fieldLocations, items: fieldItemLocations, values: fieldValueLocations };
|
|
40064
|
+
}
|
|
40065
|
+
function getNestedFieldLocations(collection, sourceFile, frontmatter) {
|
|
40066
|
+
const valueLocations = /* @__PURE__ */ new Map();
|
|
40067
|
+
if (!isCollection(collection)) return valueLocations;
|
|
40068
|
+
for (const item of collection.items) {
|
|
40069
|
+
if (!isPair(item)) continue;
|
|
40070
|
+
const key = getScalarString(item.key);
|
|
40071
|
+
if (key === void 0) continue;
|
|
40072
|
+
valueLocations.set(key, getNodeLocation(item.value ?? item.key, sourceFile, frontmatter));
|
|
40073
|
+
}
|
|
40074
|
+
return valueLocations;
|
|
39357
40075
|
}
|
|
39358
40076
|
function getScalarString(node) {
|
|
39359
40077
|
if (!isNode(node) || !("value" in node)) return void 0;
|
|
@@ -39468,7 +40186,7 @@ function frontmatterError(message, sourceFile, location) {
|
|
|
39468
40186
|
file: sourceFile
|
|
39469
40187
|
});
|
|
39470
40188
|
}
|
|
39471
|
-
function parseFrontmatterFields(fields, sourceFile, fallbackLocation, fieldLocations, fieldItemLocations) {
|
|
40189
|
+
function parseFrontmatterFields(fields, sourceFile, fallbackLocation, fieldLocations, fieldItemLocations, fieldValueLocations) {
|
|
39472
40190
|
const name = readOptionalString(
|
|
39473
40191
|
fields,
|
|
39474
40192
|
"name",
|
|
@@ -39526,7 +40244,8 @@ function parseFrontmatterFields(fields, sourceFile, fallbackLocation, fieldLocat
|
|
|
39526
40244
|
const metadata = parseMetadataField(
|
|
39527
40245
|
fields,
|
|
39528
40246
|
sourceFile,
|
|
39529
|
-
getFieldLocation("metadata", fieldLocations, fallbackLocation)
|
|
40247
|
+
getFieldLocation("metadata", fieldLocations, fallbackLocation),
|
|
40248
|
+
fieldValueLocations.get("metadata")
|
|
39530
40249
|
);
|
|
39531
40250
|
const allowedTools = parseAllowedToolsField(
|
|
39532
40251
|
fields,
|
|
@@ -39789,7 +40508,7 @@ function readOptionalStringFromRecord(record, field, context, sourceFile, locati
|
|
|
39789
40508
|
}
|
|
39790
40509
|
return value;
|
|
39791
40510
|
}
|
|
39792
|
-
function parseMetadataField(fields, sourceFile, location) {
|
|
40511
|
+
function parseMetadataField(fields, sourceFile, location, valueLocations) {
|
|
39793
40512
|
if (!Object.hasOwn(fields, "metadata")) return void 0;
|
|
39794
40513
|
const value = fields["metadata"];
|
|
39795
40514
|
if (!isRecord5(value)) {
|
|
@@ -39798,7 +40517,11 @@ function parseMetadataField(fields, sourceFile, location) {
|
|
|
39798
40517
|
const metadata = createSafeRecord();
|
|
39799
40518
|
for (const [key, item] of Object.entries(value)) {
|
|
39800
40519
|
if (typeof item !== "string") {
|
|
39801
|
-
throw frontmatterError(
|
|
40520
|
+
throw frontmatterError(
|
|
40521
|
+
`metadata value "${key}" must be a string; quote scalar values (for example, 16 as "16")`,
|
|
40522
|
+
sourceFile,
|
|
40523
|
+
valueLocations?.get(key) ?? location
|
|
40524
|
+
);
|
|
39802
40525
|
}
|
|
39803
40526
|
metadata[key] = item;
|
|
39804
40527
|
}
|
|
@@ -40977,26 +41700,29 @@ var VIRTUAL_LOC = {
|
|
|
40977
41700
|
column: 1,
|
|
40978
41701
|
offset: 0
|
|
40979
41702
|
};
|
|
40980
|
-
function
|
|
41703
|
+
function fileLoc(file) {
|
|
41704
|
+
return { file, line: 1, column: 1, offset: 0 };
|
|
41705
|
+
}
|
|
41706
|
+
function makeObjectContent(properties, file) {
|
|
40981
41707
|
return {
|
|
40982
41708
|
type: "ObjectContent",
|
|
40983
41709
|
properties,
|
|
40984
|
-
loc: VIRTUAL_LOC
|
|
41710
|
+
loc: file ? fileLoc(file) : VIRTUAL_LOC
|
|
40985
41711
|
};
|
|
40986
41712
|
}
|
|
40987
41713
|
function makeTextContent(value, file) {
|
|
40988
41714
|
return {
|
|
40989
41715
|
type: "TextContent",
|
|
40990
41716
|
value,
|
|
40991
|
-
loc: file ?
|
|
41717
|
+
loc: file ? fileLoc(file) : VIRTUAL_LOC
|
|
40992
41718
|
};
|
|
40993
41719
|
}
|
|
40994
|
-
function makeBlock(name, content) {
|
|
41720
|
+
function makeBlock(name, content, file) {
|
|
40995
41721
|
return {
|
|
40996
41722
|
type: "Block",
|
|
40997
41723
|
name,
|
|
40998
41724
|
content,
|
|
40999
|
-
loc: VIRTUAL_LOC
|
|
41725
|
+
loc: file ? fileLoc(file) : VIRTUAL_LOC
|
|
41000
41726
|
};
|
|
41001
41727
|
}
|
|
41002
41728
|
|
|
@@ -41848,9 +42574,29 @@ var GitCacheManager = class {
|
|
|
41848
42574
|
// packages/resolver/src/git-registry.ts
|
|
41849
42575
|
var TAGS_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
41850
42576
|
var DEFAULT_GIT_TIMEOUT_MS = 6e4;
|
|
42577
|
+
var GIT_TIMEOUT_ENV_VAR = "PROMPTSCRIPT_GIT_TIMEOUT";
|
|
41851
42578
|
var SEMVER_TAG_RE = /^v?\d+\.\d+\.\d+/;
|
|
42579
|
+
function envGitTimeout() {
|
|
42580
|
+
const raw = process.env[GIT_TIMEOUT_ENV_VAR];
|
|
42581
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
42582
|
+
return void 0;
|
|
42583
|
+
}
|
|
42584
|
+
const parsed = Number(raw);
|
|
42585
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
42586
|
+
}
|
|
41852
42587
|
function normalizeGitTimeout(timeout) {
|
|
41853
|
-
|
|
42588
|
+
if (timeout !== void 0 && Number.isFinite(timeout) && timeout > 0) {
|
|
42589
|
+
return timeout;
|
|
42590
|
+
}
|
|
42591
|
+
const fromEnv = envGitTimeout();
|
|
42592
|
+
if (fromEnv !== void 0) {
|
|
42593
|
+
return fromEnv;
|
|
42594
|
+
}
|
|
42595
|
+
return DEFAULT_GIT_TIMEOUT_MS;
|
|
42596
|
+
}
|
|
42597
|
+
function isPartialCloneUnsupported(error) {
|
|
42598
|
+
const message = error.message.toLowerCase();
|
|
42599
|
+
return message.includes("filtering not recognized") || message.includes("does not support filtering") || message.includes("invalid filter") || message.includes("filter is not supported") || /unknown (option|switch)[`' ]*(sparse|filter)/.test(message);
|
|
41854
42600
|
}
|
|
41855
42601
|
var GitCloneError = class extends Error {
|
|
41856
42602
|
constructor(message, url, cause) {
|
|
@@ -42082,17 +42828,20 @@ var GitRegistry = class {
|
|
|
42082
42828
|
* @param tag - Git tag to check out, or undefined for the default branch
|
|
42083
42829
|
* @param targetDir - Directory to clone into
|
|
42084
42830
|
* @param fallbackRepoUrl - Optional fallback URL to try on auth failure
|
|
42831
|
+
* @param sparsePath - Optional subdirectory to limit the checkout to.
|
|
42832
|
+
* Uses `--filter=blob:none --sparse` + `sparse-checkout` so only the
|
|
42833
|
+
* blobs for that subdirectory are fetched. Falls back to a plain
|
|
42834
|
+
* shallow clone when the server does not support partial clones.
|
|
42085
42835
|
*/
|
|
42086
|
-
async cloneAtTag(repoUrl, tag, targetDir, fallbackRepoUrl) {
|
|
42836
|
+
async cloneAtTag(repoUrl, tag, targetDir, fallbackRepoUrl, sparsePath) {
|
|
42087
42837
|
if (existsSync8(targetDir)) {
|
|
42088
42838
|
await fs2.rm(targetDir, { recursive: true, force: true });
|
|
42089
42839
|
}
|
|
42090
42840
|
await fs2.mkdir(targetDir, { recursive: true });
|
|
42091
42841
|
const git = this.createGit();
|
|
42092
|
-
const cloneOptions = tag ? ["--depth=1", `--branch=${tag}`, "--single-branch"] : ["--depth=1"];
|
|
42093
42842
|
const cloneUrl = this.auth ? this.transportUrl : repoUrl;
|
|
42094
42843
|
try {
|
|
42095
|
-
await
|
|
42844
|
+
await this.performClone(git, cloneUrl, targetDir, tag, sparsePath);
|
|
42096
42845
|
} catch (err) {
|
|
42097
42846
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
42098
42847
|
if (isGitTimeoutError(error)) {
|
|
@@ -42104,24 +42853,15 @@ var GitRegistry = class {
|
|
|
42104
42853
|
if (this.isAccessError(error)) {
|
|
42105
42854
|
if (fallbackRepoUrl) {
|
|
42106
42855
|
try {
|
|
42107
|
-
await
|
|
42856
|
+
await this.performClone(git, fallbackRepoUrl, targetDir, tag, sparsePath);
|
|
42108
42857
|
return;
|
|
42109
42858
|
} catch (fallbackErr) {
|
|
42110
|
-
|
|
42111
|
-
|
|
42112
|
-
throw createGitTimeoutError(fallbackRepoUrl, this.timeout, fbError);
|
|
42113
|
-
}
|
|
42114
|
-
if (this.isAccessError(fbError)) {
|
|
42115
|
-
throw new GitAuthError(
|
|
42116
|
-
`Authentication failed for both ${repoUrl} and fallback ${fallbackRepoUrl}`,
|
|
42117
|
-
fallbackRepoUrl,
|
|
42118
|
-
fbError
|
|
42119
|
-
);
|
|
42120
|
-
}
|
|
42121
|
-
throw new GitCloneError(
|
|
42122
|
-
`Failed to clone ${fallbackRepoUrl} at ${tag ?? "default branch"}: ${fbError.message}`,
|
|
42859
|
+
throw this.classifyFallbackCloneError(
|
|
42860
|
+
repoUrl,
|
|
42123
42861
|
fallbackRepoUrl,
|
|
42124
|
-
|
|
42862
|
+
fallbackErr,
|
|
42863
|
+
tag,
|
|
42864
|
+
"clone"
|
|
42125
42865
|
);
|
|
42126
42866
|
}
|
|
42127
42867
|
}
|
|
@@ -42134,6 +42874,92 @@ var GitRegistry = class {
|
|
|
42134
42874
|
);
|
|
42135
42875
|
}
|
|
42136
42876
|
}
|
|
42877
|
+
/**
|
|
42878
|
+
* Clone shallow, optionally partial (`--filter=blob:none --sparse`) with a
|
|
42879
|
+
* sparse-checkout cone of `sparsePath`. Retries without the partial-clone
|
|
42880
|
+
* flags when the server or local Git does not support them.
|
|
42881
|
+
*/
|
|
42882
|
+
async performClone(git, url, targetDir, tag, sparsePath) {
|
|
42883
|
+
const tagOptions = tag ? ["--branch=" + tag, "--single-branch"] : [];
|
|
42884
|
+
const baseOptions = ["--depth=1", ...tagOptions];
|
|
42885
|
+
if (!sparsePath) {
|
|
42886
|
+
await git.clone(url, targetDir, baseOptions);
|
|
42887
|
+
return;
|
|
42888
|
+
}
|
|
42889
|
+
try {
|
|
42890
|
+
await git.clone(url, targetDir, [...baseOptions, "--filter=blob:none", "--sparse"]);
|
|
42891
|
+
} catch (err) {
|
|
42892
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
42893
|
+
if (!isPartialCloneUnsupported(error)) {
|
|
42894
|
+
throw error;
|
|
42895
|
+
}
|
|
42896
|
+
if (existsSync8(targetDir)) {
|
|
42897
|
+
await fs2.rm(targetDir, { recursive: true, force: true });
|
|
42898
|
+
}
|
|
42899
|
+
await fs2.mkdir(targetDir, { recursive: true });
|
|
42900
|
+
await git.clone(url, targetDir, baseOptions);
|
|
42901
|
+
return;
|
|
42902
|
+
}
|
|
42903
|
+
const repoGit = this.createGit(targetDir);
|
|
42904
|
+
await repoGit.raw(["sparse-checkout", "set", sparsePath]);
|
|
42905
|
+
}
|
|
42906
|
+
/**
|
|
42907
|
+
* Check whether the checkout at `targetDir` uses sparse-checkout.
|
|
42908
|
+
*/
|
|
42909
|
+
async isSparseCheckout(targetDir) {
|
|
42910
|
+
const git = this.createGit(targetDir);
|
|
42911
|
+
try {
|
|
42912
|
+
const out = await git.raw(["config", "core.sparseCheckout"]);
|
|
42913
|
+
return out.trim() === "true";
|
|
42914
|
+
} catch {
|
|
42915
|
+
return false;
|
|
42916
|
+
}
|
|
42917
|
+
}
|
|
42918
|
+
/**
|
|
42919
|
+
* Disable sparse-checkout, materializing the full working tree.
|
|
42920
|
+
* Used when a root-level import needs the whole repository but the
|
|
42921
|
+
* cached clone is partial.
|
|
42922
|
+
*/
|
|
42923
|
+
async disableSparseCheckout(targetDir) {
|
|
42924
|
+
try {
|
|
42925
|
+
await this.createGit(targetDir).raw(["sparse-checkout", "disable"]);
|
|
42926
|
+
} catch (err) {
|
|
42927
|
+
this.throwIfGitTimeout(err);
|
|
42928
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
42929
|
+
}
|
|
42930
|
+
}
|
|
42931
|
+
/** Convert a raw Git error into a GitCloneError when it is a timeout. */
|
|
42932
|
+
throwIfGitTimeout(err) {
|
|
42933
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
42934
|
+
if (isGitTimeoutError(error)) {
|
|
42935
|
+
throw createGitTimeoutError(this.url, this.timeout, error);
|
|
42936
|
+
}
|
|
42937
|
+
}
|
|
42938
|
+
/**
|
|
42939
|
+
* Add paths to an existing sparse checkout so their blobs are fetched
|
|
42940
|
+
* on demand. Used when a cached partial clone needs a subdirectory that
|
|
42941
|
+
* the original cone did not cover.
|
|
42942
|
+
*/
|
|
42943
|
+
async addSparsePaths(targetDir, paths) {
|
|
42944
|
+
const extra = paths.filter((p) => p.length > 0 && p !== ".");
|
|
42945
|
+
if (extra.length === 0) {
|
|
42946
|
+
return;
|
|
42947
|
+
}
|
|
42948
|
+
const git = this.createGit(targetDir);
|
|
42949
|
+
try {
|
|
42950
|
+
await git.raw(["sparse-checkout", "add", ...extra]);
|
|
42951
|
+
} catch (addError) {
|
|
42952
|
+
const original = addError instanceof Error ? addError : new Error(String(addError));
|
|
42953
|
+
try {
|
|
42954
|
+
const listed = await git.raw(["sparse-checkout", "list"]);
|
|
42955
|
+
const current = listed.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
42956
|
+
await git.raw(["sparse-checkout", "set", .../* @__PURE__ */ new Set([...current, ...extra])]);
|
|
42957
|
+
} catch (setErr) {
|
|
42958
|
+
this.throwIfGitTimeout(setErr);
|
|
42959
|
+
throw original;
|
|
42960
|
+
}
|
|
42961
|
+
}
|
|
42962
|
+
}
|
|
42137
42963
|
/**
|
|
42138
42964
|
* List all semver tags from a remote repo.
|
|
42139
42965
|
* Results are cached via RegistryCache to avoid repeated ls-remote calls.
|
|
@@ -42199,8 +43025,9 @@ var GitRegistry = class {
|
|
|
42199
43025
|
}
|
|
42200
43026
|
await fs2.mkdir(targetDir, { recursive: true });
|
|
42201
43027
|
const git = this.createGit();
|
|
43028
|
+
const cloneUrl = this.auth ? this.transportUrl : repoUrl;
|
|
42202
43029
|
try {
|
|
42203
|
-
await this.
|
|
43030
|
+
await this.performClone(git, cloneUrl, targetDir, ref, sparsePath);
|
|
42204
43031
|
} catch (err) {
|
|
42205
43032
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
42206
43033
|
if (isGitTimeoutError(error)) {
|
|
@@ -42208,24 +43035,15 @@ var GitRegistry = class {
|
|
|
42208
43035
|
}
|
|
42209
43036
|
if (this.isAccessError(error) && fallbackRepoUrl) {
|
|
42210
43037
|
try {
|
|
42211
|
-
await this.
|
|
43038
|
+
await this.performClone(git, fallbackRepoUrl, targetDir, ref, sparsePath);
|
|
42212
43039
|
return;
|
|
42213
43040
|
} catch (fallbackErr) {
|
|
42214
|
-
|
|
42215
|
-
|
|
42216
|
-
throw createGitTimeoutError(fallbackRepoUrl, this.timeout, fbError);
|
|
42217
|
-
}
|
|
42218
|
-
if (this.isAccessError(fbError)) {
|
|
42219
|
-
throw new GitAuthError(
|
|
42220
|
-
`Authentication failed for both ${repoUrl} and fallback ${fallbackRepoUrl}`,
|
|
42221
|
-
fallbackRepoUrl,
|
|
42222
|
-
fbError
|
|
42223
|
-
);
|
|
42224
|
-
}
|
|
42225
|
-
throw new GitCloneError(
|
|
42226
|
-
`Failed to sparse-clone ${fallbackRepoUrl} at ${ref}: ${fbError.message}`,
|
|
43041
|
+
throw this.classifyFallbackCloneError(
|
|
43042
|
+
repoUrl,
|
|
42227
43043
|
fallbackRepoUrl,
|
|
42228
|
-
|
|
43044
|
+
fallbackErr,
|
|
43045
|
+
ref,
|
|
43046
|
+
"sparse-clone"
|
|
42229
43047
|
);
|
|
42230
43048
|
}
|
|
42231
43049
|
}
|
|
@@ -42243,22 +43061,26 @@ var GitRegistry = class {
|
|
|
42243
43061
|
}
|
|
42244
43062
|
}
|
|
42245
43063
|
/**
|
|
42246
|
-
*
|
|
43064
|
+
* Classify an error from the fallback clone attempt shared by
|
|
43065
|
+
* `cloneAtTag` and `cloneSparse`: timeout, auth, or a plain clone failure.
|
|
42247
43066
|
*/
|
|
42248
|
-
|
|
42249
|
-
|
|
42250
|
-
|
|
43067
|
+
classifyFallbackCloneError(repoUrl, fallbackRepoUrl, err, ref, action) {
|
|
43068
|
+
const fbError = err instanceof Error ? err : new Error(String(err));
|
|
43069
|
+
if (isGitTimeoutError(fbError)) {
|
|
43070
|
+
return createGitTimeoutError(fallbackRepoUrl, this.timeout, fbError);
|
|
43071
|
+
}
|
|
43072
|
+
if (this.isAccessError(fbError)) {
|
|
43073
|
+
return new GitAuthError(
|
|
43074
|
+
`Authentication failed for both ${repoUrl} and fallback ${fallbackRepoUrl}`,
|
|
43075
|
+
fallbackRepoUrl,
|
|
43076
|
+
fbError
|
|
43077
|
+
);
|
|
42251
43078
|
}
|
|
42252
|
-
|
|
42253
|
-
|
|
42254
|
-
|
|
42255
|
-
|
|
42256
|
-
|
|
42257
|
-
"--filter=blob:none",
|
|
42258
|
-
"--sparse"
|
|
42259
|
-
]);
|
|
42260
|
-
const repoGit = this.createGit(targetDir);
|
|
42261
|
-
await repoGit.raw(["sparse-checkout", "set", sparsePath]);
|
|
43079
|
+
return new GitCloneError(
|
|
43080
|
+
`Failed to ${action} ${fallbackRepoUrl} at ${ref ?? "default branch"}: ${fbError.message}`,
|
|
43081
|
+
fallbackRepoUrl,
|
|
43082
|
+
fbError
|
|
43083
|
+
);
|
|
42262
43084
|
}
|
|
42263
43085
|
/**
|
|
42264
43086
|
* Ensure the repository is cloned and at the correct ref.
|
|
@@ -42657,7 +43479,7 @@ function createGitTimeoutError(url, timeout, cause) {
|
|
|
42657
43479
|
return cause;
|
|
42658
43480
|
}
|
|
42659
43481
|
return new GitCloneError(
|
|
42660
|
-
`Git operation timed out after ${timeout}ms while contacting ${url}
|
|
43482
|
+
`Git operation timed out after ${timeout}ms while contacting ${url}. Raise the limit with the 'timeout' field on the registry entry or the ${GIT_TIMEOUT_ENV_VAR} environment variable.`,
|
|
42661
43483
|
url,
|
|
42662
43484
|
cause
|
|
42663
43485
|
);
|
|
@@ -43069,7 +43891,7 @@ async function discoverNativeContent(dir, logger) {
|
|
|
43069
43891
|
}
|
|
43070
43892
|
}
|
|
43071
43893
|
if (Object.keys(mergedSkills).length > 0) {
|
|
43072
|
-
blocks.push(makeBlock("skills", makeObjectContent(mergedSkills)));
|
|
43894
|
+
blocks.push(makeBlock("skills", makeObjectContent(mergedSkills, dir), dir));
|
|
43073
43895
|
}
|
|
43074
43896
|
const rootAgents = await discoverAgents(dir) ?? {};
|
|
43075
43897
|
const wrappedAgents = {};
|
|
@@ -43082,7 +43904,7 @@ async function discoverNativeContent(dir, logger) {
|
|
|
43082
43904
|
}
|
|
43083
43905
|
const mergedAgents = { ...wrappedAgents, ...rootAgents };
|
|
43084
43906
|
if (Object.keys(mergedAgents).length > 0) {
|
|
43085
|
-
blocks.push(makeBlock("agents", makeObjectContent(mergedAgents)));
|
|
43907
|
+
blocks.push(makeBlock("agents", makeObjectContent(mergedAgents, dir), dir));
|
|
43086
43908
|
}
|
|
43087
43909
|
const rootCommands = await discoverCommands(dir) ?? {};
|
|
43088
43910
|
const wrappedCommands = {};
|
|
@@ -43095,11 +43917,11 @@ async function discoverNativeContent(dir, logger) {
|
|
|
43095
43917
|
}
|
|
43096
43918
|
const mergedCommands = { ...wrappedCommands, ...rootCommands };
|
|
43097
43919
|
if (Object.keys(mergedCommands).length > 0) {
|
|
43098
|
-
blocks.push(makeBlock("shortcuts", makeObjectContent(mergedCommands)));
|
|
43920
|
+
blocks.push(makeBlock("shortcuts", makeObjectContent(mergedCommands, dir), dir));
|
|
43099
43921
|
}
|
|
43100
43922
|
const contextContent = await discoverContext(dir);
|
|
43101
43923
|
if (contextContent) {
|
|
43102
|
-
blocks.push(makeBlock("context", contextContent));
|
|
43924
|
+
blocks.push(makeBlock("context", contextContent, contextContent.loc.file));
|
|
43103
43925
|
}
|
|
43104
43926
|
if (blocks.length === 0) {
|
|
43105
43927
|
return null;
|
|
@@ -43109,7 +43931,7 @@ async function discoverNativeContent(dir, logger) {
|
|
|
43109
43931
|
blocks,
|
|
43110
43932
|
uses: [],
|
|
43111
43933
|
extends: [],
|
|
43112
|
-
loc:
|
|
43934
|
+
loc: fileLoc(dir)
|
|
43113
43935
|
};
|
|
43114
43936
|
return program2;
|
|
43115
43937
|
}
|
|
@@ -43249,7 +44071,7 @@ async function hashVendorRepository(directory) {
|
|
|
43249
44071
|
await visit(directory, "");
|
|
43250
44072
|
return `sha256-${hash.digest("hex")}`;
|
|
43251
44073
|
}
|
|
43252
|
-
async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expectedCommit, allowedUntrackedFiles = /* @__PURE__ */ new Set()) {
|
|
44074
|
+
async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expectedCommit, allowedUntrackedFiles = /* @__PURE__ */ new Set(), options = {}) {
|
|
43253
44075
|
const gitDir = join9(directory, gitDirectoryName);
|
|
43254
44076
|
async function rejectMetadataSymlinks(currentDirectory) {
|
|
43255
44077
|
for (const entry of await readdir4(currentDirectory, { withFileTypes: true })) {
|
|
@@ -43287,7 +44109,7 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
43287
44109
|
"Vendor Git config"
|
|
43288
44110
|
);
|
|
43289
44111
|
const localConfig = localConfigContent.toString("utf-8");
|
|
43290
|
-
if (/^[ \t]*\[(?:include|includeif)\b/im.test(localConfig) || /\
|
|
44112
|
+
if (/^[ \t]*\[(?:include|includeif)\b/im.test(localConfig) || /\bworktreeconfig\s*=\s*true\b/i.test(localConfig) || !options.allowPartial && (/\bpromisor\s*=\s*true\b/i.test(localConfig) || /\bpartialclone/i.test(localConfig))) {
|
|
43291
44113
|
throw new Error(`External or partial Git object sources are not allowed: ${gitDir}`);
|
|
43292
44114
|
}
|
|
43293
44115
|
await rejectMetadataPath("commondir", "Git common directories are not allowed");
|
|
@@ -43458,7 +44280,7 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
|
|
|
43458
44280
|
}
|
|
43459
44281
|
}
|
|
43460
44282
|
await collectFiles(directory, "");
|
|
43461
|
-
if (worktreeFileCount !== trackedFiles.size || regularFiles.some((path2) => !trackedFiles.has(path2))) {
|
|
44283
|
+
if (!options.allowPartial && worktreeFileCount !== trackedFiles.size || regularFiles.some((path2) => !trackedFiles.has(path2))) {
|
|
43462
44284
|
throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
|
|
43463
44285
|
}
|
|
43464
44286
|
const batchSize = 100;
|
|
@@ -43742,7 +44564,8 @@ var Resolver = class {
|
|
|
43742
44564
|
cacheEnabled;
|
|
43743
44565
|
logger;
|
|
43744
44566
|
options;
|
|
43745
|
-
|
|
44567
|
+
/** Lazy per-repository Git registries (carry per-entry timeout settings). */
|
|
44568
|
+
gitRegistries = /* @__PURE__ */ new Map();
|
|
43746
44569
|
registryCache;
|
|
43747
44570
|
constructor(options) {
|
|
43748
44571
|
this.options = options;
|
|
@@ -43750,7 +44573,6 @@ var Resolver = class {
|
|
|
43750
44573
|
this.cache = /* @__PURE__ */ new Map();
|
|
43751
44574
|
this.cacheEnabled = options.cache !== false;
|
|
43752
44575
|
this.logger = options.logger ?? noopLogger;
|
|
43753
|
-
this.gitRegistry = new GitRegistry({ url: "https://github.com/placeholder/placeholder.git" });
|
|
43754
44576
|
const defaultCacheDir = join10(
|
|
43755
44577
|
process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/tmp",
|
|
43756
44578
|
".promptscript",
|
|
@@ -43758,6 +44580,54 @@ var Resolver = class {
|
|
|
43758
44580
|
);
|
|
43759
44581
|
this.registryCache = new RegistryCache(options.cacheDir ?? defaultCacheDir);
|
|
43760
44582
|
}
|
|
44583
|
+
/**
|
|
44584
|
+
* Get (or lazily create) the Git registry for a repository URL.
|
|
44585
|
+
*
|
|
44586
|
+
* Per-repository instances carry the `timeout` from the matching
|
|
44587
|
+
* registries config entry, so large monorepo registries can raise the
|
|
44588
|
+
* clone timeout per entry (see issue #455). Falls back to
|
|
44589
|
+
* PROMPTSCRIPT_GIT_TIMEOUT / the 60s default inside GitRegistry.
|
|
44590
|
+
*/
|
|
44591
|
+
getGitRegistry(repoUrl) {
|
|
44592
|
+
const cached = this.gitRegistries.get(repoUrl);
|
|
44593
|
+
if (cached) {
|
|
44594
|
+
return cached;
|
|
44595
|
+
}
|
|
44596
|
+
const entry = this.options.registries ? findRegistryEntry(repoUrl, this.options.registries) : void 0;
|
|
44597
|
+
const registry2 = new GitRegistry({
|
|
44598
|
+
url: repoUrl,
|
|
44599
|
+
...entry?.timeout !== void 0 ? { timeout: entry.timeout } : {}
|
|
44600
|
+
});
|
|
44601
|
+
this.gitRegistries.set(repoUrl, registry2);
|
|
44602
|
+
return registry2;
|
|
44603
|
+
}
|
|
44604
|
+
/**
|
|
44605
|
+
* Clone a registry repository into its cache path. Uses the per-entry
|
|
44606
|
+
* Git registry (so the configured timeout applies) and the fallback URL
|
|
44607
|
+
* from the lockfile or the registries config.
|
|
44608
|
+
*/
|
|
44609
|
+
async cloneRegistryIntoCache(repoUrl, cachePath, tag, sparseCone, lockEntry) {
|
|
44610
|
+
const gitRegistry = this.getGitRegistry(repoUrl);
|
|
44611
|
+
const fallbackRepoUrl = lockEntry?.gitUrl ?? (this.options.registries ? findFallbackUrl(repoUrl, this.options.registries) : void 0);
|
|
44612
|
+
await gitRegistry.cloneAtTag(repoUrl, tag, cachePath, fallbackRepoUrl, sparseCone);
|
|
44613
|
+
return gitRegistry;
|
|
44614
|
+
}
|
|
44615
|
+
/**
|
|
44616
|
+
* Verify that a cached registry checkout matches a locked commit.
|
|
44617
|
+
* Cache clones may be partial (sparse cones), so partial-clone metadata
|
|
44618
|
+
* and missing out-of-cone files are allowed.
|
|
44619
|
+
*/
|
|
44620
|
+
async verifyCacheCommit(cachePath, commit) {
|
|
44621
|
+
await verifyGitRepositoryCheckout(
|
|
44622
|
+
cachePath,
|
|
44623
|
+
".git",
|
|
44624
|
+
commit,
|
|
44625
|
+
/* @__PURE__ */ new Set([".prs-registry-meta.json"]),
|
|
44626
|
+
{
|
|
44627
|
+
allowPartial: true
|
|
44628
|
+
}
|
|
44629
|
+
);
|
|
44630
|
+
}
|
|
43761
44631
|
/**
|
|
43762
44632
|
* Resolve a PromptScript file and all its dependencies.
|
|
43763
44633
|
*
|
|
@@ -44368,10 +45238,12 @@ var Resolver = class {
|
|
|
44368
45238
|
}
|
|
44369
45239
|
const program2 = {
|
|
44370
45240
|
type: "Program",
|
|
44371
|
-
blocks: [
|
|
45241
|
+
blocks: [
|
|
45242
|
+
makeBlock("skills", makeObjectContent({ [skillName]: skillProps }, absPath), absPath)
|
|
45243
|
+
],
|
|
44372
45244
|
uses: [],
|
|
44373
45245
|
extends: [],
|
|
44374
|
-
loc:
|
|
45246
|
+
loc: fileLoc(absPath)
|
|
44375
45247
|
};
|
|
44376
45248
|
return { ast: program2 };
|
|
44377
45249
|
}
|
|
@@ -44446,7 +45318,8 @@ var Resolver = class {
|
|
|
44446
45318
|
}
|
|
44447
45319
|
errors.push(
|
|
44448
45320
|
new ResolveError(
|
|
44449
|
-
`Failed to resolve parent: ${err instanceof Error ? err.message : String(err)}
|
|
45321
|
+
`Failed to resolve parent: ${err instanceof Error ? err.message : String(err)}`,
|
|
45322
|
+
err instanceof ResolveError ? err.location : void 0
|
|
44450
45323
|
)
|
|
44451
45324
|
);
|
|
44452
45325
|
}
|
|
@@ -44545,7 +45418,8 @@ var Resolver = class {
|
|
|
44545
45418
|
}
|
|
44546
45419
|
errors.push(
|
|
44547
45420
|
new ResolveError(
|
|
44548
|
-
`Failed to resolve import: ${err instanceof Error ? err.message : String(err)}
|
|
45421
|
+
`Failed to resolve import: ${err instanceof Error ? err.message : String(err)}`,
|
|
45422
|
+
err instanceof ResolveError ? err.location : void 0
|
|
44549
45423
|
)
|
|
44550
45424
|
);
|
|
44551
45425
|
}
|
|
@@ -44685,6 +45559,8 @@ var Resolver = class {
|
|
|
44685
45559
|
}
|
|
44686
45560
|
const requestedRef = lockEntry?.version ?? (version || void 0);
|
|
44687
45561
|
const tag = requestedRef && requestedRef !== "latest" && !/^[0-9a-f]{40}$/i.test(requestedRef) ? requestedRef : void 0;
|
|
45562
|
+
const subPathLastSlash = subPath.lastIndexOf("/");
|
|
45563
|
+
const sparseCone = subPathLastSlash > 0 ? subPath.slice(0, subPathLastSlash) : void 0;
|
|
44688
45564
|
let cachePath;
|
|
44689
45565
|
let vendoredPath = null;
|
|
44690
45566
|
const vendorManifest = this.options.vendorDir ? await loadVendorManifest(this.options.vendorDir) : null;
|
|
@@ -44711,12 +45587,7 @@ var Resolver = class {
|
|
|
44711
45587
|
if (lockedCommit) {
|
|
44712
45588
|
let cacheMatchesLock = false;
|
|
44713
45589
|
try {
|
|
44714
|
-
await
|
|
44715
|
-
cachePath,
|
|
44716
|
-
".git",
|
|
44717
|
-
lockedCommit,
|
|
44718
|
-
/* @__PURE__ */ new Set([".prs-registry-meta.json"])
|
|
44719
|
-
);
|
|
45590
|
+
await this.verifyCacheCommit(cachePath, lockedCommit);
|
|
44720
45591
|
cacheMatchesLock = true;
|
|
44721
45592
|
} catch {
|
|
44722
45593
|
cacheMatchesLock = false;
|
|
@@ -44730,17 +45601,16 @@ var Resolver = class {
|
|
|
44730
45601
|
this.logger.verbose(
|
|
44731
45602
|
`Registry cache does not match locked commit for ${repoUrl}. Re-cloning.`
|
|
44732
45603
|
);
|
|
44733
|
-
const
|
|
44734
|
-
|
|
44735
|
-
await this.gitRegistry.cloneAtTag(cloneRepoUrl, tag, cachePath, fallbackRepoUrl);
|
|
44736
|
-
await this.gitRegistry.checkoutCommit(cachePath, lockedCommit);
|
|
44737
|
-
await this.registryCache.set(repoUrl, effectiveVersion, lockedCommit);
|
|
44738
|
-
await verifyGitRepositoryCheckout(
|
|
45604
|
+
const gitRegistry = await this.cloneRegistryIntoCache(
|
|
45605
|
+
repoUrl,
|
|
44739
45606
|
cachePath,
|
|
44740
|
-
|
|
44741
|
-
|
|
44742
|
-
|
|
45607
|
+
tag,
|
|
45608
|
+
sparseCone,
|
|
45609
|
+
lockEntry
|
|
44743
45610
|
);
|
|
45611
|
+
await gitRegistry.checkoutCommit(cachePath, lockedCommit);
|
|
45612
|
+
await this.registryCache.set(repoUrl, effectiveVersion, lockedCommit);
|
|
45613
|
+
await this.verifyCacheCommit(cachePath, lockedCommit);
|
|
44744
45614
|
}
|
|
44745
45615
|
}
|
|
44746
45616
|
} else {
|
|
@@ -44751,22 +45621,21 @@ var Resolver = class {
|
|
|
44751
45621
|
}
|
|
44752
45622
|
this.logger.verbose(`Registry cache miss, cloning: ${repoUrl}@${tag ?? "default"}`);
|
|
44753
45623
|
cachePath = this.registryCache.getCachePath(repoUrl, effectiveVersion);
|
|
44754
|
-
const
|
|
44755
|
-
|
|
44756
|
-
|
|
45624
|
+
const gitRegistry = await this.cloneRegistryIntoCache(
|
|
45625
|
+
repoUrl,
|
|
45626
|
+
cachePath,
|
|
45627
|
+
tag,
|
|
45628
|
+
sparseCone,
|
|
45629
|
+
lockEntry
|
|
45630
|
+
);
|
|
44757
45631
|
if (lockedCommit) {
|
|
44758
45632
|
this.logger.verbose(`Checking out locked commit: ${lockedCommit}`);
|
|
44759
|
-
await
|
|
45633
|
+
await gitRegistry.checkoutCommit(cachePath, lockedCommit);
|
|
44760
45634
|
}
|
|
44761
45635
|
const commitHash = lockedCommit ?? lockEntry?.commit ?? "unknown";
|
|
44762
45636
|
await this.registryCache.set(repoUrl, effectiveVersion, commitHash);
|
|
44763
45637
|
if (lockedCommit) {
|
|
44764
|
-
await
|
|
44765
|
-
cachePath,
|
|
44766
|
-
".git",
|
|
44767
|
-
lockedCommit,
|
|
44768
|
-
/* @__PURE__ */ new Set([".prs-registry-meta.json"])
|
|
44769
|
-
);
|
|
45638
|
+
await this.verifyCacheCommit(cachePath, lockedCommit);
|
|
44770
45639
|
}
|
|
44771
45640
|
}
|
|
44772
45641
|
dependencies.add(cachePath);
|
|
@@ -44807,6 +45676,26 @@ var Resolver = class {
|
|
|
44807
45676
|
};
|
|
44808
45677
|
}
|
|
44809
45678
|
}
|
|
45679
|
+
if (!this.options.readOnly && existsSync9(cachePath) && existsSync9(join10(cachePath, ".git")) && !vendoredPath) {
|
|
45680
|
+
const gitRegistry = this.getGitRegistry(repoUrl);
|
|
45681
|
+
if (await gitRegistry.isSparseCheckout(cachePath)) {
|
|
45682
|
+
const fileMissing = !isRoot && !existsSync9(resolvedFullPath);
|
|
45683
|
+
const dirMissing = !isRoot && !existsSync9(join10(cachePath, subPath));
|
|
45684
|
+
if (isRoot) {
|
|
45685
|
+
this.logger.verbose(`Materializing full checkout for root import: ${repoUrl}`);
|
|
45686
|
+
await gitRegistry.disableSparseCheckout(cachePath);
|
|
45687
|
+
} else if (fileMissing || dirMissing) {
|
|
45688
|
+
this.logger.verbose(`Widening sparse checkout for ${repoUrl}: ${subPath}`);
|
|
45689
|
+
const paths = /* @__PURE__ */ new Set();
|
|
45690
|
+
if (sparseCone) {
|
|
45691
|
+
paths.add(sparseCone);
|
|
45692
|
+
} else if (!isMdPath && !subPath.endsWith(".prs")) {
|
|
45693
|
+
paths.add(subPath);
|
|
45694
|
+
}
|
|
45695
|
+
await gitRegistry.addSparsePaths(cachePath, [...paths]);
|
|
45696
|
+
}
|
|
45697
|
+
}
|
|
45698
|
+
}
|
|
44810
45699
|
let resolvedAST = null;
|
|
44811
45700
|
if (!isRoot && existsSync9(resolvedFullPath) && isMdPath) {
|
|
44812
45701
|
this.logger.debug(`Found .md file: ${resolvedFullPath}`);
|
|
@@ -44935,10 +45824,10 @@ var Resolver = class {
|
|
|
44935
45824
|
this.logger.debug(`Found ${Object.keys(properties).length} skill(s) in directory: ${dirPath}`);
|
|
44936
45825
|
const program2 = {
|
|
44937
45826
|
type: "Program",
|
|
44938
|
-
blocks: [makeBlock("skills", makeObjectContent(properties))],
|
|
45827
|
+
blocks: [makeBlock("skills", makeObjectContent(properties, dirPath), dirPath)],
|
|
44939
45828
|
uses: [],
|
|
44940
45829
|
extends: [],
|
|
44941
|
-
loc:
|
|
45830
|
+
loc: fileLoc(dirPath)
|
|
44942
45831
|
};
|
|
44943
45832
|
return { ast: program2 };
|
|
44944
45833
|
}
|
|
@@ -45303,7 +46192,7 @@ var HttpRegistry = class {
|
|
|
45303
46192
|
* Sleep for specified milliseconds.
|
|
45304
46193
|
*/
|
|
45305
46194
|
sleep(ms) {
|
|
45306
|
-
return new Promise((
|
|
46195
|
+
return new Promise((resolve43) => setTimeout(resolve43, ms));
|
|
45307
46196
|
}
|
|
45308
46197
|
/**
|
|
45309
46198
|
* Fetch with timeout.
|
|
@@ -45448,6 +46337,7 @@ function createHttpRegistry(options) {
|
|
|
45448
46337
|
init_src();
|
|
45449
46338
|
|
|
45450
46339
|
// packages/resolver/src/skill-validation.ts
|
|
46340
|
+
init_src();
|
|
45451
46341
|
import { basename as basename12, dirname as dirname11, join as join12 } from "path";
|
|
45452
46342
|
import { existsSync as existsSync11 } from "fs";
|
|
45453
46343
|
function validateSkillFrontmatter(rawContent, options = {}) {
|
|
@@ -45464,11 +46354,15 @@ function validateSkillFrontmatter(rawContent, options = {}) {
|
|
|
45464
46354
|
try {
|
|
45465
46355
|
parsed = parseSkillMd(rawContent, options.filePath);
|
|
45466
46356
|
} catch (error) {
|
|
45467
|
-
|
|
46357
|
+
const issue = {
|
|
45468
46358
|
severity: "error",
|
|
45469
46359
|
code: "SK000",
|
|
45470
46360
|
message: error instanceof Error ? error.message : String(error)
|
|
45471
|
-
}
|
|
46361
|
+
};
|
|
46362
|
+
if (error instanceof ResolveError && error.location) {
|
|
46363
|
+
issue.location = error.location;
|
|
46364
|
+
}
|
|
46365
|
+
issues.push(issue);
|
|
45472
46366
|
return { valid: false, issues };
|
|
45473
46367
|
}
|
|
45474
46368
|
validateName(parsed, options, issues);
|
|
@@ -45648,7 +46542,8 @@ function formatSkillValidationIssues(issues) {
|
|
|
45648
46542
|
return issues.map((i) => {
|
|
45649
46543
|
const tag = i.severity === "error" ? "\u2717" : "\u26A0";
|
|
45650
46544
|
const field = i.field ? ` [${i.field}]` : "";
|
|
45651
|
-
|
|
46545
|
+
const location = i.location ? ` (at ${i.location.file}:${i.location.line}:${i.location.column})` : "";
|
|
46546
|
+
return ` ${tag} ${i.code}${field}: ${i.message}${location}`;
|
|
45652
46547
|
}).join("\n");
|
|
45653
46548
|
}
|
|
45654
46549
|
|
|
@@ -47388,6 +48283,19 @@ var authorityInjection = {
|
|
|
47388
48283
|
}
|
|
47389
48284
|
};
|
|
47390
48285
|
|
|
48286
|
+
// packages/validator/src/external-content.ts
|
|
48287
|
+
import { isAbsolute as isAbsolute8, relative as relative9, sep as sep6 } from "node:path";
|
|
48288
|
+
function isPathInside(root, candidate) {
|
|
48289
|
+
const relation = relative9(root, candidate);
|
|
48290
|
+
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep6}`) && !isAbsolute8(relation);
|
|
48291
|
+
}
|
|
48292
|
+
function isExternalLocation(loc, config) {
|
|
48293
|
+
if (config.scanExternalContent || !loc) return false;
|
|
48294
|
+
const roots = config.externalRoots;
|
|
48295
|
+
if (!roots || roots.length === 0) return false;
|
|
48296
|
+
return roots.some((root) => isPathInside(root, loc.file));
|
|
48297
|
+
}
|
|
48298
|
+
|
|
47391
48299
|
// packages/validator/src/rules/obfuscated-content.ts
|
|
47392
48300
|
var MIN_ENCODED_LENGTH = 16;
|
|
47393
48301
|
var DECODED_CONTENT_SECURITY_PATTERNS = [
|
|
@@ -47568,6 +48476,19 @@ function isLikelyTechnicalContent(match2) {
|
|
|
47568
48476
|
}
|
|
47569
48477
|
return false;
|
|
47570
48478
|
}
|
|
48479
|
+
var NUCLEOTIDE_CHARS = new Set("ACGTUN");
|
|
48480
|
+
var AMINO_ACID_CHARS = new Set("ACDEFGHIKLMNPQRSTVWYBXZJOU");
|
|
48481
|
+
var BIO_CONTEXT_PATTERN = /\b(?:protein|peptide|amino[-\s]?acid|residue|sequence|nucleotide|genome|transcript|fasta|uniprot)\b/i;
|
|
48482
|
+
function isOverAlphabet(match2, alphabet) {
|
|
48483
|
+
for (const char of match2) {
|
|
48484
|
+
if (!alphabet.has(char)) return false;
|
|
48485
|
+
}
|
|
48486
|
+
return match2.length > 0;
|
|
48487
|
+
}
|
|
48488
|
+
function isLikelyBioSequence(text, match2) {
|
|
48489
|
+
if (isOverAlphabet(match2, NUCLEOTIDE_CHARS)) return true;
|
|
48490
|
+
return isOverAlphabet(match2, AMINO_ACID_CHARS) && BIO_CONTEXT_PATTERN.test(text);
|
|
48491
|
+
}
|
|
47571
48492
|
function isLikelyLegitimateBase64(text, match2) {
|
|
47572
48493
|
const matchIndex = text.indexOf(match2);
|
|
47573
48494
|
if (matchIndex === -1) return false;
|
|
@@ -47576,6 +48497,7 @@ function isLikelyLegitimateBase64(text, match2) {
|
|
|
47576
48497
|
if (precedingText.includes("data:application/json")) return true;
|
|
47577
48498
|
if (precedingText.includes("data:text/")) return true;
|
|
47578
48499
|
if (isLikelyTechnicalContent(match2)) return true;
|
|
48500
|
+
if (isLikelyBioSequence(text, match2)) return true;
|
|
47579
48501
|
return false;
|
|
47580
48502
|
}
|
|
47581
48503
|
function isLikelyHashOrUuid(hex) {
|
|
@@ -47784,12 +48706,16 @@ var obfuscatedContent = {
|
|
|
47784
48706
|
suggestion: "Encoded content is automatically decoded and checked for security patterns. Remove the malicious payload or use plain text."
|
|
47785
48707
|
});
|
|
47786
48708
|
}
|
|
47787
|
-
|
|
48709
|
+
if (isExternalLocation(loc, ctx.config)) {
|
|
48710
|
+
return;
|
|
48711
|
+
}
|
|
48712
|
+
const longBase64Match = (text.match(BASE64_PATTERN) || []).find(
|
|
47788
48713
|
(m) => m.length >= MIN_ENCODED_LENGTH * 2 && !isLikelyLegitimateBase64(text, m)
|
|
47789
48714
|
);
|
|
47790
|
-
if (
|
|
48715
|
+
if (longBase64Match && encodedMatches.length === 0) {
|
|
48716
|
+
const snippet = longBase64Match.length > 20 ? `${longBase64Match.substring(0, 20)}...` : longBase64Match;
|
|
47791
48717
|
ctx.report({
|
|
47792
|
-
message:
|
|
48718
|
+
message: `Long Base64-encoded content detected that may hide payloads (starts with "${snippet}")`,
|
|
47793
48719
|
location: loc,
|
|
47794
48720
|
suggestion: "If this is intentional, consider using plain text or documenting the purpose"
|
|
47795
48721
|
});
|
|
@@ -48697,11 +49623,14 @@ var safeReferenceContent = {
|
|
|
48697
49623
|
const content = res["content"];
|
|
48698
49624
|
if (typeof relPath !== "string" || typeof content !== "string") continue;
|
|
48699
49625
|
if (!relPath.startsWith("references/") && !relPath.includes("/references/")) continue;
|
|
49626
|
+
const origin = res["origin"];
|
|
49627
|
+
const location = typeof origin === "string" ? { file: origin, line: 1, column: 1, offset: 0 } : skillsBlock.loc;
|
|
49628
|
+
if (isExternalLocation(location, ctx.config)) continue;
|
|
48700
49629
|
const match2 = content.match(DIRECTIVE_PATTERN);
|
|
48701
49630
|
if (match2) {
|
|
48702
49631
|
ctx.report({
|
|
48703
49632
|
message: `Reference file "${relPath}" in skill "${skillName}" contains PRS directive '${match2[1]}' \u2014 references should contain data, not instructions`,
|
|
48704
|
-
location
|
|
49633
|
+
location,
|
|
48705
49634
|
suggestion: "Remove PRS directives from reference files. References are data files, not PromptScript source."
|
|
48706
49635
|
});
|
|
48707
49636
|
}
|
|
@@ -50512,18 +51441,18 @@ var SECURITY_STRICT_MULTILINGUAL = {
|
|
|
50512
51441
|
};
|
|
50513
51442
|
|
|
50514
51443
|
// packages/compiler/src/compiler.ts
|
|
50515
|
-
import { dirname as dirname13, isAbsolute as
|
|
51444
|
+
import { dirname as dirname13, isAbsolute as isAbsolute10, join as join13, relative as relative11, resolve as resolve15, sep as sep8 } from "path";
|
|
50516
51445
|
|
|
50517
51446
|
// packages/compiler/src/hook-script-validator.ts
|
|
50518
51447
|
init_src();
|
|
50519
51448
|
init_src4();
|
|
50520
51449
|
import { lstat as lstat7, realpath as realpath4 } from "fs/promises";
|
|
50521
51450
|
import { realpathSync, statSync } from "fs";
|
|
50522
|
-
import { dirname as dirname12, isAbsolute as
|
|
51451
|
+
import { dirname as dirname12, isAbsolute as isAbsolute9, relative as relative10, resolve as resolve14, sep as sep7 } from "path";
|
|
50523
51452
|
var PROJECT_MARKERS = [".promptscript", ".git", "package.json"];
|
|
50524
51453
|
function isInside2(root, candidate) {
|
|
50525
|
-
const relation =
|
|
50526
|
-
return relation === "" || !relation.startsWith(`..${
|
|
51454
|
+
const relation = relative10(root, candidate);
|
|
51455
|
+
return relation === "" || !relation.startsWith(`..${sep7}`) && relation !== ".." && !isAbsolute9(relation);
|
|
50527
51456
|
}
|
|
50528
51457
|
function isProjectMarker(directory, marker) {
|
|
50529
51458
|
const markerPath = resolve14(directory, marker);
|
|
@@ -50561,10 +51490,10 @@ function inferProjectRoot(localPath, configuredProjectRoot, entryPath) {
|
|
|
50561
51490
|
if (markedRoot) return markedRoot;
|
|
50562
51491
|
}
|
|
50563
51492
|
const local = localPath ? resolve14(localPath) : entryPath ? dirname12(resolve14(entryPath)) : process.cwd();
|
|
50564
|
-
const promptScriptDirectory = `${
|
|
50565
|
-
const nestedMarker = `${promptScriptDirectory}${
|
|
51493
|
+
const promptScriptDirectory = `${sep7}.promptscript`;
|
|
51494
|
+
const nestedMarker = `${promptScriptDirectory}${sep7}`;
|
|
50566
51495
|
const nestedIndex = local.indexOf(nestedMarker);
|
|
50567
|
-
if (nestedIndex >= 0) return local.slice(0, nestedIndex) ||
|
|
51496
|
+
if (nestedIndex >= 0) return local.slice(0, nestedIndex) || sep7;
|
|
50568
51497
|
return local.endsWith(promptScriptDirectory) ? dirname12(local) : local;
|
|
50569
51498
|
}
|
|
50570
51499
|
async function validateHookScriptResources(ast, projectRoot) {
|
|
@@ -50632,7 +51561,7 @@ function resolverCacheKey(projectRoot) {
|
|
|
50632
51561
|
function resolveEntryPath(entryPath) {
|
|
50633
51562
|
if (entryPath.startsWith("@")) return entryPath;
|
|
50634
51563
|
const fileName = entryPath.endsWith(".prs") || entryPath.endsWith(".md") ? entryPath : `${entryPath}.prs`;
|
|
50635
|
-
const absolutePath =
|
|
51564
|
+
const absolutePath = isAbsolute10(fileName) ? fileName : resolve15(process.cwd(), fileName);
|
|
50636
51565
|
try {
|
|
50637
51566
|
return realpathSync2.native(absolutePath);
|
|
50638
51567
|
} catch {
|
|
@@ -50686,7 +51615,7 @@ function normalizeOutputDir(dir) {
|
|
|
50686
51615
|
}
|
|
50687
51616
|
function matchesWatchPattern(path2, pattern, baseDir) {
|
|
50688
51617
|
const normalizedPath = path2.replace(/\\/g, "/");
|
|
50689
|
-
const relativePath =
|
|
51618
|
+
const relativePath = relative11(baseDir, path2).replace(/\\/g, "/");
|
|
50690
51619
|
const candidates = [relativePath, normalizedPath].flatMap((candidate) => [
|
|
50691
51620
|
candidate,
|
|
50692
51621
|
candidate.endsWith("/") ? candidate : `${candidate}/`
|
|
@@ -50698,7 +51627,7 @@ function matchesWatchPattern(path2, pattern, baseDir) {
|
|
|
50698
51627
|
return candidates.some((candidate) => minimatch(candidate, pattern, matcherOptions));
|
|
50699
51628
|
}
|
|
50700
51629
|
function absoluteWatchPath(path2, baseDir = process.cwd()) {
|
|
50701
|
-
return
|
|
51630
|
+
return isAbsolute10(path2) ? resolve15(path2) : resolve15(baseDir, path2);
|
|
50702
51631
|
}
|
|
50703
51632
|
function canonicalWatchPath(path2, baseDir = process.cwd()) {
|
|
50704
51633
|
const absolutePath = absoluteWatchPath(path2, baseDir);
|
|
@@ -50721,8 +51650,8 @@ function watchPathKey(path2, baseDir = process.cwd()) {
|
|
|
50721
51650
|
return normalizeWatchPath(canonicalWatchPath(path2, baseDir));
|
|
50722
51651
|
}
|
|
50723
51652
|
function isPathWithin(path2, root) {
|
|
50724
|
-
const relation =
|
|
50725
|
-
return relation === "" || relation !== ".." && !relation.startsWith(`..${
|
|
51653
|
+
const relation = relative11(normalizeWatchPath(root), normalizeWatchPath(path2));
|
|
51654
|
+
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep8}`) && !isAbsolute10(relation);
|
|
50726
51655
|
}
|
|
50727
51656
|
function shouldIncludeSkill(name, config) {
|
|
50728
51657
|
const includeSkills = config?.includeSkills;
|
|
@@ -50877,7 +51806,7 @@ var Compiler = class _Compiler {
|
|
|
50877
51806
|
formatTime: 0,
|
|
50878
51807
|
totalTime: 0
|
|
50879
51808
|
};
|
|
50880
|
-
const sourceLabel =
|
|
51809
|
+
const sourceLabel = isAbsolute10(entryPath) ? relative11(process.cwd(), entryPath) : entryPath;
|
|
50881
51810
|
this.logger.verbose("=== Stage 1: Resolve ===");
|
|
50882
51811
|
const startResolve = Date.now();
|
|
50883
51812
|
let resolved;
|
|
@@ -50921,11 +51850,20 @@ var Compiler = class _Compiler {
|
|
|
50921
51850
|
};
|
|
50922
51851
|
}
|
|
50923
51852
|
const compileErrors = [];
|
|
51853
|
+
const externalRoots = [];
|
|
51854
|
+
const cacheDir = this.options.resolver.cacheDir ?? join13(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/tmp", ".promptscript", "cache");
|
|
51855
|
+
externalRoots.push(cacheDir);
|
|
51856
|
+
if (this.options.resolver.vendorDir) {
|
|
51857
|
+
externalRoots.push(this.options.resolver.vendorDir);
|
|
51858
|
+
}
|
|
51859
|
+
for (const roots of Object.values(this.options.resolver.referenceRoots ?? {})) {
|
|
51860
|
+
externalRoots.push(...roots);
|
|
51861
|
+
}
|
|
51862
|
+
this.validator.updateConfig({ externalRoots });
|
|
50924
51863
|
if (!this.options.ignoreHashes && this.options.resolver.lockfile) {
|
|
50925
51864
|
this.logger.verbose("=== Stage 1.5: Reference Integrity ===");
|
|
50926
51865
|
const registryReferences = /* @__PURE__ */ new Set();
|
|
50927
51866
|
const registryReferencePaths = /* @__PURE__ */ new Map();
|
|
50928
|
-
const cacheDir = this.options.resolver.cacheDir ?? join13(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/tmp", ".promptscript", "cache");
|
|
50929
51867
|
const registryCache = new RegistryCache(cacheDir);
|
|
50930
51868
|
const referenceRoots = [];
|
|
50931
51869
|
for (const [repoUrl, dependency] of Object.entries(
|
|
@@ -50964,8 +51902,8 @@ var Compiler = class _Compiler {
|
|
|
50964
51902
|
if (block.name !== "skills" || block.content.type !== "ObjectContent") continue;
|
|
50965
51903
|
const sourceFile = block.loc.file;
|
|
50966
51904
|
const referenceRoot = sourceFile ? referenceRoots.find((root) => {
|
|
50967
|
-
const relation =
|
|
50968
|
-
return relation === "" || relation !== ".." && !relation.startsWith(`..${
|
|
51905
|
+
const relation = relative11(resolve15(root.path), resolve15(sourceFile));
|
|
51906
|
+
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep8}`) && !isAbsolute10(relation);
|
|
50969
51907
|
}) : void 0;
|
|
50970
51908
|
for (const [, skillValue] of Object.entries(block.content.properties)) {
|
|
50971
51909
|
if (typeof skillValue !== "object" || skillValue === null || !("references" in skillValue))
|
|
@@ -50977,8 +51915,8 @@ var Compiler = class _Compiler {
|
|
|
50977
51915
|
registryReferences.add(ref);
|
|
50978
51916
|
if (sourceFile && referenceRoot) {
|
|
50979
51917
|
const resolvedReference = resolve15(dirname13(sourceFile), ref);
|
|
50980
|
-
const relation =
|
|
50981
|
-
if (relation !== "" && relation !== ".." && !relation.startsWith(`..${
|
|
51918
|
+
const relation = relative11(resolve15(referenceRoot.path), resolvedReference);
|
|
51919
|
+
if (relation !== "" && relation !== ".." && !relation.startsWith(`..${sep8}`) && !isAbsolute10(relation)) {
|
|
50982
51920
|
const sourceReferences = registryReferencePaths.get(sourceFile) ?? /* @__PURE__ */ new Map();
|
|
50983
51921
|
const relativePath = relation.replaceAll("\\", "/");
|
|
50984
51922
|
const referenceKey = `${referenceRoot.repoUrl}\0${relativePath}\0${referenceRoot.version}`;
|
|
@@ -51082,7 +52020,7 @@ var Compiler = class _Compiler {
|
|
|
51082
52020
|
for (const warning of output.warnings ?? []) {
|
|
51083
52021
|
formatWarnings.push({
|
|
51084
52022
|
ruleId: warning.code,
|
|
51085
|
-
ruleName: "target-hook-compatibility",
|
|
52023
|
+
ruleName: warning.ruleName ?? "target-hook-compatibility",
|
|
51086
52024
|
severity: "warning",
|
|
51087
52025
|
message: warning.message,
|
|
51088
52026
|
...warning.suggestion ? { suggestion: warning.suggestion } : {},
|
|
@@ -51284,8 +52222,8 @@ var Compiler = class _Compiler {
|
|
|
51284
52222
|
*/
|
|
51285
52223
|
async watch(entryPath, options = {}) {
|
|
51286
52224
|
const { default: chokidar2 } = await import("chokidar");
|
|
51287
|
-
const { dirname: dirname29, resolve:
|
|
51288
|
-
const baseDir = dirname29(
|
|
52225
|
+
const { dirname: dirname29, resolve: resolve43 } = await import("path");
|
|
52226
|
+
const baseDir = dirname29(resolve43(entryPath));
|
|
51289
52227
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
51290
52228
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
51291
52229
|
const debounceMs = options.debounce ?? 300;
|
|
@@ -51336,7 +52274,7 @@ var Compiler = class _Compiler {
|
|
|
51336
52274
|
".promptscriptrc.yaml",
|
|
51337
52275
|
".promptscriptrc.yml",
|
|
51338
52276
|
"promptscript.lock"
|
|
51339
|
-
].map((fileName) =>
|
|
52277
|
+
].map((fileName) => resolve43(this.watchProjectRoot(entryPath), fileName))
|
|
51340
52278
|
].map((path2) => watchPathKey(path2))
|
|
51341
52279
|
);
|
|
51342
52280
|
let dynamicDependencyPaths = toDependencyMap(this.resolvedDependencyPaths(entryPath));
|
|
@@ -51629,7 +52567,7 @@ var Pager = class {
|
|
|
51629
52567
|
}
|
|
51630
52568
|
return;
|
|
51631
52569
|
}
|
|
51632
|
-
return new Promise((
|
|
52570
|
+
return new Promise((resolve43) => {
|
|
51633
52571
|
const pagerCmd = getPagerCommand();
|
|
51634
52572
|
const [cmd, ...args] = pagerCmd.split(" ");
|
|
51635
52573
|
if (cmd === "less" && !args.includes("-R")) {
|
|
@@ -51637,7 +52575,7 @@ var Pager = class {
|
|
|
51637
52575
|
}
|
|
51638
52576
|
if (!cmd) {
|
|
51639
52577
|
console.log(content);
|
|
51640
|
-
|
|
52578
|
+
resolve43();
|
|
51641
52579
|
return;
|
|
51642
52580
|
}
|
|
51643
52581
|
const pager = spawn2(cmd, args, {
|
|
@@ -51650,17 +52588,17 @@ var Pager = class {
|
|
|
51650
52588
|
});
|
|
51651
52589
|
pager.on("error", (_err) => {
|
|
51652
52590
|
console.log(content);
|
|
51653
|
-
|
|
52591
|
+
resolve43();
|
|
51654
52592
|
});
|
|
51655
52593
|
pager.on("close", () => {
|
|
51656
|
-
|
|
52594
|
+
resolve43();
|
|
51657
52595
|
});
|
|
51658
52596
|
if (pager.stdin) {
|
|
51659
52597
|
pager.stdin.write(content);
|
|
51660
52598
|
pager.stdin.end();
|
|
51661
52599
|
} else {
|
|
51662
52600
|
console.log(content);
|
|
51663
|
-
|
|
52601
|
+
resolve43();
|
|
51664
52602
|
}
|
|
51665
52603
|
});
|
|
51666
52604
|
}
|
|
@@ -51674,14 +52612,14 @@ init_services();
|
|
|
51674
52612
|
|
|
51675
52613
|
// packages/cli/src/utils/registry-resolver.ts
|
|
51676
52614
|
import { existsSync as existsSync12 } from "fs";
|
|
51677
|
-
import { isAbsolute as
|
|
52615
|
+
import { isAbsolute as isAbsolute11, join as join14, relative as relative12, resolve as resolve16, sep as sep9 } from "path";
|
|
51678
52616
|
async function resolveRegistrySubPath(repositoryPath, subPath) {
|
|
51679
52617
|
if (!subPath) {
|
|
51680
52618
|
return repositoryPath;
|
|
51681
52619
|
}
|
|
51682
52620
|
const result = resolve16(repositoryPath, subPath);
|
|
51683
|
-
const relation =
|
|
51684
|
-
if (relation === ".." || relation.startsWith(`..${
|
|
52621
|
+
const relation = relative12(resolve16(repositoryPath), result);
|
|
52622
|
+
if (relation === ".." || relation.startsWith(`..${sep9}`) || isAbsolute11(relation)) {
|
|
51685
52623
|
throw new Error(`Registry path escapes its repository: ${subPath}`);
|
|
51686
52624
|
}
|
|
51687
52625
|
if (existsSync12(result) && !await isRealPathInside(result, repositoryPath)) {
|
|
@@ -51780,6 +52718,7 @@ async function resolveRegistryPath(config, options = {}) {
|
|
|
51780
52718
|
ref,
|
|
51781
52719
|
path: gitConfig.path,
|
|
51782
52720
|
auth: gitConfig.auth,
|
|
52721
|
+
timeout: gitConfig.timeout,
|
|
51783
52722
|
cache: {
|
|
51784
52723
|
enabled: config.registry.cache?.enabled ?? true,
|
|
51785
52724
|
ttl: config.registry.cache?.ttl
|
|
@@ -51839,7 +52778,7 @@ init_src();
|
|
|
51839
52778
|
// packages/cli/src/utils/conflict-detector.ts
|
|
51840
52779
|
init_src();
|
|
51841
52780
|
import * as fs4 from "fs";
|
|
51842
|
-
import { basename as basename13, dirname as dirname14, resolve as resolve17, relative as
|
|
52781
|
+
import { basename as basename13, dirname as dirname14, resolve as resolve17, relative as relative13, isAbsolute as isAbsolute12, sep as sep10 } from "path";
|
|
51843
52782
|
function detectOutputConflicts(targets) {
|
|
51844
52783
|
const pathMap = /* @__PURE__ */ new Map();
|
|
51845
52784
|
for (const target of targets) {
|
|
@@ -51860,14 +52799,14 @@ function detectOutputConflicts(targets) {
|
|
|
51860
52799
|
function validateOutputPath(outputPath, outputRoot) {
|
|
51861
52800
|
const resolved = resolveOutputPath(outputPath, outputRoot);
|
|
51862
52801
|
const root = resolve17(outputRoot);
|
|
51863
|
-
const rel =
|
|
52802
|
+
const rel = relative13(root, resolved);
|
|
51864
52803
|
if (!isPathContained(rel, false)) {
|
|
51865
52804
|
return `Output path "${outputPath}" escapes the output directory ${outputRoot}`;
|
|
51866
52805
|
}
|
|
51867
52806
|
try {
|
|
51868
52807
|
const realRoot = resolveThroughExistingAncestor(root);
|
|
51869
52808
|
const realResolved = resolveThroughExistingAncestor(resolved);
|
|
51870
|
-
if (!isPathContained(
|
|
52809
|
+
if (!isPathContained(relative13(realRoot, realResolved), false)) {
|
|
51871
52810
|
return `Output path "${outputPath}" escapes the output directory ${outputRoot}`;
|
|
51872
52811
|
}
|
|
51873
52812
|
} catch {
|
|
@@ -51876,11 +52815,11 @@ function validateOutputPath(outputPath, outputRoot) {
|
|
|
51876
52815
|
return void 0;
|
|
51877
52816
|
}
|
|
51878
52817
|
function isPathInsideDir(dir, root) {
|
|
51879
|
-
const rel =
|
|
52818
|
+
const rel = relative13(resolve17(root), resolveOutputPath(dir, root));
|
|
51880
52819
|
return isPathContained(rel, true);
|
|
51881
52820
|
}
|
|
51882
52821
|
function isPathContained(rel, allowEqual) {
|
|
51883
|
-
return allowEqual && rel === "" || rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
52822
|
+
return allowEqual && rel === "" || rel !== "" && rel !== ".." && !rel.startsWith(`..${sep10}`) && !isAbsolute12(rel);
|
|
51884
52823
|
}
|
|
51885
52824
|
function resolveThroughExistingAncestor(path2) {
|
|
51886
52825
|
const missingSegments = [];
|
|
@@ -51904,7 +52843,7 @@ function resolveThroughExistingAncestor(path2) {
|
|
|
51904
52843
|
return resolve17(fs4.realpathSync.native(current), ...missingSegments);
|
|
51905
52844
|
}
|
|
51906
52845
|
function resolveOutputPath(outputPath, projectRoot) {
|
|
51907
|
-
if (
|
|
52846
|
+
if (isAbsolute12(outputPath)) {
|
|
51908
52847
|
return outputPath;
|
|
51909
52848
|
}
|
|
51910
52849
|
return resolve17(projectRoot, outputPath);
|
|
@@ -51923,12 +52862,14 @@ import {
|
|
|
51923
52862
|
rmdir,
|
|
51924
52863
|
unlink as unlink2
|
|
51925
52864
|
} from "node:fs/promises";
|
|
51926
|
-
import { basename as basename14, dirname as dirname15, isAbsolute as
|
|
52865
|
+
import { basename as basename14, dirname as dirname15, isAbsolute as isAbsolute13, relative as relative14, resolve as resolve18 } from "node:path";
|
|
51927
52866
|
import { promisify as promisify2 } from "node:util";
|
|
51928
52867
|
var execFileAsync2 = promisify2(execFile2);
|
|
51929
52868
|
var PROMPTSCRIPT_MARKER_PATTERNS = [
|
|
51930
52869
|
/^<!-- PromptScript \d{4}-\d{2}-\d{2}T[\d:.]+Z \| source: .+ \| target: .+ - do not edit -->$/,
|
|
51931
52870
|
/^# promptscript-generated: \d{4}-\d{2}-\d{2}T[\d:.]+Z \| source: .+ \| target: .+$/,
|
|
52871
|
+
/^\/\/ promptscript-generated: opencode-plugin$/,
|
|
52872
|
+
/^\/\/ Generated by PromptScript - do not edit\.$/,
|
|
51932
52873
|
/^> Auto-generated by PromptScript(?:\s.*)?$/
|
|
51933
52874
|
];
|
|
51934
52875
|
var OWNED_COMMAND_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -52256,7 +53197,7 @@ function collectManagedDirectories(outputs, outputRoot) {
|
|
|
52256
53197
|
for (const output of outputs.values()) {
|
|
52257
53198
|
for (const directory of output.managedOutputDirectories ?? []) {
|
|
52258
53199
|
const normalized = directory.replace(/\\/g, "/");
|
|
52259
|
-
if (!normalized ||
|
|
53200
|
+
if (!normalized || isAbsolute13(normalized)) continue;
|
|
52260
53201
|
if (normalized.split("/").some((segment) => segment === "..")) continue;
|
|
52261
53202
|
const absolutePath = resolve18(outputRoot, normalized);
|
|
52262
53203
|
if (isWithin(outputRoot, absolutePath)) directories.add(absolutePath);
|
|
@@ -52277,7 +53218,7 @@ function collectManagedFiles(outputs, outputRoot) {
|
|
|
52277
53218
|
for (const output of outputs.values()) {
|
|
52278
53219
|
for (const file of output.managedOutputFiles ?? []) {
|
|
52279
53220
|
const normalized = file.replace(/\\/g, "/");
|
|
52280
|
-
if (!normalized ||
|
|
53221
|
+
if (!normalized || isAbsolute13(normalized)) continue;
|
|
52281
53222
|
if (normalized.split("/").some((segment) => segment === "..")) continue;
|
|
52282
53223
|
const absolutePath = resolve18(outputRoot, normalized);
|
|
52283
53224
|
if (isWithin(outputRoot, absolutePath)) files.add(absolutePath);
|
|
@@ -52540,7 +53481,7 @@ async function removeIfUnchanged(entryPath, fileStat) {
|
|
|
52540
53481
|
return true;
|
|
52541
53482
|
}
|
|
52542
53483
|
async function openAncestorDirectories(root, directory) {
|
|
52543
|
-
const relativePath =
|
|
53484
|
+
const relativePath = relative14(root, directory);
|
|
52544
53485
|
const segments = relativePath === "" ? [] : relativePath.split(/[\\/]+/);
|
|
52545
53486
|
const paths = [root];
|
|
52546
53487
|
let current = root;
|
|
@@ -52564,8 +53505,8 @@ async function openAncestorDirectories(root, directory) {
|
|
|
52564
53505
|
return guards;
|
|
52565
53506
|
}
|
|
52566
53507
|
async function openOrCreateAncestorDirectories(root, file) {
|
|
52567
|
-
const relativePath =
|
|
52568
|
-
if (relativePath.startsWith("..") ||
|
|
53508
|
+
const relativePath = relative14(root, file);
|
|
53509
|
+
if (relativePath.startsWith("..") || isAbsolute13(relativePath)) {
|
|
52569
53510
|
return void 0;
|
|
52570
53511
|
}
|
|
52571
53512
|
await mkdir4(root, { recursive: true });
|
|
@@ -53015,8 +53956,8 @@ function scanHookOwnership(value) {
|
|
|
53015
53956
|
return scanHookOwnership(Object.values(object));
|
|
53016
53957
|
}
|
|
53017
53958
|
function isWithin(root, candidate) {
|
|
53018
|
-
const relativePath =
|
|
53019
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
53959
|
+
const relativePath = relative14(root, candidate);
|
|
53960
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute13(relativePath);
|
|
53020
53961
|
}
|
|
53021
53962
|
function isNodeError(error) {
|
|
53022
53963
|
return error instanceof Error && "code" in error;
|
|
@@ -53057,6 +53998,8 @@ async function loadBundledSkillContent(logger) {
|
|
|
53057
53998
|
var PROMPTSCRIPT_MARKERS2 = [
|
|
53058
53999
|
"<!-- PromptScript",
|
|
53059
54000
|
"# promptscript-generated:",
|
|
54001
|
+
"// promptscript-generated:",
|
|
54002
|
+
"// Generated by PromptScript - do not edit.",
|
|
53060
54003
|
"> Auto-generated by PromptScript"
|
|
53061
54004
|
];
|
|
53062
54005
|
function hasPromptScriptMarker(content) {
|
|
@@ -53246,11 +54189,77 @@ async function finalizeOutputPlan(result, options) {
|
|
|
53246
54189
|
};
|
|
53247
54190
|
}
|
|
53248
54191
|
|
|
54192
|
+
// packages/cli/src/utils/resource-filter.ts
|
|
54193
|
+
init_src();
|
|
54194
|
+
function collectResourceKinds(value, previous) {
|
|
54195
|
+
return [...previous, ...value.split(",").map((item) => item.trim())].filter(Boolean);
|
|
54196
|
+
}
|
|
54197
|
+
function parseResourceSelection(values) {
|
|
54198
|
+
if (!values || values.length === 0) return { kinds: [], invalid: [] };
|
|
54199
|
+
const kinds = [];
|
|
54200
|
+
const invalid = [];
|
|
54201
|
+
for (const raw of values.flatMap((value) => value.split(","))) {
|
|
54202
|
+
const item = raw.trim();
|
|
54203
|
+
if (!item) continue;
|
|
54204
|
+
if (isOutputResourceKind(item)) {
|
|
54205
|
+
if (!kinds.includes(item)) kinds.push(item);
|
|
54206
|
+
} else if (!invalid.includes(item)) {
|
|
54207
|
+
invalid.push(item);
|
|
54208
|
+
}
|
|
54209
|
+
}
|
|
54210
|
+
return { kinds, invalid };
|
|
54211
|
+
}
|
|
54212
|
+
function filterOutputsByResources(plan, outputs, kinds, skillBaseDirs) {
|
|
54213
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
54214
|
+
for (const file of plan.files) {
|
|
54215
|
+
if (!kinds.has(classifyOutputResource(file.owner, file.path, skillBaseDirs?.get(file.owner)))) {
|
|
54216
|
+
continue;
|
|
54217
|
+
}
|
|
54218
|
+
const existing = outputs.get(file.path);
|
|
54219
|
+
filtered.set(
|
|
54220
|
+
file.path,
|
|
54221
|
+
existing ?? {
|
|
54222
|
+
path: file.path,
|
|
54223
|
+
content: file.content,
|
|
54224
|
+
...file.mode !== void 0 ? { mode: file.mode } : {},
|
|
54225
|
+
...file.merge !== void 0 ? { merge: file.merge } : {},
|
|
54226
|
+
...file.managedOutputDirectories !== void 0 ? { managedOutputDirectories: file.managedOutputDirectories } : {},
|
|
54227
|
+
...file.managedOutputFiles !== void 0 ? { managedOutputFiles: file.managedOutputFiles } : {}
|
|
54228
|
+
}
|
|
54229
|
+
);
|
|
54230
|
+
}
|
|
54231
|
+
return {
|
|
54232
|
+
outputs: filtered,
|
|
54233
|
+
kept: filtered.size,
|
|
54234
|
+
dropped: plan.files.length - filtered.size
|
|
54235
|
+
};
|
|
54236
|
+
}
|
|
54237
|
+
|
|
54238
|
+
// packages/cli/src/utils/global-output-safety.ts
|
|
54239
|
+
import { homedir as homedir3 } from "node:os";
|
|
54240
|
+
import { resolve as resolve21 } from "node:path";
|
|
54241
|
+
var PROTECTED_USER_FILES = [
|
|
54242
|
+
{
|
|
54243
|
+
// Factory AI contract: ~/.factory/AGENTS.md is a personal override file.
|
|
54244
|
+
path: ".factory/AGENTS.md",
|
|
54245
|
+
reason: "Factory personal override (~/.factory/AGENTS.md is user-owned, never compiler output)"
|
|
54246
|
+
}
|
|
54247
|
+
];
|
|
54248
|
+
function describeProtectedUserFile(absolutePath) {
|
|
54249
|
+
const home = homedir3();
|
|
54250
|
+
for (const entry of PROTECTED_USER_FILES) {
|
|
54251
|
+
if (absolutePath === resolve21(home, entry.path)) {
|
|
54252
|
+
return { displayPath: `~/${entry.path}`, reason: entry.reason };
|
|
54253
|
+
}
|
|
54254
|
+
}
|
|
54255
|
+
return void 0;
|
|
54256
|
+
}
|
|
54257
|
+
|
|
53249
54258
|
// packages/cli/src/commands/compile.ts
|
|
53250
54259
|
init_build_profile();
|
|
53251
54260
|
init_target_config();
|
|
53252
54261
|
async function loadCompileLockfile(projectRoot, logger) {
|
|
53253
|
-
const lockfilePath =
|
|
54262
|
+
const lockfilePath = resolve22(projectRoot, "promptscript.lock");
|
|
53254
54263
|
if (!existsSync14(lockfilePath)) {
|
|
53255
54264
|
return void 0;
|
|
53256
54265
|
}
|
|
@@ -53268,7 +54277,7 @@ async function loadCompileLockfile(projectRoot, logger) {
|
|
|
53268
54277
|
}
|
|
53269
54278
|
function findConfigInDir(dir) {
|
|
53270
54279
|
for (const file of CONFIG_FILES) {
|
|
53271
|
-
const fullPath =
|
|
54280
|
+
const fullPath = resolve22(dir, file);
|
|
53272
54281
|
if (existsSync14(fullPath)) {
|
|
53273
54282
|
return fullPath;
|
|
53274
54283
|
}
|
|
@@ -53309,19 +54318,19 @@ function describeEmptyTargets(context) {
|
|
|
53309
54318
|
}
|
|
53310
54319
|
function resolveOutputBase(projectRoot, output) {
|
|
53311
54320
|
if (!output) return projectRoot;
|
|
53312
|
-
return
|
|
54321
|
+
return isAbsolute14(output) ? output : resolve22(projectRoot, output);
|
|
53313
54322
|
}
|
|
53314
54323
|
function resolveProjectPath(projectRoot, path2) {
|
|
53315
|
-
return
|
|
54324
|
+
return isAbsolute14(path2) ? path2 : resolve22(projectRoot, path2);
|
|
53316
54325
|
}
|
|
53317
54326
|
function validateWritePathSymlinks(outputPath, outputRoot) {
|
|
53318
|
-
const root =
|
|
53319
|
-
const candidate =
|
|
53320
|
-
const relativePath =
|
|
53321
|
-
if (relativePath === "" || relativePath.startsWith("..") ||
|
|
54327
|
+
const root = resolve22(outputRoot);
|
|
54328
|
+
const candidate = resolve22(root, outputPath);
|
|
54329
|
+
const relativePath = relative15(root, candidate);
|
|
54330
|
+
if (relativePath === "" || relativePath.startsWith("..") || isAbsolute14(relativePath)) return;
|
|
53322
54331
|
let current = root;
|
|
53323
54332
|
for (const segment of relativePath.split(/[\\/]/)) {
|
|
53324
|
-
current =
|
|
54333
|
+
current = resolve22(current, segment);
|
|
53325
54334
|
let stat5;
|
|
53326
54335
|
try {
|
|
53327
54336
|
stat5 = lstatSync2(current);
|
|
@@ -53452,10 +54461,21 @@ ${escaping.map((m) => ` - ${m}`).join("\n")}`,
|
|
|
53452
54461
|
"PS1003" /* INVALID_PATH */
|
|
53453
54462
|
);
|
|
53454
54463
|
}
|
|
54464
|
+
const protectedHits = plannedOutputs.map((output) => describeProtectedUserFile(resolve22(outputRoot, output.path))).filter((hit) => hit !== void 0);
|
|
54465
|
+
if (protectedHits.length > 0) {
|
|
54466
|
+
const protectedList = protectedHits.map((hit) => ` - ${hit.displayPath} (${hit.reason})`).join("\n");
|
|
54467
|
+
throw new PSError(
|
|
54468
|
+
`Refusing to write protected personal file(s):
|
|
54469
|
+
${protectedList}
|
|
54470
|
+
|
|
54471
|
+
Personal override files are never compiler output. Use --resources to install generated agent and skill directories only.`,
|
|
54472
|
+
"PS1003" /* INVALID_PATH */
|
|
54473
|
+
);
|
|
54474
|
+
}
|
|
53455
54475
|
if (!options.dryRun && !options.force && !isTTY()) {
|
|
53456
54476
|
const preflightConflicts = [];
|
|
53457
54477
|
for (const output of plannedOutputs) {
|
|
53458
|
-
const outputPath = options.output ?
|
|
54478
|
+
const outputPath = options.output ? resolve22(options.output, output.path) : resolve22(output.path);
|
|
53459
54479
|
if (!existsSync14(outputPath)) continue;
|
|
53460
54480
|
const existingContent = await readFileOrUndefined(outputPath);
|
|
53461
54481
|
const contentMatches = existingContent !== void 0 && stripPromptScriptMarkers(existingContent) === stripPromptScriptMarkers(output.content);
|
|
@@ -53480,7 +54500,7 @@ Use --force to overwrite these files.`
|
|
|
53480
54500
|
}
|
|
53481
54501
|
}
|
|
53482
54502
|
async function safeOverwrite(output, outputPath, existingContent, content) {
|
|
53483
|
-
const outputRoot2 = options.output ?
|
|
54503
|
+
const outputRoot2 = options.output ? resolve22(options.output) : process.cwd();
|
|
53484
54504
|
const rewritten = existingContent !== void 0 && await rewriteHookOutputIfUnchanged(
|
|
53485
54505
|
outputPath,
|
|
53486
54506
|
outputRoot2,
|
|
@@ -53496,7 +54516,7 @@ Use --force to overwrite these files.`
|
|
|
53496
54516
|
return rewritten;
|
|
53497
54517
|
}
|
|
53498
54518
|
async function safeCreate(output, outputPath, content) {
|
|
53499
|
-
const outputRoot2 = options.output ?
|
|
54519
|
+
const outputRoot2 = options.output ? resolve22(options.output) : process.cwd();
|
|
53500
54520
|
const created = await createHookOutputSafely(outputPath, outputRoot2, content, output.mode);
|
|
53501
54521
|
if (!created) {
|
|
53502
54522
|
const msg = `Skipped '${outputPath}' because its output path was not safe to create.`;
|
|
@@ -53506,7 +54526,7 @@ Use --force to overwrite these files.`
|
|
|
53506
54526
|
return created;
|
|
53507
54527
|
}
|
|
53508
54528
|
for (const output of plannedOutputs) {
|
|
53509
|
-
const outputPath = options.output ?
|
|
54529
|
+
const outputPath = options.output ? resolve22(options.output, output.path) : resolve22(output.path);
|
|
53510
54530
|
const fileExists3 = existsSync14(outputPath);
|
|
53511
54531
|
const existingContent = fileExists3 ? await readFileOrUndefined(outputPath) : void 0;
|
|
53512
54532
|
const existingHookOutputOwned = existingContent !== void 0 && isPromptScriptOwnedHookOutput(output.path, existingContent);
|
|
@@ -53543,7 +54563,7 @@ Use --force to overwrite these files.`
|
|
|
53543
54563
|
if (output.mode !== void 0 && existingContent !== void 0) {
|
|
53544
54564
|
const modeUpdated = await rewriteHookOutputIfUnchanged(
|
|
53545
54565
|
outputPath,
|
|
53546
|
-
options.output ?
|
|
54566
|
+
options.output ? resolve22(options.output) : process.cwd(),
|
|
53547
54567
|
existingContent,
|
|
53548
54568
|
existingContent,
|
|
53549
54569
|
output.mode
|
|
@@ -53639,7 +54659,7 @@ function printWarnings(warnings) {
|
|
|
53639
54659
|
}
|
|
53640
54660
|
async function compileAllBuilds(options, services) {
|
|
53641
54661
|
const logger = createCliLogger();
|
|
53642
|
-
const projectRoot = options.cwd ?
|
|
54662
|
+
const projectRoot = options.cwd ? resolve22(options.cwd) : process.cwd();
|
|
53643
54663
|
const configPath = resolveCompileConfigPath(projectRoot, options);
|
|
53644
54664
|
const config = await loadEffectiveConfig(configPath);
|
|
53645
54665
|
const buildNames = Object.keys(getBuildProfiles(config));
|
|
@@ -53713,7 +54733,7 @@ async function compileCommandWithResult(options, services) {
|
|
|
53713
54733
|
const spinner = createSpinner("Loading configuration...").start();
|
|
53714
54734
|
const logger = createCliLogger();
|
|
53715
54735
|
try {
|
|
53716
|
-
const projectRoot = options.cwd ?
|
|
54736
|
+
const projectRoot = options.cwd ? resolve22(options.cwd) : process.cwd();
|
|
53717
54737
|
logger.verbose("Loading configuration...");
|
|
53718
54738
|
const configPath = resolveCompileConfigPath(projectRoot, options);
|
|
53719
54739
|
const config = await loadEffectiveConfig(configPath);
|
|
@@ -53728,6 +54748,17 @@ async function compileCommandWithResult(options, services) {
|
|
|
53728
54748
|
} else {
|
|
53729
54749
|
targets = parsedTargets;
|
|
53730
54750
|
}
|
|
54751
|
+
const cliResources = options.resources && options.resources.length > 0 ? options.resources : void 0;
|
|
54752
|
+
const resourceSelection = parseResourceSelection(cliResources ?? config.output?.resources);
|
|
54753
|
+
if (resourceSelection.invalid.length > 0) {
|
|
54754
|
+
spinner.fail("Invalid resource selection");
|
|
54755
|
+
ConsoleOutput.error(
|
|
54756
|
+
`Unknown resource kind(s): ${resourceSelection.invalid.join(", ")}. Valid kinds: agents, skills, commands, mcp, hooks, plugins, main.`
|
|
54757
|
+
);
|
|
54758
|
+
process.exitCode = 1;
|
|
54759
|
+
return false;
|
|
54760
|
+
}
|
|
54761
|
+
const resourceKinds = new Set(resourceSelection.kinds);
|
|
53731
54762
|
if (targets.length === 0) {
|
|
53732
54763
|
spinner.fail("No compilation targets");
|
|
53733
54764
|
ConsoleOutput.error(
|
|
@@ -53762,7 +54793,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53762
54793
|
}
|
|
53763
54794
|
}
|
|
53764
54795
|
const lockfile = await loadCompileLockfile(projectRoot, logger);
|
|
53765
|
-
const vendorDir =
|
|
54796
|
+
const vendorDir = resolve22(projectRoot, ".promptscript/vendor");
|
|
53766
54797
|
let registryPath;
|
|
53767
54798
|
let referenceRoots;
|
|
53768
54799
|
if (options.registry) {
|
|
@@ -53784,7 +54815,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53784
54815
|
if (config.includePromptScriptSkill !== false) {
|
|
53785
54816
|
skillContent = await loadBundledSkillContent(logger);
|
|
53786
54817
|
}
|
|
53787
|
-
const localPath =
|
|
54818
|
+
const localPath = resolve22(projectRoot, ".promptscript");
|
|
53788
54819
|
const compiler = new Compiler({
|
|
53789
54820
|
resolver: {
|
|
53790
54821
|
registryPath,
|
|
@@ -53806,7 +54837,7 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53806
54837
|
ignoreHashes: options.ignoreHashes
|
|
53807
54838
|
});
|
|
53808
54839
|
const entry = buildProfile?.entry ?? config.input?.entry;
|
|
53809
|
-
const entryPath = entry ?
|
|
54840
|
+
const entryPath = entry ? resolve22(projectRoot, entry) : resolve22(localPath, "project.prs");
|
|
53810
54841
|
if (!existsSync14(entryPath)) {
|
|
53811
54842
|
spinner.fail("Entry file not found");
|
|
53812
54843
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
@@ -53838,8 +54869,13 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53838
54869
|
output: resolveOutputBase(projectRoot, configuredOutput),
|
|
53839
54870
|
force: options.force ?? config.output?.overwrite
|
|
53840
54871
|
};
|
|
54872
|
+
if (resourceKinds.size === 0 && effectiveOptions.output === homedir4()) {
|
|
54873
|
+
ConsoleOutput.warning(
|
|
54874
|
+
`Output directory is your home directory; root instruction files (for example CLAUDE.md, AGENTS.md) will be written there. Use --resources to install only generated agent and skill directories.`
|
|
54875
|
+
);
|
|
54876
|
+
}
|
|
53841
54877
|
const hasFactoryTarget = targets.some((target) => target.name === "factory");
|
|
53842
|
-
const migrateFactoryHooks = options.migrateFactoryHooks !== false;
|
|
54878
|
+
const migrateFactoryHooks = options.migrateFactoryHooks !== false && resourceKinds.size === 0;
|
|
53843
54879
|
const legacyMigration = hasFactoryTarget && migrateFactoryHooks ? await prepareLegacyFactoryMigration(result.outputs, effectiveOptions.output) : void 0;
|
|
53844
54880
|
const legacySettingsPath = hasFactoryTarget && !migrateFactoryHooks ? await detectLegacyFactorySettingsHooks(effectiveOptions.output, true) : void 0;
|
|
53845
54881
|
const finalized = await finalizeOutputPlan(result, {
|
|
@@ -53848,7 +54884,26 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53848
54884
|
logger,
|
|
53849
54885
|
additionalOutputPaths: legacyMigration ? [".factory/hooks.json"] : []
|
|
53850
54886
|
});
|
|
53851
|
-
|
|
54887
|
+
let effectiveOutputs = finalized.outputs;
|
|
54888
|
+
if (resourceKinds.size > 0) {
|
|
54889
|
+
const skillBaseDirs = /* @__PURE__ */ new Map();
|
|
54890
|
+
for (const target of targets) {
|
|
54891
|
+
if (target.config?.skillBaseDir) {
|
|
54892
|
+
skillBaseDirs.set(target.name, target.config.skillBaseDir);
|
|
54893
|
+
}
|
|
54894
|
+
}
|
|
54895
|
+
const filtered = filterOutputsByResources(
|
|
54896
|
+
finalized.outputPlan,
|
|
54897
|
+
finalized.outputs,
|
|
54898
|
+
resourceKinds,
|
|
54899
|
+
skillBaseDirs
|
|
54900
|
+
);
|
|
54901
|
+
effectiveOutputs = filtered.outputs;
|
|
54902
|
+
ConsoleOutput.info(
|
|
54903
|
+
`Resource-only compile: kept ${filtered.kept} file(s), omitted ${filtered.dropped}`
|
|
54904
|
+
);
|
|
54905
|
+
}
|
|
54906
|
+
const writeResult = await writeOutputs(effectiveOutputs, effectiveOptions, config, services);
|
|
53852
54907
|
if (legacyMigration) {
|
|
53853
54908
|
if (writeResult.skipped.includes(legacyMigration.hooksPath)) {
|
|
53854
54909
|
throw new Error(
|
|
@@ -53862,30 +54917,38 @@ Disable one of the conflicting targets or assign a custom output path.`
|
|
|
53862
54917
|
writeResult.created.includes(legacyMigration.hooksPath)
|
|
53863
54918
|
);
|
|
53864
54919
|
}
|
|
53865
|
-
|
|
53866
|
-
const cleanupResult = await cleanupManagedOutputs(plannedOutputMap, {
|
|
53867
|
-
outputRoot: effectiveOptions.output,
|
|
53868
|
-
dryRun: options.dryRun
|
|
53869
|
-
});
|
|
53870
|
-
for (const removedPath of cleanupResult.removed) {
|
|
54920
|
+
if (resourceKinds.size > 0) {
|
|
53871
54921
|
if (options.dryRun) {
|
|
53872
|
-
ConsoleOutput.dryRun(
|
|
54922
|
+
ConsoleOutput.dryRun("Would skip managed cleanup for resource-only compile");
|
|
53873
54923
|
} else {
|
|
53874
|
-
ConsoleOutput.muted(
|
|
54924
|
+
ConsoleOutput.muted("Skipped managed cleanup for resource-only compile");
|
|
53875
54925
|
}
|
|
53876
|
-
}
|
|
53877
|
-
|
|
53878
|
-
|
|
53879
|
-
|
|
53880
|
-
|
|
53881
|
-
|
|
54926
|
+
} else {
|
|
54927
|
+
const plannedOutputMap = new Map(finalized.outputs);
|
|
54928
|
+
const cleanupResult = await cleanupManagedOutputs(plannedOutputMap, {
|
|
54929
|
+
outputRoot: effectiveOptions.output,
|
|
54930
|
+
dryRun: options.dryRun
|
|
54931
|
+
});
|
|
54932
|
+
for (const removedPath of cleanupResult.removed) {
|
|
54933
|
+
if (options.dryRun) {
|
|
54934
|
+
ConsoleOutput.dryRun(`Would remove obsolete generated file: ${removedPath}`);
|
|
54935
|
+
} else {
|
|
54936
|
+
ConsoleOutput.muted(`Removed obsolete generated file: ${removedPath}`);
|
|
54937
|
+
}
|
|
53882
54938
|
}
|
|
53883
|
-
|
|
53884
|
-
|
|
53885
|
-
|
|
53886
|
-
|
|
53887
|
-
|
|
53888
|
-
|
|
54939
|
+
for (const removedDirectory of cleanupResult.removedDirectories) {
|
|
54940
|
+
if (options.dryRun) {
|
|
54941
|
+
ConsoleOutput.dryRun(`Would remove empty managed directory: ${removedDirectory}`);
|
|
54942
|
+
} else {
|
|
54943
|
+
ConsoleOutput.muted(`Removed empty managed directory: ${removedDirectory}`);
|
|
54944
|
+
}
|
|
54945
|
+
}
|
|
54946
|
+
for (const rewrittenPath of cleanupResult.rewritten ?? []) {
|
|
54947
|
+
if (options.dryRun) {
|
|
54948
|
+
ConsoleOutput.dryRun(`Would rewrite mixed managed hook file: ${rewrittenPath}`);
|
|
54949
|
+
} else {
|
|
54950
|
+
ConsoleOutput.muted(`Rewrote mixed managed hook file: ${rewrittenPath}`);
|
|
54951
|
+
}
|
|
53889
54952
|
}
|
|
53890
54953
|
}
|
|
53891
54954
|
spinner.succeed("Compilation successful");
|
|
@@ -53953,10 +55016,10 @@ function watchForChanges(projectRoot, watchConfig, callback) {
|
|
|
53953
55016
|
const includePatterns = watchConfig?.include ?? DEFAULT_WATCH_INCLUDE;
|
|
53954
55017
|
const excludePatterns = watchConfig?.exclude ?? DEFAULT_WATCH_EXCLUDE;
|
|
53955
55018
|
const matcherOptions = { dot: true, nocase: process.platform === "win32" };
|
|
53956
|
-
const relativePath = (path2) =>
|
|
55019
|
+
const relativePath = (path2) => relative15(projectRoot, path2).replace(/\\/g, "/");
|
|
53957
55020
|
const matches = (path2, patterns) => {
|
|
53958
|
-
const
|
|
53959
|
-
return patterns.some((pattern) => minimatch(
|
|
55021
|
+
const relative24 = relativePath(path2);
|
|
55022
|
+
return patterns.some((pattern) => minimatch(relative24, pattern, matcherOptions));
|
|
53960
55023
|
};
|
|
53961
55024
|
const shouldCompile = (path2) => matches(path2, includePatterns) && !matches(path2, excludePatterns);
|
|
53962
55025
|
const watcher = chokidar.watch(projectRoot, {
|
|
@@ -54030,7 +55093,7 @@ function watchForChanges(projectRoot, watchConfig, callback) {
|
|
|
54030
55093
|
// packages/cli/src/commands/validate.ts
|
|
54031
55094
|
init_loader2();
|
|
54032
55095
|
init_console();
|
|
54033
|
-
import { resolve as
|
|
55096
|
+
import { resolve as resolve23, join as join15 } from "path";
|
|
54034
55097
|
import { existsSync as existsSync15, readFileSync as readFileSync4, writeFileSync, readdirSync } from "fs";
|
|
54035
55098
|
init_src();
|
|
54036
55099
|
init_src2();
|
|
@@ -54219,7 +55282,7 @@ function discoverPrsFiles(dir, strict = false, includeSymbolicLinks = false) {
|
|
|
54219
55282
|
return results;
|
|
54220
55283
|
}
|
|
54221
55284
|
function loadValidationLockfile() {
|
|
54222
|
-
const lockfilePath =
|
|
55285
|
+
const lockfilePath = resolve23("promptscript.lock");
|
|
54223
55286
|
if (!existsSync15(lockfilePath)) {
|
|
54224
55287
|
return void 0;
|
|
54225
55288
|
}
|
|
@@ -54242,7 +55305,7 @@ async function validateCommand2(options) {
|
|
|
54242
55305
|
try {
|
|
54243
55306
|
const config = await loadConfig();
|
|
54244
55307
|
const lockfile = loadValidationLockfile();
|
|
54245
|
-
const vendorDir =
|
|
55308
|
+
const vendorDir = resolve23(".promptscript/vendor");
|
|
54246
55309
|
if (!isJsonFormat) spinner.text = "Resolving registry...";
|
|
54247
55310
|
const registry2 = await resolveRegistryPath(config, { vendorDir, lockfile });
|
|
54248
55311
|
if (!isJsonFormat) spinner.text = "Validating...";
|
|
@@ -54264,7 +55327,7 @@ async function validateCommand2(options) {
|
|
|
54264
55327
|
formatters: []
|
|
54265
55328
|
// No formatters needed for validation only
|
|
54266
55329
|
});
|
|
54267
|
-
const entryPaths = options.files && options.files.length > 0 ? options.files.map((file) =>
|
|
55330
|
+
const entryPaths = options.files && options.files.length > 0 ? options.files.map((file) => resolve23(file)) : [resolve23(config.input?.entry ?? "./.promptscript/project.prs")];
|
|
54268
55331
|
for (const entryPath of entryPaths) {
|
|
54269
55332
|
if (!existsSync15(entryPath)) {
|
|
54270
55333
|
handleEntryNotFound(entryPath, isJsonFormat, spinner);
|
|
@@ -54317,16 +55380,16 @@ function outputJsonResult(result) {
|
|
|
54317
55380
|
console.log(JSON.stringify(result, null, 2));
|
|
54318
55381
|
}
|
|
54319
55382
|
async function runFix(requestedFiles) {
|
|
54320
|
-
const files = requestedFiles && requestedFiles.length > 0 ? requestedFiles.map((file) =>
|
|
55383
|
+
const files = requestedFiles && requestedFiles.length > 0 ? requestedFiles.map((file) => resolve23(file)) : discoverPrsFiles(".promptscript");
|
|
54321
55384
|
let fixedCount = 0;
|
|
54322
55385
|
const configPath = findConfigFile();
|
|
54323
55386
|
const config = configPath ? await loadConfig(configPath) : void 0;
|
|
54324
55387
|
const lockfile = loadValidationLockfile();
|
|
54325
|
-
const vendorDir =
|
|
54326
|
-
const registryPath = config ? (await resolveRegistryPath(config, { vendorDir, lockfile })).path :
|
|
55388
|
+
const vendorDir = resolve23(".promptscript/vendor");
|
|
55389
|
+
const registryPath = config ? (await resolveRegistryPath(config, { vendorDir, lockfile })).path : resolve23("./registry");
|
|
54327
55390
|
const resolver = new Resolver({
|
|
54328
55391
|
registryPath,
|
|
54329
|
-
localPath:
|
|
55392
|
+
localPath: resolve23("./.promptscript"),
|
|
54330
55393
|
vendorDir,
|
|
54331
55394
|
lockfile,
|
|
54332
55395
|
registries: config?.registries,
|
|
@@ -54340,7 +55403,7 @@ async function runFix(requestedFiles) {
|
|
|
54340
55403
|
if (typeof declaredVersion !== "string") continue;
|
|
54341
55404
|
let ast = parseResult.ast;
|
|
54342
55405
|
try {
|
|
54343
|
-
const resolved = await resolver.resolve(
|
|
55406
|
+
const resolved = await resolver.resolve(resolve23(filePath));
|
|
54344
55407
|
ast = resolved.ast ?? ast;
|
|
54345
55408
|
} catch {
|
|
54346
55409
|
}
|
|
@@ -54389,7 +55452,7 @@ init_loader2();
|
|
|
54389
55452
|
init_console();
|
|
54390
55453
|
import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
|
|
54391
55454
|
import { existsSync as existsSync16 } from "fs";
|
|
54392
|
-
import { resolve as
|
|
55455
|
+
import { resolve as resolve24, dirname as dirname17, relative as relative16 } from "path";
|
|
54393
55456
|
async function pullCommand(options) {
|
|
54394
55457
|
const spinner = createSpinner("Loading configuration...").start();
|
|
54395
55458
|
try {
|
|
@@ -54409,10 +55472,10 @@ async function pullCommand(options) {
|
|
|
54409
55472
|
spinner.text = `Pulling ${config.inherit}...`;
|
|
54410
55473
|
const registry2 = await createRegistry(config, options, spinner);
|
|
54411
55474
|
const inheritPath = parseInheritPath(config.inherit);
|
|
54412
|
-
const destinationRoot =
|
|
54413
|
-
const destPath =
|
|
54414
|
-
const destinationRelativePath =
|
|
54415
|
-
if (destinationRelativePath.startsWith("..") ||
|
|
55475
|
+
const destinationRoot = resolve24("./.promptscript/.inherited");
|
|
55476
|
+
const destPath = resolve24(destinationRoot, inheritPath);
|
|
55477
|
+
const destinationRelativePath = relative16(destinationRoot, destPath);
|
|
55478
|
+
if (destinationRelativePath.startsWith("..") || resolve24(destPath) === resolve24(destinationRoot)) {
|
|
54416
55479
|
throw new Error(`Invalid inheritance path: ${config.inherit}`);
|
|
54417
55480
|
}
|
|
54418
55481
|
if (options.dryRun) {
|
|
@@ -54460,6 +55523,8 @@ async function createRegistry(config, options, spinner) {
|
|
|
54460
55523
|
ref: gitRef ?? gitConfig.ref,
|
|
54461
55524
|
path: gitConfig.path,
|
|
54462
55525
|
auth: gitConfig.auth,
|
|
55526
|
+
timeout: gitConfig.timeout,
|
|
55527
|
+
fallbackUrl: gitConfig.fallbackUrl,
|
|
54463
55528
|
cache: {
|
|
54464
55529
|
enabled: !options.refresh && (config.registry.cache?.enabled ?? true),
|
|
54465
55530
|
ttl: config.registry.cache?.ttl
|
|
@@ -54487,7 +55552,7 @@ async function createRegistry(config, options, spinner) {
|
|
|
54487
55552
|
if (!existsSync16(registryPath)) {
|
|
54488
55553
|
throw new Error(`Local registry path not found: ${registryPath}`);
|
|
54489
55554
|
}
|
|
54490
|
-
return createFileSystemRegistry(
|
|
55555
|
+
return createFileSystemRegistry(resolve24(registryPath));
|
|
54491
55556
|
}
|
|
54492
55557
|
function parseInheritVersion(inheritPath) {
|
|
54493
55558
|
const versionIndex = inheritPath.lastIndexOf("@");
|
|
@@ -54546,7 +55611,7 @@ function handlePullError(error, spinner) {
|
|
|
54546
55611
|
init_src();
|
|
54547
55612
|
init_loader2();
|
|
54548
55613
|
init_console();
|
|
54549
|
-
import { resolve as
|
|
55614
|
+
import { resolve as resolve26 } from "node:path";
|
|
54550
55615
|
import { readFile as readFile18 } from "node:fs/promises";
|
|
54551
55616
|
import { existsSync as existsSync18 } from "node:fs";
|
|
54552
55617
|
init_loader();
|
|
@@ -54555,7 +55620,7 @@ init_loader();
|
|
|
54555
55620
|
import { createHash as createHash5 } from "node:crypto";
|
|
54556
55621
|
import { existsSync as existsSync17 } from "node:fs";
|
|
54557
55622
|
import { lstat as lstat9, readFile as readFile17 } from "node:fs/promises";
|
|
54558
|
-
import { isAbsolute as
|
|
55623
|
+
import { isAbsolute as isAbsolute15, relative as relative17, resolve as resolve25, sep as sep11 } from "node:path";
|
|
54559
55624
|
var DIFF_SCHEMA_VERSION = 1;
|
|
54560
55625
|
var DIFF_SCHEMA_URL = "https://getpromptscript.dev/schema/diff/v1.json";
|
|
54561
55626
|
var CHANGE_KIND_ORDER = {
|
|
@@ -54574,19 +55639,19 @@ function normalizePath2(path2) {
|
|
|
54574
55639
|
return path2.replaceAll("\\", "/");
|
|
54575
55640
|
}
|
|
54576
55641
|
function reportPath(outputRoot, path2) {
|
|
54577
|
-
const absolutePath =
|
|
54578
|
-
const relation = normalizePath2(
|
|
55642
|
+
const absolutePath = resolve25(outputRoot, path2);
|
|
55643
|
+
const relation = normalizePath2(relative17(outputRoot, absolutePath));
|
|
54579
55644
|
if (!relation || relation === ".") return normalizePath2(path2);
|
|
54580
|
-
if (relation === ".." || relation.startsWith("../") ||
|
|
55645
|
+
if (relation === ".." || relation.startsWith("../") || isAbsolute15(relation)) {
|
|
54581
55646
|
return normalizePath2(path2);
|
|
54582
55647
|
}
|
|
54583
55648
|
return relation;
|
|
54584
55649
|
}
|
|
54585
55650
|
function reportSource(projectRoot, source) {
|
|
54586
55651
|
const normalized = normalizePath2(source);
|
|
54587
|
-
if (!
|
|
54588
|
-
const relation = normalizePath2(
|
|
54589
|
-
if (relation && relation !== ".." && !relation.startsWith("../") && !
|
|
55652
|
+
if (!isAbsolute15(source)) return normalized;
|
|
55653
|
+
const relation = normalizePath2(relative17(projectRoot, source));
|
|
55654
|
+
if (relation && relation !== ".." && !relation.startsWith("../") && !isAbsolute15(relation)) {
|
|
54590
55655
|
return relation;
|
|
54591
55656
|
}
|
|
54592
55657
|
return normalized;
|
|
@@ -54745,15 +55810,15 @@ function createReport(success, changes, warnings, errors, includeContent, unchan
|
|
|
54745
55810
|
};
|
|
54746
55811
|
}
|
|
54747
55812
|
function findManagedOutputOwner(removedPath, outputs, outputRoot, entryPath, projectRoot) {
|
|
54748
|
-
const candidate =
|
|
55813
|
+
const candidate = resolve25(removedPath);
|
|
54749
55814
|
for (const output of outputs.values()) {
|
|
54750
55815
|
const managedFile = (output.managedOutputFiles ?? []).some(
|
|
54751
|
-
(file) =>
|
|
55816
|
+
(file) => resolve25(outputRoot, file) === candidate
|
|
54752
55817
|
);
|
|
54753
55818
|
const managedDirectory = (directory) => {
|
|
54754
|
-
const directoryPath =
|
|
54755
|
-
const relation =
|
|
54756
|
-
return relation === "" || relation !== ".." && !relation.startsWith(`..${
|
|
55819
|
+
const directoryPath = resolve25(outputRoot, directory);
|
|
55820
|
+
const relation = relative17(directoryPath, candidate);
|
|
55821
|
+
return relation === "" || relation !== ".." && !relation.startsWith(`..${sep11}`) && !isAbsolute15(relation);
|
|
54757
55822
|
};
|
|
54758
55823
|
if (managedFile || (output.managedOutputDirectories ?? []).some(managedDirectory)) {
|
|
54759
55824
|
return outputIdentity(output, entryPath, projectRoot);
|
|
@@ -54772,8 +55837,8 @@ function createCompilationDiffErrorReport(errors, warnings, projectRoot, include
|
|
|
54772
55837
|
);
|
|
54773
55838
|
}
|
|
54774
55839
|
async function buildCompilationDiff(options) {
|
|
54775
|
-
const projectRoot =
|
|
54776
|
-
const outputRoot =
|
|
55840
|
+
const projectRoot = resolve25(options.projectRoot);
|
|
55841
|
+
const outputRoot = resolve25(options.outputRoot);
|
|
54777
55842
|
const includeContent = options.includeContent === true;
|
|
54778
55843
|
const changes = [];
|
|
54779
55844
|
const warnings = options.warnings.map((warning) => normalizeWarning(warning, projectRoot));
|
|
@@ -54782,7 +55847,7 @@ async function buildCompilationDiff(options) {
|
|
|
54782
55847
|
for (const output of options.outputs.values()) {
|
|
54783
55848
|
const identity = outputIdentity(output, options.entryPath, projectRoot);
|
|
54784
55849
|
const path2 = reportPath(outputRoot, output.path);
|
|
54785
|
-
const outputPath =
|
|
55850
|
+
const outputPath = resolve25(outputRoot, output.path);
|
|
54786
55851
|
const desiredContent = output.content;
|
|
54787
55852
|
const common = {
|
|
54788
55853
|
target: identity.target,
|
|
@@ -54954,7 +56019,7 @@ function resolveUniversalDir2(universalDir) {
|
|
|
54954
56019
|
return { universalDir: ".agents" };
|
|
54955
56020
|
}
|
|
54956
56021
|
async function loadDiffLockfile(projectRoot) {
|
|
54957
|
-
const lockfilePath =
|
|
56022
|
+
const lockfilePath = resolve26(projectRoot, "promptscript.lock");
|
|
54958
56023
|
if (!existsSync18(lockfilePath)) {
|
|
54959
56024
|
return void 0;
|
|
54960
56025
|
}
|
|
@@ -54976,7 +56041,7 @@ function printNewFilePreview(content, showFull, pager) {
|
|
|
54976
56041
|
}
|
|
54977
56042
|
}
|
|
54978
56043
|
async function compareOutput(output, outputRoot, showFull, pager) {
|
|
54979
|
-
const outputPath =
|
|
56044
|
+
const outputPath = resolve26(outputRoot, output.path);
|
|
54980
56045
|
const newContent = output.content;
|
|
54981
56046
|
if (!existsSync18(outputPath)) {
|
|
54982
56047
|
pager.write(chalk2.green(`+ ${outputPath} (new file)`));
|
|
@@ -55049,7 +56114,7 @@ async function diffCommand(options) {
|
|
|
55049
56114
|
return;
|
|
55050
56115
|
}
|
|
55051
56116
|
const lockfile = await loadDiffLockfile(projectRoot);
|
|
55052
|
-
const vendorDir =
|
|
56117
|
+
const vendorDir = resolve26(projectRoot, ".promptscript/vendor");
|
|
55053
56118
|
if (!isJsonFormat) spinner.text = "Resolving registry...";
|
|
55054
56119
|
const registry2 = await resolveRegistryPath(config, {
|
|
55055
56120
|
vendorDir,
|
|
@@ -55060,11 +56125,11 @@ async function diffCommand(options) {
|
|
|
55060
56125
|
const logger = createDiffLogger(isJsonFormat);
|
|
55061
56126
|
const prettierOptions = await resolvePrettierOptions(config, projectRoot);
|
|
55062
56127
|
const skillContent = config.includePromptScriptSkill === false ? void 0 : await loadBundledSkillContent(logger);
|
|
55063
|
-
const outputRoot =
|
|
56128
|
+
const outputRoot = resolve26(projectRoot, buildProfile?.output ?? config.output?.baseDir ?? ".");
|
|
55064
56129
|
const compiler = new Compiler({
|
|
55065
56130
|
resolver: {
|
|
55066
56131
|
registryPath: registry2.path,
|
|
55067
|
-
localPath:
|
|
56132
|
+
localPath: resolve26(projectRoot, ".promptscript"),
|
|
55068
56133
|
projectRoot,
|
|
55069
56134
|
vendorDir,
|
|
55070
56135
|
readOnly: true,
|
|
@@ -55081,7 +56146,7 @@ async function diffCommand(options) {
|
|
|
55081
56146
|
logger,
|
|
55082
56147
|
skillContent
|
|
55083
56148
|
});
|
|
55084
|
-
const entryPath =
|
|
56149
|
+
const entryPath = resolve26(
|
|
55085
56150
|
projectRoot,
|
|
55086
56151
|
buildProfile?.entry ?? config.input?.entry ?? "./.promptscript/project.prs"
|
|
55087
56152
|
);
|
|
@@ -55234,7 +56299,7 @@ function printSimpleDiff(existingLines, newLines, showFull, pager) {
|
|
|
55234
56299
|
// packages/cli/src/commands/check.ts
|
|
55235
56300
|
import { existsSync as existsSync19 } from "fs";
|
|
55236
56301
|
import { readFile as readFile19 } from "fs/promises";
|
|
55237
|
-
import { resolve as
|
|
56302
|
+
import { resolve as resolve27 } from "path";
|
|
55238
56303
|
import { parse as parseYaml8 } from "yaml";
|
|
55239
56304
|
init_src();
|
|
55240
56305
|
init_loader2();
|
|
@@ -55393,7 +56458,7 @@ async function checkCommand(_options) {
|
|
|
55393
56458
|
}
|
|
55394
56459
|
const effectiveEntries = getEffectiveEntryPaths(config);
|
|
55395
56460
|
for (const entry of effectiveEntries) {
|
|
55396
|
-
const entryPath =
|
|
56461
|
+
const entryPath = resolve27(entry);
|
|
55397
56462
|
const name = entry === (config.input?.entry ?? ".promptscript/project.prs") ? "Entry file" : `Entry file (${entry})`;
|
|
55398
56463
|
if (existsSync19(entryPath)) {
|
|
55399
56464
|
results.push({
|
|
@@ -55418,7 +56483,7 @@ async function checkCommand(_options) {
|
|
|
55418
56483
|
});
|
|
55419
56484
|
hasWarnings = true;
|
|
55420
56485
|
} else if (config.registry?.path && !config.registry.git) {
|
|
55421
|
-
const registryPath =
|
|
56486
|
+
const registryPath = resolve27(config.registry.path);
|
|
55422
56487
|
if (existsSync19(registryPath)) {
|
|
55423
56488
|
results.push({
|
|
55424
56489
|
name: "Registry path",
|
|
@@ -55503,10 +56568,10 @@ async function checkCommand(_options) {
|
|
|
55503
56568
|
message: rootTargets.length === 0 ? `${targetNames.size} target(s) configured in build profiles` : `${targetNames.size} target(s) configured`
|
|
55504
56569
|
});
|
|
55505
56570
|
}
|
|
55506
|
-
const existingEntries = effectiveEntries.filter((entry) => existsSync19(
|
|
56571
|
+
const existingEntries = effectiveEntries.filter((entry) => existsSync19(resolve27(entry)));
|
|
55507
56572
|
if (existingEntries.length > 0) {
|
|
55508
56573
|
try {
|
|
55509
|
-
const lockfilePath =
|
|
56574
|
+
const lockfilePath = resolve27("promptscript.lock");
|
|
55510
56575
|
let lockfile;
|
|
55511
56576
|
if (existsSync19(lockfilePath)) {
|
|
55512
56577
|
const parsed = parseYaml8(await readFile19(lockfilePath, "utf-8"), {
|
|
@@ -55522,12 +56587,12 @@ async function checkCommand(_options) {
|
|
|
55522
56587
|
message: "promptscript.lock"
|
|
55523
56588
|
});
|
|
55524
56589
|
}
|
|
55525
|
-
const vendorDir =
|
|
56590
|
+
const vendorDir = resolve27(".promptscript/vendor");
|
|
55526
56591
|
const registry2 = await resolveRegistryPath(config, { vendorDir, lockfile });
|
|
55527
56592
|
const compiler = new Compiler({
|
|
55528
56593
|
resolver: {
|
|
55529
|
-
registryPath:
|
|
55530
|
-
localPath:
|
|
56594
|
+
registryPath: resolve27(registry2.path),
|
|
56595
|
+
localPath: resolve27(".promptscript"),
|
|
55531
56596
|
vendorDir,
|
|
55532
56597
|
referenceRoots: registry2.repositoryUrl && registry2.repositoryPath ? { [registry2.repositoryUrl]: [registry2.repositoryPath] } : void 0,
|
|
55533
56598
|
lockfile,
|
|
@@ -55542,7 +56607,7 @@ async function checkCommand(_options) {
|
|
|
55542
56607
|
for (const entry of existingEntries) {
|
|
55543
56608
|
const name = entry === (config.input?.entry ?? ".promptscript/project.prs") ? "Project resolution" : `Project resolution (${entry})`;
|
|
55544
56609
|
try {
|
|
55545
|
-
const result = await compiler.compile(
|
|
56610
|
+
const result = await compiler.compile(resolve27(entry));
|
|
55546
56611
|
if (result.errors.length > 0) {
|
|
55547
56612
|
results.push({
|
|
55548
56613
|
name,
|
|
@@ -55629,7 +56694,7 @@ import { dirname as dirname18 } from "path";
|
|
|
55629
56694
|
|
|
55630
56695
|
// packages/cli/src/utils/version-check.ts
|
|
55631
56696
|
init_console();
|
|
55632
|
-
import { homedir as
|
|
56697
|
+
import { homedir as homedir5 } from "os";
|
|
55633
56698
|
import { join as join16 } from "path";
|
|
55634
56699
|
import { readFile as readFile20, writeFile as writeFile5, mkdir as mkdir6 } from "fs/promises";
|
|
55635
56700
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@promptscript/cli/latest";
|
|
@@ -55679,7 +56744,7 @@ function comparePrerelease2(current, latest) {
|
|
|
55679
56744
|
return 0;
|
|
55680
56745
|
}
|
|
55681
56746
|
function getCacheDir() {
|
|
55682
|
-
return join16(
|
|
56747
|
+
return join16(homedir5(), ".promptscript", ".cache");
|
|
55683
56748
|
}
|
|
55684
56749
|
function getCachePath() {
|
|
55685
56750
|
return join16(getCacheDir(), "version.json");
|
|
@@ -56107,7 +57172,7 @@ Then reference configs with \`@inherit\` or \`@use\`:
|
|
|
56107
57172
|
}
|
|
56108
57173
|
|
|
56109
57174
|
// packages/cli/src/utils/resolve-target-directory.ts
|
|
56110
|
-
import { join as join18, resolve as
|
|
57175
|
+
import { join as join18, resolve as resolve28 } from "path";
|
|
56111
57176
|
|
|
56112
57177
|
// packages/cli/src/utils/slugify.ts
|
|
56113
57178
|
function slugify(name) {
|
|
@@ -56118,7 +57183,7 @@ function slugify(name) {
|
|
|
56118
57183
|
async function resolveTargetDirectory(options, services) {
|
|
56119
57184
|
const { cwd, directoryArg, registryName, nonInteractive } = options;
|
|
56120
57185
|
if (directoryArg) {
|
|
56121
|
-
return
|
|
57186
|
+
return resolve28(directoryArg);
|
|
56122
57187
|
}
|
|
56123
57188
|
const empty = await isDirectoryEmpty(cwd, services.fs);
|
|
56124
57189
|
if (empty && nonInteractive) {
|
|
@@ -56237,7 +57302,7 @@ async function registryInitCommand(directory, options, services = createDefaultS
|
|
|
56237
57302
|
// packages/cli/src/commands/registry/validate.ts
|
|
56238
57303
|
init_services();
|
|
56239
57304
|
init_console();
|
|
56240
|
-
import { resolve as
|
|
57305
|
+
import { resolve as resolve29 } from "path";
|
|
56241
57306
|
|
|
56242
57307
|
// packages/cli/src/utils/registry-validator.ts
|
|
56243
57308
|
import { join as join19 } from "path";
|
|
@@ -56442,7 +57507,7 @@ async function registryValidateCommand(path2, options, services = createDefaultS
|
|
|
56442
57507
|
process.exitCode = 1;
|
|
56443
57508
|
return;
|
|
56444
57509
|
}
|
|
56445
|
-
const registryPath =
|
|
57510
|
+
const registryPath = resolve29(path2 ?? ".");
|
|
56446
57511
|
const spinner = createSpinner("Validating registry...").start();
|
|
56447
57512
|
try {
|
|
56448
57513
|
const result = await validateRegistry(registryPath, services);
|
|
@@ -56494,10 +57559,10 @@ async function registryValidateCommand(path2, options, services = createDefaultS
|
|
|
56494
57559
|
// packages/cli/src/commands/registry/publish.ts
|
|
56495
57560
|
init_services();
|
|
56496
57561
|
init_console();
|
|
56497
|
-
import { resolve as
|
|
57562
|
+
import { resolve as resolve30, join as join20 } from "path";
|
|
56498
57563
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
56499
57564
|
async function registryPublishCommand(path2, options, services = createDefaultServices()) {
|
|
56500
|
-
const registryPath =
|
|
57565
|
+
const registryPath = resolve30(path2 ?? ".");
|
|
56501
57566
|
try {
|
|
56502
57567
|
if (!options.force) {
|
|
56503
57568
|
const spinner2 = createSpinner("Validating registry...").start();
|
|
@@ -56535,7 +57600,7 @@ async function registryPublishCommand(path2, options, services = createDefaultSe
|
|
|
56535
57600
|
let gitRoot;
|
|
56536
57601
|
try {
|
|
56537
57602
|
git("rev-parse", "--is-inside-work-tree");
|
|
56538
|
-
gitRoot =
|
|
57603
|
+
gitRoot = resolve30(git("rev-parse", "--show-toplevel"));
|
|
56539
57604
|
} catch {
|
|
56540
57605
|
spinner.fail("Not a git repository");
|
|
56541
57606
|
ConsoleOutput.muted("Initialize with: git init");
|
|
@@ -56813,7 +57878,7 @@ init_console();
|
|
|
56813
57878
|
init_src();
|
|
56814
57879
|
import { writeFile as writeFile7, readFile as readFile25 } from "fs/promises";
|
|
56815
57880
|
import { existsSync as existsSync22 } from "fs";
|
|
56816
|
-
import { resolve as
|
|
57881
|
+
import { resolve as resolve33 } from "path";
|
|
56817
57882
|
import { parse as parseYaml12, stringify as stringifyYaml3 } from "yaml";
|
|
56818
57883
|
|
|
56819
57884
|
// packages/cli/src/commands/lock-scanner.ts
|
|
@@ -56911,16 +57976,16 @@ async function collectRemoteImports(entryPath, options) {
|
|
|
56911
57976
|
}
|
|
56912
57977
|
|
|
56913
57978
|
// packages/cli/src/commands/lock-references.ts
|
|
56914
|
-
import { homedir as
|
|
56915
|
-
import { resolve as
|
|
57979
|
+
import { homedir as homedir6 } from "os";
|
|
57980
|
+
import { resolve as resolve32, join as join22 } from "path";
|
|
56916
57981
|
|
|
56917
57982
|
// packages/cli/src/commands/lock-reference-scanner.ts
|
|
56918
57983
|
import { readFile as readFile24 } from "fs/promises";
|
|
56919
|
-
import { dirname as dirname20, isAbsolute as
|
|
57984
|
+
import { dirname as dirname20, isAbsolute as isAbsolute16, relative as relative18, resolve as resolve31, sep as sep12 } from "path";
|
|
56920
57985
|
async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
56921
57986
|
const references = {};
|
|
56922
57987
|
const sortedRoots = [...roots].sort(
|
|
56923
|
-
(left, right) =>
|
|
57988
|
+
(left, right) => resolve31(right.cachePath).length - resolve31(left.cachePath).length
|
|
56924
57989
|
);
|
|
56925
57990
|
for (const block of ast.blocks) {
|
|
56926
57991
|
if (block.name !== "skills" || block.content.type !== "ObjectContent") {
|
|
@@ -56934,7 +57999,7 @@ async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (
|
|
|
56934
57999
|
if (!Array.isArray(refs)) continue;
|
|
56935
58000
|
for (const ref of refs) {
|
|
56936
58001
|
if (typeof ref !== "string") continue;
|
|
56937
|
-
const referencePath =
|
|
58002
|
+
const referencePath = isAbsolute16(ref) ? resolve31(ref) : resolve31(dirname20(block.loc.file), ref);
|
|
56938
58003
|
const root = sortedRoots.find(
|
|
56939
58004
|
(candidate) => isInsideCachePath(referencePath, candidate.cachePath)
|
|
56940
58005
|
);
|
|
@@ -56942,7 +58007,7 @@ async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (
|
|
|
56942
58007
|
if (!await isRealPathInside(referencePath, root.cachePath)) {
|
|
56943
58008
|
throw new Error(`Registry reference is missing or escapes its repository: ${ref}`);
|
|
56944
58009
|
}
|
|
56945
|
-
const relativePath =
|
|
58010
|
+
const relativePath = relative18(resolve31(root.cachePath), referencePath).split(sep12).join("/");
|
|
56946
58011
|
const key = buildReferenceKey(root.repoUrl, relativePath, root.version);
|
|
56947
58012
|
const hash = hashContent(await readFile24(referencePath));
|
|
56948
58013
|
const previous = existing[key];
|
|
@@ -56962,9 +58027,9 @@ function normalizeRepository(value) {
|
|
|
56962
58027
|
}
|
|
56963
58028
|
async function generateLockfileReferences(config, entryPath, localPath, lockfile, imports) {
|
|
56964
58029
|
const registry2 = await resolveRegistryPath(config, { lockfile });
|
|
56965
|
-
const cacheDir = join22(
|
|
58030
|
+
const cacheDir = join22(homedir6(), ".promptscript", "cache");
|
|
56966
58031
|
const resolver = new Resolver({
|
|
56967
|
-
registryPath:
|
|
58032
|
+
registryPath: resolve32(registry2.path),
|
|
56968
58033
|
localPath,
|
|
56969
58034
|
lockfile,
|
|
56970
58035
|
registries: config.registries,
|
|
@@ -57095,14 +58160,14 @@ async function lockCommand(options) {
|
|
|
57095
58160
|
}
|
|
57096
58161
|
}
|
|
57097
58162
|
const projectRoot = process.cwd();
|
|
57098
|
-
const localPath =
|
|
57099
|
-
const entryPath = config.input?.entry ?
|
|
58163
|
+
const localPath = resolve33(projectRoot, ".promptscript");
|
|
58164
|
+
const entryPath = config.input?.entry ? resolve33(projectRoot, config.input.entry) : resolve33(localPath, "project.prs");
|
|
57100
58165
|
const registry2 = await resolveRegistryPath(config, {
|
|
57101
58166
|
...!options.update && Object.keys(existing.dependencies).length > 0 ? { lockfile: existing } : {}
|
|
57102
58167
|
});
|
|
57103
58168
|
const scannedImports = await collectRemoteImports(entryPath, {
|
|
57104
58169
|
localPath,
|
|
57105
|
-
registryPath:
|
|
58170
|
+
registryPath: resolve33(registry2.path),
|
|
57106
58171
|
registries: config.registries,
|
|
57107
58172
|
strict: true
|
|
57108
58173
|
});
|
|
@@ -57116,7 +58181,8 @@ async function lockCommand(options) {
|
|
|
57116
58181
|
requestedDependencies.set(defaultGitRegistry.url, {
|
|
57117
58182
|
versions: /* @__PURE__ */ new Set([defaultGitRegistry.ref ?? "main"]),
|
|
57118
58183
|
...defaultGitRegistry.fallbackUrl ? { fallbackUrl: defaultGitRegistry.fallbackUrl } : {},
|
|
57119
|
-
...defaultGitRegistry.auth ? { auth: defaultGitRegistry.auth } : {}
|
|
58184
|
+
...defaultGitRegistry.auth ? { auth: defaultGitRegistry.auth } : {},
|
|
58185
|
+
...defaultGitRegistry.timeout !== void 0 ? { timeout: defaultGitRegistry.timeout } : {}
|
|
57120
58186
|
});
|
|
57121
58187
|
}
|
|
57122
58188
|
for (const [, entry] of aliasEntries) {
|
|
@@ -57128,6 +58194,9 @@ async function lockCommand(options) {
|
|
|
57128
58194
|
if (typeof entry !== "string" && entry.fallbackUrl) {
|
|
57129
58195
|
requested.fallbackUrl = entry.fallbackUrl;
|
|
57130
58196
|
}
|
|
58197
|
+
if (typeof entry !== "string" && entry.timeout !== void 0) {
|
|
58198
|
+
requested.timeout = entry.timeout;
|
|
58199
|
+
}
|
|
57131
58200
|
requestedDependencies.set(repoUrl, requested);
|
|
57132
58201
|
}
|
|
57133
58202
|
for (const imp of scannedImports) {
|
|
@@ -57152,7 +58221,8 @@ async function lockCommand(options) {
|
|
|
57152
58221
|
previous,
|
|
57153
58222
|
options.update === true && matchingRepos.includes(repoUrl),
|
|
57154
58223
|
requested.fallbackUrl,
|
|
57155
|
-
requested.auth
|
|
58224
|
+
requested.auth,
|
|
58225
|
+
{ timeout: requested.timeout }
|
|
57156
58226
|
);
|
|
57157
58227
|
if (previous?.skills?.length && previous.commit !== resolved.commit) {
|
|
57158
58228
|
throw new Error(
|
|
@@ -57322,7 +58392,7 @@ import {
|
|
|
57322
58392
|
writeFile as writeFile8
|
|
57323
58393
|
} from "fs/promises";
|
|
57324
58394
|
import { existsSync as existsSync23 } from "fs";
|
|
57325
|
-
import { basename as basename15, dirname as dirname21, join as join23, resolve as
|
|
58395
|
+
import { basename as basename15, dirname as dirname21, join as join23, resolve as resolve34 } from "path";
|
|
57326
58396
|
import { parse as parseYaml13 } from "yaml";
|
|
57327
58397
|
var VENDOR_DIR = ".promptscript/vendor";
|
|
57328
58398
|
async function vendorSyncCommand(options) {
|
|
@@ -57343,7 +58413,7 @@ async function vendorSyncCommand(options) {
|
|
|
57343
58413
|
spinner.succeed(`Dry run completed (${deps.length} dependencies ready)`);
|
|
57344
58414
|
return;
|
|
57345
58415
|
}
|
|
57346
|
-
const vendorDir =
|
|
58416
|
+
const vendorDir = resolve34(VENDOR_DIR);
|
|
57347
58417
|
await validateVendorParentDirectory(vendorDir, true);
|
|
57348
58418
|
const recoveredBackup = await recoverVendorDirectory(vendorDir);
|
|
57349
58419
|
if (recoveredBackup) {
|
|
@@ -57416,7 +58486,7 @@ async function vendorCheckCommand(_options) {
|
|
|
57416
58486
|
}
|
|
57417
58487
|
const deps = getRepositoryDependencies(lockfile);
|
|
57418
58488
|
validateDependencyPaths(deps);
|
|
57419
|
-
const vendorDir =
|
|
58489
|
+
const vendorDir = resolve34(VENDOR_DIR);
|
|
57420
58490
|
await validateVendorParentDirectory(vendorDir, false);
|
|
57421
58491
|
const recoveredBackup = await recoverVendorDirectory(vendorDir);
|
|
57422
58492
|
if (recoveredBackup) {
|
|
@@ -57597,10 +58667,10 @@ init_loader2();
|
|
|
57597
58667
|
init_user_config();
|
|
57598
58668
|
init_console();
|
|
57599
58669
|
import { existsSync as existsSync24, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
57600
|
-
import { join as join24, resolve as
|
|
57601
|
-
import { homedir as
|
|
58670
|
+
import { join as join24, resolve as resolve35 } from "path";
|
|
58671
|
+
import { homedir as homedir7 } from "os";
|
|
57602
58672
|
import { parse as parseYaml14 } from "yaml";
|
|
57603
|
-
var CACHE_BASE = join24(
|
|
58673
|
+
var CACHE_BASE = join24(homedir7(), ".promptscript", "cache");
|
|
57604
58674
|
var LOCKFILE_PATH2 = "promptscript.lock";
|
|
57605
58675
|
var VENDOR_DIR2 = ".promptscript/vendor";
|
|
57606
58676
|
function loadLockfile2() {
|
|
@@ -57609,7 +58679,7 @@ function loadLockfile2() {
|
|
|
57609
58679
|
}
|
|
57610
58680
|
const parsed = parseYaml14(readFileSync5(LOCKFILE_PATH2, "utf-8"), { maxAliasCount: 100 });
|
|
57611
58681
|
if (!isValidLockfile(parsed)) {
|
|
57612
|
-
throw new Error(`Invalid lockfile: ${
|
|
58682
|
+
throw new Error(`Invalid lockfile: ${resolve35(LOCKFILE_PATH2)}`);
|
|
57613
58683
|
}
|
|
57614
58684
|
return parsed;
|
|
57615
58685
|
}
|
|
@@ -57710,14 +58780,14 @@ async function resolveCommand(importPath, options) {
|
|
|
57710
58780
|
}
|
|
57711
58781
|
const reference = parseImportReference(importPath);
|
|
57712
58782
|
const loader = new FileLoader({
|
|
57713
|
-
registryPath:
|
|
57714
|
-
localPath:
|
|
58783
|
+
registryPath: resolve35(config.registry?.path ?? "./registry"),
|
|
58784
|
+
localPath: resolve35("./.promptscript"),
|
|
57715
58785
|
registries
|
|
57716
58786
|
});
|
|
57717
|
-
const resolvedReference = loader.resolveRef(reference,
|
|
58787
|
+
const resolvedReference = loader.resolveRef(reference, resolve35(".promptscript/project.prs"));
|
|
57718
58788
|
const marker = parseRegistryMarker(resolvedReference);
|
|
57719
58789
|
if (!marker) {
|
|
57720
|
-
const localPath =
|
|
58790
|
+
const localPath = resolve35(resolvedReference);
|
|
57721
58791
|
printResolution(
|
|
57722
58792
|
{
|
|
57723
58793
|
import: importPath,
|
|
@@ -57738,7 +58808,7 @@ async function resolveCommand(importPath, options) {
|
|
|
57738
58808
|
const cacheVersion = marker.version || "latest";
|
|
57739
58809
|
const registryCache = new RegistryCache(CACHE_BASE);
|
|
57740
58810
|
const cachePath = registryCache.getCachePath(marker.repoUrl, cacheVersion);
|
|
57741
|
-
const vendorDir =
|
|
58811
|
+
const vendorDir = resolve35(VENDOR_DIR2);
|
|
57742
58812
|
const manifest = await loadVendorManifest(vendorDir);
|
|
57743
58813
|
let repositoryPath = cachePath;
|
|
57744
58814
|
let source = await registryCache.has(marker.repoUrl, cacheVersion) ? "cache" : "missing";
|
|
@@ -57811,28 +58881,28 @@ async function resolveCommand(importPath, options) {
|
|
|
57811
58881
|
|
|
57812
58882
|
// packages/cli/src/commands/inspect.ts
|
|
57813
58883
|
import { existsSync as existsSync25 } from "fs";
|
|
57814
|
-
import { resolve as
|
|
58884
|
+
import { resolve as resolve36, basename as basename16 } from "path";
|
|
57815
58885
|
init_loader2();
|
|
57816
58886
|
init_console();
|
|
57817
58887
|
async function inspectCommand(skillName, options) {
|
|
57818
58888
|
const isJson = options.format === "json";
|
|
57819
58889
|
const spinner = isJson ? createSpinner("").stop() : createSpinner("Resolving...").start();
|
|
57820
58890
|
try {
|
|
57821
|
-
const projectRoot = options.cwd ?
|
|
57822
|
-
const configPath = options.config ?
|
|
58891
|
+
const projectRoot = options.cwd ? resolve36(options.cwd) : process.cwd();
|
|
58892
|
+
const configPath = options.config ? resolve36(projectRoot, options.config) : options.cwd ? CONFIG_FILES.map((file) => resolve36(projectRoot, file)).find((file) => existsSync25(file)) : void 0;
|
|
57823
58893
|
if (options.cwd && !configPath) {
|
|
57824
58894
|
throw new Error(`No PromptScript configuration found in ${projectRoot}. Run: prs init`);
|
|
57825
58895
|
}
|
|
57826
58896
|
const config = await loadConfig(configPath);
|
|
57827
58897
|
const registry2 = await resolveRegistryPath(config);
|
|
57828
|
-
const localPath =
|
|
58898
|
+
const localPath = resolve36(projectRoot, ".promptscript");
|
|
57829
58899
|
const resolver = new Resolver({
|
|
57830
|
-
registryPath: registry2.isRemote ? registry2.path :
|
|
58900
|
+
registryPath: registry2.isRemote ? registry2.path : resolve36(projectRoot, registry2.path),
|
|
57831
58901
|
localPath,
|
|
57832
58902
|
projectRoot,
|
|
57833
58903
|
registries: config.registries
|
|
57834
58904
|
});
|
|
57835
|
-
const entryPath =
|
|
58905
|
+
const entryPath = resolve36(projectRoot, config.input?.entry ?? ".promptscript/project.prs");
|
|
57836
58906
|
if (!existsSync25(entryPath)) {
|
|
57837
58907
|
spinner.stop();
|
|
57838
58908
|
ConsoleOutput.error(`Entry file not found: ${entryPath}`);
|
|
@@ -58010,7 +59080,7 @@ function outputJson(skillName, skill, trace, sealed, composedFrom, baseSource) {
|
|
|
58010
59080
|
// packages/cli/src/commands/explain.ts
|
|
58011
59081
|
init_src();
|
|
58012
59082
|
import { existsSync as existsSync26 } from "fs";
|
|
58013
|
-
import { relative as
|
|
59083
|
+
import { relative as relative19, resolve as resolve37 } from "path";
|
|
58014
59084
|
init_loader2();
|
|
58015
59085
|
init_console();
|
|
58016
59086
|
function normalizePath3(path2) {
|
|
@@ -58091,7 +59161,7 @@ function findMatches(ast, trace, requestedPath) {
|
|
|
58091
59161
|
}
|
|
58092
59162
|
function sanitizePath(path2, options) {
|
|
58093
59163
|
if (options.absolutePaths || !path2.startsWith("/")) return path2;
|
|
58094
|
-
const relativePath =
|
|
59164
|
+
const relativePath = relative19(options.projectRoot, path2);
|
|
58095
59165
|
return relativePath || ".";
|
|
58096
59166
|
}
|
|
58097
59167
|
function sanitizeText(value, options) {
|
|
@@ -58221,24 +59291,24 @@ async function explainCommand(targetPath, options) {
|
|
|
58221
59291
|
const isJson = options.format === "json";
|
|
58222
59292
|
const spinner = isJson ? createSpinner("").stop() : createSpinner("Resolving...").start();
|
|
58223
59293
|
const outputOptions = {
|
|
58224
|
-
projectRoot:
|
|
59294
|
+
projectRoot: resolve37(options.cwd ?? process.cwd()),
|
|
58225
59295
|
absolutePaths: options.absolutePaths === true
|
|
58226
59296
|
};
|
|
58227
59297
|
try {
|
|
58228
59298
|
const projectRoot = outputOptions.projectRoot;
|
|
58229
|
-
const configPath = options.config ?
|
|
59299
|
+
const configPath = options.config ? resolve37(projectRoot, options.config) : options.cwd ? CONFIG_FILES.map((file) => resolve37(projectRoot, file)).find((file) => existsSync26(file)) : void 0;
|
|
58230
59300
|
if (options.cwd && !configPath) {
|
|
58231
59301
|
throw new Error(`No PromptScript configuration found in ${projectRoot}. Run: prs init`);
|
|
58232
59302
|
}
|
|
58233
59303
|
const config = await loadConfig(configPath);
|
|
58234
59304
|
const registry2 = await resolveRegistryPath(config);
|
|
58235
59305
|
const resolver = new Resolver({
|
|
58236
|
-
registryPath: registry2.isRemote ? registry2.path :
|
|
58237
|
-
localPath:
|
|
59306
|
+
registryPath: registry2.isRemote ? registry2.path : resolve37(projectRoot, registry2.path),
|
|
59307
|
+
localPath: resolve37(projectRoot, ".promptscript"),
|
|
58238
59308
|
projectRoot,
|
|
58239
59309
|
registries: config.registries
|
|
58240
59310
|
});
|
|
58241
|
-
const entryPath =
|
|
59311
|
+
const entryPath = resolve37(projectRoot, config.input?.entry ?? ".promptscript/project.prs");
|
|
58242
59312
|
if (!existsSync26(entryPath)) {
|
|
58243
59313
|
spinner.stop();
|
|
58244
59314
|
ConsoleOutput.error(`Entry file not found: ${sanitizePath(entryPath, outputOptions)}`);
|
|
@@ -58300,7 +59370,7 @@ init_console();
|
|
|
58300
59370
|
// packages/cli/src/commands/import.ts
|
|
58301
59371
|
init_src3();
|
|
58302
59372
|
init_console();
|
|
58303
|
-
import { resolve as
|
|
59373
|
+
import { resolve as resolve38, join as join25, basename as basename17 } from "path";
|
|
58304
59374
|
import { writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync27 } from "fs";
|
|
58305
59375
|
import { stat as stat2, readdir as readdir8, readFile as readFile27, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
|
|
58306
59376
|
function parseInstructionFrontmatter(content) {
|
|
@@ -58355,7 +59425,7 @@ async function importDirectory(dirPath) {
|
|
|
58355
59425
|
return lines.join("\n");
|
|
58356
59426
|
}
|
|
58357
59427
|
async function importCommand(file, options) {
|
|
58358
|
-
const filepath =
|
|
59428
|
+
const filepath = resolve38(file);
|
|
58359
59429
|
const inputStat = await stat2(filepath).catch(() => null);
|
|
58360
59430
|
if (inputStat?.isDirectory()) {
|
|
58361
59431
|
try {
|
|
@@ -58364,7 +59434,7 @@ async function importCommand(file, options) {
|
|
|
58364
59434
|
console.log(prsContent);
|
|
58365
59435
|
return;
|
|
58366
59436
|
}
|
|
58367
|
-
const outputDir =
|
|
59437
|
+
const outputDir = resolve38(options.output ?? ".promptscript");
|
|
58368
59438
|
const outputPath = join25(outputDir, "imported.prs");
|
|
58369
59439
|
if (existsSync27(outputPath) && !options.force) {
|
|
58370
59440
|
reportOutputConflict(outputPath);
|
|
@@ -58398,11 +59468,11 @@ async function importCommand(file, options) {
|
|
|
58398
59468
|
console.log(result.prsContent);
|
|
58399
59469
|
return;
|
|
58400
59470
|
}
|
|
58401
|
-
const outputDir =
|
|
59471
|
+
const outputDir = resolve38(options.output ?? ".promptscript");
|
|
58402
59472
|
if (!existsSync27(outputDir)) {
|
|
58403
59473
|
mkdirSync(outputDir, { recursive: true });
|
|
58404
59474
|
}
|
|
58405
|
-
const outputPath =
|
|
59475
|
+
const outputPath = resolve38(outputDir, "imported.prs");
|
|
58406
59476
|
if (existsSync27(outputPath) && !options.force) {
|
|
58407
59477
|
spinner.stop();
|
|
58408
59478
|
reportOutputConflict(outputPath);
|
|
@@ -58772,11 +59842,11 @@ init_console();
|
|
|
58772
59842
|
// packages/cli/src/telemetry/config.ts
|
|
58773
59843
|
import { existsSync as existsSync30 } from "node:fs";
|
|
58774
59844
|
import { mkdir as mkdir10, readFile as readFile29, rename as rename2, writeFile as writeFile10 } from "node:fs/promises";
|
|
58775
|
-
import { dirname as dirname22, isAbsolute as
|
|
59845
|
+
import { dirname as dirname22, isAbsolute as isAbsolute17, join as join29, resolve as resolve39 } from "node:path";
|
|
58776
59846
|
import { parseDocument as parseDocument2 } from "yaml";
|
|
58777
59847
|
|
|
58778
59848
|
// packages/telemetry/src/config.ts
|
|
58779
|
-
import { homedir as
|
|
59849
|
+
import { homedir as homedir8 } from "node:os";
|
|
58780
59850
|
import { join as join27 } from "node:path";
|
|
58781
59851
|
var DEFAULT_TELEMETRY_ENDPOINT = "https://telemetry.guziak.net/v1/events";
|
|
58782
59852
|
function isDisabled(value) {
|
|
@@ -58825,7 +59895,7 @@ function resolveTelemetryConfig(input2 = {}) {
|
|
|
58825
59895
|
return {
|
|
58826
59896
|
enabled: vetoes.length === 0,
|
|
58827
59897
|
endpoint,
|
|
58828
|
-
cacheDirectory: input2.cacheDirectory ?? join27(
|
|
59898
|
+
cacheDirectory: input2.cacheDirectory ?? join27(homedir8(), ".promptscript", ".cache"),
|
|
58829
59899
|
vetoes
|
|
58830
59900
|
};
|
|
58831
59901
|
}
|
|
@@ -58911,7 +59981,8 @@ var promptscript_v1_default = {
|
|
|
58911
59981
|
"mimo",
|
|
58912
59982
|
"deep-agents",
|
|
58913
59983
|
"forgecode",
|
|
58914
|
-
"hermes"
|
|
59984
|
+
"hermes",
|
|
59985
|
+
"gitlab-duo"
|
|
58915
59986
|
],
|
|
58916
59987
|
limits: {
|
|
58917
59988
|
maxEvents: 25,
|
|
@@ -59433,7 +60504,7 @@ var FLUSH_BUDGET_MS = 5e3;
|
|
|
59433
60504
|
var MAX_BATCHES_PER_FLUSH = 3;
|
|
59434
60505
|
var COMPLETION_RETRIES = 20;
|
|
59435
60506
|
function delay(milliseconds) {
|
|
59436
|
-
return new Promise((
|
|
60507
|
+
return new Promise((resolve43) => setTimeout(resolve43, milliseconds));
|
|
59437
60508
|
}
|
|
59438
60509
|
async function persistCompletion(cacheDirectory, remainingRecords, rejectedRecords) {
|
|
59439
60510
|
for (let attempt = 0; attempt < COMPLETION_RETRIES; attempt += 1) {
|
|
@@ -59678,7 +60749,7 @@ function runtimeMetadata(appVersion, input2 = {}) {
|
|
|
59678
60749
|
init_loader2();
|
|
59679
60750
|
init_user_config();
|
|
59680
60751
|
function resolveFrom(baseDirectory, value) {
|
|
59681
|
-
return
|
|
60752
|
+
return isAbsolute17(value) ? value : resolve39(baseDirectory, value);
|
|
59682
60753
|
}
|
|
59683
60754
|
function findProjectConfig(cwd, customPath) {
|
|
59684
60755
|
if (customPath !== void 0) {
|
|
@@ -59723,7 +60794,7 @@ async function readUserTelemetrySetting(configPath) {
|
|
|
59723
60794
|
}
|
|
59724
60795
|
}
|
|
59725
60796
|
async function resolveCliTelemetryConfig(options = {}) {
|
|
59726
|
-
const cwd = options.cwd === void 0 ? process.cwd() :
|
|
60797
|
+
const cwd = options.cwd === void 0 ? process.cwd() : resolve39(process.cwd(), options.cwd);
|
|
59727
60798
|
const userSetting = await readUserTelemetrySetting(options.userConfigPath ?? USER_CONFIG_PATH);
|
|
59728
60799
|
const projectPath = findProjectConfig(cwd, options.config);
|
|
59729
60800
|
const environmentConfig = process.env["PROMPTSCRIPT_CONFIG"];
|
|
@@ -59937,13 +61008,41 @@ import {
|
|
|
59937
61008
|
chmod,
|
|
59938
61009
|
open as open4,
|
|
59939
61010
|
lstat as lstat11,
|
|
59940
|
-
stat as stat3
|
|
59941
|
-
|
|
59942
|
-
|
|
59943
|
-
|
|
59944
|
-
import {
|
|
61011
|
+
stat as stat3,
|
|
61012
|
+
cp,
|
|
61013
|
+
mkdir as mkdir11
|
|
61014
|
+
} from "node:fs/promises";
|
|
61015
|
+
import { resolve as resolve40, join as join30, basename as basename18, dirname as dirname23, relative as relative20, isAbsolute as isAbsolute18, sep as sep13 } from "node:path";
|
|
61016
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
61017
|
+
import { tmpdir as tmpdir3, homedir as homedir9 } from "node:os";
|
|
59945
61018
|
import { parse as parseYaml15, stringify as stringifyYaml4 } from "yaml";
|
|
59946
61019
|
var REMOTE_SOURCE_PATTERN = /^[a-zA-Z0-9][\w.-]*\.[a-zA-Z]{2,}\/.+/;
|
|
61020
|
+
var MANAGED_SKILLS_DIR = join30(".promptscript", "skills");
|
|
61021
|
+
var USE_PATH_PATTERN = /^\.{1,2}\/[a-zA-Z0-9_/.-]+$/;
|
|
61022
|
+
function expandHomePath(input2) {
|
|
61023
|
+
if (input2 === "~") return homedir9();
|
|
61024
|
+
if (input2.startsWith("~/") || input2.startsWith("~\\")) {
|
|
61025
|
+
return join30(homedir9(), input2.slice(2));
|
|
61026
|
+
}
|
|
61027
|
+
return input2;
|
|
61028
|
+
}
|
|
61029
|
+
function isLocalSkillSource(source) {
|
|
61030
|
+
const trimmed = source.trim();
|
|
61031
|
+
if (trimmed.length === 0) return false;
|
|
61032
|
+
if (trimmed.startsWith("~")) {
|
|
61033
|
+
return trimmed === "~" || trimmed.slice(1, 2) === "/" || trimmed.slice(1, 2) === "\\";
|
|
61034
|
+
}
|
|
61035
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("\\")) return true;
|
|
61036
|
+
if (/^[a-zA-Z]:[\\/]/.test(trimmed)) return true;
|
|
61037
|
+
if (trimmed.startsWith("./") || trimmed.startsWith(".\\")) return true;
|
|
61038
|
+
if (trimmed.startsWith("../") || trimmed.startsWith("..\\")) return true;
|
|
61039
|
+
if (REMOTE_SOURCE_PATTERN.test(trimmed)) return false;
|
|
61040
|
+
return existsSync31(resolve40(process.cwd(), expandHomePath(trimmed)));
|
|
61041
|
+
}
|
|
61042
|
+
function toUsePath(entryDir, skillDir) {
|
|
61043
|
+
const rel = relative20(entryDir, skillDir).split(sep13).join("/");
|
|
61044
|
+
return rel.startsWith("..") ? rel : `./${rel}`;
|
|
61045
|
+
}
|
|
59947
61046
|
function parseSkillSource(source) {
|
|
59948
61047
|
const versionSeparator = source.lastIndexOf("@");
|
|
59949
61048
|
if (versionSeparator === -1) {
|
|
@@ -59962,7 +61061,7 @@ function toDependencyPin(dependency) {
|
|
|
59962
61061
|
integrity: dependency.integrity
|
|
59963
61062
|
};
|
|
59964
61063
|
}
|
|
59965
|
-
function resolveSkillDependency(repoUrl, requestedVersions, existing, forceUpdate, gitUrl, timeout =
|
|
61064
|
+
function resolveSkillDependency(repoUrl, requestedVersions, existing, forceUpdate, gitUrl, timeout = void 0) {
|
|
59966
61065
|
return gitUrl ? resolveRemoteDependency(
|
|
59967
61066
|
repoUrl,
|
|
59968
61067
|
requestedVersions,
|
|
@@ -60006,32 +61105,32 @@ async function collectProjectRemoteImports(entryFile) {
|
|
|
60006
61105
|
const projectRoot = process.cwd();
|
|
60007
61106
|
const entryFiles = /* @__PURE__ */ new Set();
|
|
60008
61107
|
if (entryFile) {
|
|
60009
|
-
entryFiles.add(
|
|
61108
|
+
entryFiles.add(resolve40(entryFile));
|
|
60010
61109
|
}
|
|
60011
61110
|
if (config) {
|
|
60012
61111
|
if (config.input?.entry) {
|
|
60013
|
-
entryFiles.add(
|
|
61112
|
+
entryFiles.add(resolve40(projectRoot, config.input.entry));
|
|
60014
61113
|
}
|
|
60015
61114
|
for (const build of Object.values(config.builds ?? {})) {
|
|
60016
61115
|
if (build.entry) {
|
|
60017
|
-
entryFiles.add(
|
|
61116
|
+
entryFiles.add(resolve40(projectRoot, build.entry));
|
|
60018
61117
|
}
|
|
60019
61118
|
}
|
|
60020
|
-
const defaultEntry =
|
|
61119
|
+
const defaultEntry = resolve40(projectRoot, ".promptscript/project.prs");
|
|
60021
61120
|
if (!config.input?.entry && (existsSync31(defaultEntry) || entryFiles.size === 0)) {
|
|
60022
61121
|
entryFiles.add(defaultEntry);
|
|
60023
61122
|
}
|
|
60024
61123
|
} else if (!entryFile) {
|
|
60025
|
-
const defaultEntry =
|
|
61124
|
+
const defaultEntry = resolve40(projectRoot, ".promptscript/project.prs");
|
|
60026
61125
|
if (existsSync31(defaultEntry)) {
|
|
60027
61126
|
entryFiles.add(defaultEntry);
|
|
60028
61127
|
} else {
|
|
60029
|
-
const promptscriptDir =
|
|
61128
|
+
const promptscriptDir = resolve40(projectRoot, ".promptscript");
|
|
60030
61129
|
if (existsSync31(promptscriptDir)) {
|
|
60031
61130
|
const entries = await readdir9(promptscriptDir);
|
|
60032
61131
|
const prsFiles = entries.filter((entry) => entry.endsWith(".prs"));
|
|
60033
61132
|
if (prsFiles.length === 1) {
|
|
60034
|
-
entryFiles.add(
|
|
61133
|
+
entryFiles.add(resolve40(promptscriptDir, prsFiles[0]));
|
|
60035
61134
|
}
|
|
60036
61135
|
}
|
|
60037
61136
|
}
|
|
@@ -60040,7 +61139,7 @@ async function collectProjectRemoteImports(entryFile) {
|
|
|
60040
61139
|
for (const projectEntry of entryFiles) {
|
|
60041
61140
|
imports.push(
|
|
60042
61141
|
...await collectRemoteImports(projectEntry, {
|
|
60043
|
-
localPath:
|
|
61142
|
+
localPath: resolve40(projectRoot, ".promptscript"),
|
|
60044
61143
|
registries: config?.registries,
|
|
60045
61144
|
strict: true,
|
|
60046
61145
|
deduplicate: false,
|
|
@@ -60086,6 +61185,10 @@ function extractSkillFilePath(source) {
|
|
|
60086
61185
|
if (!subPath) return "SKILL.md";
|
|
60087
61186
|
return subPath.toLowerCase().endsWith(".md") ? subPath : `${subPath}/SKILL.md`;
|
|
60088
61187
|
}
|
|
61188
|
+
function getRemoteSkillDiagnosticPath(source) {
|
|
61189
|
+
const sourcePath = parseSkillSource(source).path.replace(/^https?:\/\//i, "");
|
|
61190
|
+
return sourcePath.toLowerCase().endsWith(".md") ? sourcePath : `${sourcePath}/SKILL.md`;
|
|
61191
|
+
}
|
|
60089
61192
|
function deriveSkillFolderName(source) {
|
|
60090
61193
|
const subPath = extractSubPath(source);
|
|
60091
61194
|
if (!subPath) return basename18(parseSkillSource(source).path);
|
|
@@ -60112,13 +61215,15 @@ async function fetchAndValidateRemoteSkill(source, options) {
|
|
|
60112
61215
|
const cloneDir = !skillFilePath.includes("/") ? join30(tmp, repoName) : tmp;
|
|
60113
61216
|
try {
|
|
60114
61217
|
const gitRegistry = createGitRegistry({
|
|
60115
|
-
url: repoUrl
|
|
60116
|
-
timeout: DEFAULT_GIT_TIMEOUT_MS
|
|
61218
|
+
url: repoUrl
|
|
60117
61219
|
});
|
|
60118
61220
|
const cloneRef = options.version === "latest" || /^[0-9a-f]{40}$/i.test(options.version) ? void 0 : options.version;
|
|
60119
|
-
await gitRegistry.cloneAtTag(repoUrl, cloneRef, cloneDir);
|
|
60120
|
-
await gitRegistry.checkoutCommit(cloneDir, options.commit);
|
|
60121
61221
|
const subPath = extractSubPath(source);
|
|
61222
|
+
const isMdSource = subPath.toLowerCase().endsWith(".md");
|
|
61223
|
+
const coneCandidate = isMdSource ? subPath.slice(0, subPath.lastIndexOf("/")) : subPath;
|
|
61224
|
+
const sparseCone = coneCandidate.length > 0 ? coneCandidate : void 0;
|
|
61225
|
+
await gitRegistry.cloneAtTag(repoUrl, cloneRef, cloneDir, void 0, sparseCone);
|
|
61226
|
+
await gitRegistry.checkoutCommit(cloneDir, options.commit);
|
|
60122
61227
|
if (!subPath.toLowerCase().endsWith(".md") && existsSync31(join30(cloneDir, `${subPath}.prs`))) {
|
|
60123
61228
|
return {
|
|
60124
61229
|
content: "",
|
|
@@ -60159,7 +61264,16 @@ async function fetchAndValidateRemoteSkill(source, options) {
|
|
|
60159
61264
|
filePath,
|
|
60160
61265
|
existingNames: options.existingNames
|
|
60161
61266
|
});
|
|
60162
|
-
|
|
61267
|
+
const diagnosticPath = getRemoteSkillDiagnosticPath(source);
|
|
61268
|
+
const remoteSkillDir = dirname23(diagnosticPath);
|
|
61269
|
+
const issues = result.issues.map((issue) => {
|
|
61270
|
+
const message = issue.message.replaceAll(dirname23(filePath), remoteSkillDir);
|
|
61271
|
+
if (issue.location) {
|
|
61272
|
+
return { ...issue, message, location: { ...issue.location, file: diagnosticPath } };
|
|
61273
|
+
}
|
|
61274
|
+
return { ...issue, message };
|
|
61275
|
+
});
|
|
61276
|
+
return { content, integrity, valid: result.valid, issues };
|
|
60163
61277
|
} finally {
|
|
60164
61278
|
await rm2(tmp, { recursive: true, force: true }).catch(() => {
|
|
60165
61279
|
});
|
|
@@ -60225,7 +61339,7 @@ async function isStaleSkillsAddLock(lockPath) {
|
|
|
60225
61339
|
}
|
|
60226
61340
|
}
|
|
60227
61341
|
async function acquireSkillsAddLock() {
|
|
60228
|
-
const lockPath =
|
|
61342
|
+
const lockPath = resolve40(SKILLS_ADD_LOCK_PATH);
|
|
60229
61343
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
60230
61344
|
try {
|
|
60231
61345
|
const file = await open4(lockPath, "wx", 384);
|
|
@@ -60266,7 +61380,7 @@ async function acquireSkillsAddLock() {
|
|
|
60266
61380
|
await rm2(quarantinePath, { force: true });
|
|
60267
61381
|
}
|
|
60268
61382
|
}
|
|
60269
|
-
throw new Error(`Cannot acquire skills add lock: ${
|
|
61383
|
+
throw new Error(`Cannot acquire skills add lock: ${resolve40(SKILLS_ADD_LOCK_PATH)}`);
|
|
60270
61384
|
}
|
|
60271
61385
|
async function releaseSkillsAddLock(lock) {
|
|
60272
61386
|
try {
|
|
@@ -60316,7 +61430,7 @@ function validateRemoteSource(source) {
|
|
|
60316
61430
|
}
|
|
60317
61431
|
async function resolveEntryFile(fileFlag) {
|
|
60318
61432
|
if (fileFlag) {
|
|
60319
|
-
const resolved =
|
|
61433
|
+
const resolved = resolve40(fileFlag);
|
|
60320
61434
|
if (!existsSync31(resolved)) {
|
|
60321
61435
|
throw new Error(`File not found: ${resolved}`);
|
|
60322
61436
|
}
|
|
@@ -60327,7 +61441,7 @@ async function resolveEntryFile(fileFlag) {
|
|
|
60327
61441
|
try {
|
|
60328
61442
|
const config = await loadConfig();
|
|
60329
61443
|
if (config.input?.entry) {
|
|
60330
|
-
const entryPath =
|
|
61444
|
+
const entryPath = resolve40(config.input.entry);
|
|
60331
61445
|
if (existsSync31(entryPath)) {
|
|
60332
61446
|
return entryPath;
|
|
60333
61447
|
}
|
|
@@ -60335,16 +61449,16 @@ async function resolveEntryFile(fileFlag) {
|
|
|
60335
61449
|
} catch {
|
|
60336
61450
|
}
|
|
60337
61451
|
}
|
|
60338
|
-
const promptscriptDir =
|
|
61452
|
+
const promptscriptDir = resolve40(".promptscript");
|
|
60339
61453
|
if (existsSync31(promptscriptDir)) {
|
|
60340
61454
|
const entries = await readdir9(promptscriptDir);
|
|
60341
61455
|
const prsFiles = entries.filter((f) => f.endsWith(".prs"));
|
|
60342
61456
|
if (prsFiles.length === 1) {
|
|
60343
|
-
return
|
|
61457
|
+
return resolve40(promptscriptDir, prsFiles[0]);
|
|
60344
61458
|
}
|
|
60345
61459
|
if (prsFiles.length > 1) {
|
|
60346
61460
|
if (prsFiles.includes("project.prs")) {
|
|
60347
|
-
return
|
|
61461
|
+
return resolve40(promptscriptDir, "project.prs");
|
|
60348
61462
|
}
|
|
60349
61463
|
throw new Error(
|
|
60350
61464
|
`Multiple .prs files found in .promptscript/. Use --file to specify which one.`
|
|
@@ -60570,6 +61684,306 @@ async function rollbackSkillsAdd(state) {
|
|
|
60570
61684
|
}
|
|
60571
61685
|
return new Error(rollbackErrors.map((error) => error.message).join("; "));
|
|
60572
61686
|
}
|
|
61687
|
+
function failLocalSkillStep(spinner, step) {
|
|
61688
|
+
spinner.fail(step.message);
|
|
61689
|
+
if (step.hint) {
|
|
61690
|
+
ConsoleOutput.error(step.hint);
|
|
61691
|
+
}
|
|
61692
|
+
process.exitCode = 1;
|
|
61693
|
+
}
|
|
61694
|
+
async function scanManagedSkillNames(managedRoot, skillDir) {
|
|
61695
|
+
if (!existsSync31(managedRoot)) return [];
|
|
61696
|
+
const entries = await readdir9(managedRoot, { withFileTypes: true });
|
|
61697
|
+
const names = [];
|
|
61698
|
+
for (const entry of entries) {
|
|
61699
|
+
if (!entry.isDirectory()) continue;
|
|
61700
|
+
if (resolve40(managedRoot, entry.name) === resolve40(skillDir)) continue;
|
|
61701
|
+
names.push(entry.name);
|
|
61702
|
+
}
|
|
61703
|
+
return names;
|
|
61704
|
+
}
|
|
61705
|
+
function collectLocalUseNames(lines, skillDir, entryDir) {
|
|
61706
|
+
const names = [];
|
|
61707
|
+
for (const line of lines) {
|
|
61708
|
+
const usePath = extractUsePath(line);
|
|
61709
|
+
if (!usePath || !(usePath.startsWith("./") || usePath.startsWith("../"))) continue;
|
|
61710
|
+
const absUsePath = resolve40(entryDir, usePath);
|
|
61711
|
+
const dir = usePath.endsWith(".md") ? dirname23(absUsePath) : absUsePath;
|
|
61712
|
+
if (dir === resolve40(skillDir)) continue;
|
|
61713
|
+
names.push(basename18(dir));
|
|
61714
|
+
}
|
|
61715
|
+
return names;
|
|
61716
|
+
}
|
|
61717
|
+
async function collectLocalExistingNames(lockfile, lines, skillDir, entryDir) {
|
|
61718
|
+
const names = new Set(collectExistingSkillNames(lockfile));
|
|
61719
|
+
const managedRoot = resolve40(process.cwd(), MANAGED_SKILLS_DIR);
|
|
61720
|
+
for (const name of await scanManagedSkillNames(managedRoot, skillDir)) {
|
|
61721
|
+
names.add(name);
|
|
61722
|
+
}
|
|
61723
|
+
for (const name of collectLocalUseNames(lines, skillDir, entryDir)) {
|
|
61724
|
+
names.add(name);
|
|
61725
|
+
}
|
|
61726
|
+
return names;
|
|
61727
|
+
}
|
|
61728
|
+
async function classifyLocalSkillSource(expanded, copyRequested) {
|
|
61729
|
+
const absSource = resolve40(process.cwd(), expanded);
|
|
61730
|
+
if (!existsSync31(absSource)) {
|
|
61731
|
+
return { ok: false, message: `Path not found: ${expanded}` };
|
|
61732
|
+
}
|
|
61733
|
+
const lstatDetails = await lstat11(absSource);
|
|
61734
|
+
if (lstatDetails.isSymbolicLink() && !copyRequested) {
|
|
61735
|
+
return {
|
|
61736
|
+
ok: false,
|
|
61737
|
+
message: "Symbolic-linked skill directories are not supported",
|
|
61738
|
+
hint: "The resolver skips symlinked directories at compile time. Use --copy to install the skill files."
|
|
61739
|
+
};
|
|
61740
|
+
}
|
|
61741
|
+
const details = lstatDetails.isSymbolicLink() ? await stat3(absSource) : lstatDetails;
|
|
61742
|
+
if (details.isFile()) {
|
|
61743
|
+
if (!absSource.toLowerCase().endsWith(".md")) {
|
|
61744
|
+
return {
|
|
61745
|
+
ok: false,
|
|
61746
|
+
message: `Not a SKILL.md: ${expanded}`,
|
|
61747
|
+
hint: "A local file source must be a SKILL.md, or the directory holding it."
|
|
61748
|
+
};
|
|
61749
|
+
}
|
|
61750
|
+
return { ok: true, value: { skillMdPath: absSource, skillDir: dirname23(absSource) } };
|
|
61751
|
+
}
|
|
61752
|
+
if (details.isDirectory()) {
|
|
61753
|
+
const skillMdPath = join30(absSource, "SKILL.md");
|
|
61754
|
+
if (!existsSync31(skillMdPath)) {
|
|
61755
|
+
return {
|
|
61756
|
+
ok: false,
|
|
61757
|
+
message: `No SKILL.md found in: ${expanded}`,
|
|
61758
|
+
hint: "A skill directory must contain a SKILL.md file."
|
|
61759
|
+
};
|
|
61760
|
+
}
|
|
61761
|
+
return { ok: true, value: { skillMdPath, skillDir: absSource } };
|
|
61762
|
+
}
|
|
61763
|
+
return { ok: false, message: `Unsupported file type: ${expanded}` };
|
|
61764
|
+
}
|
|
61765
|
+
function planLocalUsePath(skillDir, entryDir, copyRequested) {
|
|
61766
|
+
const skillName = basename18(skillDir);
|
|
61767
|
+
const managedDir = resolve40(process.cwd(), MANAGED_SKILLS_DIR, skillName);
|
|
61768
|
+
const sourceIsManaged = resolve40(skillDir) === resolve40(managedDir);
|
|
61769
|
+
const willCopy = copyRequested && !sourceIsManaged;
|
|
61770
|
+
if (willCopy) {
|
|
61771
|
+
return { ok: true, value: { usePath: toUsePath(entryDir, managedDir), managedDir, willCopy } };
|
|
61772
|
+
}
|
|
61773
|
+
const relToRoot = relative20(process.cwd(), skillDir);
|
|
61774
|
+
if (relToRoot.startsWith("..") || isAbsolute18(relToRoot)) {
|
|
61775
|
+
return {
|
|
61776
|
+
ok: false,
|
|
61777
|
+
message: "Skill is outside the project root",
|
|
61778
|
+
hint: `"${skillDir}" cannot be referenced in place because it lies outside the project root. Use --copy to install it into ${MANAGED_SKILLS_DIR}/.`
|
|
61779
|
+
};
|
|
61780
|
+
}
|
|
61781
|
+
const usePath = toUsePath(entryDir, skillDir);
|
|
61782
|
+
if (!USE_PATH_PATTERN.test(usePath)) {
|
|
61783
|
+
return {
|
|
61784
|
+
ok: false,
|
|
61785
|
+
message: `Cannot reference this path in a .prs file: ${usePath}`,
|
|
61786
|
+
hint: "@use paths allow only letters, digits, underscores, hyphens, dots and slashes. Use --copy to install the skill under .promptscript/skills/, or rename the folder."
|
|
61787
|
+
};
|
|
61788
|
+
}
|
|
61789
|
+
return { ok: true, value: { usePath, managedDir, willCopy } };
|
|
61790
|
+
}
|
|
61791
|
+
function validateLocalSkillFrontmatter(options, skillMdPath, skillContent, existingNames, usePath, spinner) {
|
|
61792
|
+
if (options.skipValidation) return "pass";
|
|
61793
|
+
const result = validateSkillFrontmatter(skillContent, { filePath: skillMdPath, existingNames });
|
|
61794
|
+
const hasWarnings = result.issues.some((issue) => issue.severity === "warning");
|
|
61795
|
+
if (!result.valid || options.strict && hasWarnings) {
|
|
61796
|
+
spinner.fail("SKILL.md failed validation");
|
|
61797
|
+
ConsoleOutput.error(usePath);
|
|
61798
|
+
printValidationIssues(result.issues);
|
|
61799
|
+
return "fail";
|
|
61800
|
+
}
|
|
61801
|
+
if (hasWarnings) {
|
|
61802
|
+
spinner.warn("SKILL.md has validation warnings");
|
|
61803
|
+
printValidationIssues(result.issues);
|
|
61804
|
+
spinner.start("Adding skill...");
|
|
61805
|
+
}
|
|
61806
|
+
return "pass";
|
|
61807
|
+
}
|
|
61808
|
+
async function commitLocalSkillAdd(plan, spinner) {
|
|
61809
|
+
spinner.text = plan.willCopy ? "Copying skill..." : "Adding skill...";
|
|
61810
|
+
let replacedBackupDir;
|
|
61811
|
+
let copyStarted = false;
|
|
61812
|
+
try {
|
|
61813
|
+
if (plan.willCopy) {
|
|
61814
|
+
await mkdir11(dirname23(plan.managedDir), { recursive: true });
|
|
61815
|
+
if (existsSync31(plan.managedDir)) {
|
|
61816
|
+
replacedBackupDir = `${plan.managedDir}.replaced-${process.pid}-${Date.now()}`;
|
|
61817
|
+
await rename3(plan.managedDir, replacedBackupDir);
|
|
61818
|
+
}
|
|
61819
|
+
copyStarted = true;
|
|
61820
|
+
await cp(plan.skillDir, plan.managedDir, { recursive: true, dereference: true });
|
|
61821
|
+
}
|
|
61822
|
+
await assertFileUnchanged(plan.entryFile, plan.originalEntryContent);
|
|
61823
|
+
await writeFileAtomically(plan.entryFile, plan.updatedEntryContent);
|
|
61824
|
+
} catch (error) {
|
|
61825
|
+
if (copyStarted) {
|
|
61826
|
+
await rm2(plan.managedDir, { recursive: true, force: true }).catch(() => {
|
|
61827
|
+
});
|
|
61828
|
+
}
|
|
61829
|
+
if (replacedBackupDir) {
|
|
61830
|
+
await rename3(replacedBackupDir, plan.managedDir).catch(() => {
|
|
61831
|
+
});
|
|
61832
|
+
}
|
|
61833
|
+
throw error;
|
|
61834
|
+
}
|
|
61835
|
+
if (replacedBackupDir) {
|
|
61836
|
+
await rm2(replacedBackupDir, { recursive: true, force: true }).catch(() => {
|
|
61837
|
+
});
|
|
61838
|
+
}
|
|
61839
|
+
}
|
|
61840
|
+
function checkSkillNameCollision(skillName, willCopy, force, existingNames) {
|
|
61841
|
+
if (existingNames.has(skillName) && willCopy && !force) {
|
|
61842
|
+
return `Skill "${skillName}" already exists in this project`;
|
|
61843
|
+
}
|
|
61844
|
+
if (force) {
|
|
61845
|
+
existingNames.delete(skillName);
|
|
61846
|
+
}
|
|
61847
|
+
return void 0;
|
|
61848
|
+
}
|
|
61849
|
+
async function prepareLocalSkillAdd(expanded, options) {
|
|
61850
|
+
const parsed = parseSkillSource(expanded);
|
|
61851
|
+
if (parsed.version !== "latest") {
|
|
61852
|
+
return {
|
|
61853
|
+
ok: false,
|
|
61854
|
+
message: "Versioned local paths are not supported",
|
|
61855
|
+
hint: "Local skills are referenced in place, so there is no version to pin."
|
|
61856
|
+
};
|
|
61857
|
+
}
|
|
61858
|
+
const classified = await classifyLocalSkillSource(expanded, options.copy === true);
|
|
61859
|
+
if (!classified.ok) {
|
|
61860
|
+
return classified;
|
|
61861
|
+
}
|
|
61862
|
+
const { skillDir, skillMdPath } = classified.value;
|
|
61863
|
+
const entryFile = await resolveEntryFile(options.file);
|
|
61864
|
+
const originalEntryContent = await readFile30(entryFile, "utf-8");
|
|
61865
|
+
const plan = planLocalUsePath(skillDir, dirname23(entryFile), options.copy === true);
|
|
61866
|
+
if (!plan.ok) {
|
|
61867
|
+
return plan;
|
|
61868
|
+
}
|
|
61869
|
+
return {
|
|
61870
|
+
ok: true,
|
|
61871
|
+
value: {
|
|
61872
|
+
skillMdPath,
|
|
61873
|
+
skillDir,
|
|
61874
|
+
skillName: basename18(skillDir),
|
|
61875
|
+
entryFile,
|
|
61876
|
+
entryDir: dirname23(entryFile),
|
|
61877
|
+
originalEntryContent,
|
|
61878
|
+
usePath: plan.value.usePath,
|
|
61879
|
+
managedDir: plan.value.managedDir,
|
|
61880
|
+
willCopy: plan.value.willCopy
|
|
61881
|
+
}
|
|
61882
|
+
};
|
|
61883
|
+
}
|
|
61884
|
+
function printLocalSkillDryRun(ctx, newLine, spinner) {
|
|
61885
|
+
spinner.succeed("Dry run \u2014 no files modified");
|
|
61886
|
+
ConsoleOutput.newline();
|
|
61887
|
+
ConsoleOutput.dryRun(`Would add to ${ctx.entryFile}:`);
|
|
61888
|
+
ConsoleOutput.dryRun(` ${newLine}`);
|
|
61889
|
+
if (ctx.willCopy) {
|
|
61890
|
+
ConsoleOutput.dryRun(`Would copy ${ctx.skillDir} \u2192 ${ctx.managedDir}`);
|
|
61891
|
+
}
|
|
61892
|
+
ConsoleOutput.dryRun("No lockfile entry (local skills are not pinned)");
|
|
61893
|
+
}
|
|
61894
|
+
function reportLocalSkillAdded(ctx, newLine, spinner) {
|
|
61895
|
+
spinner.succeed("Skill added");
|
|
61896
|
+
ConsoleOutput.newline();
|
|
61897
|
+
ConsoleOutput.success(`${newLine} \u2192 ${ctx.entryFile}`);
|
|
61898
|
+
if (ctx.willCopy) {
|
|
61899
|
+
ConsoleOutput.muted(`Copied into ${MANAGED_SKILLS_DIR}/${ctx.skillName}`);
|
|
61900
|
+
}
|
|
61901
|
+
ConsoleOutput.muted("Local skill - not recorded in the lockfile");
|
|
61902
|
+
}
|
|
61903
|
+
function reportLocalSkillError(error, spinner) {
|
|
61904
|
+
spinner.fail("Failed to add skill");
|
|
61905
|
+
ConsoleOutput.error(error instanceof Error ? error.message : String(error));
|
|
61906
|
+
process.exitCode = 1;
|
|
61907
|
+
}
|
|
61908
|
+
async function addLocalSkill(rawSource, options, spinner) {
|
|
61909
|
+
let transactionLock;
|
|
61910
|
+
try {
|
|
61911
|
+
if (!options.dryRun) {
|
|
61912
|
+
transactionLock = await acquireSkillsAddLock();
|
|
61913
|
+
}
|
|
61914
|
+
spinner.text = "Resolving skill source...";
|
|
61915
|
+
const prepared = await prepareLocalSkillAdd(expandHomePath(rawSource.trim()), options);
|
|
61916
|
+
if (!prepared.ok) {
|
|
61917
|
+
failLocalSkillStep(spinner, prepared);
|
|
61918
|
+
return;
|
|
61919
|
+
}
|
|
61920
|
+
const ctx = prepared.value;
|
|
61921
|
+
const lines = ctx.originalEntryContent.split("\n");
|
|
61922
|
+
const alreadyImported = lines.some((line) => extractUsePath(line) === ctx.usePath);
|
|
61923
|
+
if (alreadyImported) {
|
|
61924
|
+
spinner.warn(`Skill already imported: ${ctx.usePath}`);
|
|
61925
|
+
return;
|
|
61926
|
+
}
|
|
61927
|
+
const lockfile = await loadLockfile3();
|
|
61928
|
+
const existingNames = await collectLocalExistingNames(
|
|
61929
|
+
lockfile,
|
|
61930
|
+
lines,
|
|
61931
|
+
ctx.skillDir,
|
|
61932
|
+
ctx.entryDir
|
|
61933
|
+
);
|
|
61934
|
+
const refusal = checkSkillNameCollision(
|
|
61935
|
+
ctx.skillName,
|
|
61936
|
+
ctx.willCopy,
|
|
61937
|
+
options.force === true,
|
|
61938
|
+
existingNames
|
|
61939
|
+
);
|
|
61940
|
+
if (refusal) {
|
|
61941
|
+
spinner.fail(refusal);
|
|
61942
|
+
ConsoleOutput.error("Use --force to replace it.");
|
|
61943
|
+
process.exitCode = 1;
|
|
61944
|
+
return;
|
|
61945
|
+
}
|
|
61946
|
+
spinner.text = options.skipValidation ? "Reading SKILL.md..." : "Validating SKILL.md...";
|
|
61947
|
+
const skillContent = await readFile30(ctx.skillMdPath, "utf-8");
|
|
61948
|
+
const validationOutcome = validateLocalSkillFrontmatter(
|
|
61949
|
+
options,
|
|
61950
|
+
ctx.skillMdPath,
|
|
61951
|
+
skillContent,
|
|
61952
|
+
existingNames,
|
|
61953
|
+
ctx.usePath,
|
|
61954
|
+
spinner
|
|
61955
|
+
);
|
|
61956
|
+
if (validationOutcome === "fail") {
|
|
61957
|
+
process.exitCode = 1;
|
|
61958
|
+
return;
|
|
61959
|
+
}
|
|
61960
|
+
const insertionPoint = findInsertionPoint(lines);
|
|
61961
|
+
const newLine = `@use ${ctx.usePath}`;
|
|
61962
|
+
lines.splice(insertionPoint, 0, newLine);
|
|
61963
|
+
if (options.dryRun) {
|
|
61964
|
+
printLocalSkillDryRun(ctx, newLine, spinner);
|
|
61965
|
+
return;
|
|
61966
|
+
}
|
|
61967
|
+
await commitLocalSkillAdd(
|
|
61968
|
+
{
|
|
61969
|
+
entryFile: ctx.entryFile,
|
|
61970
|
+
originalEntryContent: ctx.originalEntryContent,
|
|
61971
|
+
updatedEntryContent: lines.join("\n"),
|
|
61972
|
+
willCopy: ctx.willCopy,
|
|
61973
|
+
skillDir: ctx.skillDir,
|
|
61974
|
+
managedDir: ctx.managedDir
|
|
61975
|
+
},
|
|
61976
|
+
spinner
|
|
61977
|
+
);
|
|
61978
|
+
reportLocalSkillAdded(ctx, newLine, spinner);
|
|
61979
|
+
} catch (error) {
|
|
61980
|
+
reportLocalSkillError(error, spinner);
|
|
61981
|
+
} finally {
|
|
61982
|
+
if (transactionLock) {
|
|
61983
|
+
await releaseSkillsAddLock(transactionLock);
|
|
61984
|
+
}
|
|
61985
|
+
}
|
|
61986
|
+
}
|
|
60573
61987
|
async function skillsAddCommand(rawSource, options) {
|
|
60574
61988
|
const spinner = createSpinner("Adding skill...").start();
|
|
60575
61989
|
let rollbackState;
|
|
@@ -60583,6 +61997,10 @@ async function skillsAddCommand(rawSource, options) {
|
|
|
60583
61997
|
process.exitCode = 1;
|
|
60584
61998
|
return;
|
|
60585
61999
|
}
|
|
62000
|
+
if (isLocalSkillSource(rawSource)) {
|
|
62001
|
+
await addLocalSkill(rawSource, options, spinner);
|
|
62002
|
+
return;
|
|
62003
|
+
}
|
|
60586
62004
|
const sshCloneUrl = extractSshCloneUrl(rawSource);
|
|
60587
62005
|
const source = normalizeSkillSource(rawSource);
|
|
60588
62006
|
const sourceError = validateRemoteSource(source);
|
|
@@ -61052,6 +62470,8 @@ var __filename4 = fileURLToPath4(import.meta.url);
|
|
|
61052
62470
|
var __dirname4 = dirname28(__filename4);
|
|
61053
62471
|
var CLI_VERSION = getPackageVersion(__dirname3, "./package.json");
|
|
61054
62472
|
var program = new Command();
|
|
62473
|
+
var RESOURCES_FLAG = "--resources <items>";
|
|
62474
|
+
var RESOURCES_DESCRIPTION = "Compile only these resources (agents, skills, commands, mcp, hooks, plugins, main)";
|
|
61055
62475
|
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) => {
|
|
61056
62476
|
if (actionCommand.name() === "__telemetry-flush" && process.env["PROMPTSCRIPT_TELEMETRY_FLUSH"] === "1") {
|
|
61057
62477
|
return;
|
|
@@ -61088,11 +62508,11 @@ program.command("init").description("Initialize PromptScript in current director
|
|
|
61088
62508
|
}
|
|
61089
62509
|
return initCommand(opts);
|
|
61090
62510
|
});
|
|
61091
|
-
program.command("compile").description("Compile PromptScript to target formats").option("-b, --build <name>", "Named build profile from config.builds").option("--all-builds", "Compile all named build profiles in deterministic order").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-a, --all", "All configured targets").option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option("--dry-run", "Preview changes").option(
|
|
62511
|
+
program.command("compile").description("Compile PromptScript to target formats").option("-b, --build <name>", "Named build profile from config.builds").option("--all-builds", "Compile all named build profiles in deterministic order").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-a, --all", "All configured targets").option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option(RESOURCES_FLAG, RESOURCES_DESCRIPTION, collectResourceKinds, []).option("--dry-run", "Preview changes").option(
|
|
61092
62512
|
"--no-migrate-factory-hooks",
|
|
61093
62513
|
"Warn instead of migrating legacy .factory/settings.json hooks"
|
|
61094
62514
|
).option("--registry <path>", "Registry path (overrides config)").option("-c, --config <path>", "Path to custom config file").option("--force", "Force overwrite existing files without prompts").option("--strict", "Treat output path conflicts as errors").option("--ignore-hashes", "Skip reference integrity hash verification").option("--cwd <dir>", "Working directory (project root)").action((opts) => compileCommand(opts));
|
|
61095
|
-
program.command("build <name>").description("Compile a named build profile").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option("--dry-run", "Preview changes").option(
|
|
62515
|
+
program.command("build <name>").description("Compile a named build profile").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option(RESOURCES_FLAG, RESOURCES_DESCRIPTION, collectResourceKinds, []).option("--dry-run", "Preview changes").option(
|
|
61096
62516
|
"--no-migrate-factory-hooks",
|
|
61097
62517
|
"Warn instead of migrating legacy .factory/settings.json hooks"
|
|
61098
62518
|
).option("--registry <path>", "Registry path (overrides config)").option("-c, --config <path>", "Path to custom config file").option("--force", "Force overwrite existing files without prompts").option("--strict", "Treat output path conflicts as errors").option("--ignore-hashes", "Skip reference integrity hash verification").option("--cwd <dir>", "Working directory (project root)").action((name, opts) => compileCommand({ ...opts, build: name }));
|
|
@@ -61124,7 +62544,10 @@ program.command("resolve <import>").description("Show the lock pin and local sou
|
|
|
61124
62544
|
program.command("hook").argument("<action>", "Hook action: pre-edit or post-edit").description("Hook handler invoked by AI tools (not for direct use)").action(hookCommand);
|
|
61125
62545
|
program.command("hooks").argument("<action>", "Action: install or uninstall").argument("[tool]", "Tool: claude, gemini, copilot, cursor, windsurf, factory, cline").option("--all", "Install/uninstall for all detected tools").description("Manage PromptScript hooks for AI tools").action(hooksCommand);
|
|
61126
62546
|
var skills = program.command("skills").description("Manage PromptScript skills");
|
|
61127
|
-
skills.command("add <source>").description("Add a remote skill to the project").option("-f, --file <file>", "Target .prs file to modify").option("--dry-run", "Preview changes without writing").option("--skip-validation", "Skip SKILL.md frontmatter validation (not recommended)").option("--strict", "Treat validation warnings as errors").
|
|
62547
|
+
skills.command("add <source>").description("Add a remote or local skill to the project").option("-f, --file <file>", "Target .prs file to modify").option("--dry-run", "Preview changes without writing").option("--skip-validation", "Skip SKILL.md frontmatter validation (not recommended)").option("--strict", "Treat validation warnings as errors").option(
|
|
62548
|
+
"--copy",
|
|
62549
|
+
"Local sources: copy into .promptscript/skills/ instead of referencing in place"
|
|
62550
|
+
).option("--force", "Local sources: replace an existing skill with the same name").action((source, opts) => skillsAddCommand(source, opts));
|
|
61128
62551
|
skills.command("remove <name>").description("Remove a skill from the project").option("--dry-run", "Preview changes without writing").action((name, opts) => skillsRemoveCommand(name, opts));
|
|
61129
62552
|
skills.command("list").description("List skills imported in the current project").action(() => skillsListCommand());
|
|
61130
62553
|
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));
|