@yanlinglabs/winter-agent-runtime 0.0.40 → 0.0.43
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/dist/commands/resolver.d.ts +8 -13
- package/dist/context/agent-listing.d.ts +7 -11
- package/dist/context/attachments.d.ts +14 -23
- package/dist/context/dynamic-sections.d.ts +5 -5
- package/dist/context/git-branch-fixture.d.ts +22 -0
- package/dist/context/git-status.d.ts +2 -2
- package/dist/context/memory.d.ts +1 -1
- package/dist/context/output-styles.d.ts +2 -2
- package/dist/context/request-layout.d.ts +16 -17
- package/dist/context/seam.d.ts +7 -6
- package/dist/embedded-worker.js +3 -3
- package/dist/embedded.js +3 -3
- package/dist/engine.d.ts +3 -3
- package/dist/{index-r7yjcppm.js → index-14xkt4jp.js} +2 -2
- package/dist/{index-rhxkckyn.js → index-bh1ve8ws.js} +238 -154
- package/dist/{index-a8j104mg.js → index-kqc3tdph.js} +980 -828
- package/dist/index.js +1 -1
- package/dist/mcp/lifecycle.d.ts +2 -1
- package/dist/permissions/edit-recognition.d.ts +1 -1
- package/dist/permissions/evaluator.d.ts +19 -30
- package/dist/permissions/file-rules.d.ts +177 -277
- package/dist/permissions/grammar.d.ts +58 -0
- package/dist/permissions/policy-state.d.ts +1 -1
- package/dist/permissions/ruleset.d.ts +1 -1
- package/dist/permissions/shell-structure.d.ts +1 -1
- package/dist/plugins/bundle.d.ts +4 -6
- package/dist/plugins/loader.corpus-fixture.d.ts +26 -0
- package/dist/plugins/loader.d.ts +3 -4
- package/dist/plugins/manifest.d.ts +23 -46
- package/dist/production-wiring.d.ts +1 -1
- package/dist/provider/lean-prompt.d.ts +1 -6
- package/dist/sandbox/profile.d.ts +39 -79
- package/dist/sandbox/spawn.d.ts +5 -6
- package/dist/skills/listing.d.ts +8 -26
- package/dist/skills/store.d.ts +2 -3
- package/dist/store/dialect.d.ts +1 -1
- package/dist/subagents/availability.d.ts +10 -8
- package/dist/subagents/child-handle.d.ts +5 -5
- package/dist/subagents/definitions.d.ts +7 -6
- package/dist/subagents/fork.d.ts +4 -8
- package/dist/subagents/notification-queue.d.ts +30 -38
- package/dist/testing.js +2 -2
- package/dist/tools/descriptors/web-fetch.d.ts +1 -1
- package/dist/tools/descriptors/web-search.d.ts +1 -1
- package/dist/tools/impl/_search-budget.d.ts +1 -1
- package/dist/tools/impl/_web-fetch-net.d.ts +6 -6
- package/dist/tools/impl/_web-search-assembler.d.ts +7 -20
- package/dist/tools/impl/background-task-runtime.d.ts +13 -13
- package/dist/tools/impl/bash.d.ts +3 -3
- package/dist/tools/impl/monitor.d.ts +2 -2
- package/dist/tools/registry.d.ts +12 -0
- package/dist/toolsearch/exposure.d.ts +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web/fetchable-url.d.ts +1 -1
- package/dist/web/preapproved-hosts.d.ts +9 -31
- package/dist/workflows/store.d.ts +23 -31
- package/package.json +4 -4
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
computeActiveSlotSet,
|
|
8
8
|
resolveSlotToProvider,
|
|
9
9
|
shellWords,
|
|
10
|
-
escapeRegExpLiteral,
|
|
11
10
|
validatePermissionRuleString,
|
|
12
11
|
getRegisteredTool,
|
|
13
12
|
listRegisteredTools,
|
|
@@ -86,7 +85,7 @@ import {
|
|
|
86
85
|
providerCredentialRef2,
|
|
87
86
|
createModelClassifier2,
|
|
88
87
|
selectClassifierRoute2
|
|
89
|
-
} from "./index-
|
|
88
|
+
} from "./index-kqc3tdph.js";
|
|
90
89
|
import {
|
|
91
90
|
createKeychainCredentialStore,
|
|
92
91
|
createKeychainSecretReader,
|
|
@@ -2243,7 +2242,7 @@ var ALL_TIER_REFUSED_ENV = [
|
|
|
2243
2242
|
disableCronEnvName(WINTER_BRAND5),
|
|
2244
2243
|
mcpOAuthTestStoreEnvName(WINTER_BRAND5)
|
|
2245
2244
|
];
|
|
2246
|
-
function
|
|
2245
|
+
function escapeRegExpLiteral(literal) {
|
|
2247
2246
|
return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2248
2247
|
}
|
|
2249
2248
|
var HOST_MANAGED_REFUSED_ENV_PATTERNS = [
|
|
@@ -2258,7 +2257,7 @@ var HOST_MANAGED_REFUSED_ENV_PATTERNS = [
|
|
|
2258
2257
|
/_BASE_URL$/,
|
|
2259
2258
|
/_API_BASE$/,
|
|
2260
2259
|
/^CLAUDE_CODE_USE_/,
|
|
2261
|
-
new RegExp(`^${
|
|
2260
|
+
new RegExp(`^${escapeRegExpLiteral(envName3(WINTER_BRAND5, "USE_"))}`)
|
|
2262
2261
|
];
|
|
2263
2262
|
var HOST_MANAGED_DISABLED_SETTINGS_KEYS = ["apiKeyHelper"];
|
|
2264
2263
|
function filterSettingsEnv(env, tier, opts) {
|
|
@@ -2333,29 +2332,30 @@ var BUILTIN_OUTPUT_STYLES = [
|
|
|
2333
2332
|
];
|
|
2334
2333
|
var BUILTIN_OUTPUT_STYLE_NAMES = BUILTIN_OUTPUT_STYLES.map((s) => s.name);
|
|
2335
2334
|
var STYLE_NAME = /^[A-Za-z0-9_-]+$/;
|
|
2335
|
+
var TRUE_WORDS = new Set(["1", "true", "yes", "on"]);
|
|
2336
|
+
var FALSE_WORDS = new Set(["0", "false", "no", "off"]);
|
|
2336
2337
|
function claudeBoolean(value) {
|
|
2337
2338
|
if (typeof value === "boolean")
|
|
2338
2339
|
return value;
|
|
2339
2340
|
if (typeof value !== "string" && typeof value !== "number")
|
|
2340
2341
|
return;
|
|
2341
|
-
const
|
|
2342
|
-
if (
|
|
2342
|
+
const word = String(value).toLowerCase().trim();
|
|
2343
|
+
if (TRUE_WORDS.has(word))
|
|
2343
2344
|
return true;
|
|
2344
|
-
if (
|
|
2345
|
+
if (FALSE_WORDS.has(word))
|
|
2345
2346
|
return false;
|
|
2346
2347
|
return;
|
|
2347
2348
|
}
|
|
2349
|
+
var EXCERPT_MAX = 100;
|
|
2350
|
+
var HEADING_LINE = /^#+\s+(.+)$/;
|
|
2348
2351
|
function bodyExcerpt(body, def) {
|
|
2349
|
-
|
|
2350
|
-
`))
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
return text.length > 100 ? `${text.slice(0, 97)}...` : text;
|
|
2357
|
-
}
|
|
2358
|
-
return def;
|
|
2352
|
+
const line = body.split(`
|
|
2353
|
+
`).map((l) => l.trim()).find((l) => l.length > 0);
|
|
2354
|
+
if (line === undefined)
|
|
2355
|
+
return def;
|
|
2356
|
+
const heading = HEADING_LINE.exec(line);
|
|
2357
|
+
const text = heading !== null ? heading[1] : line;
|
|
2358
|
+
return text.length > EXCERPT_MAX ? `${text.slice(0, EXCERPT_MAX - 3)}...` : text;
|
|
2359
2359
|
}
|
|
2360
2360
|
function parseStyleFile(path, fallbackName, source) {
|
|
2361
2361
|
let raw;
|
|
@@ -2398,21 +2398,20 @@ function parsePluginStyleFile(path, pluginName, fallbackBaseName) {
|
|
|
2398
2398
|
} catch {
|
|
2399
2399
|
return null;
|
|
2400
2400
|
}
|
|
2401
|
-
const { attrs, body
|
|
2402
|
-
const
|
|
2403
|
-
const declaredName =
|
|
2404
|
-
const baseName = declaredName
|
|
2401
|
+
const { attrs, body } = parseFrontmatter(raw);
|
|
2402
|
+
const nameAttr = attrs["name"];
|
|
2403
|
+
const declaredName = nameAttr === null || nameAttr === undefined ? "" : String(nameAttr);
|
|
2404
|
+
const baseName = declaredName.length > 0 ? declaredName : fallbackBaseName;
|
|
2405
2405
|
if (!STYLE_NAME.test(baseName))
|
|
2406
2406
|
return null;
|
|
2407
|
-
const
|
|
2408
|
-
const
|
|
2409
|
-
const description =
|
|
2410
|
-
const keepCodingInstructions = claudeBoolean(attrs["keep-coding-instructions"]) === true;
|
|
2407
|
+
const descriptionAttr = attrs["description"];
|
|
2408
|
+
const declaredDescription = typeof descriptionAttr === "string" || typeof descriptionAttr === "number" || typeof descriptionAttr === "boolean" ? String(descriptionAttr).trim() : "";
|
|
2409
|
+
const description = declaredDescription.length > 0 ? declaredDescription : bodyExcerpt(body, `Output style from ${pluginName} plugin`);
|
|
2411
2410
|
return {
|
|
2412
2411
|
name: `${pluginName}:${baseName}`,
|
|
2413
2412
|
description,
|
|
2414
|
-
body: capBytes(neutralizeReminderTags(
|
|
2415
|
-
keepCodingInstructions,
|
|
2413
|
+
body: capBytes(neutralizeReminderTags(body.trim()), OUTPUT_STYLE_MAX_BYTES).text,
|
|
2414
|
+
keepCodingInstructions: claudeBoolean(attrs["keep-coding-instructions"]) === true,
|
|
2416
2415
|
source: "plugin",
|
|
2417
2416
|
replacementDowngraded: false
|
|
2418
2417
|
};
|
|
@@ -2488,15 +2487,24 @@ var ENVIRONMENT_HEADING = "# Environment";
|
|
|
2488
2487
|
var ENVIRONMENT_LEAD_IN = "You have been invoked in the following environment: ";
|
|
2489
2488
|
var WINTER_PRODUCT_LINE = "Winter runs this session as an agent runtime on behalf of a host application; the host decides how your output is shown to the user.";
|
|
2490
2489
|
function shellName(raw) {
|
|
2491
|
-
|
|
2492
|
-
|
|
2490
|
+
if (raw.trim().length === 0)
|
|
2491
|
+
return "unknown";
|
|
2492
|
+
if (raw.includes("zsh"))
|
|
2493
2493
|
return "zsh";
|
|
2494
|
-
if (
|
|
2494
|
+
if (raw.includes("bash"))
|
|
2495
2495
|
return "bash";
|
|
2496
|
-
return
|
|
2496
|
+
return raw;
|
|
2497
2497
|
}
|
|
2498
2498
|
function bullets(items) {
|
|
2499
|
-
|
|
2499
|
+
const lines = [];
|
|
2500
|
+
for (const item of items) {
|
|
2501
|
+
if (typeof item === "string")
|
|
2502
|
+
lines.push(` - ${item}`);
|
|
2503
|
+
else
|
|
2504
|
+
for (const member of item)
|
|
2505
|
+
lines.push(` - ${member}`);
|
|
2506
|
+
}
|
|
2507
|
+
return lines;
|
|
2500
2508
|
}
|
|
2501
2509
|
function modelLines(input) {
|
|
2502
2510
|
const lines = [];
|
|
@@ -2690,13 +2698,21 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync,
|
|
|
2690
2698
|
import { homedir as homedir2 } from "node:os";
|
|
2691
2699
|
import { dirname, resolve as resolve2 } from "node:path";
|
|
2692
2700
|
var DEFAULT_MAX_DEPTH2 = 5;
|
|
2693
|
-
|
|
2694
|
-
|
|
2701
|
+
function importTokenPattern() {
|
|
2702
|
+
return /(^|\s)@((?:[^\s\\]|\\ )+)/g;
|
|
2703
|
+
}
|
|
2704
|
+
var BARE_IMPORT_START = /^[A-Za-z0-9._-]/;
|
|
2705
|
+
function importTokenPath(rawToken) {
|
|
2706
|
+
const hash = rawToken.indexOf("#");
|
|
2707
|
+
const withoutFragment = hash === -1 ? rawToken : rawToken.slice(0, hash);
|
|
2708
|
+
if (withoutFragment.length === 0)
|
|
2709
|
+
return;
|
|
2710
|
+
const path = withoutFragment.replaceAll("\\ ", " ");
|
|
2695
2711
|
if (path.startsWith("./") || path.startsWith("~/"))
|
|
2696
|
-
return
|
|
2697
|
-
if (path.startsWith("/")
|
|
2698
|
-
return
|
|
2699
|
-
return
|
|
2712
|
+
return path;
|
|
2713
|
+
if (path.startsWith("/"))
|
|
2714
|
+
return path === "/" ? undefined : path;
|
|
2715
|
+
return BARE_IMPORT_START.test(path) ? path : undefined;
|
|
2700
2716
|
}
|
|
2701
2717
|
function resolveImportPath(token, containingFileDir) {
|
|
2702
2718
|
if (token.startsWith("~/"))
|
|
@@ -2765,15 +2781,9 @@ function expandTextRun(text, containingFileDir, depth, ctx) {
|
|
|
2765
2781
|
return parts.map((part, i) => i % 2 === 1 ? part : replaceImportTokens(part, containingFileDir, depth, ctx)).join("");
|
|
2766
2782
|
}
|
|
2767
2783
|
function replaceImportTokens(text, containingFileDir, depth, ctx) {
|
|
2768
|
-
return text.replace(
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
if (hashIndex !== -1)
|
|
2772
|
-
token = token.slice(0, hashIndex);
|
|
2773
|
-
if (token.length === 0)
|
|
2774
|
-
return full;
|
|
2775
|
-
token = token.replace(/\\ /g, " ");
|
|
2776
|
-
if (!isValidImportPath(token))
|
|
2784
|
+
return text.replace(importTokenPattern(), (full, leading, rawToken) => {
|
|
2785
|
+
const token = importTokenPath(rawToken);
|
|
2786
|
+
if (token === undefined)
|
|
2777
2787
|
return full;
|
|
2778
2788
|
const resolvedPath = resolveImportPath(token, containingFileDir);
|
|
2779
2789
|
if (ctx.tier !== "user") {
|
|
@@ -2905,9 +2915,9 @@ var INSTRUCTIONS_CONTEXT_LABELS = {
|
|
|
2905
2915
|
user: " (user's private global instructions for all projects)"
|
|
2906
2916
|
};
|
|
2907
2917
|
function renderInstructionsContext(files) {
|
|
2908
|
-
const entries = files.filter((
|
|
2918
|
+
const entries = files.filter((file) => file.content !== "").map((file) => `Contents of ${file.path}${INSTRUCTIONS_CONTEXT_LABELS[file.kind]}:
|
|
2909
2919
|
|
|
2910
|
-
${
|
|
2920
|
+
${file.content.trim()}`);
|
|
2911
2921
|
if (entries.length === 0)
|
|
2912
2922
|
return;
|
|
2913
2923
|
return `${INSTRUCTIONS_CONTEXT_HEADER}
|
|
@@ -3444,17 +3454,37 @@ function scanPluginSkillsAt(skillsParentDir, pluginName) {
|
|
|
3444
3454
|
}
|
|
3445
3455
|
return out;
|
|
3446
3456
|
}
|
|
3447
|
-
function
|
|
3448
|
-
const defaultSkills = scanPluginSkillsAt(join9(root, "skills"), pluginName);
|
|
3449
|
-
const overridePaths = resolveManifestComponentOverride(root, pluginName, "skills", declared, true, warnings);
|
|
3450
|
-
if (overridePaths === undefined)
|
|
3451
|
-
return defaultSkills;
|
|
3452
|
-
const overrideSkills = overridePaths.flatMap((path) => scanPluginSkillsAt(path, pluginName));
|
|
3457
|
+
function dedupeByName(entries) {
|
|
3453
3458
|
const byName = new Map;
|
|
3454
|
-
for (const entry of
|
|
3459
|
+
for (const entry of entries)
|
|
3455
3460
|
byName.set(entry.name, entry);
|
|
3456
3461
|
return [...byName.values()];
|
|
3457
3462
|
}
|
|
3463
|
+
function realPathOr(path) {
|
|
3464
|
+
try {
|
|
3465
|
+
return realpathSync3(path);
|
|
3466
|
+
} catch {
|
|
3467
|
+
return path;
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
function isInlineCommandsMap(declared) {
|
|
3471
|
+
if (typeof declared !== "object" || declared === null || Array.isArray(declared))
|
|
3472
|
+
return false;
|
|
3473
|
+
const first = Object.values(declared)[0];
|
|
3474
|
+
if (typeof first !== "object" || first === null)
|
|
3475
|
+
return false;
|
|
3476
|
+
return "source" in first || "content" in first;
|
|
3477
|
+
}
|
|
3478
|
+
function resolvePluginSkills(root, pluginName, declared, warnings) {
|
|
3479
|
+
const defaults = scanPluginSkillsAt(join9(root, "skills"), pluginName);
|
|
3480
|
+
const override = resolveManifestComponentOverride(root, pluginName, "skills", declared, true, warnings);
|
|
3481
|
+
if (override === undefined)
|
|
3482
|
+
return defaults;
|
|
3483
|
+
const all = [...defaults];
|
|
3484
|
+
for (const dir of override)
|
|
3485
|
+
all.push(...scanPluginSkillsAt(dir, pluginName));
|
|
3486
|
+
return dedupeByName(all);
|
|
3487
|
+
}
|
|
3458
3488
|
function scanPluginCommandFile(path, pluginName) {
|
|
3459
3489
|
const name = basename2(path, ".md");
|
|
3460
3490
|
let raw;
|
|
@@ -3491,7 +3521,7 @@ function scanPluginCommands(root, pluginName) {
|
|
|
3491
3521
|
return scanPluginCommandsDir(join9(root, "commands"), pluginName);
|
|
3492
3522
|
}
|
|
3493
3523
|
function scanPluginCommandsOverride(paths, pluginName) {
|
|
3494
|
-
const
|
|
3524
|
+
const all = [];
|
|
3495
3525
|
for (const path of paths) {
|
|
3496
3526
|
let isDir;
|
|
3497
3527
|
try {
|
|
@@ -3500,25 +3530,21 @@ function scanPluginCommandsOverride(paths, pluginName) {
|
|
|
3500
3530
|
continue;
|
|
3501
3531
|
}
|
|
3502
3532
|
if (isDir) {
|
|
3503
|
-
|
|
3504
|
-
byName.set(entry.name, entry);
|
|
3533
|
+
all.push(...scanPluginCommandsDir(path, pluginName));
|
|
3505
3534
|
} else {
|
|
3506
3535
|
const entry = scanPluginCommandFile(path, pluginName);
|
|
3507
3536
|
if (entry !== undefined)
|
|
3508
|
-
|
|
3537
|
+
all.push(entry);
|
|
3509
3538
|
}
|
|
3510
3539
|
}
|
|
3511
|
-
return
|
|
3540
|
+
return dedupeByName(all);
|
|
3512
3541
|
}
|
|
3513
3542
|
function resolveCommandsManifestOverride(root, pluginName, declared, warnings) {
|
|
3514
3543
|
if (declared === undefined)
|
|
3515
3544
|
return;
|
|
3516
|
-
if (
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
warnings.push(`plugin "${pluginName}"'s manifest "commands" uses the inline {name: {source|content}} form, which Winter does not support yet -- no commands were loaded from it (the default commands/ directory is still shadowed, matching claude's own behaviour whenever the key is present)`);
|
|
3520
|
-
return [];
|
|
3521
|
-
}
|
|
3545
|
+
if (isInlineCommandsMap(declared)) {
|
|
3546
|
+
warnings.push(`plugin "${pluginName}"'s manifest "commands" uses the inline {name: {source|content}} form, which Winter does not support yet -- no commands were loaded from it (the default commands/ directory is still shadowed, matching claude's own behaviour whenever the key is present)`);
|
|
3547
|
+
return [];
|
|
3522
3548
|
}
|
|
3523
3549
|
return resolveManifestComponentOverride(root, pluginName, "commands", declared, false, warnings);
|
|
3524
3550
|
}
|
|
@@ -3573,7 +3599,7 @@ function scanPluginAgents(root, pluginName) {
|
|
|
3573
3599
|
return scanPluginAgentsDir(join9(root, "agents"), pluginName);
|
|
3574
3600
|
}
|
|
3575
3601
|
function scanPluginAgentsOverride(paths, pluginName) {
|
|
3576
|
-
const
|
|
3602
|
+
const agents = {};
|
|
3577
3603
|
const rejected = [];
|
|
3578
3604
|
for (const path of paths) {
|
|
3579
3605
|
let isDir;
|
|
@@ -3584,13 +3610,14 @@ function scanPluginAgentsOverride(paths, pluginName) {
|
|
|
3584
3610
|
}
|
|
3585
3611
|
if (isDir) {
|
|
3586
3612
|
const scanned = scanPluginAgentsDir(path, pluginName);
|
|
3587
|
-
Object.
|
|
3613
|
+
for (const [name, def] of Object.entries(scanned.agents))
|
|
3614
|
+
agents[name] = def;
|
|
3588
3615
|
rejected.push(...scanned.rejected);
|
|
3589
3616
|
} else {
|
|
3590
|
-
scanPluginAgentFile(path, pluginName,
|
|
3617
|
+
scanPluginAgentFile(path, pluginName, agents, rejected);
|
|
3591
3618
|
}
|
|
3592
3619
|
}
|
|
3593
|
-
return { agents
|
|
3620
|
+
return { agents, rejected };
|
|
3594
3621
|
}
|
|
3595
3622
|
function collectMcpServers(root, manifest) {
|
|
3596
3623
|
const servers = {};
|
|
@@ -3641,26 +3668,20 @@ function readPluginHooksJson(root, pluginName, warnings) {
|
|
|
3641
3668
|
return readHooksFile(join9(root, "hooks", "hooks.json"), pluginName, "hooks/hooks.json", warnings);
|
|
3642
3669
|
}
|
|
3643
3670
|
function resolveManifestHooksStringEntries(root, pluginName, declared, warnings) {
|
|
3644
|
-
const entries =
|
|
3645
|
-
const
|
|
3646
|
-
const
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
} catch {
|
|
3650
|
-
return defaultHooksJsonPath;
|
|
3651
|
-
}
|
|
3652
|
-
})();
|
|
3653
|
-
const seenReal = new Set;
|
|
3654
|
-
const results = [];
|
|
3671
|
+
const entries = declared === undefined ? [] : Array.isArray(declared) ? declared : [declared];
|
|
3672
|
+
const standardPath = resolve6(join9(root, "hooks", "hooks.json"));
|
|
3673
|
+
const standardIdentity = realPathOr(standardPath);
|
|
3674
|
+
const accepted = new Set;
|
|
3675
|
+
const out = [];
|
|
3655
3676
|
for (const entry of entries) {
|
|
3656
|
-
if (typeof entry !== "string" || entry
|
|
3677
|
+
if (typeof entry !== "string" || entry === "")
|
|
3657
3678
|
continue;
|
|
3658
3679
|
const full = resolve6(root, entry);
|
|
3659
3680
|
if (!resolvesWithinPluginRoot(full, root)) {
|
|
3660
3681
|
warnings.paths.push(`plugin "${pluginName}"'s manifest "hooks" entry "${entry}" escapes the plugin directory -- ignoring it`);
|
|
3661
3682
|
continue;
|
|
3662
3683
|
}
|
|
3663
|
-
let isFile;
|
|
3684
|
+
let isFile = false;
|
|
3664
3685
|
try {
|
|
3665
3686
|
isFile = statSync5(full).isFile();
|
|
3666
3687
|
} catch {
|
|
@@ -3670,25 +3691,19 @@ function resolveManifestHooksStringEntries(root, pluginName, declared, warnings)
|
|
|
3670
3691
|
warnings.paths.push(`plugin "${pluginName}"'s manifest "hooks" entry "${entry}" was not found at ${full} -- ignoring it`);
|
|
3671
3692
|
continue;
|
|
3672
3693
|
}
|
|
3673
|
-
const real = (
|
|
3674
|
-
|
|
3675
|
-
return realpathSync3(full);
|
|
3676
|
-
} catch {
|
|
3677
|
-
return full;
|
|
3678
|
-
}
|
|
3679
|
-
})();
|
|
3680
|
-
if (real === defaultHooksJsonReal)
|
|
3694
|
+
const real = realPathOr(full);
|
|
3695
|
+
if (real === standardIdentity)
|
|
3681
3696
|
continue;
|
|
3682
|
-
if (
|
|
3697
|
+
if (accepted.has(real)) {
|
|
3683
3698
|
warnings.paths.push(`plugin "${pluginName}"'s manifest "hooks" entry "${entry}" duplicates another entry (both resolve to ${real}) -- loaded once`);
|
|
3684
3699
|
continue;
|
|
3685
3700
|
}
|
|
3686
|
-
|
|
3687
|
-
const
|
|
3688
|
-
if (
|
|
3689
|
-
|
|
3701
|
+
accepted.add(real);
|
|
3702
|
+
const hooks = readHooksFile(full, pluginName, `manifest "hooks" entry "${entry}"`, warnings.content);
|
|
3703
|
+
if (hooks !== undefined)
|
|
3704
|
+
out.push(hooks);
|
|
3690
3705
|
}
|
|
3691
|
-
return
|
|
3706
|
+
return out;
|
|
3692
3707
|
}
|
|
3693
3708
|
function mergeHookSources(root, pluginName, fromHooksJson, manifestHooks, pathWarnings, contentWarnings) {
|
|
3694
3709
|
const merged = {};
|
|
@@ -3727,39 +3742,39 @@ function resolveManifestComponentOverride(root, pluginName, componentKey, declar
|
|
|
3727
3742
|
if (declared === undefined)
|
|
3728
3743
|
return;
|
|
3729
3744
|
const entries = Array.isArray(declared) ? declared : [declared];
|
|
3730
|
-
const
|
|
3745
|
+
const label = `plugin "${pluginName}"'s manifest "${componentKey}"`;
|
|
3746
|
+
const kept = [];
|
|
3731
3747
|
for (const entry of entries) {
|
|
3732
|
-
if (typeof entry !== "string" || entry
|
|
3733
|
-
warnings.push(
|
|
3748
|
+
if (typeof entry !== "string" || entry === "") {
|
|
3749
|
+
warnings.push(`${label} entry ${JSON.stringify(entry)} is not a non-empty string -- ignoring it`);
|
|
3734
3750
|
continue;
|
|
3735
3751
|
}
|
|
3736
3752
|
const full = resolve6(root, entry);
|
|
3737
3753
|
if (!resolvesWithinPluginRoot(full, root)) {
|
|
3738
|
-
warnings.push(
|
|
3754
|
+
warnings.push(`${label} path "${entry}" escapes the plugin directory -- ignoring it`);
|
|
3739
3755
|
continue;
|
|
3740
3756
|
}
|
|
3741
|
-
let
|
|
3757
|
+
let isDir;
|
|
3742
3758
|
try {
|
|
3743
|
-
|
|
3759
|
+
isDir = statSync5(full).isDirectory();
|
|
3744
3760
|
} catch {
|
|
3745
|
-
|
|
3746
|
-
}
|
|
3747
|
-
if (stat === undefined) {
|
|
3748
|
-
warnings.push(`plugin "${pluginName}"'s manifest "${componentKey}" path "${entry}" was not found at ${full} -- ignoring it`);
|
|
3761
|
+
warnings.push(`${label} path "${entry}" was not found at ${full} -- ignoring it`);
|
|
3749
3762
|
continue;
|
|
3750
3763
|
}
|
|
3751
|
-
if (requireDirectory && !
|
|
3752
|
-
const
|
|
3753
|
-
|
|
3764
|
+
if (requireDirectory && !isDir) {
|
|
3765
|
+
const isSkills = componentKey === "skills";
|
|
3766
|
+
const why = isSkills ? " (skills entries must be directories containing SKILL.md)" : "";
|
|
3767
|
+
const hint = isSkills && basename2(entry).toLowerCase() === "skill.md" ? " -- point to its parent directory instead" : "";
|
|
3768
|
+
warnings.push(`${label} path "${entry}" is a file, not a directory${why}${hint} -- ignoring it`);
|
|
3754
3769
|
continue;
|
|
3755
3770
|
}
|
|
3756
|
-
|
|
3771
|
+
kept.push(full);
|
|
3757
3772
|
}
|
|
3758
|
-
return
|
|
3773
|
+
return kept;
|
|
3759
3774
|
}
|
|
3760
3775
|
function manifestOverrideIncludesDefaultDir(resolvedEntries, defaultDirPath) {
|
|
3761
|
-
const
|
|
3762
|
-
return resolvedEntries.some((entry) =>
|
|
3776
|
+
const beneath = defaultDirPath + sep3;
|
|
3777
|
+
return resolvedEntries.some((entry) => entry === defaultDirPath || entry.startsWith(beneath));
|
|
3763
3778
|
}
|
|
3764
3779
|
function shadowedFolderWarning(pluginName, componentDirName, manifestFieldName) {
|
|
3765
3780
|
return `plugin "${pluginName}": the "${componentDirName}/" folder exists but is not auto-loaded because the manifest sets "${manifestFieldName}"`;
|
|
@@ -4373,47 +4388,116 @@ function splitCommand(prompt) {
|
|
|
4373
4388
|
const args = firstSpace === -1 ? "" : trimmed.slice(firstSpace).trim();
|
|
4374
4389
|
return { name, args };
|
|
4375
4390
|
}
|
|
4376
|
-
var ARG_DOLLAR_SENTINEL = "";
|
|
4377
|
-
var ARG_BOUNDARY_SENTINEL = "";
|
|
4378
|
-
function protectSubstitutedValue(value) {
|
|
4379
|
-
const cleaned = (value ?? "").replaceAll(ARG_DOLLAR_SENTINEL, "�").replaceAll(ARG_BOUNDARY_SENTINEL, "�");
|
|
4380
|
-
return ARG_BOUNDARY_SENTINEL + cleaned.replaceAll("$", ARG_DOLLAR_SENTINEL) + ARG_BOUNDARY_SENTINEL;
|
|
4381
|
-
}
|
|
4382
4391
|
function substituteArguments(body, args, namedArgs = []) {
|
|
4383
|
-
|
|
4384
|
-
const
|
|
4385
|
-
const
|
|
4386
|
-
const
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4392
|
+
const text = cleanNoncharacters(body);
|
|
4393
|
+
const wholeArgs = cleanNoncharacters(args);
|
|
4394
|
+
const words = shellWords(args).map((w) => cleanNoncharacters(w.word));
|
|
4395
|
+
const named = namedArgs.map((name, position) => ({ name, position })).filter((n) => n.name.length > 0).sort((a, b) => b.name.length - a.name.length);
|
|
4396
|
+
const claimed = new Uint8Array(text.length);
|
|
4397
|
+
const replacements = [];
|
|
4398
|
+
let substitutions = 0;
|
|
4399
|
+
const isFree = (start, end) => {
|
|
4400
|
+
for (let k = start;k < end; k++)
|
|
4401
|
+
if (claimed[k])
|
|
4402
|
+
return false;
|
|
4403
|
+
return true;
|
|
4404
|
+
};
|
|
4405
|
+
const claim = (start, end, value) => {
|
|
4406
|
+
claimed.fill(1, start, end);
|
|
4407
|
+
replacements.push({ start, end, value });
|
|
4408
|
+
};
|
|
4409
|
+
const endsCleanly = (at) => at >= text.length || text[at] !== "[" && !isWordChar(text.charCodeAt(at));
|
|
4410
|
+
for (let i = text.indexOf("\\$");i !== -1; i = text.indexOf("\\$", i + 1)) {
|
|
4411
|
+
if (i > 0 && text[i - 1] === "\\")
|
|
4412
|
+
continue;
|
|
4413
|
+
const after = i + 2;
|
|
4414
|
+
const escapes = isDigit(text.charCodeAt(after)) || text.startsWith("ARGUMENTS", after) || named.some((n) => text.startsWith(n.name, after) && endsCleanly(after + n.name.length));
|
|
4415
|
+
if (escapes) {
|
|
4416
|
+
claim(i, after, "$");
|
|
4417
|
+
i = after - 1;
|
|
4418
|
+
}
|
|
4394
4419
|
}
|
|
4395
|
-
|
|
4396
|
-
const
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4420
|
+
for (const { name, position } of named) {
|
|
4421
|
+
const needle = "$" + name;
|
|
4422
|
+
for (let i = text.indexOf(needle);i !== -1; ) {
|
|
4423
|
+
const end = i + needle.length;
|
|
4424
|
+
if (isFree(i, end) && endsCleanly(end)) {
|
|
4425
|
+
claim(i, end, words[position] ?? "");
|
|
4426
|
+
substitutions++;
|
|
4427
|
+
i = text.indexOf(needle, end);
|
|
4428
|
+
} else {
|
|
4429
|
+
i = text.indexOf(needle, i + 1);
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
const INDEXED_PREFIX = "$ARGUMENTS[";
|
|
4434
|
+
for (let i = text.indexOf(INDEXED_PREFIX);i !== -1; ) {
|
|
4435
|
+
let j = i + INDEXED_PREFIX.length;
|
|
4436
|
+
while (isDigit(text.charCodeAt(j)))
|
|
4437
|
+
j++;
|
|
4438
|
+
const digitsStart = i + INDEXED_PREFIX.length;
|
|
4439
|
+
if (j > digitsStart && text[j] === "]" && isFree(i, j + 1)) {
|
|
4440
|
+
const index = Number(text.slice(digitsStart, j));
|
|
4441
|
+
const word = index < words.length ? words[index] : undefined;
|
|
4442
|
+
if (word !== undefined) {
|
|
4443
|
+
claim(i, j + 1, word);
|
|
4444
|
+
substitutions++;
|
|
4445
|
+
} else {
|
|
4446
|
+
claim(i, j + 1, text.slice(i, j + 1));
|
|
4447
|
+
}
|
|
4448
|
+
i = text.indexOf(INDEXED_PREFIX, j + 1);
|
|
4449
|
+
} else {
|
|
4450
|
+
i = text.indexOf(INDEXED_PREFIX, i + 1);
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
for (let i = text.indexOf("$");i !== -1; ) {
|
|
4454
|
+
let j = i + 1;
|
|
4455
|
+
while (isDigit(text.charCodeAt(j)))
|
|
4456
|
+
j++;
|
|
4457
|
+
if (j > i + 1 && !isWordChar(text.charCodeAt(j)) && isFree(i, j)) {
|
|
4458
|
+
const index = Number(text.slice(i + 1, j));
|
|
4459
|
+
const word = index < words.length ? words[index] : undefined;
|
|
4460
|
+
if (word !== undefined) {
|
|
4461
|
+
claim(i, j, word);
|
|
4462
|
+
substitutions++;
|
|
4463
|
+
}
|
|
4464
|
+
i = text.indexOf("$", j);
|
|
4465
|
+
} else {
|
|
4466
|
+
i = text.indexOf("$", i + 1);
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
const PLAIN = "$ARGUMENTS";
|
|
4470
|
+
for (let i = text.indexOf(PLAIN);i !== -1; ) {
|
|
4471
|
+
const end = i + PLAIN.length;
|
|
4472
|
+
if (isFree(i, end)) {
|
|
4473
|
+
claim(i, end, wholeArgs);
|
|
4474
|
+
substitutions++;
|
|
4475
|
+
i = text.indexOf(PLAIN, end);
|
|
4476
|
+
} else {
|
|
4477
|
+
i = text.indexOf(PLAIN, i + 1);
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
replacements.sort((a, b) => a.start - b.start);
|
|
4481
|
+
let out = "";
|
|
4482
|
+
let cursor = 0;
|
|
4483
|
+
for (const r of replacements) {
|
|
4484
|
+
out += text.slice(cursor, r.start) + r.value;
|
|
4485
|
+
cursor = r.end;
|
|
4486
|
+
}
|
|
4487
|
+
out += text.slice(cursor);
|
|
4488
|
+
if (substitutions === 0 && args.length > 0)
|
|
4489
|
+
out += `
|
|
4490
|
+
ARGUMENTS: ` + wholeArgs;
|
|
4491
|
+
return out;
|
|
4492
|
+
}
|
|
4493
|
+
function cleanNoncharacters(s) {
|
|
4494
|
+
return s.replace(/[]/g, "�");
|
|
4495
|
+
}
|
|
4496
|
+
function isDigit(code) {
|
|
4497
|
+
return code >= 48 && code <= 57;
|
|
4498
|
+
}
|
|
4499
|
+
function isWordChar(code) {
|
|
4500
|
+
return isDigit(code) || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95;
|
|
4417
4501
|
}
|
|
4418
4502
|
function substituteWorkflowArguments(body, args) {
|
|
4419
4503
|
const JSON_TOKEN = "$ARGUMENTS_JSON";
|