


























11import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
22import { homedir } from "node:os";
33import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
4+export {
5+parseCommandArgs,
6+substituteArgs,
7+} from "../../../packages/agent-core/src/harness/prompt-template-arguments.js";
8+import {
9+parseCommandArgs,
10+substituteArgs,
11+} from "../../../packages/agent-core/src/harness/prompt-template-arguments.js";
412import { CONFIG_DIR_NAME } from "../config.js";
513import { parseFrontmatter } from "../utils/frontmatter.js";
614import { createSyntheticSourceInfo, type SourceInfo } from "./source-info.js";
@@ -17,108 +25,6 @@ export interface PromptTemplate {
1725filePath: string; // Absolute path to the template file
1826}
192720-/**
21- * Parse command arguments respecting quoted strings (bash-style)
22- * Returns array of arguments
23- */
24-export function parseCommandArgs(argsString: string): string[] {
25-const args: string[] = [];
26-let current = "";
27-let inQuote: string | null = null;
28-29-for (let i = 0; i < argsString.length; i++) {
30-const char = argsString[i];
31-32-if (inQuote) {
33-if (char === inQuote) {
34-inQuote = null;
35-} else {
36-current += char;
37-}
38-} else if (char === '"' || char === "'") {
39-inQuote = char;
40-} else if (/\s/.test(char)) {
41-if (current) {
42-args.push(current);
43-current = "";
44-}
45-} else {
46-current += char;
47-}
48-}
49-50-if (current) {
51-args.push(current);
52-}
53-54-return args;
55-}
56-57-function parseSafeNonNegativeInteger(raw: string): number | undefined {
58-const parsed = Number(raw);
59-return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : undefined;
60-}
61-62-/**
63- * Substitute argument placeholders in template content
64- * Supports:
65- * - $1, $2, ... for positional args
66- * - $@ and $ARGUMENTS for all args
67- * - ${@:N} for args from Nth onwards (bash-style slicing)
68- * - ${@:N:L} for L args starting from Nth
69- *
70- * Note: Replacement happens on the template string only. Argument values
71- * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.
72- */
73-export function substituteArgs(content: string, args: string[]): string {
74-let result = content;
75-76-// Replace $1, $2, etc. with positional args FIRST (before wildcards)
77-// This prevents wildcard replacement values containing $<digit> patterns from being re-substituted
78-result = result.replace(/\$(\d+)/g, (_, num) => {
79-const parsed = parseSafeNonNegativeInteger(num);
80-if (parsed === undefined || parsed <= 0) {
81-return "";
82-}
83-const index = parsed - 1;
84-return args[index] ?? "";
85-});
86-87-// Replace ${@:start} or ${@:start:length} with sliced args (bash-style)
88-// Process BEFORE simple $@ to avoid conflicts
89-result = result.replace(/\$\{@:(\d+)(?::(\d+))?\}/g, (_, startStr, lengthStr) => {
90-const parsedStart = parseSafeNonNegativeInteger(startStr);
91-if (parsedStart === undefined) {
92-return "";
93-}
94-let start = parsedStart - 1; // Convert to 0-indexed (user provides 1-indexed)
95-// Treat 0 as 1 (bash convention: args start at 1)
96-if (start < 0) {
97-start = 0;
98-}
99-100-if (lengthStr) {
101-const length = parseSafeNonNegativeInteger(lengthStr);
102-if (length === undefined) {
103-return "";
104-}
105-return args.slice(start, start + length).join(" ");
106-}
107-return args.slice(start).join(" ");
108-});
109-110-// Pre-compute all args joined (optimization)
111-const allArgs = args.join(" ");
112-113-// Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)
114-result = result.replace(/\$ARGUMENTS/g, allArgs);
115-116-// Replace $@ with all args joined (existing syntax)
117-result = result.replace(/\$@/g, allArgs);
118-119-return result;
120-}
121-12228function loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {
12329try {
12430const rawContent = readFileSync(filePath, "utf-8");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。