@quantiya/codevibe-claude-plugin 2.0.31 → 2.0.33
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/__tests__/no-raw-control-bytes-in-source.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.js +409 -406
- package/node_modules/@quantiya/codevibe-core/dist/local-model/__tests__/ollama-context-window.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-model/ollama.d.ts +93 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/browse-prompt-urls.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/destructive-request.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +1573 -743
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-compaction.d.ts +23 -1
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/destructive-request.d.ts +28 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/index.d.ts +24 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/route-browse.d.ts +16 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/__tests__/local-gemma-browse-regression.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/__tests__/local-gemma-followup-hotfix.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/__tests__/url-protect.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/local-gemma.d.ts +58 -14
- package/node_modules/@quantiya/codevibe-core/dist/planner/url-protect.d.ts +20 -0
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-compaction.d.ts
CHANGED
|
@@ -21,8 +21,23 @@ export declare const COMPACTION_KEEP_HOT_RECENT_ITEMS = 16;
|
|
|
21
21
|
* hosted 7-day session TTL; chosen here (design leaves the number open).
|
|
22
22
|
*/
|
|
23
23
|
export declare const CONTEXT_ITEMS_RETENTION_MS: number;
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The rendered session-context section's own budget (inside the F6 total) for
|
|
26
|
+
* the implementor dispatch block and the brainstorm panel: 2,000 chars, every
|
|
27
|
+
* line capped by `capForRender`, stop at the first line that does not fit — the
|
|
28
|
+
* shipped behaviour. The planner's classification render uses
|
|
29
|
+
* `SESSION_CONTEXT_SECTION_MAX_CHARS_CLASSIFY` below (Stage-1 r1 F5 / r2 F2,
|
|
30
|
+
* 2026-09-12).
|
|
31
|
+
*/
|
|
25
32
|
export declare const SESSION_CONTEXT_SECTION_MAX_CHARS = 2000;
|
|
33
|
+
/**
|
|
34
|
+
* The planner's CLASSIFICATION render (2026-09-12): hot turns render WHOLE inside
|
|
35
|
+
* a 6,000-char section under the local runner's explicit 16K-token window.
|
|
36
|
+
* Stage-1 r1 F5 — this applies ONLY to `purpose: 'classification'`: the implementor
|
|
37
|
+
* dispatch block (hard 4,800-char total, `DISPATCH_CONTEXT_MAX_CHARS`) and the
|
|
38
|
+
* brainstorm panel keep the 2,000-char section and the per-line cap above.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SESSION_CONTEXT_SECTION_MAX_CHARS_CLASSIFY = 6000;
|
|
26
41
|
/**
|
|
27
42
|
* A1f Stage-1 R1 HIGH + Stage-2 R1 (H1/M2/M3/M5) — one distilled FACT:
|
|
28
43
|
* - `body` — the source item's COMPLETE typed payload, verbatim (M3:
|
|
@@ -136,6 +151,13 @@ export declare function compactionCachePath(sessionId: string): string;
|
|
|
136
151
|
* hot view). Never throws.
|
|
137
152
|
*/
|
|
138
153
|
export declare function loadCompactionCache(sessionId: string): Promise<SessionCompactionCache>;
|
|
154
|
+
/**
|
|
155
|
+
* Stage-1 r1 F4 — an ends-preserving cut for the ONE line that must survive even
|
|
156
|
+
* when it exceeds the section (the newest hot item): the head carries the referent,
|
|
157
|
+
* the tail the latest words, and the marker makes the cut visible to the model.
|
|
158
|
+
*/
|
|
159
|
+
export declare const RENDER_CUT_MARKER = " [\u2026] ";
|
|
160
|
+
export declare function cutPreservingEnds(text: string, max: number): string;
|
|
139
161
|
/**
|
|
140
162
|
* Stage-2 R1 H1 — the dispatch-scope predicate, applied IDENTICALLY to hot
|
|
141
163
|
* items and distilled facts (composes WITH the §5 label floor, never
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/destructive-request.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type DestructiveRequestMatch = {
|
|
2
|
+
kind: 'none';
|
|
3
|
+
}
|
|
4
|
+
/** One named file is the whole object of the deletion. */
|
|
5
|
+
| {
|
|
6
|
+
kind: 'target';
|
|
7
|
+
target: string;
|
|
8
|
+
}
|
|
9
|
+
/** A deletion of several / located / unnamed files — the question quotes the request. */
|
|
10
|
+
| {
|
|
11
|
+
kind: 'neutral';
|
|
12
|
+
};
|
|
13
|
+
/** Classify `text` against the backstop's shapes (see the module comment). */
|
|
14
|
+
export declare function matchDestructiveFileRequest(text: string): DestructiveRequestMatch;
|
|
15
|
+
/**
|
|
16
|
+
* True when `text` asks to delete / remove a named file or a file/folder object.
|
|
17
|
+
* A conservative shape matcher (a backstop, not a classifier): false for edits
|
|
18
|
+
* that only mention a file or removal inside a file.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isDestructiveFileRequest(text: string): boolean;
|
|
21
|
+
/** The file the request names as the WHOLE object of the deletion, when there is exactly that. */
|
|
22
|
+
export declare function destructiveRequestTarget(text: string): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The confirmation the classifier should have asked (P43 shape: target-specific
|
|
25
|
+
* when one named file is the whole object, otherwise quoting the request), ending
|
|
26
|
+
* with the yes/no instruction the answered round relies on.
|
|
27
|
+
*/
|
|
28
|
+
export declare function destructiveConfirmationQuestion(text: string): string;
|
|
@@ -2,6 +2,22 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
2
2
|
import { AppSyncClient } from '../appsync';
|
|
3
3
|
import { Session } from '../types';
|
|
4
4
|
import { OrchestrationStore } from './store';
|
|
5
|
+
import { type RetainedBrowsePage } from './route-browse';
|
|
6
|
+
/**
|
|
7
|
+
* WEB-BROWSING-DESIGN.md rev 6 — the address for a model-chosen fetch.
|
|
8
|
+
*
|
|
9
|
+
* The classifier owns the fetch-vs-search decision: a `browse` decision WITH
|
|
10
|
+
* `browseUrls` is a fetch, one WITHOUT is a search (`browseQuery`). This helper
|
|
11
|
+
* never turns a search into a fetch (Stage-1 r1 F4: a URL that merely appears
|
|
12
|
+
* in "search for alternatives to https://x.com" stays a search). For a fetch,
|
|
13
|
+
* the user's literal URL is the address: the classify prompt is path-redacted
|
|
14
|
+
* before the model sees it, so the model's echo can be mangled
|
|
15
|
+
* (`https://[path]` in the 2026-09-11 incident) or drift. Only when the prompt
|
|
16
|
+
* carries no URL are the model's well-formed URLs used; a fetch decision whose
|
|
17
|
+
* every URL is unusable and whose prompt has none yields no URL (the route then
|
|
18
|
+
* falls back to `browseQuery` or asks for a URL).
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveBrowseUrls(modelUrls: string[] | undefined, prompt: string): string[] | undefined;
|
|
5
21
|
import { AdvisoryAttachmentJournal } from './advisory-attachment-journal';
|
|
6
22
|
import type { ImageAttachment } from './types';
|
|
7
23
|
import { type GateDecisionSubmitDeps, type GroupDecisionSubmitDeps } from './gate-decision-submit';
|
|
@@ -765,6 +781,12 @@ export declare function routeAdvisory(deps: {
|
|
|
765
781
|
* image couldn't be used instead of answering as if none was attached.
|
|
766
782
|
*/
|
|
767
783
|
attemptedImages?: number;
|
|
784
|
+
/**
|
|
785
|
+
* 2026-09-12 — the page the `browse` route read most recently in this session.
|
|
786
|
+
* Rendered as untrusted source material the model uses ONLY when the request is
|
|
787
|
+
* about that page (the model decides relevance, the shell does not).
|
|
788
|
+
*/
|
|
789
|
+
retainedPage?: RetainedBrowsePage;
|
|
768
790
|
}): Promise<void>;
|
|
769
791
|
export declare function parseTeamWorkItems(rawArg: string): {
|
|
770
792
|
ok: true;
|
|
@@ -971,6 +993,8 @@ export declare function tokenizeCommandLine(input: string): {
|
|
|
971
993
|
error?: string;
|
|
972
994
|
};
|
|
973
995
|
export declare function handleShellUserInput(deps: HandleShellUserInputDeps): Promise<void>;
|
|
996
|
+
/** Test seam — clear the per-session retained pages between cases. */
|
|
997
|
+
export declare function resetRetainedBrowsePagesForTests(): void;
|
|
974
998
|
/**
|
|
975
999
|
* [A1g] Stage-2 round-4 (Codex round-3 MEDIUM) — the EXPLICIT per-turn panel-
|
|
976
1000
|
* ownership token. `serializeShellSubmissions` mints ONE fresh object per
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { OrchestrationStore } from './store';
|
|
2
2
|
import type { LocalGemmaAdvisoryRunner } from '../planner/local-advisory';
|
|
3
|
+
/**
|
|
4
|
+
* A page the shell read this session, retained (2026-09-12) so a follow-up
|
|
5
|
+
* ("that sounds like a summary, I am looking for your thoughts") can be answered
|
|
6
|
+
* by the local model WITH the page in front of it instead of from a three-sentence
|
|
7
|
+
* summary — or a re-fetch. Text is already terminal-sanitized and bounded.
|
|
8
|
+
*/
|
|
9
|
+
export interface RetainedBrowsePage {
|
|
10
|
+
url: string;
|
|
11
|
+
title: string;
|
|
12
|
+
text: string;
|
|
13
|
+
readAt: string;
|
|
14
|
+
}
|
|
15
|
+
/** Retained page text bound — the answerer caps again at render time. */
|
|
16
|
+
export declare const RETAINED_PAGE_MAX_CHARS = 24000;
|
|
3
17
|
export interface RouteBrowseDeps {
|
|
4
18
|
store: OrchestrationStore;
|
|
5
19
|
/** Undefined when the local model isn't installed/enabled → no-model advisory. */
|
|
@@ -11,6 +25,8 @@ export interface RouteBrowseDeps {
|
|
|
11
25
|
priorTurns?: string[];
|
|
12
26
|
/** Esc-abort signal (shell-owned AbortController). */
|
|
13
27
|
signal?: AbortSignal;
|
|
28
|
+
/** Called once readable text was extracted from a fetched page (before summarizing). */
|
|
29
|
+
onPageRead?: (page: RetainedBrowsePage) => void;
|
|
14
30
|
}
|
|
15
31
|
/**
|
|
16
32
|
* Orchestrate a `browse` route. Fetch an explicit URL, or run a keyless web
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -31,38 +31,75 @@ export interface LocalGemmaPlannerRunner {
|
|
|
31
31
|
* without inventing a successful classification or starting a task.
|
|
32
32
|
*/
|
|
33
33
|
export declare class PlannerOutputUnparseableError extends Error {
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The first {@link RAW_OUTPUT_HEAD_CHARS} characters of the model output that
|
|
36
|
+
* failed to parse (terminal-control bytes stripped), attached by the adapter so
|
|
37
|
+
* the shell's warn line records WHAT the model said. Before 2026-09-11 nothing
|
|
38
|
+
* logged the raw text and the `<channel|>` echo incident needed a live repro
|
|
39
|
+
* to diagnose. Absent when the error was raised without a raw string in hand.
|
|
40
|
+
*/
|
|
41
|
+
rawOutputHead?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Design §7 R3 (restored 2026-09-12 after the dogfood follow-up incident):
|
|
44
|
+
* `'parse'` — the model's text never became a JSON object (prose, truncated or
|
|
45
|
+
* conflicting output); `'validation'` — a JSON object with a recognised `action`
|
|
46
|
+
* was produced but a per-action key rule or the schema rejected it. The shell
|
|
47
|
+
* fails closed on the first class and may degrade the second to the safe
|
|
48
|
+
* advisory route when {@link degradeTo} names an answer-type intent.
|
|
49
|
+
*/
|
|
50
|
+
readonly kind: 'parse' | 'validation';
|
|
51
|
+
/**
|
|
52
|
+
* The rejected decision's ANSWER-TYPE intent — `advisory_response` / `brainstorm`
|
|
53
|
+
* (answered through the local advisory route) or `refuse` (rendered as the
|
|
54
|
+
* shell's deterministic refusal with this rationale) — plus whatever user-facing
|
|
55
|
+
* text it carried. NEVER set for `start_task` / `team_decompose` / `browse` (a
|
|
56
|
+
* broken decision must never start work or fetch anything), nor for `ask_user` /
|
|
57
|
+
* `familiarize` (Stage-1 r1 F2: those fail closed).
|
|
58
|
+
*/
|
|
59
|
+
readonly degradeTo?: {
|
|
60
|
+
action: PlannerDecision['action'];
|
|
61
|
+
rationale?: string;
|
|
62
|
+
advisorySummary?: string;
|
|
63
|
+
};
|
|
64
|
+
constructor(message: string, options?: {
|
|
65
|
+
kind?: 'parse' | 'validation';
|
|
66
|
+
degradeTo?: PlannerOutputUnparseableError['degradeTo'];
|
|
67
|
+
});
|
|
35
68
|
}
|
|
36
|
-
export declare
|
|
37
|
-
|
|
69
|
+
export declare function localGemmaAllowedActions(isSubprocessRunner: boolean): ReadonlySet<PlannerDecision['action']>;
|
|
70
|
+
interface LocalGemmaDecisionJsonSchema {
|
|
71
|
+
type: 'object';
|
|
38
72
|
properties: {
|
|
39
73
|
rationale: {
|
|
40
|
-
type: string;
|
|
74
|
+
type: 'string';
|
|
41
75
|
};
|
|
42
76
|
clarifying_question: {
|
|
43
|
-
type: string;
|
|
77
|
+
type: 'string';
|
|
44
78
|
};
|
|
45
79
|
advisory_summary: {
|
|
46
|
-
type: string;
|
|
80
|
+
type: 'string';
|
|
47
81
|
};
|
|
48
82
|
browseUrls: {
|
|
49
|
-
type:
|
|
83
|
+
type: 'array';
|
|
50
84
|
items: {
|
|
51
|
-
type: string;
|
|
52
|
-
pattern: string;
|
|
85
|
+
type: 'string';
|
|
53
86
|
};
|
|
54
87
|
};
|
|
55
88
|
browseQuery: {
|
|
56
|
-
type: string;
|
|
89
|
+
type: 'string';
|
|
57
90
|
};
|
|
58
91
|
action: {
|
|
59
|
-
type: string;
|
|
60
|
-
enum:
|
|
92
|
+
type: 'string';
|
|
93
|
+
enum: PlannerDecision['action'][];
|
|
61
94
|
};
|
|
62
95
|
};
|
|
63
96
|
required: string[];
|
|
64
97
|
additionalProperties: boolean;
|
|
65
|
-
}
|
|
98
|
+
}
|
|
99
|
+
/** The Ollama runner's schema (no `summarize_current_status`). */
|
|
100
|
+
export declare const LOCAL_GEMMA_DECISION_JSON_SCHEMA: LocalGemmaDecisionJsonSchema;
|
|
101
|
+
/** The subprocess runner's schema keeps `summarize_current_status` (Stage-2 codex R1-F3). */
|
|
102
|
+
export declare const LOCAL_GEMMA_SUBPROCESS_DECISION_JSON_SCHEMA: LocalGemmaDecisionJsonSchema;
|
|
66
103
|
/**
|
|
67
104
|
* Text-only route classifier prompt. It intentionally excludes repository
|
|
68
105
|
* paths, summaries, source snippets, file bodies, and the raw structural digest.
|
|
@@ -70,7 +107,13 @@ export declare const LOCAL_GEMMA_DECISION_JSON_SCHEMA: {
|
|
|
70
107
|
export declare function renderLocalGemmaPlannerPrompt(input: PlannerInput, options?: {
|
|
71
108
|
isSubprocessRunner?: boolean;
|
|
72
109
|
}): string;
|
|
73
|
-
|
|
110
|
+
/** Characters of raw model output retained on {@link PlannerOutputUnparseableError.rawOutputHead}. */
|
|
111
|
+
export declare const RAW_OUTPUT_HEAD_CHARS = 500;
|
|
112
|
+
/** Terminal-control-free, bounded head of a raw model output for the warn log. */
|
|
113
|
+
export declare function summarizeRawOutputForLog(raw: string): string;
|
|
114
|
+
export declare function parseLocalGemmaPlannerDecision(raw: string, options?: {
|
|
115
|
+
isSubprocessRunner?: boolean;
|
|
116
|
+
}): PlannerDecision;
|
|
74
117
|
export declare class LocalGemmaPlannerAdapter implements PlannerAdapter {
|
|
75
118
|
private readonly runner;
|
|
76
119
|
private activeSessionId;
|
|
@@ -79,3 +122,4 @@ export declare class LocalGemmaPlannerAdapter implements PlannerAdapter {
|
|
|
79
122
|
probe(): Promise<PlannerProbeResult>;
|
|
80
123
|
setActiveSession(sessionId: string | null): void;
|
|
81
124
|
}
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Source of the shared http(s) URL matcher (no `g` state — build with {@link httpUrlPattern}). */
|
|
2
|
+
export declare const HTTP_URL_PATTERN_SOURCE = "https?:\\/\\/[^\\s\"'`<>,)}\\]\u3001\u3002\u3003\u3008\u3009\u300A\u300B\u300C\u300D\u300E\u300F\u3010\u3011\u3014\u3015\u3016\u3017\u3018\u3019\u301A\u301B\u301C\u301D\u301E\u301F\uFF01-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65]+";
|
|
3
|
+
/** A fresh global RegExp for {@link HTTP_URL_PATTERN_SOURCE}. */
|
|
4
|
+
export declare function httpUrlPattern(): RegExp;
|
|
5
|
+
/** Replace every http(s) URL with an opaque placeholder; returns the URLs in order. */
|
|
6
|
+
export declare function protectUrls(text: string): {
|
|
7
|
+
text: string;
|
|
8
|
+
urls: string[];
|
|
9
|
+
};
|
|
10
|
+
/** Put the URLs captured by {@link protectUrls} back in place of their placeholders. */
|
|
11
|
+
export declare function restoreUrls(text: string, urls: string[]): string;
|
|
12
|
+
/** `http:`/`https:` and parseable by WHATWG `URL`; never a redacted `[path]` echo. */
|
|
13
|
+
export declare function isWellFormedHttpUrl(candidate: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The literal http(s) URLs a user typed, in order, de-duplicated, with trailing
|
|
16
|
+
* sentence punctuation dropped (`read https://x.com/a.` → `https://x.com/a`) and
|
|
17
|
+
* balanced parentheses kept (`…/wiki/Foo_(bar)` stays whole — F7). Pure text
|
|
18
|
+
* extraction — scheme/port/host validation stays in `guardedFetch`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractHttpUrls(text: string): string[];
|
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.33",
|
|
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.28",
|
|
52
52
|
"@quantiya/quorum-core": "^1.0.1",
|
|
53
53
|
"dotenv": "^16.6.1",
|
|
54
54
|
"express": "^5.1.0",
|