{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,YAAY,EAIZ,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiChD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAkBpF","sourcesContent":["import type {\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tExtensionAPI,\n\tExtensionContext,\n\tSessionEntry,\n\tSessionMessageEntry,\n} from \"@earendil-works/pi-coding-agent\";\nimport { buildTodoPlanMessageContent } from \"./plan-message.ts\";\nimport type { TodoRuntime } from \"./runtime.ts\";\n\nconst RECENT_CONTEXT_ENTRY_LIMIT = 12;\nconst RECENT_CONTEXT_CHAR_LIMIT = 12000;\n\nconst EXECUTION_INTENT_PATTERNS = [\n\t/按(这个|此|上面|上述|前面)(计划|方案)?(执行|做|实现|推进)/u,\n\t/按上面的做/u,\n\t/(开始|继续)(实现|执行|推进|做)/u,\n\t/^\\s*继续(?:吧|执行|做|推进|实现)?[。.!！]?\\s*$/u,\n\t/\\b(go ahead|proceed|execute this plan|implement the plan|start implementation|start implementing)\\b/i,\n\t/\\b(continue|continue implementation|continue implementing|continue with this|do it|ship it)\\b/i,\n];\n\nconst NON_EXECUTION_PATTERNS = [\n\t/不要(修改|改|动|实现|执行)/u,\n\t/别(修改|改|动|实现|执行)/u,\n\t/\\b(do not|don't)\\s+(modify|change|edit|implement|execute)\\b/i,\n\t/\\b(no|without)\\s+(code\\s+)?(changes?|modifications?|edits?)\\b/i,\n\t/\\b(plan only|proposal only|no implementation)\\b/i,\n\t/^(?:\\s*)(?:please\\s+)?(?:review|investigate|audit|analy[sz]e|inspect|look into|check)\\b/i,\n\t/^(?:\\s*)(?:先)?(?:调查|确认现状|审查|检查|分析)/u,\n\t/(出|给|制定|写).{0,12}(执行)?(计划|方案)/u,\n\t/\\b(?:make|write|draft|create|give me|propose)\\b.{0,30}\\b(plan|proposal|approach)\\b/i,\n];\n\nconst PLAN_HEADING_PATTERN = /\\b(implementation plan|execution plan|todo plan|task plan|acceptance criteria)\\b/i;\nconst GENERIC_PLAN_HEADING_PATTERN = /(?:^|\\n)\\s*(?:plan|proposal|approach|方案|计划)\\s*:/i;\nconst CHINESE_PLAN_PATTERN = /(计划|方案|步骤|任务|验收标准)/u;\nconst PI_TODO_PLAN_PATTERN = /\\[PI TODO PLAN\\]/;\nconst TODO_TASK_PATTERN = /(?:^|\\n)\\s*T\\d+[:.)\\s-]/i;\nconst PLAN_LIST_LINE_PATTERN = /(?:^|\\n)\\s*(?:[-*]|\\d+[.)]|\\[[ x]\\])\\s+\\S/g;\n\nexport function registerTodoAutoTrigger(pi: ExtensionAPI, runtime: TodoRuntime): void {\n\tpi.on(\"before_agent_start\", async (event, ctx): Promise<BeforeAgentStartEventResult | undefined> => {\n\t\tconst recovered = await runtime.reconcileOwners();\n\t\tif (!isExplicitlyNonExecution(event.prompt) && hasExecutionIntent(event.prompt)) {\n\t\t\tconst digest = await runtime.digest();\n\t\t\tif (digest) {\n\t\t\t\treturn { message: { customType: \"pi-todo-continuation\", content: digest, display: false } };\n\t\t\t}\n\t\t}\n\t\tif (recovered) {\n\t\t\tconst digest = await runtime.digest();\n\t\t\tif (digest) return { message: { customType: \"pi-todo-digest\", content: digest, display: false } };\n\t\t}\n\n\t\tconst content = buildAutoPlan(event, ctx);\n\t\tif (!content || (await runtime.view())) return undefined;\n\t\treturn { message: { customType: \"pi-todo-plan\", content, display: true } };\n\t});\n}\n\nfunction buildAutoPlan(event: BeforeAgentStartEvent, ctx: ExtensionContext): string | undefined {\n\tif (isExplicitlyNonExecution(event.prompt) || !hasExecutionIntent(event.prompt)) return undefined;\n\tconst currentPromptHasPlan = hasLikelyPlan(event.prompt);\n\tconst contextText = currentPromptHasPlan ? \"\" : recentContextText(ctx);\n\tif (!currentPromptHasPlan && !hasLikelyPlan(contextText)) return undefined;\n\tconst parts = [`Current user execution request:\\n${event.prompt.trim()}`];\n\tparts.push(\n\t\tcurrentPromptHasPlan\n\t\t\t? \"The current request contains the plan to execute.\"\n\t\t\t: `Recent context containing the existing plan:\\n${contextText}`,\n\t);\n\treturn buildTodoPlanMessageContent({\n\t\tsource: currentPromptHasPlan ? \"current prompt\" : \"recent context\",\n\t\tplan: parts.join(\"\\n\\n\"),\n\t});\n}\n\nfunction hasExecutionIntent(prompt: string): boolean {\n\treturn EXECUTION_INTENT_PATTERNS.some((pattern) => pattern.test(prompt));\n}\n\nfunction isExplicitlyNonExecution(prompt: string): boolean {\n\treturn NON_EXECUTION_PATTERNS.some((pattern) => pattern.test(prompt));\n}\n\nfunction hasLikelyPlan(text: string): boolean {\n\tconst listLineCount = [...text.matchAll(PLAN_LIST_LINE_PATTERN)].length;\n\treturn (\n\t\tPI_TODO_PLAN_PATTERN.test(text) ||\n\t\tPLAN_HEADING_PATTERN.test(text) ||\n\t\t(GENERIC_PLAN_HEADING_PATTERN.test(text) && listLineCount >= 2) ||\n\t\t(CHINESE_PLAN_PATTERN.test(text) && listLineCount >= 2) ||\n\t\tTODO_TASK_PATTERN.test(text) ||\n\t\tlistLineCount >= 3\n\t);\n}\n\nfunction recentContextText(ctx: ExtensionContext): string {\n\tconst text = ctx.sessionManager\n\t\t.buildContextEntries()\n\t\t.slice(-RECENT_CONTEXT_ENTRY_LIMIT)\n\t\t.map(entryText)\n\t\t.map((part) => part.trim())\n\t\t.filter(Boolean)\n\t\t.join(\"\\n\\n---\\n\\n\");\n\treturn text.length > RECENT_CONTEXT_CHAR_LIMIT ? text.slice(-RECENT_CONTEXT_CHAR_LIMIT) : text;\n}\n\nfunction entryText(entry: SessionEntry): string {\n\tswitch (entry.type) {\n\t\tcase \"message\":\n\t\t\treturn messageText(entry.message);\n\t\tcase \"custom_message\":\n\t\t\treturn typeof entry.content === \"string\"\n\t\t\t\t? entry.content\n\t\t\t\t: entry.content.flatMap((part) => (part.type === \"text\" ? [part.text] : [])).join(\"\\n\");\n\t\tcase \"compaction\":\n\t\tcase \"branch_summary\":\n\t\t\treturn entry.summary;\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\nfunction messageText(message: SessionMessageEntry[\"message\"]): string {\n\tif (!(\"content\" in message)) return \"\";\n\tif (typeof message.content === \"string\") return message.content;\n\tif (!Array.isArray(message.content)) return \"\";\n\treturn message.content.flatMap((part) => (part.type === \"text\" ? [part.text] : [])).join(\"\\n\");\n}\n"]}