@pi-unipi/core 0.1.16 → 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/constants.ts +28 -7
- package/events.ts +39 -3
- package/global-types.ts +46 -0
- package/global.d.ts +23 -0
- package/package.json +1 -1
- package/sandbox.ts +61 -13
package/constants.ts
CHANGED
|
@@ -38,6 +38,7 @@ export const MODULES = {
|
|
|
38
38
|
FOOTER: "@pi-unipi/footer",
|
|
39
39
|
UPDATER: "@pi-unipi/updater",
|
|
40
40
|
INPUT_SHORTCUTS: "@pi-unipi/input-shortcuts",
|
|
41
|
+
COCOINDEX: "@pi-unipi/cocoindex",
|
|
41
42
|
} as const;
|
|
42
43
|
|
|
43
44
|
/** Workflow command names */
|
|
@@ -215,6 +216,11 @@ export const MCP_DEFAULTS = {
|
|
|
215
216
|
TOOL_NAME_SEPARATOR: "__",
|
|
216
217
|
} as const;
|
|
217
218
|
|
|
219
|
+
/** Compactor sentinel — when passed as customInstructions to ctx.compact(),
|
|
220
|
+
* the compactor extension recognizes it and uses its zero-LLM pipeline.
|
|
221
|
+
* Other extensions can use this to trigger compactor-aware compaction. */
|
|
222
|
+
export const COMPACTOR_INSTRUCTION = "__compactor__" as const;
|
|
223
|
+
|
|
218
224
|
/** Compactor tool names */
|
|
219
225
|
export const COMPACTOR_TOOLS = {
|
|
220
226
|
COMPACT: "compact",
|
|
@@ -222,24 +228,19 @@ export const COMPACTOR_TOOLS = {
|
|
|
222
228
|
CTX_EXECUTE: "ctx_execute",
|
|
223
229
|
CTX_EXECUTE_FILE: "ctx_execute_file",
|
|
224
230
|
CTX_BATCH_EXECUTE: "ctx_batch_execute",
|
|
225
|
-
CTX_INDEX: "ctx_index",
|
|
226
|
-
CTX_SEARCH: "ctx_search",
|
|
227
|
-
CTX_FETCH_AND_INDEX: "ctx_fetch_and_index",
|
|
228
231
|
CTX_STATS: "ctx_stats",
|
|
229
232
|
CTX_DOCTOR: "ctx_doctor",
|
|
230
233
|
} as const;
|
|
231
234
|
|
|
232
235
|
/** Compactor command names */
|
|
233
236
|
export const COMPACTOR_COMMANDS = {
|
|
237
|
+
LOSSLESS_COMPACT: "lossless-compact",
|
|
234
238
|
COMPACT: "compact",
|
|
235
239
|
COMPACT_RECALL: "compact-recall",
|
|
236
240
|
COMPACT_STATS: "compact-stats",
|
|
237
241
|
COMPACT_DOCTOR: "compact-doctor",
|
|
238
242
|
COMPACT_SETTINGS: "compact-settings",
|
|
239
243
|
COMPACT_PRESET: "compact-preset",
|
|
240
|
-
COMPACT_INDEX: "compact-index",
|
|
241
|
-
COMPACT_SEARCH: "compact-search",
|
|
242
|
-
COMPACT_PURGE: "compact-purge",
|
|
243
244
|
} as const;
|
|
244
245
|
|
|
245
246
|
/** Compactor directory paths */
|
|
@@ -334,5 +335,25 @@ export const COMPACTOR_DEFAULTS = {
|
|
|
334
335
|
DEFAULT_TIMEOUT_MS: 30000,
|
|
335
336
|
SESSION_TTL_DAYS: 7,
|
|
336
337
|
CACHE_TTL_HOURS: 24,
|
|
337
|
-
|
|
338
|
+
} as const;
|
|
339
|
+
|
|
340
|
+
/** CocoIndex minimum supported CLI version. */
|
|
341
|
+
export const COCOINDEX_MIN_VERSION = "1.0" as const;
|
|
342
|
+
|
|
343
|
+
/** CocoIndex package spec installed by the interactive installer. */
|
|
344
|
+
export const COCOINDEX_PACKAGE_SPEC = `cocoindex[lancedb]>=${COCOINDEX_MIN_VERSION}` as const;
|
|
345
|
+
|
|
346
|
+
/** CocoIndex tool names */
|
|
347
|
+
export const COCOINDEX_TOOLS = {
|
|
348
|
+
SEARCH: "cocoindex_search",
|
|
349
|
+
STATUS: "cocoindex_status",
|
|
350
|
+
} as const;
|
|
351
|
+
|
|
352
|
+
/** CocoIndex command names */
|
|
353
|
+
export const COCOINDEX_COMMANDS = {
|
|
354
|
+
UPDATE: "cocoindex-update",
|
|
355
|
+
STATUS: "cocoindex-status",
|
|
356
|
+
INIT: "cocoindex-init",
|
|
357
|
+
SETTINGS: "cocoindex-settings",
|
|
358
|
+
SEARCH: "cocoindex-search",
|
|
338
359
|
} as const;
|
package/events.ts
CHANGED
|
@@ -90,6 +90,13 @@ export const UNIPI_EVENTS = {
|
|
|
90
90
|
UPDATE_APPLIED: "unipi:update:applied",
|
|
91
91
|
/** Update error */
|
|
92
92
|
UPDATE_ERROR: "unipi:update:error",
|
|
93
|
+
|
|
94
|
+
/** CocoIndex: update started */
|
|
95
|
+
COCOINDEX_UPDATE_STARTED: "unipi:cocoindex:update:started",
|
|
96
|
+
/** CocoIndex: update completed */
|
|
97
|
+
COCOINDEX_UPDATE_COMPLETED: "unipi:cocoindex:update:completed",
|
|
98
|
+
/** CocoIndex: search performed */
|
|
99
|
+
COCOINDEX_SEARCH_PERFORMED: "unipi:cocoindex:search:performed",
|
|
93
100
|
} as const;
|
|
94
101
|
|
|
95
102
|
/** Payload for MODULE_READY / MODULE_GONE */
|
|
@@ -102,6 +109,8 @@ export interface UnipiModuleEvent {
|
|
|
102
109
|
commands: string[];
|
|
103
110
|
/** Tools registered by this module */
|
|
104
111
|
tools: string[];
|
|
112
|
+
/** Load time in milliseconds (optional) */
|
|
113
|
+
loadTimeMs?: number;
|
|
105
114
|
}
|
|
106
115
|
|
|
107
116
|
/** Payload for WORKFLOW_START / WORKFLOW_END */
|
|
@@ -268,8 +277,6 @@ export interface UnipiCompactorStatsEvent {
|
|
|
268
277
|
compactions: number;
|
|
269
278
|
/** Tokens saved total */
|
|
270
279
|
tokensSaved: number;
|
|
271
|
-
/** Indexed documents count */
|
|
272
|
-
indexedDocs: number;
|
|
273
280
|
/** Sandbox executions count */
|
|
274
281
|
sandboxRuns: number;
|
|
275
282
|
/** Search queries count */
|
|
@@ -368,6 +375,32 @@ export interface UnipiUpdateErrorEvent {
|
|
|
368
375
|
phase: "check" | "install";
|
|
369
376
|
}
|
|
370
377
|
|
|
378
|
+
/** Payload for COCOINDEX_UPDATE_STARTED */
|
|
379
|
+
export interface UnipiCocoindexUpdateStartedEvent {
|
|
380
|
+
/** Project directory being indexed */
|
|
381
|
+
projectDir: string;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Payload for COCOINDEX_UPDATE_COMPLETED */
|
|
385
|
+
export interface UnipiCocoindexUpdateCompletedEvent {
|
|
386
|
+
/** Whether the update succeeded */
|
|
387
|
+
success: boolean;
|
|
388
|
+
/** Number of chunks processed */
|
|
389
|
+
chunksProcessed: number;
|
|
390
|
+
/** Duration in ms */
|
|
391
|
+
durationMs: number;
|
|
392
|
+
/** Error message if failed */
|
|
393
|
+
error?: string;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Payload for COCOINDEX_SEARCH_PERFORMED */
|
|
397
|
+
export interface UnipiCocoindexSearchPerformedEvent {
|
|
398
|
+
/** Search query */
|
|
399
|
+
query: string;
|
|
400
|
+
/** Number of results */
|
|
401
|
+
resultCount: number;
|
|
402
|
+
}
|
|
403
|
+
|
|
371
404
|
/** Payload for NOTIFICATION_SENT */
|
|
372
405
|
export interface UnipiNotificationSentEvent {
|
|
373
406
|
/** Event type that triggered notification */
|
|
@@ -408,4 +441,7 @@ export type UnipiEventPayload =
|
|
|
408
441
|
| UnipiUpdateCheckEvent
|
|
409
442
|
| UnipiUpdateAvailableEvent
|
|
410
443
|
| UnipiUpdateAppliedEvent
|
|
411
|
-
| UnipiUpdateErrorEvent
|
|
444
|
+
| UnipiUpdateErrorEvent
|
|
445
|
+
| UnipiCocoindexUpdateStartedEvent
|
|
446
|
+
| UnipiCocoindexUpdateCompletedEvent
|
|
447
|
+
| UnipiCocoindexSearchPerformedEvent;
|
package/global-types.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unipi/core — Minimal interfaces for global registry objects
|
|
3
|
+
*
|
|
4
|
+
* These interfaces cover the methods that external packages call.
|
|
5
|
+
* The actual implementations live in their respective packages
|
|
6
|
+
* (info-screen, footer, mcp) and may have richer APIs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Stat data shape returned by info data providers */
|
|
10
|
+
export interface StatDataLike {
|
|
11
|
+
value: string;
|
|
12
|
+
detail?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Minimal InfoRegistry interface for external consumers */
|
|
16
|
+
export interface InfoRegistryLike {
|
|
17
|
+
registerGroup(group: {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
icon: string;
|
|
21
|
+
priority: number;
|
|
22
|
+
config: {
|
|
23
|
+
showByDefault: boolean;
|
|
24
|
+
stats: Array<{ id: string; label: string; show: boolean }>;
|
|
25
|
+
};
|
|
26
|
+
dataProvider: () => Promise<Record<string, unknown>>;
|
|
27
|
+
}): void;
|
|
28
|
+
getGroupData(groupId: string): Promise<Record<string, unknown>>;
|
|
29
|
+
getCachedData(groupId: string): Record<string, unknown> | null;
|
|
30
|
+
invalidateCache(groupId: string): void;
|
|
31
|
+
refreshGroup(groupId: string): Record<string, unknown> | null;
|
|
32
|
+
refreshAll(): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Minimal FooterRegistry interface for external consumers */
|
|
36
|
+
export interface FooterRegistryLike {
|
|
37
|
+
registerGroup(group: unknown): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** MCP stats shape exposed via globalThis */
|
|
41
|
+
export interface McpStatsLike {
|
|
42
|
+
serversTotal?: number;
|
|
43
|
+
serversActive?: number;
|
|
44
|
+
serversFailed?: number;
|
|
45
|
+
toolsTotal?: number;
|
|
46
|
+
}
|
package/global.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unipi/core — Global type augmentations
|
|
3
|
+
*
|
|
4
|
+
* Declares `__unipi_*` properties on `globalThis` so packages
|
|
5
|
+
* can access shared registries without `as any` casts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
// eslint-disable-next-line no-var
|
|
10
|
+
var __unipi_info_registry: import("./global-types.js").InfoRegistryLike | undefined;
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line no-var
|
|
13
|
+
var __unipi_footer_registry: import("./global-types.js").FooterRegistryLike | undefined;
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line no-var
|
|
16
|
+
var __unipi_kanboard_registry: unknown;
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line no-var
|
|
19
|
+
var __unipi_mcp_stats: import("./global-types.js").McpStatsLike | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Force this to be treated as a module
|
|
23
|
+
export {};
|
package/package.json
CHANGED
package/sandbox.ts
CHANGED
|
@@ -10,20 +10,40 @@ import { WORKFLOW_COMMANDS } from "./constants.js";
|
|
|
10
10
|
/** Sandbox levels */
|
|
11
11
|
export type SandboxLevel = "read_only" | "brainstorm" | "write_unipi" | "review" | "full";
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Built-in workflow tools used when no active tool list is supplied.
|
|
15
|
+
*
|
|
16
|
+
* Workflow commands should normally call filterToolsForLevel() with the current
|
|
17
|
+
* active tool list. That keeps safe extension tools (memory, ask-user, web,
|
|
18
|
+
* notify, etc.) available while removing only tools that violate the sandbox.
|
|
19
|
+
*/
|
|
20
|
+
const FALLBACK_TOOLS: Record<SandboxLevel, readonly string[]> = {
|
|
21
|
+
/** Only read-only file tools — no bash, no write, no edit */
|
|
16
22
|
read_only: ["read", "grep", "find", "ls"],
|
|
17
|
-
/** Read + constrained write + bash (setup only) — only to .unipi/docs/specs/ */
|
|
23
|
+
/** Read + constrained write + bash (setup only) — only to .unipi/docs/specs/ by instruction */
|
|
18
24
|
brainstorm: ["read", "grep", "find", "ls", "write", "bash"],
|
|
19
25
|
/** Read + write/edit + file discovery — no bash */
|
|
20
26
|
write_unipi: ["read", "write", "edit", "grep", "find", "ls"],
|
|
21
|
-
/** Read + write + bash for git
|
|
27
|
+
/** Read + write/edit + bash for git/checks — no code editing by instruction */
|
|
22
28
|
review: ["read", "write", "edit", "grep", "find", "ls", "bash"],
|
|
23
|
-
/**
|
|
29
|
+
/** Full workflow access */
|
|
24
30
|
full: ["read", "write", "edit", "bash"],
|
|
25
31
|
};
|
|
26
32
|
|
|
33
|
+
/** Tools that are removed from the current active tool set at each level. */
|
|
34
|
+
const BLOCKED_TOOLS: Record<SandboxLevel, readonly string[]> = {
|
|
35
|
+
/** Read-only workflows must not mutate files or run shell commands. */
|
|
36
|
+
read_only: ["write", "edit", "bash"],
|
|
37
|
+
/** Brainstorm may write specs and run limited setup commands, but should not edit existing files. */
|
|
38
|
+
brainstorm: ["edit"],
|
|
39
|
+
/** Planning/docs workflows may write .unipi docs, but should not run shell commands. */
|
|
40
|
+
write_unipi: ["bash"],
|
|
41
|
+
/** Review workflows rely on command instructions to constrain writes to reviewer remarks. */
|
|
42
|
+
review: [],
|
|
43
|
+
/** Full workflows do not filter active tools. */
|
|
44
|
+
full: [],
|
|
45
|
+
};
|
|
46
|
+
|
|
27
47
|
/** Command to sandbox level mapping */
|
|
28
48
|
const COMMAND_SANDBOX: Record<string, SandboxLevel> = {
|
|
29
49
|
[WORKFLOW_COMMANDS.BRAINSTORM]: "brainstorm",
|
|
@@ -56,25 +76,53 @@ export function getSandboxLevel(commandName: string): SandboxLevel {
|
|
|
56
76
|
}
|
|
57
77
|
|
|
58
78
|
/**
|
|
59
|
-
* Get
|
|
79
|
+
* Get fallback tools for a sandbox level.
|
|
80
|
+
*
|
|
81
|
+
* Prefer filterToolsForLevel(level, activeTools) when applying a sandbox so
|
|
82
|
+
* extension tools are preserved unless explicitly blocked.
|
|
60
83
|
*/
|
|
61
84
|
export function getToolsForLevel(level: SandboxLevel): readonly string[] {
|
|
62
|
-
return
|
|
85
|
+
return FALLBACK_TOOLS[level];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get tool names explicitly blocked by a sandbox level.
|
|
90
|
+
*/
|
|
91
|
+
export function getBlockedToolsForLevel(level: SandboxLevel): readonly string[] {
|
|
92
|
+
return BLOCKED_TOOLS[level];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Filter the current active tool set for a sandbox level.
|
|
97
|
+
*
|
|
98
|
+
* This preserves safe extension tools (memory_search, memory_store, ask_user,
|
|
99
|
+
* web tools, notifications, etc.) instead of replacing the tool list with a
|
|
100
|
+
* small built-in allow-list. Only tools that violate the level are removed.
|
|
101
|
+
*/
|
|
102
|
+
export function filterToolsForLevel(
|
|
103
|
+
level: SandboxLevel,
|
|
104
|
+
activeTools: readonly string[],
|
|
105
|
+
): readonly string[] {
|
|
106
|
+
const blocked = new Set(BLOCKED_TOOLS[level]);
|
|
107
|
+
return activeTools.filter((tool) => !blocked.has(tool));
|
|
63
108
|
}
|
|
64
109
|
|
|
65
110
|
/**
|
|
66
111
|
* Get allowed tools for a command.
|
|
67
112
|
*/
|
|
68
|
-
export function getToolsForCommand(
|
|
113
|
+
export function getToolsForCommand(
|
|
114
|
+
commandName: string,
|
|
115
|
+
activeTools?: readonly string[],
|
|
116
|
+
): readonly string[] {
|
|
69
117
|
const level = getSandboxLevel(commandName);
|
|
70
|
-
return getToolsForLevel(level);
|
|
118
|
+
return activeTools ? filterToolsForLevel(level, activeTools) : getToolsForLevel(level);
|
|
71
119
|
}
|
|
72
120
|
|
|
73
121
|
/**
|
|
74
122
|
* Check if a tool is allowed at a sandbox level.
|
|
75
123
|
*/
|
|
76
124
|
export function isToolAllowed(level: SandboxLevel, toolName: string): boolean {
|
|
77
|
-
return
|
|
125
|
+
return !BLOCKED_TOOLS[level].includes(toolName);
|
|
78
126
|
}
|
|
79
127
|
|
|
80
128
|
/**
|
|
@@ -82,7 +130,7 @@ export function isToolAllowed(level: SandboxLevel, toolName: string): boolean {
|
|
|
82
130
|
*/
|
|
83
131
|
export function hasWriteAccess(commandName: string): boolean {
|
|
84
132
|
const level = getSandboxLevel(commandName);
|
|
85
|
-
return level
|
|
133
|
+
return !BLOCKED_TOOLS[level].includes("write");
|
|
86
134
|
}
|
|
87
135
|
|
|
88
136
|
/**
|
|
@@ -90,5 +138,5 @@ export function hasWriteAccess(commandName: string): boolean {
|
|
|
90
138
|
*/
|
|
91
139
|
export function hasBashAccess(commandName: string): boolean {
|
|
92
140
|
const level = getSandboxLevel(commandName);
|
|
93
|
-
return level
|
|
141
|
+
return !BLOCKED_TOOLS[level].includes("bash");
|
|
94
142
|
}
|