@quantiya/codevibe-claude-plugin 2.0.41 → 2.0.42
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/.claude-plugin/plugin.json +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/index.js +384 -384
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/local-executor-impl.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/types.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +116 -19
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/command-intent.d.ts +18 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/engage-substrate.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
|
@@ -112,6 +112,7 @@ export type SubstrateEngager = (input: {
|
|
|
112
112
|
* applies whenever the row cannot be established).
|
|
113
113
|
*/
|
|
114
114
|
requireConfined?: boolean;
|
|
115
|
+
webBrowsingActive?: boolean;
|
|
115
116
|
}) => Promise<SubstrateEngageResult>;
|
|
116
117
|
/** Backend lease is 15 minutes; three renewal opportunities fit inside it. */
|
|
117
118
|
export declare const TEAM_TRACK_HEARTBEAT_INTERVAL_MS: number;
|
|
@@ -18616,11 +18616,11 @@ function renderLocalGemmaPlannerPrompt(input, options) {
|
|
|
18616
18616
|
"Never refuse merely because the user asks about local repository files, the current directory, the workspace, or the project. Refuse only for clearly unsafe requests such as exposing secrets/credentials, destructive root/home deletion, malware, bypassing auth/paywalls, or exfiltration.",
|
|
18617
18617
|
"",
|
|
18618
18618
|
"Routing rules:",
|
|
18619
|
-
'- start_task: user asks to create, add, edit, fix, implement, refactor, test, run tests, or review a SPECIFIC, BOUNDED change \u2014 such as their pending diff, staged/uncommitted changes, a named file, or a pull request. (A BROAD "review/audit the WHOLE codebase for bugs" is read-only understanding \u2192 familiarize, NOT start_task \u2014 see below.) If the user says current directory, current working directory, repo root, workspace, ".", "./", or an absolute path, treat the target as sufficiently specified. If the requested content is obvious, such as a JavaScript hello-world file, do not ask for extra content. A SINGLE task is start_task even when it has multiple steps; choose team_decompose ONLY when the user explicitly asks for parallel work (see below).',
|
|
18619
|
+
'- start_task: user asks to create, add, edit, fix, implement, refactor, test, run tests, or review a SPECIFIC, BOUNDED change \u2014 such as their pending diff, staged/uncommitted changes, a named file, or a pull request. (A BROAD "review/audit the WHOLE codebase for bugs" is read-only understanding \u2192 familiarize, NOT start_task \u2014 see below.) If the user says current directory, current working directory, repo root, workspace, ".", "./", or an absolute path, treat the target as sufficiently specified. If the requested content is obvious, such as a JavaScript hello-world file, do not ask for extra content. A SINGLE task is start_task even when it has multiple steps; choose team_decompose ONLY when the user explicitly asks for parallel work (see below). This ALSO includes requests that fetch/check an external URL or search online AND write, save, create, or update local files, reports, or code (e.g. "check https://... and write a report into report.md" -> start_task).',
|
|
18620
18620
|
'- team_decompose: user EXPLICITLY asks to split the work into MULTIPLE PARALLEL tasks or tracks, run an "agent team", do things "in parallel", or describes 2+ INDEPENDENT pieces (typically touching different files) to run concurrently. Prefer team_decompose over start_task whenever the request names an agent team or parallel/separate tracks. A single multi-step task is start_task, NOT team_decompose.',
|
|
18621
18621
|
'- familiarize: user asks to read, inspect, understand, explain, or summarize the current project, codebase, repository, folder, files, or working directory without asking for a mutation. This ALSO covers a BROAD read-only REVIEW or AUDIT of the WHOLE repository/codebase \u2014 e.g. "review the codebase for bugs", "audit the repo for issues", "look over the whole project for problems": reviewing the ENTIRE repo for bugs/quality/security is a read-only understanding task, so it is familiarize, NOT start_task. (A BOUNDED review of a specific pending DIFF or named file is start_task instead.)',
|
|
18622
18622
|
`- brainstorm: user asks to explore options, tradeoffs, risks, architecture directions, or recommendations for THIS project's design or implementation before deciding what to design or implement. brainstorm is NOT for opinions or analysis of a web page, article, or answer from earlier in this session \u2014 that is advisory_response. Use brainstorm for exploratory prompts such as "brainstorm ways to build offline support" or "compare approaches to create a local context store". Do NOT use brainstorm when the user asks for immediate mutation, a design artifact, a hard gate, tests, review, commit, deploy, or release; choose the workflow action or ask one clarifying question.`,
|
|
18623
|
-
'- browse: user asks to read/open/fetch/summarize a specific web URL (http/https), OR to look something up on the web / search online / find the latest on a topic. Put any explicit URL(s) in "browseUrls" (array) and, when there is no URL, put the search query in "browseQuery". This route fetches the page (or searches) on the user machine and answers from the content; it is NOT a familiarize (which reads the LOCAL repo) and NOT advisory_response.',
|
|
18623
|
+
'- browse: user asks a read-only question to read/open/fetch/summarize a specific web URL (http/https), OR to look something up on the web / search online / find the latest on a topic, WITHOUT asking to create, write, or modify any local files. If the user asks to fetch a URL or search AND save/write/create local files or reports, choose start_task instead. Put any explicit URL(s) in "browseUrls" (array) and, when there is no URL, put the search query in "browseQuery". This route fetches the page (or searches) on the user machine and answers from the content; it is NOT a familiarize (which reads the LOCAL repo) and NOT advisory_response.',
|
|
18624
18624
|
options?.isSubprocessRunner ? `- advisory_response: user asks a general question that does not require repository context or file changes. Put a COMPLETE, natural, conversational ANSWER to the question in the "advisory_summary" field (a full helpful reply, like a chat assistant \u2014 NOT a one-line label or a restatement of the question); explain core principles accurately: for search/pathfinding, start with the start node in the open set, use strictly standard A* terminology (open set and closed set only; never invent other sets like missed set or turn set), and compare with Dijkstra's algorithm; explain that a more accurate, higher admissible heuristic (closer to the true remaining cost) guides the search more directly to the goal and expands fewer nodes, whereas a smaller or zero heuristic (like Dijkstra's algorithm) explores in all directions and expands more nodes; a heuristic must be admissible (never overestimate the true distance) to guarantee an optimal shortest path; write all mathematical expressions in clean plain text like f(n) = g(n) + h(n) (never use LaTeX math notation, \\text{}, math mode $, or backslashes); format the entire explanation in clean, well-structured markdown prose paragraphs separated by blank lines (do not use bullet lists, numbered sub-lists, or backslash line breaks; write complete narrative paragraphs); never use tab characters or \\t; never use double quotes inside advisory_summary (use single quotes ' if quoting terms); keep "rationale" a short internal classification reason. Answer directly and warmly, e.g. "Yes \u2014 I can \u2026".` : '- advisory_response: user asks a general question or capability question. Put a concise, natural, 1-sentence direct answer or definition in "advisory_summary" (e.g. "Yes, I can write Rust" or "A* is a best-first pathfinding algorithm that expands nodes by f(n) = g(n) + h(n)"); do NOT write preambles like "Here is..." or conversational labels; keep "rationale" a short reason. The downstream local advisory engine generates the full answer.',
|
|
18625
18625
|
options?.isSubprocessRunner ? '- FOLLOW-UP ON EARLIER CONTENT: when the user asks for your thoughts, opinion, analysis, critique, or a deeper explanation of something already fetched or answered earlier in this session (a web page that was read, a search result, a previous reply) \u2014 e.g. "I am looking for your thoughts", "what do you think about that", "go deeper on that", "is that right?" \u2014 choose advisory_response and put the COMPLETE reply in advisory_summary (no downstream answerer runs for this runner). Never brainstorm, familiarize, or browse again for such a follow-up.' : `- FOLLOW-UP ON EARLIER CONTENT: when the user asks for your thoughts, opinion, analysis, critique, or a deeper explanation of something already fetched or answered earlier in this session (a web page that was read, a search result, a previous reply) \u2014 e.g. "I am looking for your thoughts", "what do you think about that", "go deeper on that", "is that right?" \u2014 choose advisory_response with a one-sentence advisory_summary (the shell's answerer writes the full reply from the page and the conversation). Never brainstorm, familiarize, or browse again for such a follow-up.`,
|
|
18626
18626
|
options?.isSubprocessRunner ? "- summarize_current_status: user asks what changed, what the last task did, current progress, or workflow status." : "- Questions about progress, what changed, what the last task did, or workflow status are advisory_response too: the shell attaches its own status record to the answer, so never invent task history.",
|
|
@@ -18658,6 +18658,8 @@ function renderLocalGemmaPlannerPrompt(input, options) {
|
|
|
18658
18658
|
'User: "look up the React 19 release notes online" -> {"action":"browse","rationale":"web lookup","browseQuery":"React 19 release notes"}',
|
|
18659
18659
|
'User: "what is the latest LTS version of Node.js?" -> {"action":"browse","rationale":"freshness lookup needs current web info, not stale knowledge","browseQuery":"latest LTS version Node.js"}',
|
|
18660
18660
|
'User: "what is the current stable version of Python?" -> {"action":"browse","rationale":"current version is a freshness web lookup","browseQuery":"current stable version Python"}',
|
|
18661
|
+
'User: "check https://registry.npmjs.org/@quantiya/codevibe-core/latest and write a report into report.md" -> {"action":"start_task","rationale":"check external URL and write report file"}',
|
|
18662
|
+
'User: "Please use your codevibe_web_search tool to search for \\"Quantiya AI\\", then use codevibe_web_fetch to read https://quantiya.ai/ and write a 3-bullet summary of the site into a file named claude-web-test.md." -> {"action":"start_task","rationale":"search web and write summary file"}',
|
|
18661
18663
|
`User: "fyi every FLAGS.md row should also say what the default is" (session.currentTaskState is in_progress) -> {"action":"advisory_response","rationale":"a convention stated while a task runs; acknowledge, no second task","advisory_summary":"Noted \u2014 FLAGS.md rows will also state each flag's default."}`,
|
|
18662
18664
|
'User: "scratch that \u2014 descriptions should not end with a period" (session.currentTaskState is in_progress) -> {"action":"advisory_response","rationale":"retracts an earlier rule while a task runs","advisory_summary":"Understood \u2014 descriptions will not end with a period."}',
|
|
18663
18665
|
'User: "also add a --cv-quiet flag to release.sh" (session.currentTaskState is in_progress) -> {"action":"start_task","rationale":"asks for a new deliverable while a task runs"}',
|
|
@@ -21326,6 +21328,57 @@ function buildCommandIntentMetadata(text2) {
|
|
|
21326
21328
|
if (intent)
|
|
21327
21329
|
return { command_intent: buildCommandIntentEnvelope(intent) };
|
|
21328
21330
|
}
|
|
21331
|
+
function isWebAccessNeeded(text2) {
|
|
21332
|
+
return !text2 || typeof text2 != "string" ? !1 : /https?:\/\/[^\s]+/i.test(text2) || /\bwww\.[^\s]+/i.test(text2) ? !0 : /(?:^|[.?!;])\s*(?:please\s+)?(?:implement|build|create|add|support|develop)\b[\s\S]{0,50}?\b(?:feature|functionality|function|button|capability|endpoint|command|module|ui|api|service)\b/i.test(
|
|
21333
|
+
text2
|
|
21334
|
+
) || /\b(?:feature|functionality|function|capability)\b[\s\S]{0,40}?\b(?:to|that|which)\s+(?:search|browse|look\s+up)\b/i.test(
|
|
21335
|
+
text2
|
|
21336
|
+
) || /(?:实现|添加|开发|支持|做个|写个)[\s\S]{0,30}?(?:功能|特性)/.test(text2) || /(?:功能|特性)[\s\S]{0,30}?(?:实现|添加|开发|支持)/.test(text2) || /(?:機能|기능)[\s\S]{0,30}?(?:実装|追加|作成|開発|구현|추가)/.test(text2) || /(?:実装|追加|作成|開発|구현|추가)[\s\S]{0,30}?(?:機能|기능)/.test(text2) ? !1 : !!(/(?:^|[.?!;])\s*(?:please\s+)?(?:search|browse)\s+(?:the\s+(?:web|internet)\b|online)(?:\s+(?:for|about)\b|\s*[,.;?!]?$)/i.test(
|
|
21337
|
+
text2
|
|
21338
|
+
) || /(?:^|[.?!;])\s*(?:please\s+)?look\s+up\s+(?!where\b|how\b|who\b|why\b)[\w\s.-]{1,60}?\s+(?:online|on\s+the\s+web\b|on\s+the\s+internet\b)(?:\s+(?:for|about)\b|\s*[,.;?!]?$)/i.test(
|
|
21339
|
+
text2
|
|
21340
|
+
) && !/\bonline\s+(?:checkout|users?|status|banking|store|shop|service|mode|game|player|account|system|portal|flow|documentation)\b/i.test(
|
|
21341
|
+
text2
|
|
21342
|
+
) || /(?:^|[.?!;])\s*(?:please\s+)?(?:use|try|run|perform|do)\s+(?:a\s+)?(?:web|internet|online)\s+search(?:\s+(?:for|about|on)\b|\s*[,.;?!]?$)(?!\s+(?:api|service|endpoint|tests?|feature|sdk|library|component|function|code)\b)/i.test(
|
|
21343
|
+
text2
|
|
21344
|
+
) || /(?:^|[.?!;])\s*(?:please\s+)?(?:google\s+(?:this|it|that)\b|search\s+(?:on\s+google|google)\s+for\b)/i.test(
|
|
21345
|
+
text2
|
|
21346
|
+
) || /(?:^|[.?!;,。!?;])\s*(?:请|帮我|麻烦)?\s*(?:(?:去?上网|在网上|去官网|在官网|在官方网站)(?:搜索|查找|查阅|查一下|搜一下)(?!到|过|出|的|结果)|去网上搜(?:一下|索)|谷歌一下|(?:查阅|查找|搜索)(?:官网|官方网站)(?:的)?(?:文档|说明|api)|(?:在线|官网|联网)搜索一下)/i.test(
|
|
21347
|
+
text2
|
|
21348
|
+
) || /(?:^|[.?!;])\s*(?:(?:ネット|オンライン)で\s*(?:検索して(?:みて|ください)?|調べて(?:みて|ください)?|探して(?:みて|ください)?)(?=$|[\s。、.!?])|ウェブ検索で\s*[\u4E00-\u9FFF\u30A0-\u30FF\w ]{1,20}を(?:調べて|探して))|(?:^|[.?!;])\s*[\w\s\u3040-\u30FF\u4E00-\u9FFF]{0,20}?ググ[るっ](?=$|[\s.?!;。~])/i.test(
|
|
21349
|
+
text2
|
|
21350
|
+
) || /(?:^|[.?!;])\s*(?:[\w\s가-힣]{0,40}?\s+)?(?:인터넷|온라인|구글)에서\s*(?:검색해(?:봐|줘|요)|찾아(?:봐|줘)|조회해(?:봐|줘))(?=$|[\s.?!;。~])/i.test(
|
|
21351
|
+
text2
|
|
21352
|
+
));
|
|
21353
|
+
}
|
|
21354
|
+
function hasFileMutationIntent(text2) {
|
|
21355
|
+
if (!text2 || typeof text2 != "string") return !1;
|
|
21356
|
+
let stripped = stripLeadingAgentControlToken(text2).trim(), textWithoutUrls = stripped.replace(/https?:\/\/[^\s]+/gi, " ").trim();
|
|
21357
|
+
if (/\b(?:how\s+(?:to|do\s+I|can\s+I)|explain\s+how\s+to|tell\s+me\s+how\s+to)\b/i.test(stripped) || /(?:^|[.?!;])\s*(?:what\s+(?:is|are)\b|c[oó]mo\s+(?:hacer|puedo|se\s+puede|escribir|guardar|crear)|comment\s+(?:faire|écrire|sauvegarder|créer|enregistrer)|wie\s+(?:kann\s+ich|macht\s+man|schreibt\s+man|speichert\s+man|erstellt\s+man))\b/i.test(stripped) || /(?:如何|怎么|怎样|告诉我(?:如何|怎么|怎样)|解释如何|请问|什么是)/.test(stripped) || /(?:どうやって|方法(?:を(?:教えて|説明して))|やり方を教えて|でしょうか|とは(?:何|なん)ですか)/.test(stripped) || /(?:어떻게|방법을?\s*(?:알려줘|설명해줘)|법\s*설명|하는지\s*알려줘)/.test(stripped))
|
|
21358
|
+
return !1;
|
|
21359
|
+
if (/>{1,2}\s*[\w./-]+\b/.test(textWithoutUrls))
|
|
21360
|
+
return !0;
|
|
21361
|
+
let fileExt = "(?:md|markdown|txt|json|csv|ts|js|tsx|jsx|py|html|css|yaml|yml|log|sh|xml|toml|sql|env)", writeToFilePatternEn = new RegExp(
|
|
21362
|
+
`\\b(?:write|save|create|dump|output|put|export|store|record|guardar|escribir|crear|enregistrer|\xE9crire|cr\xE9er|sauvegarder|speichern|schreiben|erstellen)\\b[\\s\\S]*?\\b(?:into|to|in|as|en|dans|auf|zu)\\b(?!\\s+(?:chat|console|stdout|screen|terminal)\\b)[\\s\\S]*?(?:(?:a|an|the|un|une|ein|eine|el|la)?\\s*file(?:\\s+named|\\s+called)?\\s+)?[\\w./-]+\\.${fileExt}\\b`,
|
|
21363
|
+
"i"
|
|
21364
|
+
), writeToFilePatternGermanic = new RegExp(
|
|
21365
|
+
`\\b(?:in|auf|zu|into|to)\\s+[\\w./-]+\\.${fileExt}[\\s\\S]*?\\b(?:speichern|schreiben|erstellen|ablegen)\\b`,
|
|
21366
|
+
"i"
|
|
21367
|
+
), namedFilePatternEn = /\b(?:into|to|in|en|dans|auf|zu)\s+(?:a|an|un|une|ein|eine|el|la)?\s*file(?:\s+(?:named|called))?\s+[\w./-]+\b/i, createFilePatternEn = /\b(?:create|add|touch)\s+(?:a|an|the)?\s*(?:new\s+)?(?:file|markdown\s+file|script)\b/i, directFileVerbPatternEn = new RegExp(
|
|
21368
|
+
`\\b(?:create|write|touch|add|crear|escribir|cr\xE9er|\xE9crire|erstellen)\\s+[\\w./-]+\\.${fileExt}\\b`,
|
|
21369
|
+
"i"
|
|
21370
|
+
), writeToFilePatternZh = new RegExp(
|
|
21371
|
+
`(?:\u5199\u5165|\u4FDD\u5B58\u5230?|\u521B\u5EFA|\u751F\u6210|\u8F93\u51FA\u5230|\u5B58\u5165|\u5BFC\u51FA\u5230?|\u8BB0\u5F55\u5230?)[\\s\\S]*?[\\w./-]+\\.${fileExt}\\b`,
|
|
21372
|
+
"i"
|
|
21373
|
+
), writeToFilePatternJa = new RegExp(
|
|
21374
|
+
`(?:[\\w./-]+\\.${fileExt}[\\s\\S]*?(?:\u306B|\u3078)?\\s*(?:\u66F8\u304D\u51FA|\u4FDD\u5B58|\u4F5C\u6210|\u751F\u6210|\u51FA\u529B|\u8A18\u9332|\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8)|(?:\u66F8\u304D\u51FA|\u4FDD\u5B58|\u4F5C\u6210|\u751F\u6210|\u51FA\u529B|\u8A18\u9332|\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8)[\\s\\S]*?[\\w./-]+\\.${fileExt})`,
|
|
21375
|
+
"i"
|
|
21376
|
+
), writeToFilePatternKo = new RegExp(
|
|
21377
|
+
`(?:[\\w./-]+\\.${fileExt}[\\s\\S]*?(?:\uC5D0|\uC73C\uB85C|\uB85C)?\\s*(?:\uC800\uC7A5|\uC791\uC131|\uC0DD\uC131|\uAE30\uB85D|\uCD9C\uB825|\uB0B4\uBCF4\uB0B4\uAE30)|(?:\uC800\uC7A5|\uC791\uC131|\uC0DD\uC131|\uAE30\uB85D|\uCD9C\uB825|\uB0B4\uBCF4\uB0B4\uAE30)[\\s\\S]*?[\\w./-]+\\.${fileExt})`,
|
|
21378
|
+
"i"
|
|
21379
|
+
);
|
|
21380
|
+
return writeToFilePatternEn.test(textWithoutUrls) || writeToFilePatternGermanic.test(textWithoutUrls) || namedFilePatternEn.test(textWithoutUrls) || createFilePatternEn.test(textWithoutUrls) || directFileVerbPatternEn.test(textWithoutUrls) || writeToFilePatternZh.test(textWithoutUrls) || writeToFilePatternJa.test(textWithoutUrls) || writeToFilePatternKo.test(textWithoutUrls);
|
|
21381
|
+
}
|
|
21329
21382
|
|
|
21330
21383
|
// src/orchestration-shell/route-browse.ts
|
|
21331
21384
|
var RETAINED_PAGE_MAX_CHARS = 12e4, NO_MODEL_PREFIX = "Local CodeVibe model is required to read and summarize web pages.", RUN_INSTALL = "Run `codevibe model install` from a Pro/Max account, then ask again. No hosted model was called and no code was changed.";
|
|
@@ -21390,17 +21443,29 @@ function fetchErrorMessage(err, url) {
|
|
|
21390
21443
|
async function readUrl(deps, runner, url) {
|
|
21391
21444
|
let { store, userPrompt, signal } = deps, dispUrl = sanitizeForTerminal(url);
|
|
21392
21445
|
advise(store, `Reading ${dispUrl}\u2026`);
|
|
21393
|
-
let body, finalUrl, fetch2 = deps.guardedFetchFn ?? guardedFetch;
|
|
21446
|
+
let body, finalUrl, contentType = "", fetch2 = deps.guardedFetchFn ?? guardedFetch;
|
|
21394
21447
|
try {
|
|
21395
|
-
let res = await fetch2(url, signal);
|
|
21396
|
-
body = res.body, finalUrl = res.finalUrl;
|
|
21448
|
+
let res = await fetch2(url, signal, { allowJson: !0 });
|
|
21449
|
+
body = res.body, finalUrl = res.finalUrl, contentType = res.contentType;
|
|
21397
21450
|
} catch (err) {
|
|
21398
21451
|
if (signal?.aborted) return;
|
|
21399
21452
|
let suffix = deps.delegateAnswer ? " The mentioned agent was not consulted." : "";
|
|
21400
21453
|
err instanceof FetchError ? advise(store, `${fetchErrorMessage(err, dispUrl)}${suffix}`) : advise(store, `Couldn't read ${dispUrl} (${sanitizeForTerminal(err.message)}). No code was changed.${suffix}`);
|
|
21401
21454
|
return;
|
|
21402
21455
|
}
|
|
21403
|
-
let dispFinal = sanitizeForTerminal(finalUrl),
|
|
21456
|
+
let dispFinal = sanitizeForTerminal(finalUrl), title = dispFinal, text2 = "";
|
|
21457
|
+
if (contentType.toLowerCase().includes("application/json"))
|
|
21458
|
+
try {
|
|
21459
|
+
let parsed = JSON.parse(body);
|
|
21460
|
+
text2 = JSON.stringify(parsed, null, 2);
|
|
21461
|
+
} catch {
|
|
21462
|
+
text2 = body;
|
|
21463
|
+
}
|
|
21464
|
+
else {
|
|
21465
|
+
let extracted = await htmlToText(body);
|
|
21466
|
+
title = extracted.title || dispFinal, text2 = extracted.text || "";
|
|
21467
|
+
}
|
|
21468
|
+
let safeTitle = sanitizeForTerminal(title).slice(0, 200), fullSafeText = sanitizeForTerminal(text2);
|
|
21404
21469
|
if (signal?.aborted) return;
|
|
21405
21470
|
if (!fullSafeText.trim()) {
|
|
21406
21471
|
let suffix = deps.delegateAnswer ? " The mentioned agent was not consulted." : "";
|
|
@@ -21529,7 +21594,19 @@ async function readSearchResults(deps, runner, query, results) {
|
|
|
21529
21594
|
advise(store, `Reading top ${targetResults.length} web pages in parallel\u2026`);
|
|
21530
21595
|
let fetch2 = deps.guardedFetchFn ?? guardedFetch, fetchPromises = targetResults.map(async (res) => {
|
|
21531
21596
|
try {
|
|
21532
|
-
let fetched = await fetch2(res.url, signal
|
|
21597
|
+
let fetched = await fetch2(res.url, signal, { allowJson: !0 }), title = res.title || "", text2 = "";
|
|
21598
|
+
if ((fetched.contentType || "").toLowerCase().includes("application/json"))
|
|
21599
|
+
try {
|
|
21600
|
+
let parsed = JSON.parse(fetched.body);
|
|
21601
|
+
text2 = JSON.stringify(parsed, null, 2);
|
|
21602
|
+
} catch {
|
|
21603
|
+
text2 = fetched.body;
|
|
21604
|
+
}
|
|
21605
|
+
else {
|
|
21606
|
+
let extracted = await htmlToText(fetched.body);
|
|
21607
|
+
title = extracted.title || title, text2 = extracted.text || "";
|
|
21608
|
+
}
|
|
21609
|
+
let safeTitle = sanitizeForTerminal(title).slice(0, 200), rawText = text2 || "";
|
|
21533
21610
|
return rawText.trim() ? {
|
|
21534
21611
|
finalUrl: fetched.finalUrl,
|
|
21535
21612
|
safeTitle,
|
|
@@ -31273,7 +31350,7 @@ function stripAgyWebPlugin(workdir) {
|
|
|
31273
31350
|
function buildImplementorArgv(agent, mode, workdir, options) {
|
|
31274
31351
|
switch (agent) {
|
|
31275
31352
|
case "CLAUDE": {
|
|
31276
|
-
if (
|
|
31353
|
+
if (!!options?.mcpConfigPath) {
|
|
31277
31354
|
let disallowedTools = mode === "plan" ? "WebFetch,WebSearch,Bash,Agent,Task,Workflow,SendMessage,ListAgents" : "WebFetch,WebSearch,Agent,Task,Workflow,SendMessage,ListAgents", baseTools = mode === "plan" ? "Read,Grep,Glob" : "Read,Grep,Glob,Edit,Write,Bash", allowedTools = `${baseTools},mcp__codevibe-web__codevibe_web_search,mcp__codevibe-web__codevibe_web_fetch`;
|
|
31278
31355
|
return {
|
|
31279
31356
|
argv: [
|
|
@@ -31310,7 +31387,7 @@ function buildImplementorArgv(agent, mode, workdir, options) {
|
|
|
31310
31387
|
let sandbox = mode === "plan" ? "read-only" : "workspace-write", lastMessagePath = import_node_path.default.join(
|
|
31311
31388
|
import_node_os.default.tmpdir(),
|
|
31312
31389
|
`quorum-impl-codex-${process.pid}-${(0, import_uuid4.v4)()}.txt`
|
|
31313
|
-
), webEnabled =
|
|
31390
|
+
), webEnabled = !!options?.mcpConfigPath, mcpServer = webEnabled ? extractMcpServerConfig(options?.mcpConfigPath) : null;
|
|
31314
31391
|
return webEnabled && mcpServer ? {
|
|
31315
31392
|
argv: [
|
|
31316
31393
|
"codex",
|
|
@@ -31360,7 +31437,7 @@ function buildImplementorArgv(agent, mode, workdir, options) {
|
|
|
31360
31437
|
throw new Error(
|
|
31361
31438
|
"buildImplementorArgv: ANTIGRAVITY requires an absolute workdir (agy is workspace-centric \u2014 --add-dir is its only view of the tree); the call site must thread it (AGY-2.0 D3)"
|
|
31362
31439
|
);
|
|
31363
|
-
let webEnabled =
|
|
31440
|
+
let webEnabled = !!options?.mcpConfigPath, mcpServer = webEnabled ? extractMcpServerConfig(options?.mcpConfigPath) : null;
|
|
31364
31441
|
return webEnabled && mcpServer && setupAgyWebPlugin(workdir, mcpServer), {
|
|
31365
31442
|
argv: [...agyImplementorArgvPrefix(mode), workdir, "--print", ""],
|
|
31366
31443
|
capture: { kind: "stdout" }
|
|
@@ -47859,7 +47936,7 @@ var LocalExecutorImpl = class {
|
|
|
47859
47936
|
"none"
|
|
47860
47937
|
), { args, substrateEngaged: !1 };
|
|
47861
47938
|
}
|
|
47862
|
-
let result = await this.substrateEngager({
|
|
47939
|
+
let isWebActive = args.webTurnActive === !0, result = await this.substrateEngager({
|
|
47863
47940
|
taskId: effectiveTaskId,
|
|
47864
47941
|
agentKind,
|
|
47865
47942
|
workdir: args.workingDir,
|
|
@@ -47868,7 +47945,8 @@ var LocalExecutorImpl = class {
|
|
|
47868
47945
|
// A1d (design §8.1) — thread the spawn's confinement demand so the engager
|
|
47869
47946
|
// can build the WRITE-CONFINED resolver row for a broker-less agent
|
|
47870
47947
|
// (GEMINI/ANTIGRAVITY) rather than immediately returning `reduced_trust`.
|
|
47871
|
-
requireConfined: args.requireConfined === !0
|
|
47948
|
+
requireConfined: args.requireConfined === !0,
|
|
47949
|
+
webBrowsingActive: isWebActive
|
|
47872
47950
|
});
|
|
47873
47951
|
if (result.mode === "reduced_trust") {
|
|
47874
47952
|
if (args.requireConfined)
|
|
@@ -57040,6 +57118,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
57040
57118
|
* are removed with the task's other per-task state at its terminal cleanup.
|
|
57041
57119
|
*/
|
|
57042
57120
|
this.singleTaskContextByTask = /* @__PURE__ */ new Map();
|
|
57121
|
+
this.webAccessByTask = /* @__PURE__ */ new Map();
|
|
57043
57122
|
/**
|
|
57044
57123
|
* CP-1.f revise-context fix (dogfood task 2ac68708, 2026-06-11) — the BINDING
|
|
57045
57124
|
* user-requested changes for a task, accumulated across ALL revise rounds.
|
|
@@ -58306,7 +58385,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
58306
58385
|
})).workflowState;
|
|
58307
58386
|
} catch (err) {
|
|
58308
58387
|
let wasNewest = this.activeTaskId === taskId, restoreTo = previousActive && this.singleTaskContextByTask.has(previousActive.taskId) ? previousActive : null;
|
|
58309
|
-
wasNewest && (this.activeTaskId = restoreTo?.taskId ?? null, this.activeBrief = restoreTo?.brief ?? null, restoreTo && (this.activeImplementorAgent = restoreTo.agent)), this.singleTaskContextByTask.delete(taskId), this.startTasksInFlight.delete(taskId);
|
|
58388
|
+
wasNewest && (this.activeTaskId = restoreTo?.taskId ?? null, this.activeBrief = restoreTo?.brief ?? null, restoreTo && (this.activeImplementorAgent = restoreTo.agent)), this.singleTaskContextByTask.delete(taskId), this.webAccessByTask.delete(taskId), this.startTasksInFlight.delete(taskId);
|
|
58310
58389
|
for (let i = this.pendingGateDispatches.length - 1; i >= 0; i--) {
|
|
58311
58390
|
let pending = this.pendingGateDispatches[i];
|
|
58312
58391
|
(pending.envelopeTaskId === taskId || !pending.envelopeTaskId && wasNewest) && this.pendingGateDispatches.splice(i, 1);
|
|
@@ -58942,8 +59021,12 @@ ${section}`);
|
|
|
58942
59021
|
settlePending = resolve23;
|
|
58943
59022
|
}),
|
|
58944
59023
|
...args.teamAuthority ? { teamAuthority: args.teamAuthority } : {}
|
|
58945
|
-
};
|
|
58946
|
-
if (
|
|
59024
|
+
}, needsWeb = this.webAccessByTask.get(args.taskId);
|
|
59025
|
+
if (needsWeb === void 0) {
|
|
59026
|
+
let originalPrompt = this.singleTaskContextByTask.get(args.taskId)?.brief ?? this.activeBriefByTask.get(args.taskId)?.brief ?? (args.roundNumber === 0 ? args.brief : this.activeBrief ?? "");
|
|
59027
|
+
needsWeb = isWebAccessNeeded(originalPrompt), this.webAccessByTask.set(args.taskId, needsWeb);
|
|
59028
|
+
}
|
|
59029
|
+
if (needsWeb && (args.agent === "CLAUDE" || args.agent === "ANTIGRAVITY"))
|
|
58947
59030
|
try {
|
|
58948
59031
|
agentWebTurn = await startAgentWebTurn({
|
|
58949
59032
|
sessionId: this.deps.session.sessionId,
|
|
@@ -58981,6 +59064,7 @@ ${section}`);
|
|
|
58981
59064
|
// (`setActiveTaskId`), so the LE's `args.taskId ?? this.taskId` fallback
|
|
58982
59065
|
// yields byte-identical single-impl substrate engagement.
|
|
58983
59066
|
taskId: args.taskId,
|
|
59067
|
+
webTurnActive: !!agentWebTurn?.mcpConfigPath,
|
|
58984
59068
|
timeoutMs: null,
|
|
58985
59069
|
stdinTty: !0,
|
|
58986
59070
|
// PHASE-CP-10-MIN (#585) — the cooperative abort signal (#C10M-16).
|
|
@@ -60203,7 +60287,7 @@ ${section}`);
|
|
|
60203
60287
|
));
|
|
60204
60288
|
}
|
|
60205
60289
|
for (let taskId of taskIds)
|
|
60206
|
-
this.activeBriefByTask.get(taskId)?.taskGroupId === taskGroupId && (this.activeBriefByTask.delete(taskId), this.activeAttachmentsByTask.delete(taskId));
|
|
60290
|
+
this.activeBriefByTask.get(taskId)?.taskGroupId === taskGroupId && (this.activeBriefByTask.delete(taskId), this.activeAttachmentsByTask.delete(taskId), this.webAccessByTask.delete(taskId));
|
|
60207
60291
|
if (this.teamAttachmentsByGroup.delete(taskGroupId), failures.length > 0) {
|
|
60208
60292
|
try {
|
|
60209
60293
|
this.surfaceHalt(
|
|
@@ -60281,7 +60365,7 @@ ${section}`);
|
|
|
60281
60365
|
});
|
|
60282
60366
|
return;
|
|
60283
60367
|
}
|
|
60284
|
-
if (opts?.preserveReviseContext || (this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), opts?.taskContinues !== !0 && this.singleTaskContextByTask.delete(taskId), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId), appendContextItem(this.deps.session.sessionId, {
|
|
60368
|
+
if (opts?.preserveReviseContext || (this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), opts?.taskContinues !== !0 && (this.singleTaskContextByTask.delete(taskId), this.webAccessByTask.delete(taskId)), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId), appendContextItem(this.deps.session.sessionId, {
|
|
60285
60369
|
kind: "verdict",
|
|
60286
60370
|
author: { role: "engine" },
|
|
60287
60371
|
sensitivity: "user",
|
|
@@ -60362,7 +60446,7 @@ ${section}`);
|
|
|
60362
60446
|
error: err?.message
|
|
60363
60447
|
}), historySnapshot = null;
|
|
60364
60448
|
}
|
|
60365
|
-
this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.singleTaskContextByTask.delete(taskId), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId);
|
|
60449
|
+
this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.singleTaskContextByTask.delete(taskId), this.webAccessByTask.delete(taskId), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId);
|
|
60366
60450
|
let shadow = this.shadowsByTask.get(taskId);
|
|
60367
60451
|
if (!shadow) {
|
|
60368
60452
|
logger.info("[QuorumLoop] promote no-op \u2014 no in-memory shadow for task", { taskId });
|
|
@@ -68776,7 +68860,10 @@ async function handleShellUserInput(deps) {
|
|
|
68776
68860
|
}, decision, showClassifySpinner = store.getState().progress === null;
|
|
68777
68861
|
showClassifySpinner && store.dispatch({ type: "TASK_PROGRESS", event: { phase: "planner_classifying" } });
|
|
68778
68862
|
try {
|
|
68779
|
-
decision = await dispatchClassify(plannerInput), isLocalPlannerRuntime(args) && decision.action === "
|
|
68863
|
+
decision = await dispatchClassify(plannerInput), isLocalPlannerRuntime(args) && decision.action === "browse" && hasFileMutationIntent(plannerInput.prompt) && (decision = {
|
|
68864
|
+
action: "start_task",
|
|
68865
|
+
rationale: decision.rationale ? `${decision.rationale} (promoted to start_task due to file mutation intent)` : "web request with file mutation intent"
|
|
68866
|
+
}), isLocalPlannerRuntime(args) && decision.action === "start_task" && plannerInput.clarifications.length === 0 && isDestructiveFileRequest(plannerInput.prompt) && (logger.warn(
|
|
68780
68867
|
"[orchestration-shell] P43 backstop: a destructive file request was classified start_task without a confirmation this turn; asking first",
|
|
68781
68868
|
{ rationale: decision.rationale }
|
|
68782
68869
|
), decision = {
|
|
@@ -72365,6 +72452,14 @@ async function assertAuditOutsideWorkdir(auditPath, workdir) {
|
|
|
72365
72452
|
return resolvedAuditPath;
|
|
72366
72453
|
}
|
|
72367
72454
|
async function engageSubstrate(input) {
|
|
72455
|
+
if (input.webBrowsingActive)
|
|
72456
|
+
return {
|
|
72457
|
+
mode: "reduced_trust",
|
|
72458
|
+
reducedTrust: !0,
|
|
72459
|
+
reducedTrustReason: `Agent web browsing active for ${input.agentKind} \u2014 running in reduced-trust mode with shadow-diff capture and guarded web tools`,
|
|
72460
|
+
teardown: async () => {
|
|
72461
|
+
}
|
|
72462
|
+
};
|
|
72368
72463
|
let provider = providerForAgent(input.agentKind);
|
|
72369
72464
|
if (provider === null)
|
|
72370
72465
|
return input.requireConfined ? engageWriteConfinedResolverSandbox(input) : {
|
|
@@ -74904,6 +74999,7 @@ async function buildQuorumLoopExecutor(args) {
|
|
|
74904
74999
|
userContextFn: async () => ""
|
|
74905
75000
|
}, localExecutor = new LocalExecutorImpl({
|
|
74906
75001
|
sessionId: session.sessionId,
|
|
75002
|
+
logger,
|
|
74907
75003
|
// CP-1.f Hybrid authority split (mirrors the team LE) — the DESKTOP seeds
|
|
74908
75004
|
// the implementor command allowlist so `enforceCommand` permits the spawn;
|
|
74909
75005
|
// write/read/network stay empty (the engine authorizes PATH scopes via a
|
|
@@ -75145,6 +75241,7 @@ async function buildTeamLocalExecutor(args) {
|
|
|
75145
75241
|
userContextFn: async () => ""
|
|
75146
75242
|
}, localExecutor = new LocalExecutorImpl({
|
|
75147
75243
|
sessionId: session.sessionId,
|
|
75244
|
+
logger,
|
|
75148
75245
|
initialScope,
|
|
75149
75246
|
baseCtx: {
|
|
75150
75247
|
sessionId: session.sessionId,
|
|
@@ -53,4 +53,22 @@ export declare function extractAllAgentMentionIntents(text: string): AgentMentio
|
|
|
53
53
|
export declare function stripLeadingAgentControlToken(text: string): string;
|
|
54
54
|
export declare function buildCommandIntentEnvelope(intent: AgentMentionIntent): CommandIntentEnvelope;
|
|
55
55
|
export declare function buildCommandIntentMetadata(text: string): CommandIntentMetadata | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Detects whether a prompt or brief expresses need for external web browsing or online searching.
|
|
58
|
+
* Used by QuorumLoop to dynamically attach web tools ONLY when needed, preserving full
|
|
59
|
+
* sandboxing for normal non-web tasks.
|
|
60
|
+
*
|
|
61
|
+
* Supports language-agnostic URLs, as well as English, Chinese, and Japanese web search intents.
|
|
62
|
+
*/
|
|
63
|
+
export declare function isWebAccessNeeded(text: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Detects whether a prompt expresses intent to create, write, save, or modify local files/reports,
|
|
66
|
+
* as opposed to a purely read-only conversational request.
|
|
67
|
+
* Used as a backstop when classifying or routing web requests so that prompts asking to fetch/search
|
|
68
|
+
* AND write/save to a local file route to `start_task` (implementor execution) instead of desktop `browse`.
|
|
69
|
+
*
|
|
70
|
+
* Designed to handle English, Chinese, Japanese, Korean, European languages, and universal structural patterns
|
|
71
|
+
* (e.g. file targets and shell redirection), while accurately filtering out informational "how-to" / conceptual questions.
|
|
72
|
+
*/
|
|
73
|
+
export declare function hasFileMutationIntent(text: string): boolean;
|
|
56
74
|
export {};
|
|
@@ -690,6 +690,7 @@ export declare class QuorumLoop {
|
|
|
690
690
|
* are removed with the task's other per-task state at its terminal cleanup.
|
|
691
691
|
*/
|
|
692
692
|
private readonly singleTaskContextByTask;
|
|
693
|
+
private readonly webAccessByTask;
|
|
693
694
|
/**
|
|
694
695
|
* CP-1.f revise-context fix (dogfood task 2ac68708, 2026-06-11) — the BINDING
|
|
695
696
|
* user-requested changes for a task, accumulated across ALL revise rounds.
|
|
@@ -80,6 +80,8 @@ export interface EngageSubstrateInput {
|
|
|
80
80
|
claudeScratchHostRoot?: string;
|
|
81
81
|
/** Safe locale source for the sanitized env (default: none). */
|
|
82
82
|
localeSource?: Readonly<Record<string, string | undefined>>;
|
|
83
|
+
/** If true, the turn has active web tools (MCP bridge) and runs in reduced-trust mode. */
|
|
84
|
+
webBrowsingActive?: boolean;
|
|
83
85
|
}
|
|
84
86
|
/**
|
|
85
87
|
* The substrate-engaged result: the spawn seam runs the agent via
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantiya/codevibe-claude-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.42",
|
|
4
4
|
"description": "Control Claude Code from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"codevibe": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=22.0.0"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@quantiya/codevibe-core": "^2.0.
|
|
51
|
+
"@quantiya/codevibe-core": "^2.0.37",
|
|
52
52
|
"@quantiya/quorum-core": "^1.0.1",
|
|
53
53
|
"dotenv": "^16.6.1",
|
|
54
54
|
"express": "^5.1.0",
|