{"version":3,"file":"task-intent.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/task-intent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA0EH,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAgE1G,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAe1F;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElF;AAKD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKnD","sourcesContent":["/**\n * Shared task mutation-intent classifier.\n *\n * Single authority for reading a task's wording, answering two different\n * questions from one prohibition analysis:\n *\n * - `classifyTaskMutationIntent` / `expectsImplementationMutation`: does the\n *   task REQUIRE file changes? Consumed by the completion mutation guard,\n *   which blocks completion, so its vocabulary is deliberately narrow.\n * - `taskMayMutate`: COULD the task plausibly change files? Consumed by\n *   acceptance level inference, which only raises evidence gates, so its\n *   vocabulary is deliberately broad (any bare write verb).\n *\n * Explicit read-only wording (\"do not modify\", \"review only\") is a task-level\n * intent only when no write imperative survives outside those phrases. A task\n * like \"Do not modify tests; implement the fix\" is an implementation task with\n * a scoped constraint, not a read-only task.\n */\n\nconst REVIEW_ONLY_PATTERNS = [\n\t/\\breview only\\b/i,\n\t/\\bsuggest fixes only\\b/i,\n\t/\\bonly return findings\\b/i,\n\t/\\breturn findings only\\b/i,\n];\n\nconst REVIEWER_REQUIRED_EDIT_PATTERNS = [\n\t/\\bmust\\s+(?:edit|modify|change|fix|patch|apply|implement)\\b/i,\n\t/\\brequired\\s+to\\s+(?:edit|modify|change|fix|patch|apply|implement)\\b/i,\n\t/(?:^|[.!?\\n]\\s*)implement\\s+(?:the\\s+)?(?:approved|requested|specified|file|code|source|fix(?:es)?|changes?)\\b/i,\n\t/\\bregardless\\s+of\\s+findings\\b/i,\n\t/\\balways\\s+(?:edit|modify|change|fix|patch|apply|implement)\\b/i,\n\t/\\bapply\\s+(?:the\\s+)?fix(?:es)?\\s+directly\\b/i,\n\t/\\bmake\\s+(?:the\\s+)?code\\s+changes\\b/i,\n];\n\n// The prohibition's object ends at punctuation or at a coordinating word\n// (but/and/then), so a follow-on clause like \"but implement the fix\" stays in\n// the text for write-intent testing instead of being swallowed as the object.\nconst NO_EDIT_PROHIBITION_PATTERN =\n\t/\\b(?:do not|don't|must not)\\s+(?:edit|modify|write(?:\\s+to)?|touch|change)\\b((?:(?!\\b(?:but|and|then)\\b)[^.;,:!?\\n–—-])*)/gi;\n\n/** Objects of a no-edit prohibition that mean \"the codebase in general\" rather than a named scope. */\nconst GENERIC_PROHIBITION_OBJECT =\n\t/^\\s*(?:(?:any|all|the|these|those|your|our|existing|project|product|source|sources|config|configs|repo|repository)[\\s/,-]*)*(?:files?|code|codebase|sources?|anything|repo(?:sitory)?)?\\s*$/i;\n\nconst SCOPED_NO_EDIT_CONSTRAINT_PATTERNS = [\n\t/\\bdo not edit files?\\s+outside\\b/i,\n\t/\\bdo not edit\\s+outside\\b/i,\n\t/\\bdo not edit\\s+unrelated files?\\b/i,\n\t/\\bdo not change\\s+unrelated files?\\b/i,\n\t/\\bdo not modify\\s+unrelated files?\\b/i,\n];\n\nconst NO_TOOL_INTENT_PATTERNS = [\n\t/\\bno tools? needed\\b/i,\n\t/\\bno tools? required\\b/i,\n\t/\\bwithout using tools\\b/i,\n\t/\\bdo not use tools\\b/i,\n\t/\\bdon't use tools\\b/i,\n];\n\nconst READ_ONLY_DELIVERABLE_PATTERNS = [\n\t/\\b(?:draft|write|compose|prepare|produce)\\s+(?:(?:a|an|the)\\s+)?(?:github\\s+)?(?:issue|bug report|issue draft|issue body|proposal|plan|report|summary|findings?|analysis|recommendations?)\\b/i,\n\t/\\b(?:issue|bug report)\\s+(?:draft|body|template)\\b/i,\n\t/\\b(?:return|provide|produce)\\s+(?:text|markdown|answer|findings?|recommendations?)\\s+only\\b/i,\n];\n\nconst RESEARCH_AGENT_PATTERNS = [/\\binvestigate\\b/i, /\\bscout\\b/i, /\\bresearch(?:er)?\\b/i];\n\nconst FIX_OR_PATCH_IMPLEMENTATION_PATTERN =\n\t/\\b(?:fix|patch)\\s+(?:(?:it|this|that|them|each|any|all|these|those)\\b|(?:(?:a|an|the|any|all)\\s+)?(?:(?:failing|failed|broken|flaky|red|cold|start|current|existing|reported|approved|known|regression|unit|integration|e2e|source|typescript|type-?script|ts|type-?check|compiler)\\s+)*(?:bug|defect|issues?|problems?|failures?|regressions?|tests?|errors?|items?|typos?|code|source|implementation|component|function|module|class|method|logic|file|files|readme|docs?|changelog|package\\.json|config|manifest|extension|prompt|command|lint(?:ing)?|build|ci|type-?check|type\\s+checking)\\b)/i;\n\nconst WORKER_IMPLEMENTATION_PATTERNS = [\n\t/\\b(?:implement|edit|modify|refactor|delete)\\b/i,\n\tFIX_OR_PATCH_IMPLEMENTATION_PATTERN,\n\t/\\b(?:update|add|remove|replace|create)\\b(?!\\s+(?:(?:a|an|the)\\s+)?(?:report|summary|findings?)(?:\\b|$))/i,\n\t/\\bapply\\s+(?:the\\s+)?(?:(?:suggested|proposed|recommended)\\s+)?(?:changes?|fix(?:es)?|patch)\\b/i,\n\t/\\bmake\\s+(?:the\\s+)?changes\\b/i,\n\t/\\bdo those fixes\\b/i,\n];\n\nconst GENERAL_IMPLEMENTATION_PATTERNS = [\n\t/\\b(?:implement|edit|modify|refactor)\\b/i,\n\tFIX_OR_PATCH_IMPLEMENTATION_PATTERN,\n\t/\\bapply\\s+(?:the\\s+)?(?:(?:suggested|proposed|recommended)\\s+)?(?:changes?|fix(?:es)?|patch)\\b/i,\n\t/\\bmake\\s+(?:the\\s+)?changes\\b/i,\n\t/\\bdo those fixes\\b/i,\n\t/\\b(?:update|add|remove|replace|delete|create)\\s+(?:the\\s+)?(?:file|files|code|source|implementation|test|tests|component|function|module|class|method|logic|import|imports|readme|docs?|changelog|package\\.json|config|manifest|extension|prompt|command)\\b/i,\n];\n\nexport type TaskMutationIntent = { kind: \"implementation\" } | { kind: \"read-only\" } | { kind: \"unknown\" };\n\nfunction stripFrameworkInstructions(task: string): string {\n\treturn task\n\t\t.split(\"\\n\")\n\t\t.filter((line) => !/^\\s*\\[(?:Write to|Read from):/i.test(line))\n\t\t.filter(\n\t\t\t(line) =>\n\t\t\t\t!/^\\s*(?:Create and maintain progress at:|Update progress at:|\\*\\*Output:\\*\\*|Write your findings to(?: exactly this path)?:|Return the complete artifact in your final response\\.|The runtime will persist it to exactly this path:|Do not call contact_supervisor merely because no write-capable tool is available\\.|This path is authoritative for this run\\.|Ignore any other output filename or output path mentioned elsewhere)/i.test(\n\t\t\t\t\tline,\n\t\t\t\t),\n\t\t)\n\t\t.join(\"\\n\");\n}\n\nfunction stripPatterns(task: string, patterns: RegExp[]): string {\n\tlet stripped = task;\n\tfor (const pattern of patterns) {\n\t\tconst flags = pattern.flags.includes(\"g\") ? pattern.flags : `${pattern.flags}g`;\n\t\tstripped = stripped.replace(new RegExp(pattern.source, flags), \" \");\n\t}\n\treturn stripped;\n}\n\ninterface NoEditProhibitionAnalysis {\n\t/** True when any prohibition (or review-only/no-tool wording) is present. */\n\tpresent: boolean;\n\t/** True when a prohibition covers files/code in general; such wording wins over write verbs. */\n\tblanket: boolean;\n\t/** Task text with prohibition phrases and their objects removed, for write-intent testing. */\n\tstrippedText: string;\n}\n\nfunction analyzeNoEditProhibitions(taskText: string): NoEditProhibitionAnalysis {\n\tlet present =\n\t\tREVIEW_ONLY_PATTERNS.some((pattern) => pattern.test(taskText)) ||\n\t\tNO_TOOL_INTENT_PATTERNS.some((pattern) => pattern.test(taskText));\n\tlet blanket = present;\n\tlet strippedText = stripPatterns(taskText, [...REVIEW_ONLY_PATTERNS, ...NO_TOOL_INTENT_PATTERNS]);\n\tstrippedText = strippedText.replace(\n\t\tnew RegExp(NO_EDIT_PROHIBITION_PATTERN.source, NO_EDIT_PROHIBITION_PATTERN.flags),\n\t\t(_match, object: string) => {\n\t\t\tpresent = true;\n\t\t\tif (GENERIC_PROHIBITION_OBJECT.test(object)) blanket = true;\n\t\t\treturn \" \";\n\t\t},\n\t);\n\treturn { present, blanket, strippedText };\n}\n\nfunction taskHasReadOnlyDeliverable(taskText: string): boolean {\n\treturn READ_ONLY_DELIVERABLE_PATTERNS.some((pattern) => pattern.test(taskText));\n}\n\nfunction isReviewerStyleAgent(agent: string): boolean {\n\treturn /\\b(?:advisor|reviewer|oracle)\\b/i.test(agent);\n}\n\nfunction hasImplementationIntent(agent: string, taskText: string): boolean {\n\tif (isReviewerStyleAgent(agent)) return REVIEWER_REQUIRED_EDIT_PATTERNS.some((pattern) => pattern.test(taskText));\n\tif (agent === \"worker\") return WORKER_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));\n\treturn GENERAL_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));\n}\n\nexport function classifyTaskMutationIntent(agent: string, task: string): TaskMutationIntent {\n\tconst taskText = stripFrameworkInstructions(task);\n\tconst taskTextWithoutScopedConstraints = stripPatterns(taskText, SCOPED_NO_EDIT_CONSTRAINT_PATTERNS);\n\tconst prohibitions = analyzeNoEditProhibitions(taskTextWithoutScopedConstraints);\n\tif (prohibitions.present) {\n\t\tif (prohibitions.blanket) return { kind: \"read-only\" };\n\t\treturn hasImplementationIntent(agent, prohibitions.strippedText)\n\t\t\t? { kind: \"implementation\" }\n\t\t\t: { kind: \"read-only\" };\n\t}\n\n\tif (RESEARCH_AGENT_PATTERNS.some((pattern) => pattern.test(agent))) return { kind: \"read-only\" };\n\tif (hasImplementationIntent(agent, taskText)) return { kind: \"implementation\" };\n\tif (isReviewerStyleAgent(agent)) return { kind: \"read-only\" };\n\treturn taskHasReadOnlyDeliverable(taskTextWithoutScopedConstraints) ? { kind: \"read-only\" } : { kind: \"unknown\" };\n}\n\nexport function expectsImplementationMutation(agent: string, task: string): boolean {\n\treturn classifyTaskMutationIntent(agent, task).kind === \"implementation\";\n}\n\n/** Bare write verbs that make a task write-capable for acceptance inference. */\nconst MAY_MUTATE_VERB_PATTERN = /\\b(?:fix|implement|update|write|edit|modify|migrate|delete|remove|refactor|commit)\\b/i;\n\n/**\n * Whether the task could plausibly change files. Blanket prohibitions win;\n * write verbs inside a scoped prohibition's object or a read-only deliverable\n * phrase (\"write a summary report\") do not count; any other bare write verb\n * does.\n */\nexport function taskMayMutate(task: string): boolean {\n\tconst taskText = stripPatterns(stripFrameworkInstructions(task), SCOPED_NO_EDIT_CONSTRAINT_PATTERNS);\n\tconst prohibitions = analyzeNoEditProhibitions(taskText);\n\tif (prohibitions.blanket) return false;\n\treturn MAY_MUTATE_VERB_PATTERN.test(stripPatterns(prohibitions.strippedText, READ_ONLY_DELIVERABLE_PATTERNS));\n}\n"]}