@quantiya/codevibe-claude-plugin 2.0.37 → 2.0.39

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.
Files changed (25) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/node_modules/@quantiya/codevibe-core/dist/credential-broker/scrubber.d.ts +8 -0
  3. package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +1 -1
  4. package/node_modules/@quantiya/codevibe-core/dist/index.js +450 -441
  5. package/node_modules/@quantiya/codevibe-core/dist/local-model/ollama.d.ts +10 -0
  6. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/m7-brief-exclusion.test.d.ts +1 -0
  7. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/m7-repo-state-freshness.test.d.ts +1 -0
  8. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/m7-user-context.test.d.ts +1 -0
  9. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/m7-worktree-fingerprint.test.d.ts +1 -0
  10. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/user-rules.test.d.ts +1 -0
  11. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/brainstorm-quorum.d.ts +5 -3
  12. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.d.ts +12 -0
  13. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +3235 -2662
  14. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-compaction.d.ts +111 -2
  15. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-items.d.ts +21 -1
  16. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/context-store.d.ts +44 -0
  17. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/index.d.ts +64 -8
  18. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +20 -0
  19. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/route-browse.d.ts +1 -1
  20. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/slash-router.d.ts +8 -0
  21. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/user-rules.d.ts +83 -0
  22. package/node_modules/@quantiya/codevibe-core/dist/planner/index.d.ts +1 -1
  23. package/node_modules/@quantiya/codevibe-core/dist/planner/local-advisory.d.ts +3 -1
  24. package/node_modules/@quantiya/codevibe-core/package.json +1 -1
  25. package/package.json +2 -2
@@ -45,6 +45,25 @@ export declare const SESSION_CONTEXT_SECTION_MAX_CHARS_CLASSIFY = 6000;
45
45
  * between multi-agent deliberation turns while preserving the overall budget.
46
46
  */
47
47
  export declare const SESSION_CONTEXT_SECTION_MAX_CHARS_BRAINSTORM = 4800;
48
+ /**
49
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.1 "Budget") — the user-context list's
50
+ * budgets. Pins are placed first, newest first; messages then fill their own
51
+ * budget, newest first, each message's text capped with an ends-preserving
52
+ * cut. Implementors and the decomposer get the larger budgets (their list rides
53
+ * the stdin, outside the 4,800-char dispatch block); the planner's
54
+ * classification render and the brainstorm panel get the smaller ones inside
55
+ * their section, plus a message floor reserved before the hot tail.
56
+ */
57
+ export declare const USER_CONTEXT_PIN_MAX_CHARS_IMPLEMENTOR = 2400;
58
+ export declare const USER_CONTEXT_MESSAGE_MAX_CHARS_IMPLEMENTOR = 2000;
59
+ export declare const USER_CONTEXT_PIN_MAX_CHARS_PLANNER = 1600;
60
+ export declare const USER_CONTEXT_MESSAGE_MAX_CHARS_PLANNER = 1500;
61
+ export declare const USER_CONTEXT_MESSAGE_FLOOR_CHARS = 600;
62
+ export declare const USER_CONTEXT_MESSAGE_LINE_MAX_CHARS = 300;
63
+ /** §3.2 — the implementor (and decomposer) header: the wording tested in E12. */
64
+ export declare const USER_CONTEXT_HEADER_IMPLEMENTOR = "The user's own words from earlier in this session, oldest first: rules the shell pinned and the user's recent messages. Follow every standing rule, convention or preference they state; where two conflict, the later one wins. They take precedence over the repository context and any codebase overview below. Other requests in these messages are context only; the TASK above is what to do now.";
65
+ /** §3.2 — the planner and panel header; the lines below it stay self-describing if trimming cuts it (E6). */
66
+ export declare const USER_CONTEXT_HEADER_PLANNER = "The user's own words from earlier in this session, oldest first, including the latest ones shown above; where two entries conflict, the later one wins:";
48
67
  /**
49
68
  * A1f Stage-1 R1 HIGH + Stage-2 R1 (H1/M2/M3/M5) — one distilled FACT:
50
69
  * - `body` — the source item's COMPLETE typed payload, verbatim (M3:
@@ -243,7 +262,15 @@ export declare function maybeFireCompactionSafetyValve(sessionId: string): Promi
243
262
  * `null` = the chain failed verification — fail-closed, rehydrate NOTHING
244
263
  * (the A1e projection contract).
245
264
  */
246
- export declare function rehydrateSessionContext(deps: {
265
+ export declare function rehydrateSessionContext(deps: RehydrateSessionContextDeps,
266
+ /**
267
+ * M7 — receives the verified items this rehydration read, so the user list
268
+ * (rendered from the log, not the cache — §3.2) needs no second read.
269
+ */
270
+ observe?: {
271
+ verifiedItems?: (items: readonly ContextItem[]) => void;
272
+ }): Promise<RehydratedSessionContext | null>;
273
+ export interface RehydrateSessionContextDeps {
247
274
  sessionId: string;
248
275
  role: ContextItemProjectionRole;
249
276
  clearance: ContextItemSensitivity;
@@ -253,7 +280,7 @@ export declare function rehydrateSessionContext(deps: {
253
280
  * dispatch. ABSENT (e.g. the decomposer, pre-task) → session-scoped only.
254
281
  */
255
282
  scope?: DispatchScope;
256
- }): Promise<RehydratedSessionContext | null>;
283
+ }
257
284
  /**
258
285
  * Render the rehydrated session context as ONE bounded prompt section (fed
259
286
  * to `composeDispatchContextBlock`'s `renderSessionContextFn` seam —
@@ -271,6 +298,88 @@ export declare function renderRehydratedSessionContext(deps: {
271
298
  /** Classifier control state comes from the current request, not prior decisions. */
272
299
  purpose?: 'classification';
273
300
  }): Promise<string>;
301
+ /** One live pinned rule the list may show. */
302
+ export interface UserContextPin {
303
+ seq: string;
304
+ id: string;
305
+ /** `- [pinned rule] …` — redacted, on one line. */
306
+ line: string;
307
+ }
308
+ /** One earlier message the list may show. */
309
+ export interface UserContextMessage {
310
+ seq: string;
311
+ id: string;
312
+ /** `- [earlier message] …` — redacted, on one line, text capped. */
313
+ line: string;
314
+ }
315
+ export interface UserContextCandidates {
316
+ /** Live pins, oldest first. */
317
+ pins: UserContextPin[];
318
+ /** Messages eligible for the list (after the request-part exclusion and the merge rule), oldest first. */
319
+ messages: UserContextMessage[];
320
+ }
321
+ /** A live pin for `/rules` and the revocation guard (label-permitted for the planner). */
322
+ export interface LiveUserRule {
323
+ id: string;
324
+ seq: string;
325
+ text: string;
326
+ source: 'turn' | 'explicit';
327
+ }
328
+ /** True for a pinned-rule or a pin-retirement `decision` body. */
329
+ export declare function isUserRuleBody(body: unknown): boolean;
330
+ /** §3.1 DL-2 — every live pin, oldest first (the `/rules` numbering). */
331
+ export declare function liveUserRules(items: readonly ContextItem[]): LiveUserRule[];
332
+ /** The session's live pins from the VERIFIED log; `null` when the chain does not verify. */
333
+ export declare function readLiveUserRules(sessionId: string): Promise<LiveUserRule[] | null>;
334
+ /**
335
+ * §3.1 — select what the list may show for a role: the label floor
336
+ * (`projectItemsForRole`), live pins, and the user's own messages (human
337
+ * `turn` items only — never agent, conductor or panel turns). With
338
+ * `requestText` (implementors and the decomposer), a message the brief's
339
+ * request part already carries is left out. Merge rule (R2-F1): a listed
340
+ * message whose WHOLE text is its pin appears once, as the pin; otherwise the
341
+ * message and its pin both appear, ordered by `seq`. A retired pin (`/rules
342
+ * forget`) takes its words out of its message: a whole-text message leaves the
343
+ * list, and a longer message stays without the pinned sentence(s) — or leaves
344
+ * too when they cannot be cut out (implementation gate R1-F2) — so the rule's
345
+ * words stop reaching agents. Pure; exported for tests.
346
+ */
347
+ export declare function selectUserContextCandidates(items: readonly ContextItem[], opts: {
348
+ role: ContextItemProjectionRole;
349
+ clearance: ContextItemSensitivity;
350
+ requestText?: string;
351
+ }): UserContextCandidates;
352
+ /**
353
+ * §3.1 presentation — the newest `keptPinCount` pins and `keptMessageCount`
354
+ * messages merged by `seq`, oldest first. Older pins that did not fit collapse
355
+ * into one `[N older pinned rules omitted — /rules lists them all]` line at the
356
+ * top; messages that did not fit become `[N earlier messages omitted]` exactly
357
+ * where they were, between the shown entries. Pure; exported for tests.
358
+ */
359
+ export declare function presentUserContext(candidates: UserContextCandidates, keptPinCount: number, keptMessageCount: number): string[];
360
+ /**
361
+ * §3.2 — the implementor (and decomposer) list from verified items: pins
362
+ * within 2,400 chars, then messages within 2,000, newest first, presented
363
+ * oldest first under the binding header. Returns '' when there is nothing to
364
+ * show. Pure; exported for tests.
365
+ */
366
+ export declare function renderUserContextFromItems(items: readonly ContextItem[], opts: {
367
+ role: ContextItemProjectionRole;
368
+ clearance: ContextItemSensitivity;
369
+ requestText?: string;
370
+ }): string;
371
+ /**
372
+ * §3.2/§3.3 — the implementor's and the decomposer's user-context section,
373
+ * read from the VERIFIED log. `requestText` is the round's (or the
374
+ * decomposer's) brief. Fail-closed to '' (one warning per session) — the
375
+ * dispatch proceeds without it. Never throws.
376
+ */
377
+ export declare function renderUserContextSection(deps: {
378
+ sessionId: string;
379
+ role: ContextItemProjectionRole;
380
+ clearance: ContextItemSensitivity;
381
+ requestText?: string;
382
+ }): Promise<string>;
274
383
  /**
275
384
  * §6 Eviction/GC — TTL-only retention sweep of the per-session log dirs
276
385
  * under `~/.codevibe/context-items/`: a session dir whose NEWEST file mtime
@@ -1,4 +1,4 @@
1
- import { loadContextStore, resolveContextRef, probeWorkspaceGitHead } from './context-store';
1
+ import { loadContextStore, resolveContextRef, probeWorkspaceGitHead, probeWorkspaceTreeFingerprint } from './context-store';
2
2
  import type { StructuralSummaryGenerator, RepoSummary } from '../structural-summary/types';
3
3
  import type { Tier } from './types';
4
4
  /** AppSync's pinned blind-hold ciphertext ceiling (ASCII base64 characters). */
@@ -285,6 +285,12 @@ export interface RepoStateBody {
285
285
  summary: string;
286
286
  /** The workspace git HEAD recorded AT READ TIME (§8.3 freshness). */
287
287
  gitHead?: string;
288
+ /**
289
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.5) — the working-tree fingerprint
290
+ * recorded AT READ START (`probeWorkspaceTreeFingerprint`). A record without
291
+ * one (written before M7) never projects fresh at an unchanged HEAD.
292
+ */
293
+ worktreeFingerprint?: string;
288
294
  producedAt: string;
289
295
  }
290
296
  export type RepoStateProjection = {
@@ -337,6 +343,16 @@ export declare const NON_GIT_REPO_STATE_MAX_AGE_MS: number;
337
343
  * error, git missing, unborn HEAD) proves nothing and borrows NOTHING:
338
344
  * never fresh (no F5 allowance) and NO re-delegation (a re-read under a
339
345
  * failing probe records no head → a permanent loop) — stale, no-fire.
346
+ * - M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.5, DL-4) — an UNCHANGED HEAD is
347
+ * necessary but no longer sufficient: Accept applies a diff without
348
+ * committing, so the overview can contradict the tree while HEAD stays
349
+ * put. The record's `worktreeFingerprint` must equal a fresh
350
+ * `probeWorkspaceTreeFingerprint`. A differing fingerprint (applied,
351
+ * uncommitted edits), a record without one (written before M7) or a
352
+ * failed / timed-out probe is STALE with NO re-delegation — a re-read per
353
+ * Accept would be a frontier read of the whole codebase; the overview
354
+ * returns at the next commit (HEAD moves → re-read) or familiarize. Each
355
+ * probe's duration is logged (the per-dispatch cost on a dirty tree).
340
356
  */
341
357
  export declare function projectRepoStateForDispatch(deps: {
342
358
  sessionId: string;
@@ -346,6 +362,8 @@ export declare function projectRepoStateForDispatch(deps: {
346
362
  onStaleRedelegate?: () => void;
347
363
  /** Test seam — defaults to the real git probe. */
348
364
  probeGitHeadFn?: typeof probeWorkspaceGitHead;
365
+ /** Test seam — defaults to the real working-tree fingerprint probe (M7). */
366
+ probeTreeFingerprintFn?: typeof probeWorkspaceTreeFingerprint;
349
367
  }): Promise<RepoStateProjection>;
350
368
  /**
351
369
  * The deterministic-emitter write path for a freshly-delegated codebase
@@ -359,6 +377,8 @@ export declare function appendRepoStateItem(deps: {
359
377
  /** The LE AgentKind that authored the read (e.g. 'CLAUDE'). */
360
378
  agentId: string;
361
379
  gitHead?: string;
380
+ /** M7 §3.5 — the working-tree fingerprint at read start. */
381
+ worktreeFingerprint?: string;
362
382
  producedAt?: string;
363
383
  }): Promise<ContextItem | null>;
364
384
  /**
@@ -87,6 +87,11 @@ export interface RepoStateRecord {
87
87
  producedAt: string;
88
88
  /** The git HEAD the overview was produced at, when captured cheaply. */
89
89
  gitHead?: string;
90
+ /**
91
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.5) — the working-tree fingerprint at
92
+ * read start (`probeWorkspaceTreeFingerprint`). Absent on older records.
93
+ */
94
+ worktreeFingerprint?: string;
90
95
  }
91
96
  /**
92
97
  * §5.4 — `slice_selector` is FORMALLY TYPED so the writer and the
@@ -359,6 +364,45 @@ export type WorkspaceGitHeadProbe = {
359
364
  * the sound handling, pinned by test.
360
365
  */
361
366
  export declare function probeWorkspaceGitHead(workspaceRoot: string): Promise<WorkspaceGitHeadProbe>;
367
+ /**
368
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.5, DL-4) — the dirty-tree fingerprint
369
+ * probe outcome. `durationMs` feeds the per-dispatch log line.
370
+ */
371
+ export type WorkspaceTreeFingerprintProbe = {
372
+ kind: 'fingerprint';
373
+ value: string;
374
+ entries: number;
375
+ durationMs: number;
376
+ } | {
377
+ kind: 'probe-failed';
378
+ durationMs: number;
379
+ };
380
+ /** §3.5 — the whole probe's budget; running past it is a failed probe (R1-F9). */
381
+ export declare const WORKSPACE_TREE_FINGERPRINT_TIMEOUT_MS = 3000;
382
+ /**
383
+ * M7 §3.5 — a lock-free fingerprint of the working tree's applied-but-
384
+ * uncommitted state: SHA-256 over every entry of
385
+ * `git --no-optional-locks status --porcelain=v1 -z --untracked-files=all`
386
+ * (run with `LC_ALL=C`, from the repository root) with the `lstat` size and
387
+ * mtime of each listed path.
388
+ * - `--no-optional-locks` never takes or rewrites `.git/index` (a plain
389
+ * `git status` refreshes it — design E7);
390
+ * - `--untracked-files=all` lists every untracked file on its own, so an edit
391
+ * inside an untracked directory moves the value (`=normal` collapses the
392
+ * directory to one entry — E7);
393
+ * - the stat half catches a second edit to an already-modified file, whose
394
+ * porcelain line does not change;
395
+ * - a rename/copy entry's source-path field is skipped, and a listed path that
396
+ * no longer exists hashes as `absent` (R1-F15).
397
+ * A clean tree hashes the empty string. A timeout, a git failure or a
398
+ * non-repository is `probe-failed`, which the freshness projection treats as
399
+ * stale without a re-read. Known limit: a further edit inside an already-dirty
400
+ * submodule does not move the value (git reports one entry for it). Never
401
+ * throws.
402
+ */
403
+ export declare function probeWorkspaceTreeFingerprint(workspaceRoot: string, options?: {
404
+ timeoutMs?: number;
405
+ }): Promise<WorkspaceTreeFingerprintProbe>;
362
406
  /**
363
407
  * Hash the generation inputs (§4.2 conjunct (d)). A `StructuralSummary` is a
364
408
  * pure function of `tree content × generation inputs`; this hashes the
@@ -207,6 +207,16 @@ export interface RunOrchestrationShellArgs {
207
207
  agent: string;
208
208
  roundNumber: number;
209
209
  }) => Promise<string>;
210
+ /**
211
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.3) — the user's own words for every
212
+ * implementor round; `runOrchestrationShell` installs `renderUserContextSection`.
213
+ */
214
+ userContextFn?: (input: {
215
+ taskId: string;
216
+ agent: string;
217
+ roundNumber: number;
218
+ brief: string;
219
+ }) => Promise<string>;
210
220
  };
211
221
  /**
212
222
  * PHASE-589/469 W3.2 — the two-phase group-escalation decision deps, built in
@@ -266,7 +276,10 @@ export { renderEntryAsLine, runLineLogFallback } from './non-tty-fallback';
266
276
  export { initInkRuntime, getInkRuntime } from './ink-runtime';
267
277
  export { reducer } from './reducer';
268
278
  export { createOrchestrationStore, type OrchestrationStore } from './store';
269
- export { routeBrowse, type RouteBrowseDeps } from './route-browse';
279
+ export { routeBrowse, RETAINED_PAGE_MAX_CHARS, type RouteBrowseDeps, type RetainedBrowsePage, } from './route-browse';
280
+ export { composeBrainstormPanelBrief, fitTextToBudget, MAX_BRAINSTORM_PAGE_CHARS, MAX_BRAINSTORM_PAGE_TOKENS, MAX_BRAINSTORM_PAGE_BYTES, } from './brainstorm-quorum';
281
+ export { extractQueryRelevantSnippets, htmlToText } from './web/extract';
282
+ export { validateAgyArgPrompt, AGY_ARG_PROMPT_MAX_UTF8_BYTES, } from '../agy-cli-contract';
270
283
  export type { Mode, Tier, PlannerDecision, AgentKind, PlannerHealthState, RunningTaskState, ReviewerSeatState, GateState, ExecutionEventEntry, RefusalEventEntry, BypassEventEntry, MobileEventEntry, EventStreamEntry, ConversationEntry, QueuedTask, PendingClarification, OrchestrationState, OrchestrationAction, LastModeFile, TeamState, TeamTrackEntry, TeamTrackState, TeamMergeGateStatus, LiveProgress, } from './types';
271
284
  export { formatElapsed, isSpinnerPhase, renderProgressLine, type TaskProgressEvent, type OnProgress, } from './task-progress';
272
285
  export { runDeclaredTestSurfaces, DECLARED_TEST_TIMEOUT_MS, type DeclaredTestResult, type DeclaredTestReason, type RunDeclaredTestSurfacesArgs, } from './declared-test-runner';
@@ -673,8 +686,25 @@ export declare function routeTeamDecompose(deps: {
673
686
  /** Stage-2 R3 HIGH — the loop's durable store, so the live launch persists the retained spec + attachments. */
674
687
  durableStore?: RevertManifestStore;
675
688
  }): Promise<void>;
676
- /** Test seam — reset the module-level A1e composer (vitest-gated). */
689
+ /** Test seam — reset the module-level A1e and M7 composers (vitest-gated). */
677
690
  export declare function resetDispatchContextComposerForTests(): void;
691
+ /** Test seam — install the M7 decomposer user-context composer (vitest-gated). */
692
+ export declare function setUserContextComposerForTests(composer: ((brief: string) => Promise<string>) | null): void;
693
+ /**
694
+ * A1e §8.3 (design "Freshness" bullet) — the QUIET background re-delegation
695
+ * of the codebase read, fired when a `repo_state` projection finds the
696
+ * workspace git-HEAD diverged from the record. Mirrors `routeFamiliarize`'s
697
+ * frontier-delegation half but renders NOTHING (no advisory, no spinner) —
698
+ * it only refreshes the persisted `repo_state` (legacy record + typed
699
+ * ContextItem, both stamped with the HEAD probed AT READ TIME) so the NEXT
700
+ * projection is fresh. Best-effort: every failure is logged and dropped —
701
+ * a background refresh must never affect the dispatch that triggered it.
702
+ * Exported for tests.
703
+ */
704
+ export declare function redelegateRepoStateReadQuietly(deps: {
705
+ args: RunOrchestrationShellArgs;
706
+ workspaceRoot: string;
707
+ }): Promise<void>;
678
708
  /**
679
709
  * CP-4 §4.1 (#600) — `familiarize` desktop route: the context-priming task.
680
710
  *
@@ -1089,6 +1119,28 @@ export declare function resetTurnAuthoringStateForTests(): void;
1089
1119
  * on any exit path. Non-throwing (delete on a Map/Set never throws).
1090
1120
  */
1091
1121
  export declare function clearTurnAuthoringSessionState(sessionId: string): void;
1122
+ /**
1123
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.1, DL-2) — `/rule <text>`: pin the text
1124
+ * verbatim (capped) as a durable `user_rule` decision with source `explicit`,
1125
+ * and return the acknowledgement once the append is durable. The fail-soft
1126
+ * floor (no at-rest key) pins nothing and says so. Exported for tests.
1127
+ */
1128
+ export declare function pinExplicitUserRule(sessionId: string, commandText: string): Promise<string>;
1129
+ /**
1130
+ * M7 DL-2 — `/rules` lists every live pin, numbered oldest first; `/rules
1131
+ * forget <n>` retires pin n with an append-only `user_rule_retired` decision
1132
+ * whose `refs` names it and whose body carries its `seq` — identical texts share
1133
+ * a content address, so the `seq` names this occurrence (implementation gate
1134
+ * Stage 1 R1-F1). The renderer drops that pin and takes its words out of the
1135
+ * message it came from (R1-F2). Reads the VERIFIED log; an unverifiable chain
1136
+ * lists nothing. Exported for tests.
1137
+ */
1138
+ export declare function runUserRulesCommand(sessionId: string, commandText: string): Promise<string>;
1139
+ /** What `authorTurnContextItems` authored that the turn mirror still needs. */
1140
+ export interface TurnContextAuthoringResult {
1141
+ /** M7 — the pin acknowledgements shown this turn (dispatched and added to the delta). */
1142
+ pinAcknowledgements: string[];
1143
+ }
1092
1144
  /**
1093
1145
  * A1f (design §6 + the A1e-deferred full-vocabulary authoring) — author this
1094
1146
  * turn's typed ContextItems at the ONE per-turn chokepoint: the turn mirror
@@ -1097,12 +1149,16 @@ export declare function clearTurnAuthoringSessionState(sessionId: string): void;
1097
1149
  * turn's conversation delta.
1098
1150
  *
1099
1151
  * Deterministic emitter-assigned labels (§4.2 — never the conductor):
1100
- * - human `turn` (DURABLE per Finding-2) — Stage-2 R1 H1: labeled
1101
- * planner/brainstorm ONLY (conversation, not task contract — §5
1102
- * explicitly excludes the full conversation from implementor windows;
1103
- * the implementor-sanctioned "answered clarifications + prior handoff
1104
- * turns" ride the existing brief-composition path, not this projection).
1152
+ * - human `turn` (DURABLE per Finding-2) — labeled planner/brainstorm AND
1153
+ * implementor (M7, SHARED-CONTEXT-M7-ADDENDUM.md §3.1 "Labels", DL-1
1154
+ * design-locked 2026-09-14, replacing Stage-2 R1 H1's planner/brainstorm-
1155
+ * only label): implementors receive the user's own earlier messages,
1156
+ * bounded and redacted, through `renderUserContextSection`; reviewer and
1157
+ * resolver stay out (DL-3). Nothing already written is relabelled.
1105
1158
  * An answering turn carries `refs` to the question item it answers (M5).
1159
+ * - `decision` `{action:'user_rule'}` when the turn states a standing rule
1160
+ * (the M7 pin grammar) — authored after the durable human turn, `refs`
1161
+ * naming it, and acknowledged once durable (step 1b).
1106
1162
  * - `decision` per planner-decision entry (author `conductor`; durable) —
1107
1163
  * broadly visible (task-shaping, §6 distillation payload), task-scoped
1108
1164
  * when the decision carries a taskId (H1 scope).
@@ -1139,7 +1195,7 @@ export declare function authorTurnContextItems(deps: {
1139
1195
  */
1140
1196
  panelOwnedThisTurn?: boolean;
1141
1197
  turnOwnership?: BrainstormTurnOwnership;
1142
- }): Promise<void>;
1198
+ }): Promise<TurnContextAuthoringResult>;
1143
1199
  export declare function emitOrchestrationTurnMirror(deps: {
1144
1200
  store: OrchestrationStore;
1145
1201
  sessionId: string;
@@ -371,6 +371,26 @@ export interface QuorumLoopDeps {
371
371
  agent: AgentKind;
372
372
  roundNumber: number;
373
373
  }) => Promise<string>;
374
+ /**
375
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.3, design-locked 2026-09-14) — the
376
+ * user's own words for THIS implementor round: one chronological list of the
377
+ * session's pinned rules and the user's earlier messages, minus any message
378
+ * the round's brief already carries in its request part. Called on EVERY
379
+ * round (round 0, a team track's round 0, revise, continuation) with that
380
+ * round's brief, so a rule stated while a task runs reaches its next revise
381
+ * round. STDIN-only, after the brief and before the prior rationale and the
382
+ * repository context — never `args.brief`/`task_brief`, so reviewers and the
383
+ * hosted engine never see it (DL-3). Wired by `cli.ts` through the
384
+ * dispatch-context tap; `runOrchestrationShell` installs
385
+ * `renderUserContextSection`. Returns `''` for "no section". ABSENT (legacy /
386
+ * companion / tests) → byte-identical stdin.
387
+ */
388
+ projectUserContext?: (input: {
389
+ taskId: string;
390
+ agent: AgentKind;
391
+ roundNumber: number;
392
+ brief: string;
393
+ }) => Promise<string>;
374
394
  /**
375
395
  * CP-1.f LOCK RP-6 — this orchestration host's detected coding agents
376
396
  * (UPPERCASE `CLAUDE` / `CODEX` / `GEMINI`), computed ONCE by `cli.ts` via
@@ -15,7 +15,7 @@ export interface RetainedBrowsePage {
15
15
  readAt: string;
16
16
  }
17
17
  /** Retained page text bound — the answerer caps again at render time. */
18
- export declare const RETAINED_PAGE_MAX_CHARS = 24000;
18
+ export declare const RETAINED_PAGE_MAX_CHARS = 120000;
19
19
  export interface RouteBrowseDeps {
20
20
  store: OrchestrationStore;
21
21
  /** Undefined when the local model isn't installed/enabled → no-model advisory. */
@@ -34,6 +34,14 @@ export interface SlashCommandInfo {
34
34
  name: string;
35
35
  blurb: string;
36
36
  }
37
+ /**
38
+ * M7 (SHARED-CONTEXT-M7-ADDENDUM.md §3.1, DL-2) — the PENDING markers the
39
+ * `/rule` family returns; `handleShellUserInput` authors / reads the session's
40
+ * pinned rules and rewrites the output (the router stays pure — no store, no log).
41
+ */
42
+ export declare const USER_RULE_PIN_PENDING = "PENDING \u2014 entrypoint pins the rule";
43
+ export declare const USER_RULES_LIST_PENDING = "PENDING \u2014 entrypoint lists pinned rules";
44
+ export declare const USER_RULES_FORGET_PENDING = "PENDING \u2014 entrypoint retires a pinned rule";
37
45
  /** True if `command` is a shell-exit command (`/quit` / `/exit`). */
38
46
  export declare function isExitCommand(command: string): boolean;
39
47
  /**
@@ -0,0 +1,83 @@
1
+ /** `decision` body action of a pinned rule (§3.1 "Item"). */
2
+ export declare const USER_RULE_ACTION = "user_rule";
3
+ /** `decision` body action retiring the pinned rule named in its `refs`. */
4
+ export declare const USER_RULE_RETIRED_ACTION = "user_rule_retired";
5
+ /**
6
+ * The roles a human turn and a pinned rule are labelled for (§3.1 "Labels"):
7
+ * the planner, the brainstorm panel and implementors. Reviewer and resolver
8
+ * are excluded everywhere (DL-3).
9
+ */
10
+ export declare const USER_WORDS_VISIBLE_TO: readonly ["planner", "brainstorm", "implementor"];
11
+ /** A pinned rule's text is capped at this many chars (ends-preserving cut). */
12
+ export declare const USER_RULE_MAX_CHARS = 600;
13
+ /**
14
+ * The label that opens a brief's background-only handoff section
15
+ * (`composeImplementationBrief`, index.ts). Everything before it is the brief's
16
+ * REQUEST PART: the request, its clarifications and the task review contract.
17
+ */
18
+ export declare const WORKFLOW_HANDOFF_SECTION_LABEL = "Workflow handoff context:";
19
+ export type PinRule = 'standing-scope' | 'rule-label' | 'revocation';
20
+ export interface PinCapture {
21
+ /** The matching sentence(s), verbatim and in source order, joined by one space. */
22
+ text: string;
23
+ rules: PinRule[];
24
+ }
25
+ export interface PinMatchContext {
26
+ /** True when the session already holds a live pin — only then can a revocation pin. */
27
+ hasPriorPins?: boolean;
28
+ }
29
+ /** Split into sentences: newlines, then [.!?] followed by whitespace — not after a common abbreviation. */
30
+ export declare function splitSentences(text: string): string[];
31
+ /** Cap a rule's text for storage (the pin grammar's capture and `/rule` share it). */
32
+ export declare function capUserRuleText(text: string): string;
33
+ /**
34
+ * The pin grammar (§3.1 "Pinning (a)"): the standing-rule capture for one human
35
+ * turn, or null. Per sentence, skipping questions and fenced code; the matching
36
+ * sentence plus the one before it when the match has fewer than six words.
37
+ * Slash commands are never captured. A revocation fires only when
38
+ * `ctx.hasPriorPins`.
39
+ */
40
+ export declare function matchPinRule(turnText: string, ctx?: PinMatchContext): PinCapture | null;
41
+ /** Collapse every whitespace run to one space, trimmed. */
42
+ export declare function collapseWhitespace(text: string): string;
43
+ /** Remove a leading `@agent` mention, as the planner's prompt does. */
44
+ export declare function stripLeadingAgentMention(text: string): string;
45
+ /**
46
+ * The brief's request part (§3.1 "Which messages"): the text before its
47
+ * `Workflow handoff context:` section — the request itself, its clarifications
48
+ * and the task review contract. A brief without that section is all request.
49
+ */
50
+ export declare function requestPartOf(brief: string): string;
51
+ /**
52
+ * Does the brief's request part already carry this message? Exact containment
53
+ * after collapsing whitespace, with and without a leading `@agent` mention. A
54
+ * message the brief no longer carries verbatim (rewritten attachment tokens,
55
+ * renumbered image chips, a hard-cap cut) does not match and stays in the list
56
+ * as context (§3.6).
57
+ */
58
+ export declare function briefRequestContainsMessage(requestPart: string, message: string): boolean;
59
+ /**
60
+ * A retired pin's source message without the pinned sentence(s) (implementation
61
+ * gate Stage 1 R1-F2): `/rules forget` must stop the rule's words reaching
62
+ * agents even when the user stated it inside a longer message. The message is
63
+ * split into sentences after collapsing whitespace; each sentence of the pin
64
+ * text must equal one of them, and every equal sentence is removed. Returns null
65
+ * when a pin sentence is not a whole sentence of the message — a pin cut at 600
66
+ * chars, a sentence split around fenced code, or a rule captured from a line
67
+ * that broke mid-sentence, whose continuation would otherwise stay behind
68
+ * (Stage 1 r2 N8) — or when no letter or digit is left; the caller then leaves
69
+ * the whole message out.
70
+ */
71
+ export declare function messageWithoutRule(message: string, ruleText: string): string | null;
72
+ /** The placeholder for an absolute local path (§3.1 "Text"). */
73
+ export declare const LOCAL_PATH_PLACEHOLDER = "[local path]";
74
+ export declare function redactLocalPaths(text: string): string;
75
+ /** Known secret shapes (core's scrubber patterns) → `[redacted secret]`, then local paths. */
76
+ export declare function redactUserText(text: string): string;
77
+ /** One list line's text: redacted and on one line. */
78
+ export declare function renderUserText(text: string): string;
79
+ /**
80
+ * §3.1 "Acknowledgement" — shown once the pin is durable; the same scrubbed
81
+ * text the agents receive.
82
+ */
83
+ export declare function renderPinAcknowledgement(pinText: string): string;
@@ -4,4 +4,4 @@ export { PlannerCacheLayer } from './cache';
4
4
  export { PlannerHealthMachine } from './health-state';
5
5
  export { BackendPlannerClient, PlannerBudgetExceededError, PlannerTierGateRejectedError, type PlannerAppSyncTransport, type PlannerCryptoBridge, type SessionKeyResolver, type ShellEventEmit, type EmitShellEventFn, } from './client';
6
6
  export { LocalGemmaPlannerAdapter, parseLocalGemmaPlannerDecision, PlannerOutputUnparseableError, renderLocalGemmaPlannerPrompt, type LocalGemmaPlannerRunner, } from './local-gemma';
7
- export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, renderLocalGemmaMultiBrowsePrompt, renderLocalGemmaBrowsePrompt, MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS, MAX_MULTI_BROWSE_RENDERED_PROMPT_CHARS, type LocalGemmaAdvisoryRunner, } from './local-advisory';
7
+ export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, renderLocalGemmaMultiBrowsePrompt, renderLocalGemmaBrowsePrompt, MAX_BROWSE_CONTENT_CHARS, MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS, MAX_MULTI_BROWSE_RENDERED_PROMPT_CHARS, type LocalGemmaAdvisoryRunner, } from './local-advisory';
@@ -39,12 +39,14 @@ export interface LocalGemmaAdvisoryOptions {
39
39
  */
40
40
  think?: boolean;
41
41
  }
42
+ export declare const MAX_RENDERED_PROMPT_CHARS = 30000;
43
+ export declare const MAX_RENDERED_PROMPT_TOKENS = 7500;
42
44
  export declare function redactAbsoluteLocalPaths(text: string): string;
43
45
  export declare function renderLocalGemmaFamiliarizePrompt(args: {
44
46
  userPrompt: string;
45
47
  summary: StructuralSummary;
46
48
  }): string;
47
- export declare const MAX_BROWSE_CONTENT_CHARS = 12000;
49
+ export declare const MAX_BROWSE_CONTENT_CHARS = 24000;
48
50
  export declare const MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS = 6000;
49
51
  /**
50
52
  * WEB-BROWSING (docs/WEB-BROWSING-DESIGN.md): build the advisory prompt for a
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.32",
3
+ "version": "2.0.34",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-claude-plugin",
3
- "version": "2.0.37",
3
+ "version": "2.0.39",
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.32",
51
+ "@quantiya/codevibe-core": "^2.0.34",
52
52
  "@quantiya/quorum-core": "^1.0.1",
53
53
  "dotenv": "^16.6.1",
54
54
  "express": "^5.1.0",