@arbiterforge/ca-pi 0.6.3 → 0.10.0
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/README.md +41 -98
- package/package.json +1 -1
- package/plugins/ca-pi/CHANGELOG.md +145 -0
- package/plugins/ca-pi/COMMANDS.md +138 -68
- package/plugins/ca-pi/SKILLS.md +137 -30
- package/plugins/ca-pi/agents/INDEX.md +3 -2
- package/plugins/ca-pi/agents/checkpoint-aggregator.md +8 -7
- package/plugins/ca-pi/agents/design-quality-reviewer.md +1 -1
- package/plugins/ca-pi/agents/finding-triage.md +31 -14
- package/plugins/ca-pi/agents/verdict-aggregator.md +64 -0
- package/plugins/ca-pi/{ORCHESTRATOR.md → arbiter.md} +37 -36
- package/plugins/ca-pi/extensions/codearbiter.js +844 -19
- package/plugins/ca-pi/generated/command-catalog.json +386 -196
- package/plugins/ca-pi/generated/roles.json +9 -0
- package/plugins/ca-pi/hooks/_arbiterstatelib.py +59 -11
- package/plugins/ca-pi/hooks/_bashguardlib.py +30 -12
- package/plugins/ca-pi/hooks/_gitexec.py +23 -0
- package/plugins/ca-pi/hooks/_githooks.py +50 -23
- package/plugins/ca-pi/hooks/_hooklib.py +148 -20
- package/plugins/ca-pi/hooks/_host.py +9 -1
- package/plugins/ca-pi/hooks/_metricslib.py +20 -0
- package/plugins/ca-pi/hooks/_modelib.py +762 -0
- package/plugins/ca-pi/hooks/_protectedlib.py +13 -4
- package/plugins/ca-pi/hooks/_prunelib.py +51 -12
- package/plugins/ca-pi/hooks/_prunepolicy.py +33 -7
- package/plugins/ca-pi/hooks/_readinjectlib.py +10 -4
- package/plugins/ca-pi/hooks/_releaselib.py +278 -48
- package/plugins/ca-pi/hooks/_updatelib.py +230 -50
- package/plugins/ca-pi/hooks/doctor.py +58 -9
- package/plugins/ca-pi/hooks/git-enforce.py +10 -3
- package/plugins/ca-pi/hooks/hostapi.py +220 -22
- package/plugins/ca-pi/hooks/pi-bridge.py +10 -4
- package/plugins/ca-pi/hooks/prompt-submit.py +486 -0
- package/plugins/ca-pi/hooks/prune-transcript.py +23 -3
- package/plugins/ca-pi/hooks/session-start.py +529 -435
- package/plugins/ca-pi/hooks/statusline.py +28 -10
- package/plugins/ca-pi/hooks/wire-statusline.py +13 -8
- package/plugins/ca-pi/includes/anti-slop-design/INDEX.md +1 -1
- package/plugins/ca-pi/includes/command-compatibility.md +16 -0
- package/plugins/ca-pi/includes/dangerous-mode.md +57 -0
- package/plugins/ca-pi/includes/ops-mode.md +96 -0
- package/plugins/ca-pi/includes/pi-host-notes.md +10 -1
- package/plugins/ca-pi/includes/redirect.md +12 -1
- package/plugins/ca-pi/includes/routing-table.md +14 -5
- package/plugins/ca-pi/includes/safety-core.md +86 -0
- package/plugins/ca-pi/includes/smarts/core.md +1 -1
- package/plugins/ca-pi/routines/INDEX.md +1 -1
- package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +55 -3
- package/plugins/ca-pi/routines/decision-lifecycle/references/adr-template.md +9 -1
- package/plugins/ca-pi/routines/decompose/SKILL.md +1 -1
- package/plugins/ca-pi/routines/dispatching-parallel-agents/SKILL.md +4 -4
- package/plugins/ca-pi/routines/release/SKILL.md +1 -1
- package/plugins/ca-pi/skills/ca-checkpoint/SKILL.md +5 -4
- package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-context-check/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-create-context/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-decompose/SKILL.md +6 -0
- package/plugins/ca-pi/skills/ca-doctor/SKILL.md +4 -0
- package/plugins/ca-pi/skills/ca-init/SKILL.md +18 -1
- package/plugins/ca-pi/skills/ca-pr/SKILL.md +17 -1
- package/plugins/ca-pi/skills/ca-review/SKILL.md +3 -4
- package/plugins/ca-pi/skills/ca-spike/SKILL.md +15 -8
- package/plugins/ca-pi/skills/ca-status/SKILL.md +13 -1
- package/plugins/ca-pi/skills/ca-watch/SKILL.md +6 -0
- package/plugins/ca-pi/includes/dev-mode.md +0 -30
- package/plugins/ca-pi/skills/ca-arbiter/SKILL.md +0 -36
- package/plugins/ca-pi/skills/ca-dev/SKILL.md +0 -42
|
@@ -291,7 +291,7 @@ var PI_STATUS_RESULT_KEYS = /* @__PURE__ */ new Set([
|
|
|
291
291
|
"questions",
|
|
292
292
|
"overrides",
|
|
293
293
|
"sprint",
|
|
294
|
-
"
|
|
294
|
+
"mode",
|
|
295
295
|
"prune"
|
|
296
296
|
]);
|
|
297
297
|
function minimalEnvironment(identities, userHome) {
|
|
@@ -577,14 +577,14 @@ function statusResult(response) {
|
|
|
577
577
|
const patch = record(response.resultPatch);
|
|
578
578
|
if (patch === void 0 || !exactKeys(patch, /* @__PURE__ */ new Set(["footerStatus"]))) return void 0;
|
|
579
579
|
const value = record(patch.footerStatus);
|
|
580
|
-
if (value === void 0 || !exactKeys(value, PI_STATUS_RESULT_KEYS) || value.status !== "ok" || typeof value.stage !== "string" || value.stage.length < 1 || value.stage.length > 128 || CONTROL_RE.test(value.stage) || boundedStatusCount(value.tasks) === void 0 || boundedStatusCount(value.questions) === void 0 || boundedStatusCount(value.overrides) === void 0 || typeof value.sprint !== "boolean" ||
|
|
580
|
+
if (value === void 0 || !exactKeys(value, PI_STATUS_RESULT_KEYS) || value.status !== "ok" || typeof value.stage !== "string" || value.stage.length < 1 || value.stage.length > 128 || CONTROL_RE.test(value.stage) || boundedStatusCount(value.tasks) === void 0 || boundedStatusCount(value.questions) === void 0 || boundedStatusCount(value.overrides) === void 0 || typeof value.sprint !== "boolean" || value.mode !== "arbiter" && value.mode !== "dangerous" && value.mode !== "ops" || value.prune !== null && (typeof value.prune !== "string" || value.prune.length > 256 || CONTROL_RE.test(value.prune))) return void 0;
|
|
581
581
|
return {
|
|
582
582
|
stage: value.stage,
|
|
583
583
|
tasks: value.tasks,
|
|
584
584
|
questions: value.questions,
|
|
585
585
|
overrides: value.overrides,
|
|
586
586
|
sprint: value.sprint,
|
|
587
|
-
|
|
587
|
+
mode: value.mode,
|
|
588
588
|
prune: value.prune === null ? void 0 : value.prune
|
|
589
589
|
};
|
|
590
590
|
}
|
|
@@ -1224,7 +1224,9 @@ import { posix as posix3, win32 as win324 } from "node:path";
|
|
|
1224
1224
|
// src/activity.ts
|
|
1225
1225
|
import { types as utilTypes } from "node:util";
|
|
1226
1226
|
var ACTIVITY_POLICY = Object.freeze({
|
|
1227
|
-
|
|
1227
|
+
// 16 active rows feed the sidebar subagents panel (spec pi-sidebar-panel);
|
|
1228
|
+
// the footer keeps its own tighter display bound.
|
|
1229
|
+
maxActive: 16,
|
|
1228
1230
|
maxRecent: 8,
|
|
1229
1231
|
activeTtlMs: 2 * 60 * 60 * 1e3,
|
|
1230
1232
|
recentTtlMs: 5 * 60 * 1e3,
|
|
@@ -3556,10 +3558,10 @@ function parsePlanLedger(markdown) {
|
|
|
3556
3558
|
if (lines.length > MAX_LEDGER_LINES) return void 0;
|
|
3557
3559
|
let found;
|
|
3558
3560
|
for (let lineIndex = 0; lineIndex < lines.length - 1; lineIndex += 1) {
|
|
3559
|
-
const
|
|
3561
|
+
const header2 = splitTableRow(lines[lineIndex]);
|
|
3560
3562
|
const separator = splitTableRow(lines[lineIndex + 1]);
|
|
3561
|
-
if (
|
|
3562
|
-
const normalizedHeaders =
|
|
3563
|
+
if (header2 === void 0 || separator === void 0 || !isSeparator(separator, header2.length)) continue;
|
|
3564
|
+
const normalizedHeaders = header2.map((cell) => cell.toLowerCase().replace(/\s+/gu, " "));
|
|
3563
3565
|
const taskColumns = normalizedHeaders.flatMap((cell, index) => TASK_HEADERS.has(cell) ? [index] : []);
|
|
3564
3566
|
const statusColumns = normalizedHeaders.flatMap((cell, index) => cell === "status" ? [index] : []);
|
|
3565
3567
|
if (taskColumns.length !== 1 || statusColumns.length !== 1) {
|
|
@@ -3572,7 +3574,7 @@ function parsePlanLedger(markdown) {
|
|
|
3572
3574
|
for (let rowIndex = lineIndex + 2; rowIndex < lines.length; rowIndex += 1) {
|
|
3573
3575
|
const cells = splitTableRow(lines[rowIndex]);
|
|
3574
3576
|
if (cells === void 0) break;
|
|
3575
|
-
if (cells.length !==
|
|
3577
|
+
if (cells.length !== header2.length) return void 0;
|
|
3576
3578
|
const id = cells[taskColumns[0]];
|
|
3577
3579
|
const status = taskStatus(cells[statusColumns[0]]);
|
|
3578
3580
|
if (!TASK_ID.test(id) || CONTROL.test(id) || status === void 0 || ids.has(id)) return void 0;
|
|
@@ -4479,7 +4481,7 @@ function adaptPiFooterState(source) {
|
|
|
4479
4481
|
const entriesValue = callMember2(manager, "getEntries");
|
|
4480
4482
|
const snapshotSession = normalizeSnapshotSession(source.usageSnapshot?.session);
|
|
4481
4483
|
const usage = snapshotSession ?? aggregateSessionUsage(entriesValue);
|
|
4482
|
-
const
|
|
4484
|
+
const sparkline2 = sparklineSeries(entriesValue);
|
|
4483
4485
|
const ageSeconds = sessionAge(callMember2(manager, "getHeader"), now);
|
|
4484
4486
|
const session = usage ? { ...usage, ...ageSeconds === void 0 ? {} : { ageSeconds } } : void 0;
|
|
4485
4487
|
const rawContext = object(callMember2(source.context, "getContextUsage"));
|
|
@@ -4507,7 +4509,7 @@ function adaptPiFooterState(source) {
|
|
|
4507
4509
|
...daily ? { daily } : {},
|
|
4508
4510
|
...updateVersion ? { update: { version: updateVersion } } : {},
|
|
4509
4511
|
...activity ? { activity } : {},
|
|
4510
|
-
...
|
|
4512
|
+
...sparkline2 ? { sparkline: sparkline2 } : {}
|
|
4511
4513
|
};
|
|
4512
4514
|
}
|
|
4513
4515
|
|
|
@@ -4650,9 +4652,10 @@ function gitSegment(git, compact) {
|
|
|
4650
4652
|
return `${colored(COLORS.normal, lead)}${divider}${colored(branchColor, `${branch}${git.dirty ? "*" : ""}`)}`;
|
|
4651
4653
|
}
|
|
4652
4654
|
function governanceSegment(governance) {
|
|
4653
|
-
const
|
|
4655
|
+
const modeBadge = governance.mode === "dangerous" ? " [DANGEROUS]" : governance.mode === "ops" ? " [OPS]" : "";
|
|
4656
|
+
const badge = modeBadge || (governance.sprint ? " [SPRINT]" : "");
|
|
4654
4657
|
const prune = governance.prune ? sanitize2(governance.prune, "") : "";
|
|
4655
|
-
return `${colored(COLORS.ok, "\u25CF")} ${colored(COLORS.normal, `stage:${sanitize2(governance.stage)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(COLORS.normal, `tasks:${boundedCount(governance.tasks)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(governance.questions > 0 ? COLORS.danger : COLORS.muted, `q:${boundedCount(governance.questions)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(governance.overrides > 0 ? COLORS.danger : COLORS.muted, `over:${boundedCount(governance.overrides)}`)}` + (prune ? ` ${colored(COLORS.deep, "\xB7")} ${colored(COLORS.muted, `prune:${prune}`)}` : "") + (badge ? colored(governance.
|
|
4658
|
+
return `${colored(COLORS.ok, "\u25CF")} ${colored(COLORS.normal, `stage:${sanitize2(governance.stage)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(COLORS.normal, `tasks:${boundedCount(governance.tasks)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(governance.questions > 0 ? COLORS.danger : COLORS.muted, `q:${boundedCount(governance.questions)}`)} ${colored(COLORS.deep, "\xB7")} ${colored(governance.overrides > 0 ? COLORS.danger : COLORS.muted, `over:${boundedCount(governance.overrides)}`)}` + (prune ? ` ${colored(COLORS.deep, "\xB7")} ${colored(COLORS.muted, `prune:${prune}`)}` : "") + (badge ? colored(governance.mode === "dangerous" ? COLORS.danger : COLORS.bright, badge) : "");
|
|
4656
4659
|
}
|
|
4657
4660
|
function usageRow(label, usage) {
|
|
4658
4661
|
return `${colored(COLORS.muted, label.padEnd(7))} ${colored(COLORS.deep, "\u2502")} ${colored(COLORS.primary, "\u2193")} ${colored(COLORS.normal, formatTokens(usage.inputTokens).padStart(6))} ${colored(COLORS.primary, "\u2191")} ${colored(COLORS.normal, formatTokens(usage.outputTokens).padStart(6))} ${colored(COLORS.deep, "\u2502")} ${colored(COLORS.ok, formatUsd(usage.costUsd))}`;
|
|
@@ -4693,8 +4696,8 @@ var SPARK_GLYPHS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586",
|
|
|
4693
4696
|
function activityRows(activity) {
|
|
4694
4697
|
const rows = activity.slice(0, ACTIVITY_MAX_ROWS).map((item) => {
|
|
4695
4698
|
const glyph = item.state === "active" ? colored(COLORS.ok, "\u25CF") : colored(COLORS.muted, "\u2713");
|
|
4696
|
-
const
|
|
4697
|
-
return `${glyph} ${sanitize2(item.kind, "job")}:${sanitize2(item.label)}${
|
|
4699
|
+
const age2 = item.ageSeconds === void 0 ? "" : ` ${formatDuration(item.ageSeconds)}`;
|
|
4700
|
+
return `${glyph} ${sanitize2(item.kind, "job")}:${sanitize2(item.label)}${age2}`;
|
|
4698
4701
|
});
|
|
4699
4702
|
if (rows.length === 0) return rows;
|
|
4700
4703
|
rows[0] = `${colored(COLORS.bright, "activity")} ${rows[0]}`;
|
|
@@ -4767,8 +4770,8 @@ function renderCompact(input, box) {
|
|
|
4767
4770
|
if (readValue !== void 0 || writeValue !== void 0) {
|
|
4768
4771
|
bits.push(`cache ${read + write > 0 ? Math.round(read / (read + write) * 100) : 0}%`);
|
|
4769
4772
|
}
|
|
4770
|
-
const
|
|
4771
|
-
if (
|
|
4773
|
+
const age2 = usage.ageSeconds;
|
|
4774
|
+
if (age2 !== void 0) bits.push(`age ${formatDuration(age2)}`);
|
|
4772
4775
|
return bits.join(" \xB7 ");
|
|
4773
4776
|
}, "");
|
|
4774
4777
|
const daily = guard(() => {
|
|
@@ -4893,6 +4896,7 @@ var PiFooterLifecycle = class {
|
|
|
4893
4896
|
governance;
|
|
4894
4897
|
updateVersion;
|
|
4895
4898
|
gitFacts;
|
|
4899
|
+
lastInput;
|
|
4896
4900
|
activationEnabled = false;
|
|
4897
4901
|
expected = false;
|
|
4898
4902
|
installed = false;
|
|
@@ -4900,6 +4904,16 @@ var PiFooterLifecycle = class {
|
|
|
4900
4904
|
requestActivityRender() {
|
|
4901
4905
|
requestRender(this.tui);
|
|
4902
4906
|
}
|
|
4907
|
+
/** The live tui handle captured by the footer factory; the sidebar
|
|
4908
|
+
* compositor probes it for the undocumented doRender hook. */
|
|
4909
|
+
currentTui() {
|
|
4910
|
+
return this.tui;
|
|
4911
|
+
}
|
|
4912
|
+
/** The most recently rendered footer input — the sidebar's session,
|
|
4913
|
+
* subagents and workspace panels reuse these already-gathered facts. */
|
|
4914
|
+
lastRenderedInput() {
|
|
4915
|
+
return this.lastInput;
|
|
4916
|
+
}
|
|
4903
4917
|
health() {
|
|
4904
4918
|
return Object.freeze({
|
|
4905
4919
|
expected: this.expected,
|
|
@@ -4982,10 +4996,11 @@ var PiFooterLifecycle = class {
|
|
|
4982
4996
|
questions: this.governance.questions,
|
|
4983
4997
|
overrides: this.governance.overrides,
|
|
4984
4998
|
sprint: this.governance.sprint,
|
|
4985
|
-
|
|
4999
|
+
mode: this.governance.mode,
|
|
4986
5000
|
...this.governance.prune === void 0 ? {} : { prune: this.governance.prune }
|
|
4987
5001
|
}
|
|
4988
5002
|
};
|
|
5003
|
+
this.lastInput = enriched;
|
|
4989
5004
|
const rendered = renderFooter(enriched, {
|
|
4990
5005
|
width,
|
|
4991
5006
|
noColor: Object.prototype.hasOwnProperty.call(process.env, "NO_COLOR")
|
|
@@ -5063,6 +5078,7 @@ var PiFooterLifecycle = class {
|
|
|
5063
5078
|
this.governance = void 0;
|
|
5064
5079
|
this.updateVersion = void 0;
|
|
5065
5080
|
this.gitFacts = void 0;
|
|
5081
|
+
this.lastInput = void 0;
|
|
5066
5082
|
this.activationEnabled = false;
|
|
5067
5083
|
this.expected = false;
|
|
5068
5084
|
this.refreshQueue = Promise.resolve();
|
|
@@ -5079,6 +5095,675 @@ var PiFooterLifecycle = class {
|
|
|
5079
5095
|
}
|
|
5080
5096
|
};
|
|
5081
5097
|
|
|
5098
|
+
// src/sidebar.ts
|
|
5099
|
+
var SIDEBAR_MAX_AGENT_ROWS = 16;
|
|
5100
|
+
var MAX_TODO_ROWS = 12;
|
|
5101
|
+
var MAX_MCP_ROWS = 8;
|
|
5102
|
+
var MAX_LIST_ITEMS = 256;
|
|
5103
|
+
var MAX_TEXT_POINTS3 = 512;
|
|
5104
|
+
var SPARK_GLYPHS2 = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
5105
|
+
var ESC2 = "\x1B";
|
|
5106
|
+
var RESET2 = `${ESC2}[0m`;
|
|
5107
|
+
var HEADER_COLOR = `${ESC2}[38;2;178;102;255m`;
|
|
5108
|
+
var MUTED = `${ESC2}[38;2;150;150;162m`;
|
|
5109
|
+
var OK = `${ESC2}[38;2;120;220;150m`;
|
|
5110
|
+
var WARN = `${ESC2}[38;2;255;184;76m`;
|
|
5111
|
+
var OSC_RE2 = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?/gu;
|
|
5112
|
+
var CSI_RE2 = /\x1b\[[0-?]*[ -/]*[@-~]?/gu;
|
|
5113
|
+
var ESCAPE_RE2 = /\x1b[@-_]/gu;
|
|
5114
|
+
var CONTROL_RE3 = /[\u0000-\u001f\u007f-\u009f\u061c\u200b-\u200f\u2028\u2029\u202a-\u202e\u2060-\u206f\ufeff]/gu;
|
|
5115
|
+
function sanitize3(value) {
|
|
5116
|
+
if (typeof value !== "string") return "";
|
|
5117
|
+
return value.replace(OSC_RE2, "").replace(CSI_RE2, "").replace(ESCAPE_RE2, "").replace(CONTROL_RE3, "").slice(0, MAX_TEXT_POINTS3);
|
|
5118
|
+
}
|
|
5119
|
+
function boundedNumber2(value, maximum) {
|
|
5120
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return 0;
|
|
5121
|
+
return Math.min(value, maximum);
|
|
5122
|
+
}
|
|
5123
|
+
var COLOR_PALETTE = { header: HEADER_COLOR, muted: MUTED, ok: OK, warn: WARN, reset: RESET2 };
|
|
5124
|
+
var PLAIN_PALETTE = { header: "", muted: "", ok: "", warn: "", reset: "" };
|
|
5125
|
+
function fit(text2, context) {
|
|
5126
|
+
const { width, metrics, palette } = context;
|
|
5127
|
+
let value = text2;
|
|
5128
|
+
let visible;
|
|
5129
|
+
try {
|
|
5130
|
+
visible = metrics.visibleWidth(value);
|
|
5131
|
+
} catch {
|
|
5132
|
+
value = "";
|
|
5133
|
+
visible = 0;
|
|
5134
|
+
}
|
|
5135
|
+
if (visible > width) {
|
|
5136
|
+
try {
|
|
5137
|
+
value = metrics.truncateToWidth(value, width, "\u2026");
|
|
5138
|
+
visible = metrics.visibleWidth(value);
|
|
5139
|
+
} catch {
|
|
5140
|
+
value = "";
|
|
5141
|
+
visible = 0;
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
if (visible > width) {
|
|
5145
|
+
value = "";
|
|
5146
|
+
visible = 0;
|
|
5147
|
+
}
|
|
5148
|
+
const padded = value + " ".repeat(width - visible);
|
|
5149
|
+
return palette.reset === "" ? padded : padded + palette.reset;
|
|
5150
|
+
}
|
|
5151
|
+
function header(title, context) {
|
|
5152
|
+
const { width, palette } = context;
|
|
5153
|
+
const label = ` ${title} `;
|
|
5154
|
+
const room = Math.max(0, width - label.length - 2);
|
|
5155
|
+
const bar = "\u2500";
|
|
5156
|
+
const text2 = `${bar}${label}${bar.repeat(room)}`.slice(0, width);
|
|
5157
|
+
return fit(`${palette.header}${text2}`, context);
|
|
5158
|
+
}
|
|
5159
|
+
function tokensLabel(input, output) {
|
|
5160
|
+
const compact = (value) => value >= 1e3 ? `${(value / 1e3).toFixed(1)}k` : String(value);
|
|
5161
|
+
return `${compact(input)}\u2191 ${compact(output)}\u2193`;
|
|
5162
|
+
}
|
|
5163
|
+
function sparkline(series) {
|
|
5164
|
+
const bounded = series.slice(-16).map((value) => boundedNumber2(value, Number.MAX_SAFE_INTEGER));
|
|
5165
|
+
if (bounded.length === 0) return "";
|
|
5166
|
+
const maximum = Math.max(...bounded);
|
|
5167
|
+
return bounded.map((value) => {
|
|
5168
|
+
const level = maximum > 0 ? Math.min(8, Math.max(1, Math.ceil(value / maximum * 8))) : 1;
|
|
5169
|
+
return SPARK_GLYPHS2[level - 1];
|
|
5170
|
+
}).join("");
|
|
5171
|
+
}
|
|
5172
|
+
function sessionPanel(session, context) {
|
|
5173
|
+
const { palette } = context;
|
|
5174
|
+
const lines = [header("session", context)];
|
|
5175
|
+
const model = sanitize3(session.model);
|
|
5176
|
+
const thinking = sanitize3(session.thinkingLevel);
|
|
5177
|
+
if (model !== "") lines.push(fit(` ${model}${thinking === "" ? "" : `${palette.muted} \xB7 ${thinking}`}`, context));
|
|
5178
|
+
const percent = boundedNumber2(session.contextPercent, 999);
|
|
5179
|
+
if (session.contextPercent !== void 0) {
|
|
5180
|
+
const cells = 10;
|
|
5181
|
+
const filled = Math.min(cells, Math.round(Math.min(percent, 100) / 100 * cells));
|
|
5182
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
|
|
5183
|
+
const tone = percent >= 80 ? palette.warn : palette.ok;
|
|
5184
|
+
lines.push(fit(` ctx ${tone}${bar}${palette.reset === "" ? "" : palette.reset} ${Math.round(percent)}%`, context));
|
|
5185
|
+
}
|
|
5186
|
+
const input = boundedNumber2(session.inputTokens, Number.MAX_SAFE_INTEGER);
|
|
5187
|
+
const output = boundedNumber2(session.outputTokens, Number.MAX_SAFE_INTEGER);
|
|
5188
|
+
const cost = boundedNumber2(session.costUsd, 1e9);
|
|
5189
|
+
if (session.inputTokens !== void 0 || session.outputTokens !== void 0 || session.costUsd !== void 0) {
|
|
5190
|
+
lines.push(fit(` ${tokensLabel(input, output)}${palette.muted} \xB7 $${cost.toFixed(cost >= 100 ? 0 : 2)}`, context));
|
|
5191
|
+
}
|
|
5192
|
+
if (session.burn !== void 0 && session.burn.length > 0) {
|
|
5193
|
+
lines.push(fit(` burn ${sparkline(session.burn)}`, context));
|
|
5194
|
+
}
|
|
5195
|
+
return lines;
|
|
5196
|
+
}
|
|
5197
|
+
function agentGlyph(row, palette) {
|
|
5198
|
+
if (row.state === "active") return `${palette.ok}\u25CF${palette.reset === "" ? "" : palette.reset}`;
|
|
5199
|
+
return `${palette.muted}\u25CB${palette.reset === "" ? "" : palette.reset}`;
|
|
5200
|
+
}
|
|
5201
|
+
function age(seconds) {
|
|
5202
|
+
const bounded = boundedNumber2(seconds, 3650 * 86400);
|
|
5203
|
+
if (bounded >= 3600) return `${Math.floor(bounded / 3600)}h`;
|
|
5204
|
+
if (bounded >= 60) return `${Math.floor(bounded / 60)}m`;
|
|
5205
|
+
return `${Math.floor(bounded)}s`;
|
|
5206
|
+
}
|
|
5207
|
+
function agentsPanel(rows, context) {
|
|
5208
|
+
const { palette } = context;
|
|
5209
|
+
const lines = [header("agents", context)];
|
|
5210
|
+
const bounded = rows.slice(0, MAX_LIST_ITEMS);
|
|
5211
|
+
for (const row of bounded.slice(0, SIDEBAR_MAX_AGENT_ROWS)) {
|
|
5212
|
+
const label = sanitize3(row.label);
|
|
5213
|
+
const kind = row.kind === "job" ? "job" : "child";
|
|
5214
|
+
const suffix = row.ageSeconds === void 0 ? "" : ` ${age(row.ageSeconds)}`;
|
|
5215
|
+
lines.push(fit(` ${agentGlyph(row, palette)} ${label}${palette.muted} \xB7 ${kind}${suffix}`, context));
|
|
5216
|
+
}
|
|
5217
|
+
if (bounded.length > SIDEBAR_MAX_AGENT_ROWS) {
|
|
5218
|
+
lines.push(fit(` ${palette.muted}+${bounded.length - SIDEBAR_MAX_AGENT_ROWS} more`, context));
|
|
5219
|
+
}
|
|
5220
|
+
return lines;
|
|
5221
|
+
}
|
|
5222
|
+
function workspacePanel(workspace, context) {
|
|
5223
|
+
const { palette } = context;
|
|
5224
|
+
const lines = [header("workspace", context)];
|
|
5225
|
+
const repository = sanitize3(workspace.repository);
|
|
5226
|
+
if (repository !== "") {
|
|
5227
|
+
const dirty = workspace.dirty === true ? `${palette.warn} \u25CF` : "";
|
|
5228
|
+
lines.push(fit(` ${repository}${dirty}`, context));
|
|
5229
|
+
}
|
|
5230
|
+
const cwd = sanitize3(workspace.cwd);
|
|
5231
|
+
if (cwd !== "") lines.push(fit(` ${palette.muted}${cwd}`, context));
|
|
5232
|
+
return lines;
|
|
5233
|
+
}
|
|
5234
|
+
var TODO_GLYPHS = {
|
|
5235
|
+
done: "\u2713",
|
|
5236
|
+
active: "\u25B8",
|
|
5237
|
+
open: "\xB7"
|
|
5238
|
+
};
|
|
5239
|
+
function todosPanel(rows, context) {
|
|
5240
|
+
const { palette } = context;
|
|
5241
|
+
const lines = [header("todos", context)];
|
|
5242
|
+
const bounded = rows.slice(0, MAX_LIST_ITEMS);
|
|
5243
|
+
for (const row of bounded.slice(0, MAX_TODO_ROWS)) {
|
|
5244
|
+
const glyph = TODO_GLYPHS[row.state] ?? TODO_GLYPHS.open;
|
|
5245
|
+
const tone = row.state === "done" ? palette.muted : row.state === "active" ? palette.ok : "";
|
|
5246
|
+
lines.push(fit(` ${tone}${glyph} ${sanitize3(row.text)}`, context));
|
|
5247
|
+
}
|
|
5248
|
+
if (bounded.length > MAX_TODO_ROWS) {
|
|
5249
|
+
lines.push(fit(` ${palette.muted}+${bounded.length - MAX_TODO_ROWS} more`, context));
|
|
5250
|
+
}
|
|
5251
|
+
return lines;
|
|
5252
|
+
}
|
|
5253
|
+
function mcpPanel(rows, context) {
|
|
5254
|
+
const { palette } = context;
|
|
5255
|
+
const lines = [header("mcp", context)];
|
|
5256
|
+
const bounded = rows.slice(0, MAX_LIST_ITEMS);
|
|
5257
|
+
for (const row of bounded.slice(0, MAX_MCP_ROWS)) {
|
|
5258
|
+
const state = sanitize3(row.state);
|
|
5259
|
+
const tone = state === "connected" ? palette.ok : palette.muted;
|
|
5260
|
+
lines.push(fit(` ${tone}\u25CF${palette.reset === "" ? "" : palette.reset} ${sanitize3(row.name)}${palette.muted} \xB7 ${state}`, context));
|
|
5261
|
+
}
|
|
5262
|
+
return lines;
|
|
5263
|
+
}
|
|
5264
|
+
function renderSidebar(input, width, metrics, options) {
|
|
5265
|
+
const safeWidth = Number.isSafeInteger(width) && width > 0 ? Math.min(width, 160) : 40;
|
|
5266
|
+
const palette = options?.noColor === true ? PLAIN_PALETTE : COLOR_PALETTE;
|
|
5267
|
+
const context = { width: safeWidth, metrics, palette };
|
|
5268
|
+
const lines = [];
|
|
5269
|
+
const panels = [
|
|
5270
|
+
["session", () => {
|
|
5271
|
+
const session = input.session;
|
|
5272
|
+
return session === void 0 ? void 0 : sessionPanel(session, context);
|
|
5273
|
+
}],
|
|
5274
|
+
["agents", () => {
|
|
5275
|
+
const rows = input.subagents;
|
|
5276
|
+
return rows === void 0 || rows.length === 0 ? void 0 : agentsPanel(rows, context);
|
|
5277
|
+
}],
|
|
5278
|
+
["workspace", () => {
|
|
5279
|
+
const workspace = input.workspace;
|
|
5280
|
+
return workspace === void 0 ? void 0 : workspacePanel(workspace, context);
|
|
5281
|
+
}],
|
|
5282
|
+
["todos", () => {
|
|
5283
|
+
const rows = input.todos;
|
|
5284
|
+
return rows === void 0 || rows.length === 0 ? void 0 : todosPanel(rows, context);
|
|
5285
|
+
}],
|
|
5286
|
+
["mcp", () => {
|
|
5287
|
+
const rows = input.mcp;
|
|
5288
|
+
return rows === void 0 || rows.length === 0 ? void 0 : mcpPanel(rows, context);
|
|
5289
|
+
}]
|
|
5290
|
+
];
|
|
5291
|
+
for (const [title, render] of panels) {
|
|
5292
|
+
let rendered;
|
|
5293
|
+
try {
|
|
5294
|
+
rendered = render();
|
|
5295
|
+
} catch {
|
|
5296
|
+
rendered = [header(title, context), fit(` ${palette.muted}(unavailable)`, context)];
|
|
5297
|
+
}
|
|
5298
|
+
if (rendered === void 0 || rendered.length === 0) continue;
|
|
5299
|
+
if (lines.length > 0) lines.push(fit("", context));
|
|
5300
|
+
lines.push(...rendered);
|
|
5301
|
+
}
|
|
5302
|
+
return Object.freeze(lines);
|
|
5303
|
+
}
|
|
5304
|
+
|
|
5305
|
+
// src/sidebar-compositor.ts
|
|
5306
|
+
var SIDEBAR_DEFAULT_WIDTH = 40;
|
|
5307
|
+
var SIDEBAR_MIN_WIDTH = 24;
|
|
5308
|
+
var SIDEBAR_MAX_WIDTH = 60;
|
|
5309
|
+
var SIDEBAR_MAIN_COLUMN_FLOOR = 60;
|
|
5310
|
+
var GEOMETRY_FAILURE_LIMIT = 3;
|
|
5311
|
+
var ESC3 = "\x1B";
|
|
5312
|
+
var SYNC_START = `${ESC3}[?2026h`;
|
|
5313
|
+
var SYNC_END = `${ESC3}[?2026l`;
|
|
5314
|
+
var CURSOR_SAVE = `${ESC3}7`;
|
|
5315
|
+
var CURSOR_RESTORE = `${ESC3}8`;
|
|
5316
|
+
var WRAP_OFF = `${ESC3}[?7l`;
|
|
5317
|
+
var WRAP_ON = `${ESC3}[?7h`;
|
|
5318
|
+
var RESET3 = `${ESC3}[0m`;
|
|
5319
|
+
function unavailable(reason) {
|
|
5320
|
+
return Object.freeze({
|
|
5321
|
+
installed: false,
|
|
5322
|
+
reason,
|
|
5323
|
+
setWidth: () => void 0,
|
|
5324
|
+
dispose: () => void 0
|
|
5325
|
+
});
|
|
5326
|
+
}
|
|
5327
|
+
function columnsDescriptor(terminal) {
|
|
5328
|
+
let target = terminal;
|
|
5329
|
+
while (target !== null) {
|
|
5330
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, "columns");
|
|
5331
|
+
if (descriptor !== void 0) return descriptor;
|
|
5332
|
+
target = Object.getPrototypeOf(target);
|
|
5333
|
+
}
|
|
5334
|
+
return void 0;
|
|
5335
|
+
}
|
|
5336
|
+
function probeSidebarSupport(tui, terminal, metrics) {
|
|
5337
|
+
if (typeof metrics?.visibleWidth !== "function" || typeof metrics?.truncateToWidth !== "function") {
|
|
5338
|
+
return { ok: false, reason: "no-metrics" };
|
|
5339
|
+
}
|
|
5340
|
+
if (typeof tui?.doRender !== "function") return { ok: false, reason: "no-dorender" };
|
|
5341
|
+
const descriptor = columnsDescriptor(terminal);
|
|
5342
|
+
if (descriptor === void 0 || descriptor.configurable !== true) {
|
|
5343
|
+
return { ok: false, reason: "columns-not-configurable" };
|
|
5344
|
+
}
|
|
5345
|
+
return { ok: true };
|
|
5346
|
+
}
|
|
5347
|
+
function clampWidth(width) {
|
|
5348
|
+
if (typeof width !== "number" || !Number.isFinite(width)) return SIDEBAR_DEFAULT_WIDTH;
|
|
5349
|
+
return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_MIN_WIDTH, Math.floor(width)));
|
|
5350
|
+
}
|
|
5351
|
+
var Compositor = class {
|
|
5352
|
+
constructor(ports, width) {
|
|
5353
|
+
this.ports = ports;
|
|
5354
|
+
this.width = width;
|
|
5355
|
+
this.hadOwnColumns = Object.getOwnPropertyDescriptor(ports.terminal, "columns") !== void 0;
|
|
5356
|
+
this.hadOwnDoRender = Object.getOwnPropertyDescriptor(ports.tui, "doRender") !== void 0;
|
|
5357
|
+
this.originalDescriptor = columnsDescriptor(ports.terminal);
|
|
5358
|
+
this.liveRawColumns = this.originalDescriptor.value;
|
|
5359
|
+
this.originalDoRender = ports.tui.doRender;
|
|
5360
|
+
this.defineNarrowedColumns();
|
|
5361
|
+
this.paintAfterRender = (...args) => {
|
|
5362
|
+
const result3 = this.originalDoRender.apply(ports.tui, args);
|
|
5363
|
+
this.paint();
|
|
5364
|
+
return result3;
|
|
5365
|
+
};
|
|
5366
|
+
ports.tui.doRender = this.paintAfterRender;
|
|
5367
|
+
}
|
|
5368
|
+
ports;
|
|
5369
|
+
active = true;
|
|
5370
|
+
width;
|
|
5371
|
+
geometryFailures = 0;
|
|
5372
|
+
warned = false;
|
|
5373
|
+
narrowedGetter;
|
|
5374
|
+
/** Live raw width for data-descriptor terminals: the host's resize handler
|
|
5375
|
+
* assigns `terminal.columns = N`, which our accessor's setter records here so
|
|
5376
|
+
* neither the host nor the paint path ever sees a stale install-time width. */
|
|
5377
|
+
liveRawColumns;
|
|
5378
|
+
hadOwnColumns;
|
|
5379
|
+
hadOwnDoRender;
|
|
5380
|
+
originalDescriptor;
|
|
5381
|
+
originalDoRender;
|
|
5382
|
+
paintAfterRender;
|
|
5383
|
+
get installed() {
|
|
5384
|
+
return this.active;
|
|
5385
|
+
}
|
|
5386
|
+
setWidth(width) {
|
|
5387
|
+
if (!this.active) return;
|
|
5388
|
+
this.width = clampWidth(width);
|
|
5389
|
+
this.defineNarrowedColumns();
|
|
5390
|
+
try {
|
|
5391
|
+
this.ports.tui.requestRender();
|
|
5392
|
+
} catch {
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
dispose() {
|
|
5396
|
+
if (!this.active) return;
|
|
5397
|
+
this.active = false;
|
|
5398
|
+
try {
|
|
5399
|
+
const own = Object.getOwnPropertyDescriptor(this.ports.terminal, "columns");
|
|
5400
|
+
if (own?.get === this.narrowedGetter) {
|
|
5401
|
+
if (!this.hadOwnColumns) {
|
|
5402
|
+
delete this.ports.terminal.columns;
|
|
5403
|
+
} else if (this.originalDescriptor.get !== void 0) {
|
|
5404
|
+
Object.defineProperty(this.ports.terminal, "columns", this.originalDescriptor);
|
|
5405
|
+
} else {
|
|
5406
|
+
Object.defineProperty(this.ports.terminal, "columns", {
|
|
5407
|
+
...this.originalDescriptor,
|
|
5408
|
+
value: this.liveRawColumns
|
|
5409
|
+
});
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
} catch {
|
|
5413
|
+
}
|
|
5414
|
+
try {
|
|
5415
|
+
if (this.ports.tui.doRender === this.paintAfterRender) {
|
|
5416
|
+
if (this.hadOwnDoRender) this.ports.tui.doRender = this.originalDoRender;
|
|
5417
|
+
else delete this.ports.tui.doRender;
|
|
5418
|
+
}
|
|
5419
|
+
} catch {
|
|
5420
|
+
}
|
|
5421
|
+
try {
|
|
5422
|
+
this.ports.tui.requestRender();
|
|
5423
|
+
} catch {
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
readRawColumns() {
|
|
5427
|
+
return this.originalDescriptor.get !== void 0 ? this.originalDescriptor.get.call(this.ports.terminal) : this.liveRawColumns;
|
|
5428
|
+
}
|
|
5429
|
+
/** "too-narrow" is a recoverable skip — the hooks stay installed and the
|
|
5430
|
+
* next paint re-checks; `undefined` means the surface is no longer
|
|
5431
|
+
* understood and counts toward disposal. */
|
|
5432
|
+
rawGeometry() {
|
|
5433
|
+
const own = Object.getOwnPropertyDescriptor(this.ports.terminal, "columns");
|
|
5434
|
+
if (own?.get !== this.narrowedGetter) return void 0;
|
|
5435
|
+
let rawColumns2;
|
|
5436
|
+
try {
|
|
5437
|
+
rawColumns2 = this.readRawColumns();
|
|
5438
|
+
} catch {
|
|
5439
|
+
return void 0;
|
|
5440
|
+
}
|
|
5441
|
+
const rows = this.ports.terminal.rows;
|
|
5442
|
+
if (typeof rawColumns2 !== "number" || !Number.isFinite(rawColumns2)) return void 0;
|
|
5443
|
+
if (typeof rows !== "number" || !Number.isFinite(rows) || rows <= 0) return void 0;
|
|
5444
|
+
if (rawColumns2 < this.width + SIDEBAR_MAIN_COLUMN_FLOOR) return "too-narrow";
|
|
5445
|
+
return { rawColumns: Math.floor(rawColumns2), rows: Math.floor(rows) };
|
|
5446
|
+
}
|
|
5447
|
+
defineNarrowedColumns() {
|
|
5448
|
+
const narrowed = () => {
|
|
5449
|
+
const geometry = this.rawGeometry();
|
|
5450
|
+
if (geometry === void 0 || geometry === "too-narrow") {
|
|
5451
|
+
try {
|
|
5452
|
+
return this.readRawColumns();
|
|
5453
|
+
} catch {
|
|
5454
|
+
return this.width + SIDEBAR_MAIN_COLUMN_FLOOR;
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
return geometry.rawColumns - (this.width + 1);
|
|
5458
|
+
};
|
|
5459
|
+
this.narrowedGetter = narrowed;
|
|
5460
|
+
Object.defineProperty(this.ports.terminal, "columns", {
|
|
5461
|
+
configurable: true,
|
|
5462
|
+
enumerable: true,
|
|
5463
|
+
get: narrowed,
|
|
5464
|
+
// The host's resize handler assigns `columns`; route the assignment to
|
|
5465
|
+
// the original setter, or record it as the live raw width.
|
|
5466
|
+
set: (value) => {
|
|
5467
|
+
if (this.originalDescriptor.set !== void 0) {
|
|
5468
|
+
try {
|
|
5469
|
+
this.originalDescriptor.set.call(this.ports.terminal, value);
|
|
5470
|
+
} catch {
|
|
5471
|
+
}
|
|
5472
|
+
} else {
|
|
5473
|
+
this.liveRawColumns = value;
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
});
|
|
5477
|
+
}
|
|
5478
|
+
/** AC-3: paint inside a synchronized-output envelope; every cycle
|
|
5479
|
+
* re-validates raw geometry first and a persistent failure disposes. */
|
|
5480
|
+
paint() {
|
|
5481
|
+
if (!this.active) return;
|
|
5482
|
+
try {
|
|
5483
|
+
const geometry = this.rawGeometry();
|
|
5484
|
+
if (geometry === "too-narrow") return;
|
|
5485
|
+
if (geometry === void 0) {
|
|
5486
|
+
this.geometryFailures += 1;
|
|
5487
|
+
if (this.geometryFailures >= GEOMETRY_FAILURE_LIMIT) this.dispose();
|
|
5488
|
+
return;
|
|
5489
|
+
}
|
|
5490
|
+
this.geometryFailures = 0;
|
|
5491
|
+
const lines = renderSidebar(this.ports.dataSource(), this.width, this.ports.metrics, {
|
|
5492
|
+
noColor: this.ports.noColor
|
|
5493
|
+
});
|
|
5494
|
+
const separatorColumn = geometry.rawColumns - this.width;
|
|
5495
|
+
const parts = [SYNC_START, CURSOR_SAVE, WRAP_OFF];
|
|
5496
|
+
for (let row = 1; row <= geometry.rows; row += 1) {
|
|
5497
|
+
const content = row - 1 < lines.length ? lines[row - 1] : " ".repeat(this.width);
|
|
5498
|
+
parts.push(`${ESC3}[${row};${separatorColumn}H${RESET3}\u2502${content}`);
|
|
5499
|
+
}
|
|
5500
|
+
parts.push(WRAP_ON, CURSOR_RESTORE, SYNC_END);
|
|
5501
|
+
this.ports.writeOut(parts.join(""));
|
|
5502
|
+
} catch {
|
|
5503
|
+
this.dispose();
|
|
5504
|
+
if (!this.warned) {
|
|
5505
|
+
this.warned = true;
|
|
5506
|
+
try {
|
|
5507
|
+
this.ports.notify("codeArbiter sidebar disabled after a paint failure; run /ca-doctor.");
|
|
5508
|
+
} catch {
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
};
|
|
5514
|
+
function installSidebar(ports, options) {
|
|
5515
|
+
const probe = probeSidebarSupport(ports.tui, ports.terminal, ports.metrics);
|
|
5516
|
+
if (!probe.ok) return unavailable(probe.reason);
|
|
5517
|
+
const width = clampWidth(options.width);
|
|
5518
|
+
const descriptor = columnsDescriptor(ports.terminal);
|
|
5519
|
+
let rawColumns2;
|
|
5520
|
+
try {
|
|
5521
|
+
rawColumns2 = descriptor.get !== void 0 ? descriptor.get.call(ports.terminal) : descriptor.value;
|
|
5522
|
+
} catch {
|
|
5523
|
+
return unavailable("geometry-unreadable");
|
|
5524
|
+
}
|
|
5525
|
+
if (typeof rawColumns2 !== "number" || !Number.isFinite(rawColumns2) || rawColumns2 < width + SIDEBAR_MAIN_COLUMN_FLOOR) {
|
|
5526
|
+
return unavailable("terminal-too-narrow");
|
|
5527
|
+
}
|
|
5528
|
+
const hadOwnColumns = Object.getOwnPropertyDescriptor(ports.terminal, "columns") !== void 0;
|
|
5529
|
+
try {
|
|
5530
|
+
return new Compositor(ports, width);
|
|
5531
|
+
} catch {
|
|
5532
|
+
try {
|
|
5533
|
+
if (hadOwnColumns) Object.defineProperty(ports.terminal, "columns", descriptor);
|
|
5534
|
+
else delete ports.terminal.columns;
|
|
5535
|
+
} catch {
|
|
5536
|
+
}
|
|
5537
|
+
return unavailable("install-failed");
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
|
|
5541
|
+
// src/sidebar-manager.ts
|
|
5542
|
+
var SIDEBAR_AUTO_ON_MIN_COLUMNS = 120;
|
|
5543
|
+
var SIDEBAR_SYNTAX = "Usage: /ca-sidebar on|off|toggle|width N (N clamped 24..60)";
|
|
5544
|
+
var DEGRADED_REASONS = Object.freeze(/* @__PURE__ */ new Set([
|
|
5545
|
+
"no-dorender",
|
|
5546
|
+
"columns-not-configurable",
|
|
5547
|
+
"no-metrics",
|
|
5548
|
+
"geometry-unreadable",
|
|
5549
|
+
"install-failed"
|
|
5550
|
+
]));
|
|
5551
|
+
function clampWidth2(width) {
|
|
5552
|
+
return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_MIN_WIDTH, Math.floor(width)));
|
|
5553
|
+
}
|
|
5554
|
+
function rawColumns(terminal) {
|
|
5555
|
+
try {
|
|
5556
|
+
const value = terminal?.columns;
|
|
5557
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : void 0;
|
|
5558
|
+
} catch {
|
|
5559
|
+
return void 0;
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
var Manager = class {
|
|
5563
|
+
constructor(ports) {
|
|
5564
|
+
this.ports = ports;
|
|
5565
|
+
}
|
|
5566
|
+
ports;
|
|
5567
|
+
registered = false;
|
|
5568
|
+
expected = false;
|
|
5569
|
+
compositor;
|
|
5570
|
+
width = SIDEBAR_DEFAULT_WIDTH;
|
|
5571
|
+
userDisabled = false;
|
|
5572
|
+
autoDecided = false;
|
|
5573
|
+
lastReason;
|
|
5574
|
+
metrics;
|
|
5575
|
+
register(context) {
|
|
5576
|
+
if (!interactiveParent(context)) return false;
|
|
5577
|
+
this.expected = true;
|
|
5578
|
+
if (!this.registered) {
|
|
5579
|
+
this.ports.pi.registerCommand("ca-sidebar", {
|
|
5580
|
+
description: "Toggle or resize the codeArbiter sidebar (on|off|toggle|width N).",
|
|
5581
|
+
handler: async (args, commandContext) => {
|
|
5582
|
+
await this.handle(args, commandContext);
|
|
5583
|
+
}
|
|
5584
|
+
});
|
|
5585
|
+
this.registered = true;
|
|
5586
|
+
}
|
|
5587
|
+
return true;
|
|
5588
|
+
}
|
|
5589
|
+
async autoInstall(context) {
|
|
5590
|
+
if (!interactiveParent(context)) return;
|
|
5591
|
+
if (this.autoDecided || this.userDisabled || this.compositor?.installed === true) return;
|
|
5592
|
+
if (this.ports.currentTui() === void 0) return;
|
|
5593
|
+
const columns = rawColumns(this.ports.terminal());
|
|
5594
|
+
if (columns === void 0) return;
|
|
5595
|
+
this.autoDecided = true;
|
|
5596
|
+
if (columns < SIDEBAR_AUTO_ON_MIN_COLUMNS) {
|
|
5597
|
+
this.lastReason = "auto-off-narrow";
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
await this.install(context);
|
|
5601
|
+
}
|
|
5602
|
+
dispose() {
|
|
5603
|
+
try {
|
|
5604
|
+
this.compositor?.dispose();
|
|
5605
|
+
} catch {
|
|
5606
|
+
}
|
|
5607
|
+
this.compositor = void 0;
|
|
5608
|
+
this.expected = false;
|
|
5609
|
+
this.userDisabled = false;
|
|
5610
|
+
this.autoDecided = false;
|
|
5611
|
+
this.lastReason = void 0;
|
|
5612
|
+
this.width = SIDEBAR_DEFAULT_WIDTH;
|
|
5613
|
+
}
|
|
5614
|
+
health() {
|
|
5615
|
+
const installed = this.compositor?.installed === true;
|
|
5616
|
+
const reason = installed ? void 0 : this.compositor?.reason ?? this.lastReason;
|
|
5617
|
+
return Object.freeze({
|
|
5618
|
+
expected: this.expected,
|
|
5619
|
+
installed,
|
|
5620
|
+
degraded: !installed && reason !== void 0 && DEGRADED_REASONS.has(reason),
|
|
5621
|
+
...reason === void 0 ? {} : { reason }
|
|
5622
|
+
});
|
|
5623
|
+
}
|
|
5624
|
+
async install(context) {
|
|
5625
|
+
const tui = this.ports.currentTui();
|
|
5626
|
+
const terminal = this.ports.terminal();
|
|
5627
|
+
if (tui === void 0 || terminal === void 0) {
|
|
5628
|
+
this.lastReason = tui === void 0 ? "no-tui" : "no-terminal";
|
|
5629
|
+
return false;
|
|
5630
|
+
}
|
|
5631
|
+
if (this.metrics === void 0) {
|
|
5632
|
+
try {
|
|
5633
|
+
this.metrics = await this.ports.loadMetrics?.();
|
|
5634
|
+
} catch {
|
|
5635
|
+
this.metrics = void 0;
|
|
5636
|
+
}
|
|
5637
|
+
if (this.metrics === void 0) {
|
|
5638
|
+
this.lastReason = "no-metrics";
|
|
5639
|
+
return false;
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
const notify = (message) => {
|
|
5643
|
+
try {
|
|
5644
|
+
context.ui.notify(message, "warning");
|
|
5645
|
+
} catch {
|
|
5646
|
+
}
|
|
5647
|
+
};
|
|
5648
|
+
const compositor = installSidebar({
|
|
5649
|
+
tui,
|
|
5650
|
+
terminal,
|
|
5651
|
+
metrics: this.metrics,
|
|
5652
|
+
writeOut: this.ports.writeOut,
|
|
5653
|
+
notify,
|
|
5654
|
+
dataSource: this.ports.dataSource,
|
|
5655
|
+
noColor: this.ports.noColor()
|
|
5656
|
+
}, { width: this.width });
|
|
5657
|
+
this.compositor = compositor;
|
|
5658
|
+
this.lastReason = compositor.installed ? void 0 : compositor.reason;
|
|
5659
|
+
return compositor.installed;
|
|
5660
|
+
}
|
|
5661
|
+
notifyInfo(context, message, level = "info") {
|
|
5662
|
+
try {
|
|
5663
|
+
context.ui.notify(message, level);
|
|
5664
|
+
} catch {
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5667
|
+
async turnOn(context) {
|
|
5668
|
+
this.userDisabled = false;
|
|
5669
|
+
this.autoDecided = true;
|
|
5670
|
+
if (this.compositor?.installed === true) {
|
|
5671
|
+
this.notifyInfo(context, "codeArbiter sidebar is already on.");
|
|
5672
|
+
return;
|
|
5673
|
+
}
|
|
5674
|
+
const installed = await this.install(context);
|
|
5675
|
+
if (!installed) {
|
|
5676
|
+
this.notifyInfo(context, `codeArbiter sidebar unavailable (${this.lastReason ?? "unknown"}); native rendering is untouched.`, "warning");
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5679
|
+
turnOff(context) {
|
|
5680
|
+
this.userDisabled = true;
|
|
5681
|
+
this.autoDecided = true;
|
|
5682
|
+
try {
|
|
5683
|
+
this.compositor?.dispose();
|
|
5684
|
+
} catch {
|
|
5685
|
+
}
|
|
5686
|
+
this.compositor = void 0;
|
|
5687
|
+
this.lastReason = "off";
|
|
5688
|
+
this.notifyInfo(context, "codeArbiter sidebar off.");
|
|
5689
|
+
}
|
|
5690
|
+
async handle(rawArgs, context) {
|
|
5691
|
+
if (!interactiveParent(context)) return;
|
|
5692
|
+
const args = typeof rawArgs === "string" ? rawArgs.trim().split(/\s+/u).filter(Boolean) : [];
|
|
5693
|
+
if (args.length === 0 || args.length === 1 && args[0] === "toggle") {
|
|
5694
|
+
if (this.compositor?.installed === true) this.turnOff(context);
|
|
5695
|
+
else await this.turnOn(context);
|
|
5696
|
+
return;
|
|
5697
|
+
}
|
|
5698
|
+
if (args.length === 1 && args[0] === "on") {
|
|
5699
|
+
await this.turnOn(context);
|
|
5700
|
+
return;
|
|
5701
|
+
}
|
|
5702
|
+
if (args.length === 1 && args[0] === "off") {
|
|
5703
|
+
this.turnOff(context);
|
|
5704
|
+
return;
|
|
5705
|
+
}
|
|
5706
|
+
if (args.length === 2 && args[0] === "width" && /^\d{1,4}$/u.test(args[1])) {
|
|
5707
|
+
this.width = clampWidth2(Number(args[1]));
|
|
5708
|
+
if (this.compositor?.installed === true) this.compositor.setWidth(this.width);
|
|
5709
|
+
else this.notifyInfo(context, `codeArbiter sidebar width set to ${this.width}; the sidebar is off.`);
|
|
5710
|
+
return;
|
|
5711
|
+
}
|
|
5712
|
+
this.notifyInfo(context, SIDEBAR_SYNTAX, "warning");
|
|
5713
|
+
}
|
|
5714
|
+
};
|
|
5715
|
+
function createSidebarManager(ports) {
|
|
5716
|
+
return new Manager(ports);
|
|
5717
|
+
}
|
|
5718
|
+
|
|
5719
|
+
// src/sidebar-data.ts
|
|
5720
|
+
function sessionFromFooter(footer) {
|
|
5721
|
+
const context = footer.context;
|
|
5722
|
+
const contextPercent = context !== void 0 && typeof context.windowTokens === "number" && Number.isFinite(context.windowTokens) && context.windowTokens > 0 && typeof context.usedTokens === "number" && Number.isFinite(context.usedTokens) ? context.usedTokens / context.windowTokens * 100 : void 0;
|
|
5723
|
+
const session = {
|
|
5724
|
+
...footer.model?.name === void 0 ? {} : { model: footer.model.name },
|
|
5725
|
+
...footer.model?.thinking === void 0 ? {} : { thinkingLevel: footer.model.thinking },
|
|
5726
|
+
...contextPercent === void 0 ? {} : { contextPercent },
|
|
5727
|
+
...footer.session === void 0 ? {} : {
|
|
5728
|
+
inputTokens: footer.session.inputTokens,
|
|
5729
|
+
outputTokens: footer.session.outputTokens,
|
|
5730
|
+
costUsd: footer.session.costUsd
|
|
5731
|
+
},
|
|
5732
|
+
...footer.sparkline === void 0 || footer.sparkline.length === 0 ? {} : { burn: footer.sparkline }
|
|
5733
|
+
};
|
|
5734
|
+
return Object.keys(session).length === 0 ? void 0 : session;
|
|
5735
|
+
}
|
|
5736
|
+
function sidebarInputFromFooter(footer) {
|
|
5737
|
+
if (footer === void 0) return {};
|
|
5738
|
+
const session = sessionFromFooter(footer);
|
|
5739
|
+
const subagents = footer.activity !== void 0 && footer.activity.length > 0 ? footer.activity.map((item) => ({
|
|
5740
|
+
kind: item.kind,
|
|
5741
|
+
label: item.label,
|
|
5742
|
+
state: item.state,
|
|
5743
|
+
...item.ageSeconds === void 0 ? {} : { ageSeconds: item.ageSeconds }
|
|
5744
|
+
})) : void 0;
|
|
5745
|
+
const workspace = footer.git === void 0 ? void 0 : {
|
|
5746
|
+
cwd: footer.folder,
|
|
5747
|
+
...footer.git.repository === void 0 ? {} : { repository: footer.git.repository },
|
|
5748
|
+
...footer.git.dirty === void 0 ? {} : { dirty: footer.git.dirty }
|
|
5749
|
+
};
|
|
5750
|
+
return {
|
|
5751
|
+
...session === void 0 ? {} : { session },
|
|
5752
|
+
...subagents === void 0 ? {} : { subagents },
|
|
5753
|
+
...workspace === void 0 ? {} : { workspace }
|
|
5754
|
+
};
|
|
5755
|
+
}
|
|
5756
|
+
var TODO_STATE = Object.freeze({
|
|
5757
|
+
PENDING: "open",
|
|
5758
|
+
IN_PROGRESS: "active",
|
|
5759
|
+
ACCEPTED: "done"
|
|
5760
|
+
});
|
|
5761
|
+
function sidebarTodosFromPlan(state) {
|
|
5762
|
+
const tasks = state?.activePlan.tasks;
|
|
5763
|
+
if (tasks === void 0 || tasks.length === 0) return void 0;
|
|
5764
|
+
return tasks.map((task) => ({ text: task.id, state: TODO_STATE[task.status] }));
|
|
5765
|
+
}
|
|
5766
|
+
|
|
5082
5767
|
// src/tool-guard.ts
|
|
5083
5768
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
5084
5769
|
import { realpathSync as realpathSync6 } from "node:fs";
|
|
@@ -6127,6 +6812,12 @@ async function collectPiDoctorInput(dependencies) {
|
|
|
6127
6812
|
expected: dependencies.footerExpected === true,
|
|
6128
6813
|
initialized: dependencies.footerInitialized === true
|
|
6129
6814
|
},
|
|
6815
|
+
sidebar: {
|
|
6816
|
+
expected: dependencies.sidebarExpected === true,
|
|
6817
|
+
installed: dependencies.sidebarInstalled === true,
|
|
6818
|
+
degraded: dependencies.sidebarDegraded === true,
|
|
6819
|
+
...dependencies.sidebarReason === void 0 ? {} : { reason: dependencies.sidebarReason }
|
|
6820
|
+
},
|
|
6130
6821
|
background: {
|
|
6131
6822
|
expected: dependencies.backgroundExpected === true,
|
|
6132
6823
|
initialized: dependencies.backgroundInitialized === true,
|
|
@@ -6163,6 +6854,7 @@ var REMEDIATION = {
|
|
|
6163
6854
|
"module-identity": "Reinstall the active Pi CLI and ca-pi from their approved origins, then restart Pi.",
|
|
6164
6855
|
"final-arguments": "Reinstall ca-pi, remove competing mutating tool definitions, and run /ca-doctor again.",
|
|
6165
6856
|
footer: "Restart Pi in an interactive parent session; if the rich footer still fails, reinstall ca-pi and run /ca-doctor again.",
|
|
6857
|
+
sidebar: "Run /ca-sidebar on in a wide terminal; if the probe still reports unavailable, this Pi build changed its render surface \u2014 keep the footer and file an issue.",
|
|
6166
6858
|
background: "Stop active work, restart Pi, and run /ca-doctor before launching another background job.",
|
|
6167
6859
|
"active-dispatch": "Require passing supported-version real-host promotion/CI evidence before closing PI-AC-28."
|
|
6168
6860
|
};
|
|
@@ -6261,6 +6953,12 @@ function diagnosePi(input) {
|
|
|
6261
6953
|
input.footer.expected ? "The rich footer initialized in the current interactive parent session." : "The rich footer is intentionally absent outside an active interactive parent session.",
|
|
6262
6954
|
input.footer.expected ? "The rich footer did not initialize in the current interactive parent session." : "The rich footer initialized outside an active interactive parent session; isolation is breached."
|
|
6263
6955
|
),
|
|
6956
|
+
diagnosis(
|
|
6957
|
+
"sidebar",
|
|
6958
|
+
input.sidebar.expected ? !input.sidebar.degraded : !input.sidebar.installed && !input.sidebar.degraded,
|
|
6959
|
+
input.sidebar.expected ? input.sidebar.installed ? "The probe-gated sidebar compositor is installed." : `The sidebar is not installed (${input.sidebar.reason ?? "off"}); native rendering is untouched.` : "The sidebar is intentionally absent outside an interactive parent session.",
|
|
6960
|
+
!input.sidebar.expected && input.sidebar.installed ? "The sidebar compositor installed outside an interactive parent session; isolation is breached." : `The sidebar hook probe failed (${input.sidebar.reason ?? "unknown"}); this Pi build changed its render surface and native rendering is untouched.`
|
|
6961
|
+
),
|
|
6264
6962
|
diagnosis(
|
|
6265
6963
|
"background",
|
|
6266
6964
|
input.background.expected ? input.background.initialized && input.background.healthy : !input.background.initialized,
|
|
@@ -9024,6 +9722,88 @@ async function appendPiCompactionAudit(record2) {
|
|
|
9024
9722
|
}
|
|
9025
9723
|
|
|
9026
9724
|
// src/extension.ts
|
|
9725
|
+
var COMMAND_VISIBILITY_ORDER = ["core", "advanced", "alias", "internal", "deprecated"];
|
|
9726
|
+
var COMMAND_WORKFLOW_ORDER = [
|
|
9727
|
+
"evaluate",
|
|
9728
|
+
"initialize",
|
|
9729
|
+
"change",
|
|
9730
|
+
"review",
|
|
9731
|
+
"decide",
|
|
9732
|
+
"ship",
|
|
9733
|
+
"operate",
|
|
9734
|
+
"extend",
|
|
9735
|
+
"help"
|
|
9736
|
+
];
|
|
9737
|
+
function plainRecord2(value) {
|
|
9738
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
9739
|
+
}
|
|
9740
|
+
function sameStrings2(actual, expected) {
|
|
9741
|
+
return actual.length === expected.length && actual.every((item, index) => item === expected[index]);
|
|
9742
|
+
}
|
|
9743
|
+
function validLegacyRoutes(value) {
|
|
9744
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string" && /^[a-z][a-z0-9-]*$/u.test(item)) && new Set(value).size === value.length && sameStrings2(value, [...value].sort());
|
|
9745
|
+
}
|
|
9746
|
+
function commandCatalogEntries(value) {
|
|
9747
|
+
const envelopeKeys = ["commands", "compatibility", "schemaVersion", "visibilityOrder", "workflowOrder"];
|
|
9748
|
+
if (!plainRecord2(value) || !sameStrings2(Object.keys(value).sort(), envelopeKeys) || value.schemaVersion !== 1 || !Array.isArray(value.visibilityOrder) || !sameStrings2(value.visibilityOrder, COMMAND_VISIBILITY_ORDER) || !Array.isArray(value.workflowOrder) || !sameStrings2(value.workflowOrder, COMMAND_WORKFLOW_ORDER) || !plainRecord2(value.compatibility) || !plainRecord2(value.commands)) {
|
|
9749
|
+
throw new Error("codeArbiter Pi command catalog envelope is invalid; run /ca-doctor.");
|
|
9750
|
+
}
|
|
9751
|
+
const commands = value.commands;
|
|
9752
|
+
const names = Object.keys(commands);
|
|
9753
|
+
if (!sameStrings2(names, [...names].sort()) || names.length === 0) {
|
|
9754
|
+
throw new Error("codeArbiter Pi command catalog envelope has no sorted commands; run /ca-doctor.");
|
|
9755
|
+
}
|
|
9756
|
+
const entries = [];
|
|
9757
|
+
for (const name of names) {
|
|
9758
|
+
const fail2 = () => {
|
|
9759
|
+
throw new Error(`codeArbiter Pi command catalog entry ${name} is invalid; run /ca-doctor.`);
|
|
9760
|
+
};
|
|
9761
|
+
const value2 = commands[name];
|
|
9762
|
+
if (!plainRecord2(value2)) {
|
|
9763
|
+
throw new Error(`codeArbiter Pi command catalog entry ${name} is invalid; run /ca-doctor.`);
|
|
9764
|
+
}
|
|
9765
|
+
const raw = value2;
|
|
9766
|
+
if (raw.name !== name || typeof raw.description !== "string" || raw.description === "" || raw.skillPath !== `skills/ca-${name}/SKILL.md` || !COMMAND_VISIBILITY_ORDER.includes(raw.visibility) || !COMMAND_WORKFLOW_ORDER.includes(raw.workflow)) {
|
|
9767
|
+
fail2();
|
|
9768
|
+
}
|
|
9769
|
+
const visibility = raw.visibility;
|
|
9770
|
+
const commonKeys = ["description", "name", "skillPath", "visibility", "workflow"];
|
|
9771
|
+
let expectedKeys;
|
|
9772
|
+
if (visibility === "core" || visibility === "advanced" || visibility === "internal") {
|
|
9773
|
+
expectedKeys = [...commonKeys, "canonical", "legacyRoutes"].sort();
|
|
9774
|
+
if (raw.canonical !== name || !validLegacyRoutes(raw.legacyRoutes)) fail2();
|
|
9775
|
+
} else if (visibility === "alias") {
|
|
9776
|
+
expectedKeys = [...commonKeys, "canonical", "replacement"].sort();
|
|
9777
|
+
if (typeof raw.canonical !== "string" || !/^[a-z][a-z0-9-]*$/u.test(raw.canonical) || typeof raw.replacement !== "string" || !raw.replacement.startsWith(`${raw.canonical} `)) fail2();
|
|
9778
|
+
} else {
|
|
9779
|
+
expectedKeys = [...commonKeys, "replacement"].sort();
|
|
9780
|
+
if (typeof raw.replacement !== "string" || raw.replacement === "") fail2();
|
|
9781
|
+
}
|
|
9782
|
+
if (!sameStrings2(Object.keys(raw).sort(), expectedKeys)) fail2();
|
|
9783
|
+
entries.push(Object.freeze({ ...raw }));
|
|
9784
|
+
}
|
|
9785
|
+
const entriesByName = new Map(entries.map((entry) => [entry.name, entry]));
|
|
9786
|
+
const expectedLegacyRoutes = /* @__PURE__ */ new Map();
|
|
9787
|
+
for (const entry of entries) {
|
|
9788
|
+
if (entry.visibility === "alias") {
|
|
9789
|
+
const target = entriesByName.get(entry.canonical);
|
|
9790
|
+
if (target === void 0 || target.visibility === "alias" || target.visibility === "deprecated") {
|
|
9791
|
+
throw new Error(`codeArbiter Pi command catalog entry ${entry.name} has an invalid alias target; run /ca-doctor.`);
|
|
9792
|
+
}
|
|
9793
|
+
const routes = expectedLegacyRoutes.get(entry.canonical) ?? [];
|
|
9794
|
+
routes.push(entry.name);
|
|
9795
|
+
expectedLegacyRoutes.set(entry.canonical, routes);
|
|
9796
|
+
}
|
|
9797
|
+
}
|
|
9798
|
+
for (const entry of entries) {
|
|
9799
|
+
if (entry.visibility === "alias" || entry.visibility === "deprecated") continue;
|
|
9800
|
+
const expected = (expectedLegacyRoutes.get(entry.name) ?? []).sort();
|
|
9801
|
+
if (!sameStrings2(entry.legacyRoutes ?? [], expected)) {
|
|
9802
|
+
throw new Error(`codeArbiter Pi command catalog entry ${entry.name} has broken legacy-route closure; run /ca-doctor.`);
|
|
9803
|
+
}
|
|
9804
|
+
}
|
|
9805
|
+
return Object.freeze(entries);
|
|
9806
|
+
}
|
|
9027
9807
|
var PI_TRUST_REQUIRED_STATUS = "codeArbiter host: pi waiting for project trust - run /trust in Pi, approve this project, then start a new session";
|
|
9028
9808
|
function hasAffirmativeProjectTrust(context) {
|
|
9029
9809
|
try {
|
|
@@ -9167,6 +9947,19 @@ function ownershipStatus(pi, dependencies, nativePlanRegistered = false, nativeJ
|
|
|
9167
9947
|
}
|
|
9168
9948
|
return `codeArbiter host: pi degraded - ${native.length + jobs.length} native command ownership conflict(s); operations blocked`;
|
|
9169
9949
|
}
|
|
9950
|
+
var PERSONA_SENTINEL = "<!-- codearbiter:persona-sentinel -->";
|
|
9951
|
+
async function loadPersonaFrom(packageRoot) {
|
|
9952
|
+
const [safetyCore, body] = await Promise.all([
|
|
9953
|
+
readFile6(resolve15(packageRoot, "includes", "safety-core.md"), "utf8"),
|
|
9954
|
+
readFile6(resolve15(packageRoot, "arbiter.md"), "utf8")
|
|
9955
|
+
]);
|
|
9956
|
+
return `${safetyCore.replace(/\n+$/, "")}
|
|
9957
|
+
|
|
9958
|
+
${body.replace(/\n+$/, "")}
|
|
9959
|
+
|
|
9960
|
+
${PERSONA_SENTINEL}
|
|
9961
|
+
`;
|
|
9962
|
+
}
|
|
9170
9963
|
function installParent(pi, dependencies) {
|
|
9171
9964
|
let enabled = false;
|
|
9172
9965
|
let persona = "";
|
|
@@ -9199,6 +9992,21 @@ function installParent(pi, dependencies) {
|
|
|
9199
9992
|
currentActivity2,
|
|
9200
9993
|
dependencies.collectGitFacts ?? collectGitFacts
|
|
9201
9994
|
);
|
|
9995
|
+
const sidebar = createSidebarManager({
|
|
9996
|
+
pi,
|
|
9997
|
+
currentTui: () => footer.currentTui(),
|
|
9998
|
+
terminal: () => process.stdout,
|
|
9999
|
+
...loadFooterMetrics === void 0 ? {} : { loadMetrics: loadFooterMetrics },
|
|
10000
|
+
dataSource: () => {
|
|
10001
|
+
const input = sidebarInputFromFooter(footer.lastRenderedInput());
|
|
10002
|
+
const todos = sidebarTodosFromPlan(plan?.status());
|
|
10003
|
+
return todos === void 0 ? input : { ...input, todos };
|
|
10004
|
+
},
|
|
10005
|
+
writeOut: (text2) => {
|
|
10006
|
+
process.stdout.write(text2);
|
|
10007
|
+
},
|
|
10008
|
+
noColor: () => Object.prototype.hasOwnProperty.call(process.env, "NO_COLOR")
|
|
10009
|
+
});
|
|
9202
10010
|
const readActivation = dependencies.readActivation ?? isEnabled;
|
|
9203
10011
|
dependencies.installDispatch?.(() => readyLifecycle, currentActivity2);
|
|
9204
10012
|
dependencies.installCompaction?.(() => readyLifecycle);
|
|
@@ -9233,6 +10041,7 @@ function installParent(pi, dependencies) {
|
|
|
9233
10041
|
}
|
|
9234
10042
|
return Object.freeze({
|
|
9235
10043
|
footer: footerHealth,
|
|
10044
|
+
sidebar: sidebar.health(),
|
|
9236
10045
|
background: Object.freeze({
|
|
9237
10046
|
expected: backgroundExpected,
|
|
9238
10047
|
initialized: backgroundInitialized,
|
|
@@ -9253,6 +10062,7 @@ function installParent(pi, dependencies) {
|
|
|
9253
10062
|
activeLifecycle = void 0;
|
|
9254
10063
|
readyLifecycle = void 0;
|
|
9255
10064
|
if (background !== void 0) await background.stop("session-switch");
|
|
10065
|
+
sidebar.dispose();
|
|
9256
10066
|
activity?.dispose();
|
|
9257
10067
|
activity = void 0;
|
|
9258
10068
|
dependencies.enforcementReadiness?.deactivate();
|
|
@@ -9275,6 +10085,9 @@ function installParent(pi, dependencies) {
|
|
|
9275
10085
|
readUpdateVersion: dependencies.readFooterUpdateVersion
|
|
9276
10086
|
});
|
|
9277
10087
|
if (!isCurrent()) return;
|
|
10088
|
+
sidebar.register(context);
|
|
10089
|
+
await sidebar.autoInstall(context);
|
|
10090
|
+
if (!isCurrent()) return;
|
|
9278
10091
|
if (!markerEnabled) {
|
|
9279
10092
|
activeLifecycle = void 0;
|
|
9280
10093
|
dependencies.enforcementReadiness?.deactivate();
|
|
@@ -9370,13 +10183,16 @@ function installParent(pi, dependencies) {
|
|
|
9370
10183
|
if (enabled) publishStatus(context, degradedStatus() ?? "codeArbiter host: pi governed");
|
|
9371
10184
|
});
|
|
9372
10185
|
pi.on("agent_settled", async (_event, context) => {
|
|
10186
|
+
const sequence = lifecycleSequence;
|
|
9373
10187
|
await footer.refresh(context, { activation: { enabled: footerActivationEnabled } });
|
|
10188
|
+
if (sequence === lifecycleSequence) await sidebar.autoInstall(context);
|
|
9374
10189
|
if (enabled) publishStatus(context, degradedStatus());
|
|
9375
10190
|
});
|
|
9376
10191
|
const stopSession = async (reason, context) => {
|
|
9377
10192
|
readyLifecycle = void 0;
|
|
9378
10193
|
activeLifecycle = void 0;
|
|
9379
10194
|
await background?.stop(reason);
|
|
10195
|
+
sidebar.dispose();
|
|
9380
10196
|
activity?.dispose();
|
|
9381
10197
|
activity = void 0;
|
|
9382
10198
|
footer.dispose();
|
|
@@ -9523,7 +10339,9 @@ async function codeArbiterPi(pi) {
|
|
|
9523
10339
|
if (parent === packageRoot) throw new Error("codeArbiter could not locate the ca-pi package; run /ca-doctor.");
|
|
9524
10340
|
packageRoot = parent;
|
|
9525
10341
|
}
|
|
9526
|
-
const catalog =
|
|
10342
|
+
const catalog = commandCatalogEntries(
|
|
10343
|
+
JSON.parse(await readFile6(resolve15(packageRoot, "generated", "command-catalog.json"), "utf8"))
|
|
10344
|
+
);
|
|
9527
10345
|
const toolClasses = loadPiToolClasses(define_CODEARBITER_PI_TOOL_CLASSES_default);
|
|
9528
10346
|
const rawPermissionSurfaces = define_CODEARBITER_PI_PERMISSION_POLICY_SURFACES_default;
|
|
9529
10347
|
if (rawPermissionSurfaces === null || typeof rawPermissionSurfaces !== "object" || Array.isArray(rawPermissionSurfaces)) {
|
|
@@ -9601,7 +10419,7 @@ async function codeArbiterPi(pi) {
|
|
|
9601
10419
|
pi.appendEntry(customType, data);
|
|
9602
10420
|
},
|
|
9603
10421
|
enforcementReadiness: enforcement,
|
|
9604
|
-
loadPersona: async () => await
|
|
10422
|
+
loadPersona: async () => await loadPersonaFrom(packageRoot),
|
|
9605
10423
|
resetBridge,
|
|
9606
10424
|
prepareFooterBridge: (cwd) => {
|
|
9607
10425
|
prepareBridgeIdentity(cwd);
|
|
@@ -9720,6 +10538,10 @@ async function codeArbiterPi(pi) {
|
|
|
9720
10538
|
bridgePrepared: enabledForDoctor && trustedForDoctor && pythonResolutionAttempted,
|
|
9721
10539
|
footerExpected: health.footer.expected,
|
|
9722
10540
|
footerInitialized: health.footer.initialized,
|
|
10541
|
+
sidebarExpected: health.sidebar.expected,
|
|
10542
|
+
sidebarInstalled: health.sidebar.installed,
|
|
10543
|
+
sidebarDegraded: health.sidebar.degraded,
|
|
10544
|
+
...health.sidebar.reason === void 0 ? {} : { sidebarReason: health.sidebar.reason },
|
|
9723
10545
|
backgroundExpected: health.background.expected,
|
|
9724
10546
|
backgroundInitialized: health.background.initialized,
|
|
9725
10547
|
backgroundHealthy: health.background.healthy,
|
|
@@ -9791,8 +10613,10 @@ async function codeArbiterPi(pi) {
|
|
|
9791
10613
|
});
|
|
9792
10614
|
}
|
|
9793
10615
|
export {
|
|
10616
|
+
PERSONA_SENTINEL,
|
|
9794
10617
|
PI_RUNTIME_DIAGNOSIS,
|
|
9795
10618
|
boundedPiEnvironment,
|
|
10619
|
+
commandCatalogEntries,
|
|
9796
10620
|
compatibilityDirection,
|
|
9797
10621
|
createCodeArbiterPi,
|
|
9798
10622
|
createPiFooterMetricsLoader,
|
|
@@ -9802,6 +10626,7 @@ export {
|
|
|
9802
10626
|
installParent,
|
|
9803
10627
|
installPiDispatch,
|
|
9804
10628
|
installPiFarmPreview,
|
|
10629
|
+
loadPersonaFrom,
|
|
9805
10630
|
renderPiDoctorReportBlock,
|
|
9806
10631
|
resolvePiBackgroundShell,
|
|
9807
10632
|
resolvePiRuntime,
|