pi-ui-extend 0.1.13 → 0.1.15
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 +1 -1
- package/dist/app/app.d.ts +5 -0
- package/dist/app/app.js +82 -12
- package/dist/app/commands/command-controller.js +1 -0
- package/dist/app/commands/command-host.d.ts +3 -0
- package/dist/app/commands/command-model-actions.d.ts +2 -0
- package/dist/app/commands/command-model-actions.js +40 -4
- package/dist/app/commands/command-navigation-actions.js +3 -0
- package/dist/app/commands/command-registry.d.ts +1 -0
- package/dist/app/commands/command-registry.js +8 -0
- package/dist/app/extensions/extension-ui-controller.d.ts +16 -5
- package/dist/app/extensions/extension-ui-controller.js +99 -61
- package/dist/app/input/input-action-controller.d.ts +1 -0
- package/dist/app/input/input-action-controller.js +8 -2
- package/dist/app/logger.d.ts +25 -0
- package/dist/app/logger.js +90 -0
- package/dist/app/model/model-usage-status.js +30 -15
- package/dist/app/popup/menu-items-controller.d.ts +2 -0
- package/dist/app/popup/menu-items-controller.js +45 -6
- package/dist/app/popup/popup-action-controller.d.ts +2 -1
- package/dist/app/popup/popup-action-controller.js +7 -4
- package/dist/app/popup/popup-menu-controller.d.ts +36 -23
- package/dist/app/popup/popup-menu-controller.js +68 -322
- package/dist/app/rendering/conversation-entry-renderer.js +3 -3
- package/dist/app/rendering/conversation-viewport.d.ts +10 -2
- package/dist/app/rendering/conversation-viewport.js +157 -16
- package/dist/app/rendering/editor-panels.js +4 -2
- package/dist/app/rendering/popup-menu-renderer.d.ts +50 -0
- package/dist/app/rendering/popup-menu-renderer.js +307 -0
- package/dist/app/rendering/render-controller.js +5 -13
- package/dist/app/rendering/status-line-renderer.d.ts +1 -1
- package/dist/app/rendering/status-line-renderer.js +27 -24
- package/dist/app/rendering/toast-controller.d.ts +11 -3
- package/dist/app/rendering/toast-controller.js +53 -12
- package/dist/app/runtime.d.ts +2 -1
- package/dist/app/runtime.js +20 -10
- package/dist/app/screen/mouse-controller.d.ts +2 -2
- package/dist/app/screen/mouse-controller.js +27 -48
- package/dist/app/screen/screen-styler.d.ts +1 -1
- package/dist/app/screen/screen-styler.js +9 -7
- package/dist/app/screen/scroll-controller.d.ts +11 -9
- package/dist/app/screen/scroll-controller.js +50 -45
- package/dist/app/session/lazy-session-manager.d.ts +11 -0
- package/dist/app/session/lazy-session-manager.js +539 -0
- package/dist/app/session/pix-system-message.d.ts +16 -0
- package/dist/app/session/pix-system-message.js +64 -0
- package/dist/app/session/session-event-controller.d.ts +11 -0
- package/dist/app/session/session-event-controller.js +58 -2
- package/dist/app/session/session-history.d.ts +18 -0
- package/dist/app/session/session-history.js +72 -3
- package/dist/app/session/session-lifecycle-controller.d.ts +6 -2
- package/dist/app/session/session-lifecycle-controller.js +7 -2
- package/dist/app/session/tabs-controller.d.ts +13 -1
- package/dist/app/session/tabs-controller.js +248 -27
- package/dist/app/todo/todo-model.d.ts +3 -1
- package/dist/app/todo/todo-model.js +14 -2
- package/dist/app/types.d.ts +5 -2
- package/dist/app/workspace/workspace-actions-controller.d.ts +2 -0
- package/dist/app/workspace/workspace-actions-controller.js +12 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.js +73 -25
- package/dist/default-pix-config.js +2 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +1 -0
- package/dist/schemas/pi-tools-suite-schema.js +1 -0
- package/dist/schemas/pix-schema.d.ts +2 -1
- package/dist/schemas/pix-schema.js +5 -4
- package/dist/terminal-width.d.ts +2 -0
- package/dist/terminal-width.js +64 -3
- package/external/pi-tools-suite/README.md +1 -0
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +12 -3
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +2 -4
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +2 -2
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +8 -2
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +102 -50
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +81 -2
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +29 -8
- package/external/pi-tools-suite/src/config.ts +8 -0
- package/external/pi-tools-suite/src/dcp/index.ts +16 -1
- package/external/pi-tools-suite/src/dcp/state.ts +35 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +3 -0
- package/external/pi-tools-suite/src/todo/index.ts +181 -11
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +23 -10
- package/external/pi-tools-suite/src/todo/todo.ts +10 -5
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +33 -6
- package/external/pi-tools-suite/src/todo/tool/types.ts +9 -1
- package/external/pi-tools-suite/src/todo/view/format.ts +2 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +2 -1
- package/external/pi-tools-suite/src/usage/index.ts +5 -2
- package/external/pi-tools-suite/src/usage/lib/google.ts +6 -13
- package/package.json +1 -1
- package/schemas/pi-tools-suite.json +4 -0
- package/schemas/pix.json +6 -2
package/dist/config.js
CHANGED
|
@@ -4,9 +4,13 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { applyEdits, modify, parse } from "jsonc-parser";
|
|
5
5
|
import { appIconThemeFromFallbackFlag, appIconThemeOverrideFromEnv, parseAppIconThemeName, resolveAppIconThemeNameFromEnv, } from "./app/icons.js";
|
|
6
6
|
import { DEFAULT_PIX_CONFIG_JSONC } from "./default-pix-config.js";
|
|
7
|
+
const PIX_SCHEMA_URL = "https://unpkg.com/pi-ui-extend/schemas/pix.json";
|
|
7
8
|
export function getPixConfigPath(homeDir = homedir()) {
|
|
8
9
|
return join(homeDir, ".config", "pi", "pix.jsonc");
|
|
9
10
|
}
|
|
11
|
+
export function getProjectPixConfigPath(cwd) {
|
|
12
|
+
return join(cwd, ".pi", "pix.jsonc");
|
|
13
|
+
}
|
|
10
14
|
const PIX_CONFIG_PATH = getPixConfigPath();
|
|
11
15
|
const DEFAULT_TOOL_RENDERER = {
|
|
12
16
|
default: {
|
|
@@ -68,9 +72,6 @@ const DEFAULT_MODEL_COLORS = {
|
|
|
68
72
|
"antigravity/antigravity-claude-*": "error",
|
|
69
73
|
},
|
|
70
74
|
};
|
|
71
|
-
const DEFAULT_ICON_THEME = {
|
|
72
|
-
name: "nerdFont",
|
|
73
|
-
};
|
|
74
75
|
const DEFAULT_DICTATION = {
|
|
75
76
|
language: "en",
|
|
76
77
|
languages: {
|
|
@@ -164,17 +165,21 @@ function extractDefaultModelConfig(raw) {
|
|
|
164
165
|
return undefined;
|
|
165
166
|
const configured = raw.defaultModel ?? raw.modelDefault;
|
|
166
167
|
if (typeof configured === "string") {
|
|
167
|
-
|
|
168
|
-
return modelRef ? { modelRef } : undefined;
|
|
168
|
+
return normalizeDefaultModelRef(configured);
|
|
169
169
|
}
|
|
170
170
|
if (!isPlainObject(configured))
|
|
171
171
|
return undefined;
|
|
172
172
|
const modelRef = nonEmptyString(configured.modelRef) ?? nonEmptyString(configured.model);
|
|
173
173
|
if (!modelRef)
|
|
174
174
|
return undefined;
|
|
175
|
-
const
|
|
175
|
+
const normalizedModel = normalizeDefaultModelRef(modelRef);
|
|
176
|
+
if (!normalizedModel)
|
|
177
|
+
return undefined;
|
|
178
|
+
const thinking = normalizeDefaultThinking(configured.thinking)
|
|
179
|
+
?? normalizeDefaultThinking(configured.thinkingLevel)
|
|
180
|
+
?? normalizedModel.thinking;
|
|
176
181
|
return {
|
|
177
|
-
modelRef,
|
|
182
|
+
modelRef: normalizedModel.modelRef,
|
|
178
183
|
...(thinking === undefined ? {} : { thinking }),
|
|
179
184
|
};
|
|
180
185
|
}
|
|
@@ -241,6 +246,11 @@ function extractDictationConfig(raw) {
|
|
|
241
246
|
languages,
|
|
242
247
|
} : undefined;
|
|
243
248
|
}
|
|
249
|
+
function extractIgnoreContextFiles(raw) {
|
|
250
|
+
if (!isPlainObject(raw))
|
|
251
|
+
return undefined;
|
|
252
|
+
return typeof raw.ignoreContextFiles === "boolean" ? raw.ignoreContextFiles : undefined;
|
|
253
|
+
}
|
|
244
254
|
function normalizeDictationLanguage(value) {
|
|
245
255
|
if (typeof value !== "string")
|
|
246
256
|
return undefined;
|
|
@@ -253,6 +263,9 @@ function normalizeThinkingLevel(value) {
|
|
|
253
263
|
const normalized = value.trim().toLowerCase();
|
|
254
264
|
return THINKING_LEVELS.includes(normalized) ? normalized : undefined;
|
|
255
265
|
}
|
|
266
|
+
function normalizeDefaultThinking(value) {
|
|
267
|
+
return normalizeThinkingLevel(value);
|
|
268
|
+
}
|
|
256
269
|
function nonEmptyString(value) {
|
|
257
270
|
if (typeof value !== "string")
|
|
258
271
|
return undefined;
|
|
@@ -274,15 +287,29 @@ function defaultPixConfig() {
|
|
|
274
287
|
modelColors: DEFAULT_MODEL_COLORS,
|
|
275
288
|
iconTheme: { name: resolveAppIconThemeNameFromEnv() },
|
|
276
289
|
dictation: DEFAULT_DICTATION,
|
|
290
|
+
ignoreContextFiles: false,
|
|
277
291
|
};
|
|
278
292
|
}
|
|
293
|
+
function pixConfigFromParsed(parsed, fallback = defaultPixConfig()) {
|
|
294
|
+
const toolRenderer = extractToolRendererConfig(parsed) ?? fallback.toolRenderer;
|
|
295
|
+
const outputFilters = extractOutputFiltersConfig(parsed) ?? fallback.outputFilters;
|
|
296
|
+
const defaultModel = extractDefaultModelConfig(parsed) ?? fallback.defaultModel;
|
|
297
|
+
const promptEnhancer = extractPromptEnhancerConfig(parsed) ?? fallback.promptEnhancer;
|
|
298
|
+
const autocomplete = extractAutocompleteConfig(parsed) ?? fallback.autocomplete;
|
|
299
|
+
const modelColors = extractModelColorsConfig(parsed) ?? fallback.modelColors;
|
|
300
|
+
const configuredIconTheme = extractIconThemeConfig(parsed) ?? fallback.iconTheme;
|
|
301
|
+
const iconTheme = { name: appIconThemeOverrideFromEnv() ?? configuredIconTheme.name };
|
|
302
|
+
const dictation = extractDictationConfig(parsed) ?? fallback.dictation;
|
|
303
|
+
const ignoreContextFiles = extractIgnoreContextFiles(parsed) ?? fallback.ignoreContextFiles;
|
|
304
|
+
return { toolRenderer, outputFilters, ...(defaultModel === undefined ? {} : { defaultModel }), promptEnhancer, autocomplete, modelColors, iconTheme, dictation, ignoreContextFiles };
|
|
305
|
+
}
|
|
279
306
|
export function resolveDefaultModelRef(config) {
|
|
280
307
|
const modelRef = config.defaultModel?.modelRef.trim();
|
|
281
308
|
if (!modelRef)
|
|
282
309
|
return undefined;
|
|
283
310
|
const thinking = config.defaultModel?.thinking;
|
|
284
311
|
if (!thinking)
|
|
285
|
-
return modelRef;
|
|
312
|
+
return stripThinkingSuffix(modelRef);
|
|
286
313
|
return `${stripThinkingSuffix(modelRef)}:${thinking}`;
|
|
287
314
|
}
|
|
288
315
|
export function savePixDefaultModel(modelRef) {
|
|
@@ -297,7 +324,7 @@ export function savePixDefaultModel(modelRef) {
|
|
|
297
324
|
return extractDefaultModelConfig(parseJsonc(updated));
|
|
298
325
|
}
|
|
299
326
|
export function savePixDefaultThinking(thinking, fallbackModelRef) {
|
|
300
|
-
const normalizedThinking =
|
|
327
|
+
const normalizedThinking = normalizeDefaultThinking(thinking);
|
|
301
328
|
if (!normalizedThinking)
|
|
302
329
|
return undefined;
|
|
303
330
|
const configPath = PIX_CONFIG_PATH;
|
|
@@ -318,6 +345,21 @@ export function savePixAutocompleteModel(modelRef) {
|
|
|
318
345
|
writeFileSync(configPath, updated);
|
|
319
346
|
return extractAutocompleteConfig(parseJsonc(updated)) ?? { ...DEFAULT_AUTOCOMPLETE, modelRef: modelRef.trim() };
|
|
320
347
|
}
|
|
348
|
+
export function saveProjectPixIgnoreContextFiles(cwd, ignoreContextFiles) {
|
|
349
|
+
const configPath = getProjectPixConfigPath(cwd);
|
|
350
|
+
const source = existsSync(configPath) ? readFileSync(configPath, "utf8") : `{
|
|
351
|
+
"$schema": "${PIX_SCHEMA_URL}"
|
|
352
|
+
}
|
|
353
|
+
`;
|
|
354
|
+
const updated = upsertPixIgnoreContextFilesInJsonc(source, ignoreContextFiles);
|
|
355
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
356
|
+
writeFileSync(configPath, updated);
|
|
357
|
+
return extractIgnoreContextFiles(parseJsonc(updated)) ?? ignoreContextFiles;
|
|
358
|
+
}
|
|
359
|
+
export function upsertPixIgnoreContextFilesInJsonc(source, ignoreContextFiles) {
|
|
360
|
+
const formattingOptions = { insertSpaces: true, tabSize: 2 };
|
|
361
|
+
return applyEdits(source, modify(source, ["ignoreContextFiles"], ignoreContextFiles, { formattingOptions }));
|
|
362
|
+
}
|
|
321
363
|
export function upsertPixDefaultModelInJsonc(source, modelRef) {
|
|
322
364
|
const normalized = normalizeDefaultModelRef(modelRef);
|
|
323
365
|
if (!normalized)
|
|
@@ -332,7 +374,7 @@ export function upsertPixDefaultModelInJsonc(source, modelRef) {
|
|
|
332
374
|
return upsertPixDefaultModelObjectInJsonc(source, parsed, next);
|
|
333
375
|
}
|
|
334
376
|
export function upsertPixDefaultThinkingInJsonc(source, thinking, fallbackModelRef) {
|
|
335
|
-
const normalizedThinking =
|
|
377
|
+
const normalizedThinking = normalizeDefaultThinking(thinking);
|
|
336
378
|
if (!normalizedThinking)
|
|
337
379
|
return source;
|
|
338
380
|
const parsed = parseJsonc(source);
|
|
@@ -370,7 +412,7 @@ function normalizeDefaultModelRef(modelRef) {
|
|
|
370
412
|
if (colonIndex <= 0)
|
|
371
413
|
return { modelRef: trimmed };
|
|
372
414
|
const suffix = trimmed.slice(colonIndex + 1);
|
|
373
|
-
const thinking =
|
|
415
|
+
const thinking = normalizeDefaultThinking(suffix);
|
|
374
416
|
return thinking ? { modelRef: trimmed.slice(0, colonIndex), thinking } : { modelRef: trimmed };
|
|
375
417
|
}
|
|
376
418
|
function stripThinkingSuffix(modelRef) {
|
|
@@ -378,7 +420,7 @@ function stripThinkingSuffix(modelRef) {
|
|
|
378
420
|
if (colonIndex <= 0)
|
|
379
421
|
return modelRef;
|
|
380
422
|
const suffix = modelRef.slice(colonIndex + 1);
|
|
381
|
-
return
|
|
423
|
+
return normalizeDefaultThinking(suffix) ? modelRef.slice(0, colonIndex) : modelRef;
|
|
382
424
|
}
|
|
383
425
|
function extractToolRendererRule(value) {
|
|
384
426
|
if (!isPlainObject(value))
|
|
@@ -415,32 +457,38 @@ function ensurePixConfigExists(configPath) {
|
|
|
415
457
|
throw error;
|
|
416
458
|
}
|
|
417
459
|
}
|
|
418
|
-
export function loadPixConfig() {
|
|
460
|
+
export function loadPixConfig(cwd) {
|
|
419
461
|
const configPath = PIX_CONFIG_PATH;
|
|
420
462
|
try {
|
|
421
463
|
ensurePixConfigExists(configPath);
|
|
422
464
|
}
|
|
423
465
|
catch (error) {
|
|
424
466
|
process.stderr.write(`[pix] Failed to create ${configPath}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
425
|
-
return defaultPixConfig();
|
|
467
|
+
return loadProjectPixConfig(cwd, defaultPixConfig());
|
|
426
468
|
}
|
|
427
469
|
try {
|
|
428
470
|
const raw = readFileSync(configPath, "utf8");
|
|
429
471
|
const parsed = parseJsonc(raw);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return
|
|
472
|
+
return loadProjectPixConfig(cwd, pixConfigFromParsed(parsed));
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
process.stderr.write(`[pix] Failed to load ${configPath}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
476
|
+
return loadProjectPixConfig(cwd, defaultPixConfig());
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function loadProjectPixConfig(cwd, fallback) {
|
|
480
|
+
if (!cwd)
|
|
481
|
+
return fallback;
|
|
482
|
+
const configPath = getProjectPixConfigPath(cwd);
|
|
483
|
+
if (!existsSync(configPath))
|
|
484
|
+
return fallback;
|
|
485
|
+
try {
|
|
486
|
+
const raw = readFileSync(configPath, "utf8");
|
|
487
|
+
return pixConfigFromParsed(parseJsonc(raw), fallback);
|
|
440
488
|
}
|
|
441
489
|
catch (error) {
|
|
442
490
|
process.stderr.write(`[pix] Failed to load ${configPath}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
443
|
-
return
|
|
491
|
+
return fallback;
|
|
444
492
|
}
|
|
445
493
|
}
|
|
446
494
|
export function savePixDictationLanguage(language) {
|
|
@@ -2,6 +2,8 @@ export const DEFAULT_PIX_CONFIG_JSONC = String.raw `{
|
|
|
2
2
|
"$schema": "https://unpkg.com/pi-ui-extend/schemas/pix.json",
|
|
3
3
|
// pix renderer configuration
|
|
4
4
|
"defaultModel": { "modelRef": "openai-codex/gpt-5.5", "thinking": "medium" },
|
|
5
|
+
// Disable AGENTS.md / CLAUDE.md discovery for this project when set in <cwd>/.pi/pix.jsonc.
|
|
6
|
+
"ignoreContextFiles": false,
|
|
5
7
|
|
|
6
8
|
"toolRenderer": {
|
|
7
9
|
"default": { "previewLines": 0, "direction": "head", "color": "toolTitle" },
|
|
@@ -9,6 +9,7 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
|
|
|
9
9
|
$schema: Type.TOptional<Type.TString>;
|
|
10
10
|
enabled: Type.TOptional<Type.TBoolean>;
|
|
11
11
|
disabledModules: Type.TOptional<Type.TArray<Type.TString>>;
|
|
12
|
+
todoThinking: Type.TOptional<Type.TBoolean>;
|
|
12
13
|
terminalBell: Type.TOptional<Type.TObject<{
|
|
13
14
|
sound: Type.TOptional<Type.TBoolean>;
|
|
14
15
|
}>>;
|
|
@@ -203,6 +203,7 @@ export const PiToolsSuiteConfigSchema = Type.Object({
|
|
|
203
203
|
$schema: Type.Optional(Type.String({ description: "JSON Schema URL used by editors for validation and autocomplete." })),
|
|
204
204
|
enabled: Type.Optional(Type.Boolean({ description: "Enable or disable the entire pi-tools-suite extension." })),
|
|
205
205
|
disabledModules: Type.Optional(Type.Array(Type.String(), { description: "List of disabled module names (e.g. ['lsp', 'prompt-commands'])." })),
|
|
206
|
+
todoThinking: Type.Optional(Type.Boolean({ description: "Enable per-todo thinking levels and automatic thinking switch/restore when tasks become in-progress/completed." })),
|
|
206
207
|
terminalBell: Type.Optional(TerminalBellConfig),
|
|
207
208
|
dcp: Type.Optional(DcpConfig),
|
|
208
209
|
asyncSubagents: Type.Optional(AsyncSubagentsConfig),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeBox JSON Schema definitions for pix.jsonc (~/.config/pi/pix.jsonc).
|
|
2
|
+
* TypeBox JSON Schema definitions for pix.jsonc (~/.config/pi/pix.jsonc or <cwd>/.pi/pix.jsonc).
|
|
3
3
|
*
|
|
4
4
|
* These schemas describe the _user-facing_ config shape — all fields are optional
|
|
5
5
|
* because the runtime applies generous defaults. The generated JSON Schema files
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { Type, Static } from "typebox";
|
|
9
9
|
export declare const PixConfigSchema: Type.TObject<{
|
|
10
10
|
$schema: Type.TOptional<Type.TString>;
|
|
11
|
+
ignoreContextFiles: Type.TOptional<Type.TBoolean>;
|
|
11
12
|
defaultModel: Type.TOptional<Type.TObject<{
|
|
12
13
|
modelRef: Type.TOptional<Type.TString>;
|
|
13
14
|
thinking: Type.TOptional<Type.TUnion<Type.TLiteral<string>[]>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeBox JSON Schema definitions for pix.jsonc (~/.config/pi/pix.jsonc).
|
|
2
|
+
* TypeBox JSON Schema definitions for pix.jsonc (~/.config/pi/pix.jsonc or <cwd>/.pi/pix.jsonc).
|
|
3
3
|
*
|
|
4
4
|
* These schemas describe the _user-facing_ config shape — all fields are optional
|
|
5
5
|
* because the runtime applies generous defaults. The generated JSON Schema files
|
|
@@ -9,7 +9,7 @@ import { Type } from "typebox";
|
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Shared primitives
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
|
-
const
|
|
12
|
+
const DefaultThinkingSelection = Type.Union(["off", "minimal", "low", "medium", "high", "xhigh"].map((v) => Type.Literal(v)), { description: "Default model thinking budget level." });
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
14
|
// Tool renderer
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
@@ -33,7 +33,7 @@ const OutputFiltersConfig = Type.Object({
|
|
|
33
33
|
}, { description: "Output filter patterns." });
|
|
34
34
|
const DefaultModelConfig = Type.Object({
|
|
35
35
|
modelRef: Type.Optional(Type.String({ description: "Provider/model identifier, e.g. 'openai-codex/gpt-5.4'." })),
|
|
36
|
-
thinking: Type.Optional(
|
|
36
|
+
thinking: Type.Optional(DefaultThinkingSelection),
|
|
37
37
|
}, { description: "Default model selection for new sessions." });
|
|
38
38
|
const PromptEnhancerConfig = Type.Object({
|
|
39
39
|
modelRef: Type.Optional(Type.String({ description: "Model used for prompt enhancement." })),
|
|
@@ -73,6 +73,7 @@ const DictationConfig = Type.Object({
|
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
74
|
export const PixConfigSchema = Type.Object({
|
|
75
75
|
$schema: Type.Optional(Type.String({ description: "JSON Schema URL used by editors for validation and autocomplete." })),
|
|
76
|
+
ignoreContextFiles: Type.Optional(Type.Boolean({ description: "Disable AGENTS.md / CLAUDE.md discovery for sessions started in this project, equivalent to pi --no-context-files." })),
|
|
76
77
|
defaultModel: Type.Optional(DefaultModelConfig),
|
|
77
78
|
toolRenderer: Type.Optional(ToolRendererConfig),
|
|
78
79
|
outputFilters: Type.Optional(OutputFiltersConfig),
|
|
@@ -86,6 +87,6 @@ export const PixConfigSchema = Type.Object({
|
|
|
86
87
|
$id: "https://unpkg.com/pi-ui-extend/schemas/pix.json",
|
|
87
88
|
$schema: "https://json-schema.org/draft-07/schema#",
|
|
88
89
|
title: "Pix Configuration",
|
|
89
|
-
description: "Configuration for the pix terminal renderer (~/.config/pi/pix.jsonc).",
|
|
90
|
+
description: "Configuration for the pix terminal renderer (~/.config/pi/pix.jsonc, with project overrides in <cwd>/.pi/pix.jsonc).",
|
|
90
91
|
additionalProperties: true,
|
|
91
92
|
});
|
package/dist/terminal-width.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare function expandTabs(text: string, tabWidth?: number): string;
|
|
2
2
|
export declare function stringDisplayWidth(text: string): number;
|
|
3
3
|
export declare function sliceByDisplayWidth(text: string, width: number): string;
|
|
4
|
+
export declare function displayIndexForColumn(text: string, column: number): number;
|
|
5
|
+
export declare function sliceByDisplayColumns(text: string, startColumn: number, endColumn: number): string;
|
|
4
6
|
export declare function padOrTrimDisplay(text: string, width: number): string;
|
|
5
7
|
export declare function wrapDisplayLine(text: string, width: number): string[];
|
|
6
8
|
export declare function wrapDisplayLineByWords(text: string, width: number): string[];
|
package/dist/terminal-width.js
CHANGED
|
@@ -4,6 +4,8 @@ const EMOJI_PRESENTATION_REGEX = /\p{Emoji_Presentation}/u;
|
|
|
4
4
|
const EMOJI_REGEX = /\p{Emoji}/u;
|
|
5
5
|
const GRAPHEME_SEGMENTER = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(undefined, { granularity: "grapheme" }) : undefined;
|
|
6
6
|
export function expandTabs(text, tabWidth = TAB_WIDTH) {
|
|
7
|
+
if (!text.includes("\t"))
|
|
8
|
+
return text;
|
|
7
9
|
let result = "";
|
|
8
10
|
let column = 0;
|
|
9
11
|
for (const cluster of displayClusters(text)) {
|
|
@@ -29,6 +31,8 @@ export function expandTabs(text, tabWidth = TAB_WIDTH) {
|
|
|
29
31
|
return result;
|
|
30
32
|
}
|
|
31
33
|
export function stringDisplayWidth(text) {
|
|
34
|
+
if (isPrintableAscii(text))
|
|
35
|
+
return text.length;
|
|
32
36
|
let width = 0;
|
|
33
37
|
for (const cluster of displayClusters(text)) {
|
|
34
38
|
width += cluster.width;
|
|
@@ -37,6 +41,8 @@ export function stringDisplayWidth(text) {
|
|
|
37
41
|
}
|
|
38
42
|
export function sliceByDisplayWidth(text, width) {
|
|
39
43
|
const safeWidth = Math.max(0, width);
|
|
44
|
+
if (isPrintableAscii(text))
|
|
45
|
+
return text.slice(0, safeWidth);
|
|
40
46
|
let result = "";
|
|
41
47
|
let used = 0;
|
|
42
48
|
let sawAnsi = false;
|
|
@@ -58,13 +64,41 @@ export function sliceByDisplayWidth(text, width) {
|
|
|
58
64
|
return `${result}${ANSI_RESET}`;
|
|
59
65
|
return result;
|
|
60
66
|
}
|
|
67
|
+
export function displayIndexForColumn(text, column) {
|
|
68
|
+
const targetColumn = Math.max(1, column);
|
|
69
|
+
let displayColumn = 1;
|
|
70
|
+
for (const cluster of indexedDisplayClusters(text)) {
|
|
71
|
+
if (targetColumn <= displayColumn)
|
|
72
|
+
return cluster.start;
|
|
73
|
+
if (cluster.ansi || cluster.width <= 0)
|
|
74
|
+
continue;
|
|
75
|
+
const nextColumn = displayColumn + cluster.width;
|
|
76
|
+
if (targetColumn < nextColumn)
|
|
77
|
+
return cluster.start;
|
|
78
|
+
if (targetColumn === nextColumn)
|
|
79
|
+
return cluster.end;
|
|
80
|
+
displayColumn = nextColumn;
|
|
81
|
+
}
|
|
82
|
+
return text.length;
|
|
83
|
+
}
|
|
84
|
+
export function sliceByDisplayColumns(text, startColumn, endColumn) {
|
|
85
|
+
const startIndex = displayIndexForColumn(text, startColumn);
|
|
86
|
+
const endIndex = Math.max(startIndex, displayIndexForColumn(text, endColumn));
|
|
87
|
+
return text.slice(startIndex, endIndex);
|
|
88
|
+
}
|
|
61
89
|
export function padOrTrimDisplay(text, width) {
|
|
62
90
|
const safeWidth = Math.max(0, width);
|
|
91
|
+
if (isPrintableAscii(text)) {
|
|
92
|
+
const trimmed = text.slice(0, safeWidth);
|
|
93
|
+
return `${trimmed}${" ".repeat(Math.max(0, safeWidth - trimmed.length))}`;
|
|
94
|
+
}
|
|
63
95
|
const trimmed = sliceByDisplayWidth(text, safeWidth);
|
|
64
96
|
return `${trimmed}${" ".repeat(Math.max(0, safeWidth - stringDisplayWidth(trimmed)))}`;
|
|
65
97
|
}
|
|
66
98
|
export function wrapDisplayLine(text, width) {
|
|
67
99
|
const safeWidth = Math.max(1, width);
|
|
100
|
+
if (isPrintableAscii(text))
|
|
101
|
+
return wrapPrintableAsciiLine(text, safeWidth);
|
|
68
102
|
const chunks = [];
|
|
69
103
|
let chunk = "";
|
|
70
104
|
let chunkWidth = 0;
|
|
@@ -152,6 +186,23 @@ function appendTokenToEmptyChunk(token, width, chunks) {
|
|
|
152
186
|
function trimTrailingWhitespace(text) {
|
|
153
187
|
return text.replace(/\s+$/u, "");
|
|
154
188
|
}
|
|
189
|
+
function isPrintableAscii(text) {
|
|
190
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
191
|
+
const code = text.charCodeAt(index);
|
|
192
|
+
if (code < 0x20 || code > 0x7e)
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
function wrapPrintableAsciiLine(text, width) {
|
|
198
|
+
if (text.length <= width)
|
|
199
|
+
return [text];
|
|
200
|
+
const chunks = [];
|
|
201
|
+
for (let start = 0; start < text.length; start += width) {
|
|
202
|
+
chunks.push(text.slice(start, start + width));
|
|
203
|
+
}
|
|
204
|
+
return chunks;
|
|
205
|
+
}
|
|
155
206
|
function ansiSequenceLength(text, index) {
|
|
156
207
|
if (text.charCodeAt(index) !== 0x1b)
|
|
157
208
|
return 0;
|
|
@@ -179,29 +230,39 @@ function ansiSequenceLength(text, index) {
|
|
|
179
230
|
return 2;
|
|
180
231
|
}
|
|
181
232
|
function* displayClusters(text) {
|
|
233
|
+
for (const cluster of indexedDisplayClusters(text)) {
|
|
234
|
+
yield { text: cluster.text, width: cluster.width, ansi: cluster.ansi };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function* indexedDisplayClusters(text) {
|
|
182
238
|
for (let index = 0; index < text.length;) {
|
|
183
239
|
const ansiLength = ansiSequenceLength(text, index);
|
|
184
240
|
if (ansiLength > 0) {
|
|
241
|
+
const start = index;
|
|
185
242
|
const cluster = text.slice(index, index + ansiLength);
|
|
186
|
-
yield { text: cluster, width: 0, ansi: true };
|
|
187
243
|
index += ansiLength;
|
|
244
|
+
yield { text: cluster, width: 0, ansi: true, start, end: index };
|
|
188
245
|
continue;
|
|
189
246
|
}
|
|
190
247
|
const nextAnsiIndex = text.indexOf("\x1b", index + 1);
|
|
191
248
|
const textEnd = nextAnsiIndex === -1 ? text.length : nextAnsiIndex;
|
|
192
249
|
const segment = text.slice(index, textEnd);
|
|
193
250
|
if (GRAPHEME_SEGMENTER) {
|
|
251
|
+
let segmentOffset = index;
|
|
194
252
|
for (const { segment: cluster } of GRAPHEME_SEGMENTER.segment(segment)) {
|
|
195
|
-
|
|
253
|
+
const start = segmentOffset;
|
|
254
|
+
segmentOffset += cluster.length;
|
|
255
|
+
yield { text: cluster, width: graphemeDisplayWidth(cluster), ansi: false, start, end: segmentOffset };
|
|
196
256
|
}
|
|
197
257
|
index = textEnd;
|
|
198
258
|
continue;
|
|
199
259
|
}
|
|
200
260
|
while (index < textEnd) {
|
|
261
|
+
const start = index;
|
|
201
262
|
const codePoint = text.codePointAt(index) ?? 0;
|
|
202
263
|
const cluster = String.fromCodePoint(codePoint);
|
|
203
|
-
yield { text: cluster, width: graphemeDisplayWidth(cluster), ansi: false };
|
|
204
264
|
index += codePointLength(codePoint);
|
|
265
|
+
yield { text: cluster, width: graphemeDisplayWidth(cluster), ansi: false, start, end: index };
|
|
205
266
|
}
|
|
206
267
|
}
|
|
207
268
|
}
|
|
@@ -62,6 +62,7 @@ DCP settings are stored only under `dcp` in the user shared config file `~/.conf
|
|
|
62
62
|
"enabled": true,
|
|
63
63
|
"compress": {
|
|
64
64
|
"minContextPercent": "25%",
|
|
65
|
+
"maxContextPercent": "65%",
|
|
65
66
|
"maxContextLimit": 160000,
|
|
66
67
|
"nudgeFrequency": 1,
|
|
67
68
|
"iterationNudgeThreshold": 8,
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
5
4
|
import { DEFAULT_PROJECT_ID, PROVIDER_ID } from "./constants";
|
|
6
5
|
import type { OpencodeAntigravityAccount, OpencodeAntigravityImportResult, OpencodeAntigravityStorage, PiAuthCredential, PiAuthData } from "./types";
|
|
7
6
|
|
|
7
|
+
export const PI_AUTH_PATH = join(homedir(), ".pi", "agent", "auth.json");
|
|
8
|
+
|
|
9
|
+
function testPiAuthPath(): string | undefined {
|
|
10
|
+
return process.env.NODE_ENV === "test" ? process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH : undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
export function splitRefresh(refresh: string): { refreshToken: string; projectId?: string; managedProjectId?: string } {
|
|
9
14
|
const [refreshToken = "", projectId = "", managedProjectId = ""] = refresh.split("|");
|
|
10
15
|
return {
|
|
@@ -33,13 +38,17 @@ export function decodeApiKey(apiKey: string): { access: string; projectId?: stri
|
|
|
33
38
|
return { access, projectId: projectId || undefined };
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
function getDefaultOpencodeAccountsPath(): string {
|
|
41
|
+
export function getDefaultOpencodeAccountsPath(): string {
|
|
37
42
|
const configDir = process.env.OPENCODE_CONFIG_DIR ?? join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "opencode");
|
|
38
43
|
return join(configDir, "antigravity-accounts.json");
|
|
39
44
|
}
|
|
40
45
|
|
|
46
|
+
export async function importDefaultOpencodeAntigravityAccount(options: { overwrite?: boolean } = {}): Promise<OpencodeAntigravityImportResult> {
|
|
47
|
+
return importOpencodeAntigravityAccount({ sourcePath: getDefaultOpencodeAccountsPath(), authPath: getPiAuthPath(), overwrite: options.overwrite });
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
export function getPiAuthPath(): string {
|
|
42
|
-
return
|
|
51
|
+
return testPiAuthPath() ?? PI_AUTH_PATH;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
export async function readJsonFile<T>(path: string, fallback: T): Promise<T> {
|
|
@@ -40,17 +40,15 @@ export function formatImportResult(result: OpencodeAntigravityImportResult): str
|
|
|
40
40
|
return `Could not import Antigravity auth from ${result.sourcePath}: ${result.reason ?? "unknown error"}.`;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export function parseAddAccountCommandArgs(args: string): { activate?: boolean; email?: string
|
|
43
|
+
export function parseAddAccountCommandArgs(args: string): { activate?: boolean; email?: string } {
|
|
44
44
|
const tokens = tokenizeArgs(args);
|
|
45
|
-
const parsed: { activate?: boolean; email?: string
|
|
45
|
+
const parsed: { activate?: boolean; email?: string } = {};
|
|
46
46
|
for (let i = 0; i < tokens.length; i += 1) {
|
|
47
47
|
const token = tokens[i];
|
|
48
48
|
if (token === "--activate" || token === "-a") {
|
|
49
49
|
parsed.activate = true;
|
|
50
50
|
} else if (token === "--email" && tokens[i + 1]) {
|
|
51
51
|
parsed.email = tokens[++i];
|
|
52
|
-
} else if (token === "--auth-path" && tokens[i + 1]) {
|
|
53
|
-
parsed.authPath = tokens[++i];
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
return parsed;
|
|
@@ -4,8 +4,8 @@ export const STATUS_KEY = "dcp:antigravity";
|
|
|
4
4
|
export const LEGACY_STATUS_KEY = "antigravity";
|
|
5
5
|
export const ALL_ACCOUNTS_EXHAUSTED_MARKER = "ANTIGRAVITY_ALL_ACCOUNTS_EXHAUSTED";
|
|
6
6
|
|
|
7
|
-
export const CLIENT_ID =
|
|
8
|
-
export const CLIENT_SECRET =
|
|
7
|
+
export const CLIENT_ID = "";
|
|
8
|
+
export const CLIENT_SECRET = "";
|
|
9
9
|
export const REDIRECT_URI = "http://localhost:51121/oauth-callback";
|
|
10
10
|
export const SCOPES = [
|
|
11
11
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
@@ -4,7 +4,7 @@ import { formatAddAccountResult, formatImportResult, parseAddAccountCommandArgs,
|
|
|
4
4
|
import { API_ID, DEFAULT_PROJECT_ID, ENDPOINT_DAILY, PROVIDER_ID } from "./constants";
|
|
5
5
|
import { modelDefinitions } from "./models";
|
|
6
6
|
import { addAntigravityAccount, loginAntigravity, refreshAntigravityToken } from "./oauth";
|
|
7
|
-
import { emitAntigravityStatus, getCurrentAntigravityStatus, publishAntigravityAuthStartupSection, rememberAntigravityApi, rememberAntigravityUi } from "./status";
|
|
7
|
+
import { emitAntigravityStatus, getCurrentAntigravityStatus, notifyAntigravityLoginFailure, notifyAntigravityProviderFailure, publishAntigravityAuthStartupSection, rememberAntigravityApi, rememberAntigravityUi } from "./status";
|
|
8
8
|
import { streamAntigravity } from "./stream";
|
|
9
9
|
|
|
10
10
|
export { importOpencodeAntigravityAccount } from "./auth-store";
|
|
@@ -22,6 +22,12 @@ export default async function antigravityAuth(pi: ExtensionAPI): Promise<void> {
|
|
|
22
22
|
pi.on("before_provider_request", (_event, ctx) => {
|
|
23
23
|
rememberAntigravityUi(ctx.ui);
|
|
24
24
|
});
|
|
25
|
+
pi.on("message_end", (event, ctx) => {
|
|
26
|
+
rememberAntigravityUi(ctx.ui);
|
|
27
|
+
const message = event.message;
|
|
28
|
+
if (message.role !== "assistant" || message.provider !== PROVIDER_ID || message.stopReason !== "error" || !message.errorMessage) return;
|
|
29
|
+
notifyAntigravityProviderFailure(message.errorMessage, { ui: ctx.ui, model: message.model });
|
|
30
|
+
});
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
pi.registerCommand("antigravity-import", {
|
|
@@ -63,7 +69,7 @@ export default async function antigravityAuth(pi: ExtensionAPI): Promise<void> {
|
|
|
63
69
|
ctx.ui?.notify?.(formatAddAccountResult(result), "info");
|
|
64
70
|
emitAntigravityStatus(await getCurrentAntigravityStatus());
|
|
65
71
|
} catch (error) {
|
|
66
|
-
|
|
72
|
+
notifyAntigravityLoginFailure(error);
|
|
67
73
|
}
|
|
68
74
|
},
|
|
69
75
|
});
|