@vanillagreen/pi-qol 1.8.0 → 2.0.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 +7 -7
- package/extensions/qol/bridges.ts +5 -5
- package/extensions/qol/compaction-handoff.ts +1 -1
- package/extensions/qol/constants.ts +12 -12
- package/extensions/qol/glyphs.ts +3 -3
- package/extensions/qol/handoff.ts +2 -2
- package/extensions/qol/rate-limit-auto-resume.ts +1 -1
- package/extensions/qol/session-search/context.ts +2 -2
- package/extensions/qol/session-search/index.ts +2 -2
- package/extensions/qol/settings.ts +10 -10
- package/extensions/qol.ts +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# pi-qol
|
|
2
2
|
|
|
3
|
-

|
|
4
|
+

|
|
5
|
+

|
|
6
6
|
|
|
7
7
|
Quality-of-life extension for Pi: compact statusline, multiline input, session naming and search, scheduled prompts, notifications, and a permission gate.
|
|
8
8
|
|
|
@@ -29,11 +29,11 @@ Via [npm](https://www.npmjs.com/package/@vanillagreen/pi-qol):
|
|
|
29
29
|
pi install npm:@vanillagreen/pi-qol
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Via [
|
|
32
|
+
Via [kendex](https://github.com/vanillagreencom/kendex):
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
cargo install --git https://github.com/vanillagreencom/
|
|
36
|
-
|
|
35
|
+
cargo install --git https://github.com/vanillagreencom/kendex.git kendex
|
|
36
|
+
kendex add vanillagreencom/kendex --pi-extension pi-qol --harness pi -y
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Commands
|
|
@@ -54,7 +54,7 @@ Arguments support autocomplete. `/schedule` accepts `ms`, `s`, `m`, `h`, and `d`
|
|
|
54
54
|
|
|
55
55
|
## Settings
|
|
56
56
|
|
|
57
|
-
Open `/extensions:settings`; settings appear under the **QOL** tab. Names below match the labels shown there, grouped as the editor groups them. Project settings in `.pi/settings.json` apply only after Pi marks the workspace trusted; before trust,
|
|
57
|
+
Open `/extensions:settings`; settings appear under the **QOL** tab. Names below match the labels shown there, grouped as the editor groups them. Project settings in `.pi/settings.json` apply only after Pi marks the workspace trusted; before trust, kendex Pi extensions read user/global settings only. Glyph style: each package exposes `glyphStyle` (`unicode` default, `ascii` for terminal-safe chrome). `@vanillagreen/pi-tool-renderer.globalGlyphStyleOverride=ascii` forces ASCII chrome across kendex Pi extensions while leaving tool/model/user content unchanged.
|
|
58
58
|
|
|
59
59
|
| Group | Setting | What it does |
|
|
60
60
|
| --- | --- | --- |
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
CAVEMAN_BRIDGE_SYMBOL,
|
|
3
3
|
PI_AGENTS_STATUSLINE_SYMBOL,
|
|
4
4
|
QUESTION_SERVICE_SYMBOL,
|
|
5
|
-
|
|
5
|
+
KENDEX_MODAL_LOCK_SYMBOL,
|
|
6
6
|
} from "./constants.js";
|
|
7
7
|
|
|
8
8
|
export interface CavemanBridge {
|
|
@@ -37,7 +37,7 @@ export interface QuestionServiceLike {
|
|
|
37
37
|
subscribe(listener: (event: any) => void): () => void;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
interface
|
|
40
|
+
interface kendexModalLock {
|
|
41
41
|
depth: number;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -63,11 +63,11 @@ export function getQuestionService(): QuestionServiceLike | undefined {
|
|
|
63
63
|
return undefined;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
export function
|
|
66
|
+
export function acquirekendexModalLock(): () => void {
|
|
67
67
|
const host = globalThis as unknown as Record<PropertyKey, unknown>;
|
|
68
|
-
const existing = host[
|
|
68
|
+
const existing = host[KENDEX_MODAL_LOCK_SYMBOL] as kendexModalLock | undefined;
|
|
69
69
|
const lock = existing && typeof existing.depth === "number" ? existing : { depth: 0 };
|
|
70
|
-
host[
|
|
70
|
+
host[KENDEX_MODAL_LOCK_SYMBOL] = lock;
|
|
71
71
|
lock.depth += 1;
|
|
72
72
|
let released = false;
|
|
73
73
|
return () => {
|
|
@@ -151,7 +151,7 @@ export function handoffStampedPath(baseDir: string, timestamp: number): string {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
export function handoffBaseDir(sessionId: string, root: string = piUserDir()): string {
|
|
154
|
-
return join(root, "
|
|
154
|
+
return join(root, "kendex", "sessions", safeFileName(sessionId), QOL_BUDGET_HANDOFF_FOLDER);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
export interface WriteHandoffOptions {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const INSTALL_SYMBOL = Symbol.for("
|
|
1
|
+
export const INSTALL_SYMBOL = Symbol.for("kendex.pi-qol.installed");
|
|
2
2
|
export const CONFIG_ID = "@vanillagreen/pi-qol";
|
|
3
3
|
|
|
4
4
|
export const STATUS_KEY = "qol-attachments";
|
|
@@ -10,22 +10,22 @@ export const SESSION_MANAGER_STATUS_KEY = "session-manager";
|
|
|
10
10
|
export const IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".tif", ".tiff", ".heic", ".heif"]);
|
|
11
11
|
export const IMAGE_PATH_PATTERN = /(^|[\s(\[{<"'`])(@?(?:~|\.\.?|\/)[^\s)\]}>"'`]+?\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))(?=$|[\s)\]}>"'`,.;:!?])/gi;
|
|
12
12
|
|
|
13
|
-
export const QUESTION_SERVICE_SYMBOL = Symbol.for("
|
|
14
|
-
export const QOL_NOTIFICATION_SERVICE_SYMBOL = Symbol.for("
|
|
15
|
-
export const
|
|
16
|
-
export const CAVEMAN_BRIDGE_SYMBOL = Symbol.for("
|
|
17
|
-
export const PI_AGENTS_STATUSLINE_SYMBOL = Symbol.for("
|
|
13
|
+
export const QUESTION_SERVICE_SYMBOL = Symbol.for("kendex.pi-questions.service");
|
|
14
|
+
export const QOL_NOTIFICATION_SERVICE_SYMBOL = Symbol.for("kendex.pi-qol.notification-service");
|
|
15
|
+
export const KENDEX_MODAL_LOCK_SYMBOL = Symbol.for("kendex.pi.modal-lock");
|
|
16
|
+
export const CAVEMAN_BRIDGE_SYMBOL = Symbol.for("kendex.pi.caveman");
|
|
17
|
+
export const PI_AGENTS_STATUSLINE_SYMBOL = Symbol.for("kendex.pi-agents-tmux.statusline");
|
|
18
18
|
|
|
19
19
|
export const CAVEMAN_ICON_ACTIVE = "\uee9a";
|
|
20
20
|
export const CAVEMAN_ICON_INACTIVE = "\u{f19e0}";
|
|
21
21
|
|
|
22
|
-
export const THINKING_TIMER_STORE_SYMBOL = Symbol.for("
|
|
23
|
-
export const THINKING_TIMER_PATCH_SYMBOL = Symbol.for("
|
|
24
|
-
export const SESSION_SEARCH_PENDING_SYMBOL = Symbol.for("
|
|
25
|
-
export const PENDING_QUEUE_THEME_PATCH_SYMBOL = Symbol.for("
|
|
26
|
-
export const STATUS_TEXT_ALIGNMENT_PATCH_SYMBOL = Symbol.for("
|
|
22
|
+
export const THINKING_TIMER_STORE_SYMBOL = Symbol.for("kendex.pi-qol.thinking-timer.store");
|
|
23
|
+
export const THINKING_TIMER_PATCH_SYMBOL = Symbol.for("kendex.pi-qol.thinking-timer.patch");
|
|
24
|
+
export const SESSION_SEARCH_PENDING_SYMBOL = Symbol.for("kendex.pi-qol.session-search.pending-context");
|
|
25
|
+
export const PENDING_QUEUE_THEME_PATCH_SYMBOL = Symbol.for("kendex.pi-qol.pending-queue.theme-patch");
|
|
26
|
+
export const STATUS_TEXT_ALIGNMENT_PATCH_SYMBOL = Symbol.for("kendex.pi-qol.status-text-alignment-patch");
|
|
27
27
|
|
|
28
|
-
export const QUESTION_OPENED_EVENT = "
|
|
28
|
+
export const QUESTION_OPENED_EVENT = "kendex:pi-questions:opened";
|
|
29
29
|
export const QUESTION_NOTIFY_DEDUP_MS = 2000;
|
|
30
30
|
|
|
31
31
|
export const DEFAULT_NOTIFICATION_TITLE = "Pi";
|
package/extensions/qol/glyphs.ts
CHANGED
|
@@ -19,14 +19,14 @@ function projectSettingsPath(cwd: string): string {
|
|
|
19
19
|
while (true) {
|
|
20
20
|
const candidate = join(current, ".pi", "settings.json");
|
|
21
21
|
if (existsSync(candidate)) return candidate;
|
|
22
|
-
if (existsSync(join(current, ".pi")) || existsSync(join(current, ".git")) || existsSync(join(current, ".
|
|
22
|
+
if (existsSync(join(current, ".pi")) || existsSync(join(current, ".git")) || existsSync(join(current, ".kendex-lock.json"))) return candidate;
|
|
23
23
|
const parent = dirname(current);
|
|
24
24
|
if (parent === current) return join(resolve(cwd), ".pi", "settings.json");
|
|
25
25
|
current = parent;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const PROJECT_TRUST_SYMBOL = Symbol.for("
|
|
29
|
+
const PROJECT_TRUST_SYMBOL = Symbol.for("kendex.pi.project-trust");
|
|
30
30
|
|
|
31
31
|
interface ProjectTrustRegistry {
|
|
32
32
|
projectSettings?: Map<string, boolean>;
|
|
@@ -72,7 +72,7 @@ function readPackageConfig(packageId: string, cwd?: string): Record<string, unkn
|
|
|
72
72
|
if (!existsSync(settingsPath)) continue;
|
|
73
73
|
try {
|
|
74
74
|
const parsed = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
75
|
-
const config = parsed?.
|
|
75
|
+
const config = parsed?.kendex?.extensionManager?.config?.[packageId];
|
|
76
76
|
if (config && typeof config === "object" && !Array.isArray(config)) Object.assign(merged, config);
|
|
77
77
|
} catch {
|
|
78
78
|
// Ignore malformed optional manager config.
|
|
@@ -2,7 +2,7 @@ import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
|
2
2
|
import type { Message } from "@earendil-works/pi-ai";
|
|
3
3
|
import { complete } from "./pi-ai-compat.js";
|
|
4
4
|
import { BorderedLoader, type ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import {
|
|
5
|
+
import { acquirekendexModalLock } from "./bridges.js";
|
|
6
6
|
import { serializeMessagesForSummary } from "./compaction.js";
|
|
7
7
|
import { HANDOFF_SYSTEM_PROMPT } from "./constants.js";
|
|
8
8
|
import { settingBoolean } from "./settings.js";
|
|
@@ -40,7 +40,7 @@ export async function runHandoff(args: string, ctx: ExtensionCommandContext): Pr
|
|
|
40
40
|
const conversationText = serializeMessagesForSummary(messages);
|
|
41
41
|
const currentSessionFile = ctx.sessionManager.getSessionFile();
|
|
42
42
|
|
|
43
|
-
const releaseModalLock =
|
|
43
|
+
const releaseModalLock = acquirekendexModalLock();
|
|
44
44
|
let result: string | null = null;
|
|
45
45
|
let generationError: unknown;
|
|
46
46
|
try {
|
|
@@ -4,7 +4,7 @@ import { ansiRed } from "./ansi.js";
|
|
|
4
4
|
import { boundedSettingNumber, settingBoolean, settingString } from "./settings.js";
|
|
5
5
|
import { stringifyError } from "./util.js";
|
|
6
6
|
|
|
7
|
-
export const RATE_LIMIT_AUTO_RESUME_EVENT = "
|
|
7
|
+
export const RATE_LIMIT_AUTO_RESUME_EVENT = "kendex:rate-limit";
|
|
8
8
|
export const DEFAULT_RATE_LIMIT_RESUME_MESSAGE = "Hit API rate limit. It has been reset. Continue";
|
|
9
9
|
|
|
10
10
|
const MAX_TIMER_DELAY_MS = 2_147_000_000;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import { SessionManager, type ExtensionAPI, type ExtensionContext, type Theme } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Text } from "@earendil-works/pi-tui";
|
|
4
|
-
import {
|
|
4
|
+
import { acquirekendexModalLock } from "../bridges.js";
|
|
5
5
|
import { generateQolSummary, serializeMessagesForSummary } from "../compaction.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_SESSION_SEARCH_SUMMARY_INPUT_CHARS,
|
|
@@ -89,7 +89,7 @@ export async function buildSessionSearchContextMessageWithLoader(ctx: ExtensionC
|
|
|
89
89
|
const title = sessionDisplayName(result);
|
|
90
90
|
if (!ctx.hasUI) return buildSessionSearchContextMessage(ctx, result, customPrompt);
|
|
91
91
|
ctx.ui.setStatus(SESSION_SEARCH_STATUS_KEY, `Summarizing ${title}...`);
|
|
92
|
-
const releaseModalLock =
|
|
92
|
+
const releaseModalLock = acquirekendexModalLock();
|
|
93
93
|
let failure: unknown;
|
|
94
94
|
try {
|
|
95
95
|
const message = await ctx.ui.custom<QolSessionSearchPendingMessage | null>((tui: any, theme: any, _kb: any, done: (value: QolSessionSearchPendingMessage | null) => void) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
2
|
+
import { acquirekendexModalLock } from "../bridges.js";
|
|
3
3
|
import { SESSION_SEARCH_CONTEXT_TYPE, SESSION_SEARCH_STATUS_KEY } from "../constants.js";
|
|
4
4
|
import { settingNumber } from "../settings.js";
|
|
5
5
|
import { stringifyError } from "../util.js";
|
|
@@ -122,7 +122,7 @@ export async function openQolSessionSearch(pi: ExtensionAPI, ctx: ExtensionConte
|
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
const sessions = await refreshQolSessionSearchCache(ctx);
|
|
125
|
-
const releaseModalLock =
|
|
125
|
+
const releaseModalLock = acquirekendexModalLock();
|
|
126
126
|
let action: QolSessionPaletteAction | undefined;
|
|
127
127
|
try {
|
|
128
128
|
const currentModel = ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined;
|
|
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { CONFIG_ID } from "./constants.js";
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type kendexConfig = Record<string, unknown>;
|
|
7
7
|
|
|
8
8
|
export function expandHome(input: string): string {
|
|
9
9
|
if (input === "~") return homedir();
|
|
@@ -16,14 +16,14 @@ export function projectSettingsPath(cwd: string): string {
|
|
|
16
16
|
while (true) {
|
|
17
17
|
const candidate = join(current, ".pi", "settings.json");
|
|
18
18
|
if (existsSync(candidate)) return candidate;
|
|
19
|
-
if (existsSync(join(current, ".pi")) || existsSync(join(current, ".git")) || existsSync(join(current, ".
|
|
19
|
+
if (existsSync(join(current, ".pi")) || existsSync(join(current, ".git")) || existsSync(join(current, ".kendex-lock.json"))) return candidate;
|
|
20
20
|
const parent = dirname(current);
|
|
21
21
|
if (parent === current) return join(resolve(cwd), ".pi", "settings.json");
|
|
22
22
|
current = parent;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const PROJECT_TRUST_SYMBOL = Symbol.for("
|
|
26
|
+
const PROJECT_TRUST_SYMBOL = Symbol.for("kendex.pi.project-trust");
|
|
27
27
|
|
|
28
28
|
interface ProjectTrustRegistry {
|
|
29
29
|
projectSettings?: Map<string, boolean>;
|
|
@@ -63,13 +63,13 @@ export function piSettingsPaths(cwd = process.cwd()): string[] {
|
|
|
63
63
|
return projectSettingsTrusted(project) ? [user, project] : [user];
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
export function
|
|
67
|
-
const merged:
|
|
66
|
+
export function readkendexConfig(cwd?: string): kendexConfig {
|
|
67
|
+
const merged: kendexConfig = {};
|
|
68
68
|
for (const path of piSettingsPaths(cwd)) {
|
|
69
69
|
if (!existsSync(path)) continue;
|
|
70
70
|
try {
|
|
71
71
|
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
72
|
-
const config = parsed?.
|
|
72
|
+
const config = parsed?.kendex?.extensionManager?.config?.[CONFIG_ID];
|
|
73
73
|
if (config && typeof config === "object" && !Array.isArray(config)) Object.assign(merged, config);
|
|
74
74
|
} catch {
|
|
75
75
|
// Ignore malformed optional manager config.
|
|
@@ -79,17 +79,17 @@ export function readVstackConfig(cwd?: string): VstackConfig {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function settingBoolean(key: string, fallback: boolean, cwd?: string): boolean {
|
|
82
|
-
const value =
|
|
82
|
+
const value = readkendexConfig(cwd)[key];
|
|
83
83
|
return typeof value === "boolean" ? value : fallback;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export function settingString(key: string, fallback: string, cwd?: string): string {
|
|
87
|
-
const value =
|
|
87
|
+
const value = readkendexConfig(cwd)[key];
|
|
88
88
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
export function settingStringAllowEmpty(key: string, fallback: string, cwd?: string): string {
|
|
92
|
-
const value =
|
|
92
|
+
const value = readkendexConfig(cwd)[key];
|
|
93
93
|
return typeof value === "string" ? value.trim() : fallback;
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -99,7 +99,7 @@ export function newlineFallbackKey(cwd?: string): "ctrl+j" | "none" {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
export function settingNumber(key: string, fallback: number, cwd?: string): number {
|
|
102
|
-
const value =
|
|
102
|
+
const value = readkendexConfig(cwd)[key];
|
|
103
103
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
|
|
104
104
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
105
105
|
}
|
package/extensions/qol.ts
CHANGED
|
@@ -924,7 +924,7 @@ export default function qol(pi: ExtensionAPI): void {
|
|
|
924
924
|
|
|
925
925
|
const tryOpenExtensionManagerSettings = async (ctx: ExtensionCommandContext): Promise<boolean> => {
|
|
926
926
|
const host = globalThis as unknown as Record<PropertyKey, unknown>;
|
|
927
|
-
const openQuickSettings = host[Symbol.for("
|
|
927
|
+
const openQuickSettings = host[Symbol.for("kendex.pi.extension-manager.open-quick-settings")];
|
|
928
928
|
if (typeof openQuickSettings !== "function") return false;
|
|
929
929
|
try {
|
|
930
930
|
await (openQuickSettings as (ctx: ExtensionCommandContext, hint?: string) => Promise<void>)(ctx, "pi-qol");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vanillagreen/pi-qol",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Pi quality-of-life extension: compact statusline/π prompt, reliable multiline input, styled pasted-image chips, session naming/search/context import, scheduled prompts, handoff, permission prompts, notifications, custom compaction, and a collapsed-thinking timer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"extensions": [
|
|
15
15
|
"./extensions/qol.ts"
|
|
16
16
|
],
|
|
17
|
-
"image": "https://raw.githubusercontent.com/vanillagreencom/
|
|
17
|
+
"image": "https://raw.githubusercontent.com/vanillagreencom/kendex/main/pi-extensions/pi-qol/assets/settings-panel.png"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"test": "bun test ./tests"
|
|
21
21
|
},
|
|
22
|
-
"
|
|
22
|
+
"kendex": {
|
|
23
23
|
"extensionManager": {
|
|
24
24
|
"displayName": "QOL",
|
|
25
25
|
"settings": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
{
|
|
37
37
|
"key": "glyphStyle",
|
|
38
38
|
"label": "Glyph style",
|
|
39
|
-
"description": "Glyphs for
|
|
39
|
+
"description": "Glyphs for kendex-owned UI chrome. Unicode is the default; ASCII uses plain box/status/separator characters for terminal compatibility. pi-tool-renderer's global override wins when set.",
|
|
40
40
|
"type": "enum",
|
|
41
41
|
"enumValues": [
|
|
42
42
|
"unicode",
|
|
@@ -911,7 +911,7 @@
|
|
|
911
911
|
{
|
|
912
912
|
"key": "compaction.handoffArtifactEnabled",
|
|
913
913
|
"label": "Write pre-compaction handoff artifact",
|
|
914
|
-
"description": "When enabled, write a JSON handoff artifact under ~/.pi/agent/
|
|
914
|
+
"description": "When enabled, write a JSON handoff artifact under ~/.pi/agent/kendex/sessions/<session>/pi-qol/handoff/ containing the previous summary, last task state, and recently-referenced file/artifact paths. Each write creates a stamped file and a latest.json pointer. Applies to every budget-guard compaction (regardless of compaction.customEnabled), and to manual/idle compactions only when compaction.customEnabled is on. Write failures surface a QOL warning and a handoffArtifactError field in the compaction details.",
|
|
915
915
|
"type": "boolean",
|
|
916
916
|
"default": true,
|
|
917
917
|
"category": "Compaction Budget Guard",
|
|
@@ -976,12 +976,12 @@
|
|
|
976
976
|
],
|
|
977
977
|
"repository": {
|
|
978
978
|
"type": "git",
|
|
979
|
-
"url": "git+https://github.com/vanillagreencom/
|
|
979
|
+
"url": "git+https://github.com/vanillagreencom/kendex.git",
|
|
980
980
|
"directory": "pi-extensions/pi-qol"
|
|
981
981
|
},
|
|
982
|
-
"homepage": "https://github.com/vanillagreencom/
|
|
982
|
+
"homepage": "https://github.com/vanillagreencom/kendex/tree/main/pi-extensions/pi-qol",
|
|
983
983
|
"bugs": {
|
|
984
|
-
"url": "https://github.com/vanillagreencom/
|
|
984
|
+
"url": "https://github.com/vanillagreencom/kendex/issues"
|
|
985
985
|
},
|
|
986
986
|
"author": "vanillagreen",
|
|
987
987
|
"publishConfig": {
|