omni-pi 0.8.2 → 0.9.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/CHANGELOG.md +12 -0
- package/PROVIDERS.md +3 -1
- package/README.md +25 -3
- package/extensions/omni-core/index.ts +22 -0
- package/extensions/omni-providers/index.ts +2 -2
- package/package.json +10 -10
- package/src/commands.ts +12 -0
- package/src/model-command.ts +32 -4
- package/src/model-refresh-state.ts +39 -0
- package/src/model-setup.ts +45 -0
- package/src/repo-map-contracts.ts +93 -0
- package/src/repo-map-index.ts +467 -0
- package/src/repo-map-rank.ts +201 -0
- package/src/repo-map-runtime.ts +120 -0
- package/src/repo-map-store.ts +46 -0
- package/src/rtk.ts +408 -0
- package/src/theme.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.3 - 2026-04-17
|
|
4
|
+
|
|
5
|
+
### Model refresh flow
|
|
6
|
+
|
|
7
|
+
- added a custom model refresh flow so newly released provider models can be picked up without repeating setup from scratch
|
|
8
|
+
- stored refresh state separately so daily checks can detect when a refresh is needed and avoid redundant prompts
|
|
9
|
+
- added coverage for the refresh command, state handling, and daily refresh behavior
|
|
10
|
+
|
|
3
11
|
## 0.8.2 - 2026-04-07
|
|
4
12
|
|
|
5
13
|
### Single-brain runtime
|
|
@@ -23,6 +31,10 @@
|
|
|
23
31
|
- removed the unused `pi-subagents` dependency
|
|
24
32
|
- added npm overrides for `@mozilla/readability`, `brace-expansion`, `picomatch`, and `vite`
|
|
25
33
|
|
|
34
|
+
## 0.8.1 - 2026-04-07
|
|
35
|
+
|
|
36
|
+
- blocked Anthropic oAuth login to avoid bans from recent policy changes on the Claude Code subscription ToS
|
|
37
|
+
|
|
26
38
|
## 0.8.0 - 2026-04-06
|
|
27
39
|
|
|
28
40
|
### Runtime and UX
|
package/PROVIDERS.md
CHANGED
|
@@ -62,7 +62,9 @@ The bundled-provider list below is expected to stay in sync with the exported pr
|
|
|
62
62
|
|
|
63
63
|
For custom providers that expose a compatible model listing endpoint, Omni-Pi can fetch models for you after you add the provider details and credentials.
|
|
64
64
|
|
|
65
|
-
On launch, Omni-Pi
|
|
65
|
+
On launch, Omni-Pi refreshes authenticated, discoverable custom providers that are already configured in `models.json` at most once per day.
|
|
66
|
+
|
|
67
|
+
You can also run `/model-setup refresh` to re-discover those custom provider models on demand.
|
|
66
68
|
|
|
67
69
|
## When To Use Which Path
|
|
68
70
|
|
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Requires Node.js 22 or newer.
|
|
|
14
14
|
- `/omni-mode` turns on Omni's specialized interview, plan, build, and verify workflow for the current project.
|
|
15
15
|
- Keeps durable standards and project context in `.omni/`, even when Omni mode is off.
|
|
16
16
|
- Writes specs, tasks, and progress into `.omni/` once Omni mode is enabled.
|
|
17
|
+
- Adds a repo map that indexes supported source files, ranks them by structure plus recent activity, and injects a compact codebase-awareness block into Omni prompts.
|
|
17
18
|
- Bundles web search, guided interviews, themed UI, native micro-UI via Glimpse, a task viewer, a powerbar, custom provider/model management, and automatic updates out of the box.
|
|
18
19
|
|
|
19
20
|
## Install
|
|
@@ -29,7 +30,7 @@ cd your-project
|
|
|
29
30
|
omni
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
Custom provider setup and bundled provider behavior are documented in [PROVIDERS.md](PROVIDERS.md).
|
|
33
|
+
Custom provider setup, refresh behavior, and bundled provider behavior are documented in [PROVIDERS.md](PROVIDERS.md).
|
|
33
34
|
|
|
34
35
|
## Features
|
|
35
36
|
|
|
@@ -41,6 +42,25 @@ Omni-Pi now ships the essential skill-discovery stack in the package itself:
|
|
|
41
42
|
- `skill-creator` is bundled for creating project-specific skills when nothing suitable exists
|
|
42
43
|
- `brainstorming` is bundled and used for Omni planning and task creation flows
|
|
43
44
|
|
|
45
|
+
### Repo Map
|
|
46
|
+
|
|
47
|
+
Omni-Pi now includes a SoulForge-style repo map for codebase awareness while Omni mode is on.
|
|
48
|
+
|
|
49
|
+
The first shipped version includes:
|
|
50
|
+
|
|
51
|
+
- incremental indexing of supported repo files while respecting `.gitignore`
|
|
52
|
+
- symbol/import extraction for TypeScript/JavaScript-family files with graceful fallback for partial/unsupported cases
|
|
53
|
+
- graph-aware ranking blended with current-turn boosts from recent reads, edits, writes, and prompt mentions
|
|
54
|
+
- budget-aware prompt rendering so Omni gets a compact ranked view of important files and exported symbols
|
|
55
|
+
- runtime cache storage under `.pi/repo-map/` rather than durable `.omni/` memory
|
|
56
|
+
|
|
57
|
+
Current deferred roadmap items remain intentional and visible in docs rather than hidden in code:
|
|
58
|
+
|
|
59
|
+
- semantic symbol summaries
|
|
60
|
+
- git co-change ranking
|
|
61
|
+
- richer analysis views such as dead-code or clone-detection signals
|
|
62
|
+
- broader parser/language coverage as needed
|
|
63
|
+
|
|
44
64
|
### Bundled Extensions
|
|
45
65
|
|
|
46
66
|
| Extension | What it does |
|
|
@@ -66,7 +86,7 @@ Omni-Pi now bundles [Glimpse](https://github.com/HazAT/glimpse) for native micro
|
|
|
66
86
|
|
|
67
87
|
| Command | Description |
|
|
68
88
|
|---------|-------------|
|
|
69
|
-
| `/model-setup` | Add
|
|
89
|
+
| `/model-setup` | Add, refresh, or remove custom provider/model entries |
|
|
70
90
|
| `/manage-providers` | Remove stored auth for bundled providers |
|
|
71
91
|
| `/omni-mode` | Toggle persistent Omni mode on or off for this project |
|
|
72
92
|
| `/companion` | Toggle the Glimpse floating companion widget |
|
|
@@ -87,12 +107,13 @@ Omni-Pi checks for new versions on startup (cached, re-checks every 4 hours). Wh
|
|
|
87
107
|
|
|
88
108
|
`/model-setup` is for custom providers and custom model entries only.
|
|
89
109
|
|
|
90
|
-
Use
|
|
110
|
+
Use `/model-setup` when you want to configure:
|
|
91
111
|
|
|
92
112
|
- a custom provider id
|
|
93
113
|
- an API type and base URL
|
|
94
114
|
- an API key for that custom provider
|
|
95
115
|
- discovered models or manual model entries
|
|
116
|
+
- a manual refresh of already configured custom providers
|
|
96
117
|
|
|
97
118
|
Use `/manage-providers` to remove stored auth for bundled Pi providers.
|
|
98
119
|
|
|
@@ -106,6 +127,7 @@ Omni-Pi keeps its current branding and shell at all times, but the specialized w
|
|
|
106
127
|
|
|
107
128
|
- When Omni mode is off, Omni behaves like normal Pi and only uses `.omni/` as passive standards/context when those files already exist.
|
|
108
129
|
- When Omni mode is on, Omni lazily initializes or migrates `.omni/` on the first real turn, then uses the full interview, planning, task, and verification workflow.
|
|
130
|
+
- While Omni mode is on, Omni also maintains a runtime repo map in `.pi/repo-map/` so prompts can include a compact ranked view of important files and symbols.
|
|
109
131
|
- During Omni init, Omni can discover standards from files like `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, Copilot instructions, Cursor rules, Windsurf rules, and Continue rules, then ask whether to keep those standards in Omni's durable memory.
|
|
110
132
|
- In Git repos, Omni ensures `.pi/` is ignored because that directory is only runtime-local Pi state.
|
|
111
133
|
- While Omni mode is on, every planned or executed task checks for required skills, auto-installs matching skills into `.omni/project-skills/`, creates a project skill when none exists, records task-to-skill dependencies, and removes project skills once no open task still needs them.
|
|
@@ -13,12 +13,23 @@ import {
|
|
|
13
13
|
registerPiCommands,
|
|
14
14
|
} from "../../src/pi.js";
|
|
15
15
|
import { registerProviderAuthCommand } from "../../src/provider-auth-command.js";
|
|
16
|
+
import {
|
|
17
|
+
buildRepoMapPromptSuffix,
|
|
18
|
+
registerRepoMapTracking,
|
|
19
|
+
warmRepoMap,
|
|
20
|
+
} from "../../src/repo-map-runtime.js";
|
|
21
|
+
import {
|
|
22
|
+
formatRtkModeStatus,
|
|
23
|
+
refreshRtkStatusIndicator,
|
|
24
|
+
registerRtkBashRouting,
|
|
25
|
+
} from "../../src/rtk.js";
|
|
16
26
|
import {
|
|
17
27
|
createOmniTheme,
|
|
18
28
|
ensurePiSettings,
|
|
19
29
|
formatOmniModeStatus,
|
|
20
30
|
loadSavedTheme,
|
|
21
31
|
readOmniMode,
|
|
32
|
+
readRtkMode,
|
|
22
33
|
} from "../../src/theme.js";
|
|
23
34
|
import { registerThemeCommand } from "../../src/theme-command.js";
|
|
24
35
|
import { registerTodoShortcut } from "../../src/todo-shortcut.js";
|
|
@@ -33,6 +44,8 @@ export default function omniCoreExtension(api: ExtensionAPI): void {
|
|
|
33
44
|
registerThemeCommand(api);
|
|
34
45
|
registerTodoShortcut(api);
|
|
35
46
|
registerUpdater(api);
|
|
47
|
+
registerRtkBashRouting(api);
|
|
48
|
+
registerRepoMapTracking(api);
|
|
36
49
|
|
|
37
50
|
api.on("session_start", async (_event, ctx) => {
|
|
38
51
|
await ensurePiSettings(ctx.cwd);
|
|
@@ -42,6 +55,11 @@ export default function omniCoreExtension(api: ExtensionAPI): void {
|
|
|
42
55
|
ctx.ui.setTheme(createOmniTheme());
|
|
43
56
|
ctx.ui.setHeader((_tui, theme) => renderHeader(theme));
|
|
44
57
|
ctx.ui.setStatus("omni", formatOmniModeStatus(omniMode));
|
|
58
|
+
ctx.ui.setStatus("rtk", formatRtkModeStatus(readRtkMode(ctx.cwd), false));
|
|
59
|
+
await refreshRtkStatusIndicator(ctx);
|
|
60
|
+
if (omniMode) {
|
|
61
|
+
void warmRepoMap(ctx.cwd);
|
|
62
|
+
}
|
|
45
63
|
});
|
|
46
64
|
|
|
47
65
|
api.on("before_agent_start", async (event, ctx) => {
|
|
@@ -62,10 +80,14 @@ export default function omniCoreExtension(api: ExtensionAPI): void {
|
|
|
62
80
|
const onboardingKickoff = init.initResult?.onboardingInterviewNeeded
|
|
63
81
|
? buildOnboardingInterviewKickoff(init.initResult)
|
|
64
82
|
: "";
|
|
83
|
+
const repoMapPrompt = await buildRepoMapPromptSuffix(ctx.cwd, {
|
|
84
|
+
prompt: typeof event.prompt === "string" ? event.prompt : "",
|
|
85
|
+
});
|
|
65
86
|
const prompt = [
|
|
66
87
|
event.systemPrompt,
|
|
67
88
|
passivePrompt,
|
|
68
89
|
workflowPrompt,
|
|
90
|
+
repoMapPrompt,
|
|
69
91
|
onboardingKickoff,
|
|
70
92
|
]
|
|
71
93
|
.filter(Boolean)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
import { disableAnthropicOAuth } from "../../src/anthropic-auth-guard.js";
|
|
4
|
-
import {
|
|
4
|
+
import { refreshAuthenticatedProviderModelsWithDailyGuard } from "../../src/model-setup.js";
|
|
5
5
|
import { registerOmniProviders } from "../../src/providers.js";
|
|
6
6
|
|
|
7
7
|
export default async function omniProvidersExtension(
|
|
@@ -11,6 +11,6 @@ export default async function omniProvidersExtension(
|
|
|
11
11
|
|
|
12
12
|
api.on("session_start", async (_event, ctx) => {
|
|
13
13
|
disableAnthropicOAuth(ctx.modelRegistry);
|
|
14
|
-
await
|
|
14
|
+
await refreshAuthenticatedProviderModelsWithDailyGuard(ctx.modelRegistry);
|
|
15
15
|
});
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omni-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Single-agent Pi package that interviews the user, documents the spec, and implements work in bounded slices.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Eduard-David Gyarmati",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/
|
|
10
|
+
"url": "https://github.com/edgyarmati/Omni-Pi"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/
|
|
12
|
+
"homepage": "https://github.com/edgyarmati/Omni-Pi#readme",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/
|
|
14
|
+
"url": "https://github.com/edgyarmati/Omni-Pi/issues"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=22"
|
|
@@ -78,12 +78,12 @@
|
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@anthropic-ai/claude-agent-sdk": "0.2.84",
|
|
81
|
-
"@juanibiapina/pi-extension-settings": "^0.6.
|
|
82
|
-
"@juanibiapina/pi-powerbar": "^0.
|
|
83
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
84
|
-
"glimpseui": "^0.
|
|
85
|
-
"pi-interview": "^0.
|
|
86
|
-
"pi-web-access": "^0.10.
|
|
81
|
+
"@juanibiapina/pi-extension-settings": "^0.6.1",
|
|
82
|
+
"@juanibiapina/pi-powerbar": "^0.8.0",
|
|
83
|
+
"@mariozechner/pi-coding-agent": "^0.67.68",
|
|
84
|
+
"glimpseui": "^0.7.0",
|
|
85
|
+
"pi-interview": "^0.6.2",
|
|
86
|
+
"pi-web-access": "^0.10.6",
|
|
87
87
|
"zod": "^4.3.6"
|
|
88
88
|
},
|
|
89
89
|
"overrides": {
|
package/src/commands.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AppCommandDefinition } from "./pi.js";
|
|
2
|
+
import { executeRtkCommand } from "./rtk.js";
|
|
2
3
|
import { formatOmniModeStatus, readOmniMode, saveOmniMode } from "./theme.js";
|
|
3
4
|
|
|
4
5
|
export function createOmniCommands(): AppCommandDefinition[] {
|
|
@@ -22,5 +23,16 @@ export function createOmniCommands(): AppCommandDefinition[] {
|
|
|
22
23
|
: "Omni mode is now OFF. Omni will keep using durable standards from .omni/ when present, but task workflow state is disabled.";
|
|
23
24
|
},
|
|
24
25
|
},
|
|
26
|
+
{
|
|
27
|
+
name: "omni-rtk",
|
|
28
|
+
description:
|
|
29
|
+
"Install RTK and control Omni's bash-side RTK routing (status, install, on, off)",
|
|
30
|
+
async execute(context) {
|
|
31
|
+
if (!context.runtime) {
|
|
32
|
+
return "The /omni-rtk command is only available inside Omni-Pi interactive sessions.";
|
|
33
|
+
}
|
|
34
|
+
return await executeRtkCommand(context.args, context.runtime.ctx);
|
|
35
|
+
},
|
|
36
|
+
},
|
|
25
37
|
];
|
|
26
38
|
}
|
package/src/model-command.ts
CHANGED
|
@@ -7,7 +7,10 @@ import type {
|
|
|
7
7
|
} from "@mariozechner/pi-coding-agent";
|
|
8
8
|
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
refreshAuthenticatedProviderModelsWithDailyGuard,
|
|
12
|
+
runModelSetupWizard,
|
|
13
|
+
} from "./model-setup.js";
|
|
11
14
|
import { searchableSelect } from "./searchable-select.js";
|
|
12
15
|
|
|
13
16
|
interface ModelsJsonModel {
|
|
@@ -101,6 +104,23 @@ async function handleAdd(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
101
104
|
ctx.ui.notify(result.summary, "info");
|
|
102
105
|
}
|
|
103
106
|
|
|
107
|
+
async function handleRefresh(ctx: ExtensionCommandContext): Promise<void> {
|
|
108
|
+
const result = await refreshAuthenticatedProviderModelsWithDailyGuard(
|
|
109
|
+
ctx.modelRegistry,
|
|
110
|
+
{ force: true },
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (result.refreshedProviders.length === 0) {
|
|
114
|
+
ctx.ui.notify("No eligible custom providers were refreshed.", "info");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
ctx.ui.notify(
|
|
119
|
+
`Refreshed custom providers: ${result.refreshedProviders.join(", ")}.`,
|
|
120
|
+
"info",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
104
124
|
async function handleList(ctx: ExtensionCommandContext): Promise<void> {
|
|
105
125
|
const config = await readModelsJson();
|
|
106
126
|
const custom = getCustomModels(config);
|
|
@@ -149,21 +169,28 @@ async function handleList(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
149
169
|
|
|
150
170
|
export function registerModelCommand(api: ExtensionAPI): void {
|
|
151
171
|
api.registerCommand("model-setup", {
|
|
152
|
-
description:
|
|
172
|
+
description:
|
|
173
|
+
"Add custom providers/models, refresh discovered models, or remove custom model entries",
|
|
153
174
|
async handler(args: string, ctx: ExtensionCommandContext) {
|
|
154
175
|
const sub = args.trim().toLowerCase();
|
|
155
176
|
|
|
156
177
|
if (sub === "add") return handleAdd(ctx);
|
|
178
|
+
if (sub === "refresh") return handleRefresh(ctx);
|
|
157
179
|
if (sub === "list") return handleList(ctx);
|
|
158
180
|
|
|
159
181
|
const choice = await searchableSelect(ctx.ui, "Model setup:", [
|
|
160
182
|
{
|
|
161
|
-
label: "add
|
|
183
|
+
label: "add — Add a custom provider or model",
|
|
162
184
|
value: "add",
|
|
163
185
|
searchText: "add custom provider model",
|
|
164
186
|
},
|
|
165
187
|
{
|
|
166
|
-
label: "
|
|
188
|
+
label: "refresh — Re-discover models for configured custom providers",
|
|
189
|
+
value: "refresh",
|
|
190
|
+
searchText: "refresh rediscover custom provider models",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
label: "list — Show custom models / remove model entries",
|
|
167
194
|
value: "list",
|
|
168
195
|
searchText: "list remove custom models",
|
|
169
196
|
},
|
|
@@ -171,6 +198,7 @@ export function registerModelCommand(api: ExtensionAPI): void {
|
|
|
171
198
|
if (!choice) return;
|
|
172
199
|
|
|
173
200
|
if (choice === "add") return handleAdd(ctx);
|
|
201
|
+
if (choice === "refresh") return handleRefresh(ctx);
|
|
174
202
|
if (choice === "list") return handleList(ctx);
|
|
175
203
|
},
|
|
176
204
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
5
|
+
|
|
6
|
+
export interface ModelRefreshState {
|
|
7
|
+
lastSuccessfulRefreshDate?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getModelRefreshStatePath(agentDir = getAgentDir()): string {
|
|
11
|
+
return path.join(agentDir, "model-refresh-state.json");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getLocalDateStamp(date = new Date()): string {
|
|
15
|
+
const year = date.getFullYear();
|
|
16
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
17
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
18
|
+
return `${year}-${month}-${day}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function readModelRefreshState(
|
|
22
|
+
statePath = getModelRefreshStatePath(),
|
|
23
|
+
): Promise<ModelRefreshState> {
|
|
24
|
+
try {
|
|
25
|
+
const content = await readFile(statePath, "utf8");
|
|
26
|
+
const parsed = JSON.parse(content) as ModelRefreshState;
|
|
27
|
+
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
28
|
+
} catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function writeModelRefreshState(
|
|
34
|
+
state: ModelRefreshState,
|
|
35
|
+
statePath = getModelRefreshStatePath(),
|
|
36
|
+
): Promise<void> {
|
|
37
|
+
await mkdir(path.dirname(statePath), { recursive: true });
|
|
38
|
+
await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
|
|
39
|
+
}
|
package/src/model-setup.ts
CHANGED
|
@@ -7,6 +7,18 @@ import path from "node:path";
|
|
|
7
7
|
import type { ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
8
8
|
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
9
9
|
|
|
10
|
+
import {
|
|
11
|
+
getLocalDateStamp,
|
|
12
|
+
readModelRefreshState,
|
|
13
|
+
writeModelRefreshState,
|
|
14
|
+
} from "./model-refresh-state.js";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
getLocalDateStamp,
|
|
18
|
+
readModelRefreshState,
|
|
19
|
+
writeModelRefreshState,
|
|
20
|
+
} from "./model-refresh-state.js";
|
|
21
|
+
|
|
10
22
|
import type { OmniConfig } from "./contracts.js";
|
|
11
23
|
import { discoverProviderModels, type OmniProviderModel } from "./providers.js";
|
|
12
24
|
import { searchableSelect } from "./searchable-select.js";
|
|
@@ -410,6 +422,39 @@ export async function refreshAuthenticatedProviderModels(
|
|
|
410
422
|
return refreshed.refreshedProviders;
|
|
411
423
|
}
|
|
412
424
|
|
|
425
|
+
export async function refreshAuthenticatedProviderModelsWithDailyGuard(
|
|
426
|
+
modelRegistry: ModelRegistryLike,
|
|
427
|
+
options?: {
|
|
428
|
+
force?: boolean;
|
|
429
|
+
now?: Date;
|
|
430
|
+
statePath?: string;
|
|
431
|
+
},
|
|
432
|
+
): Promise<{ refreshedProviders: string[]; skipped: boolean }> {
|
|
433
|
+
const today = getLocalDateStamp(options?.now);
|
|
434
|
+
if (!options?.force) {
|
|
435
|
+
const state = await readModelRefreshState(options?.statePath);
|
|
436
|
+
if (state.lastSuccessfulRefreshDate === today) {
|
|
437
|
+
return { refreshedProviders: [], skipped: true };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const refreshedProviders =
|
|
442
|
+
await refreshAuthenticatedProviderModels(modelRegistry);
|
|
443
|
+
|
|
444
|
+
if (refreshedProviders.length > 0) {
|
|
445
|
+
try {
|
|
446
|
+
await writeModelRefreshState(
|
|
447
|
+
{ lastSuccessfulRefreshDate: today },
|
|
448
|
+
options?.statePath,
|
|
449
|
+
);
|
|
450
|
+
} catch {
|
|
451
|
+
// Keep the refreshed models even if the durable refresh stamp cannot be written.
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return { refreshedProviders, skipped: false };
|
|
456
|
+
}
|
|
457
|
+
|
|
413
458
|
function sanitizeProviderId(input: string): string {
|
|
414
459
|
return input.trim().toLowerCase().replace(/\s+/gu, "-");
|
|
415
460
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
export const REPO_MAP_DIR = path.join(".pi", "repo-map");
|
|
4
|
+
export const REPO_MAP_STATE_FILE = path.join(REPO_MAP_DIR, "state.json");
|
|
5
|
+
export const REPO_MAP_SCHEMA_VERSION = 1;
|
|
6
|
+
|
|
7
|
+
export type RepoMapParserStatus =
|
|
8
|
+
| "indexed"
|
|
9
|
+
| "unsupported"
|
|
10
|
+
| "binary-fallback"
|
|
11
|
+
| "parse-fallback";
|
|
12
|
+
|
|
13
|
+
export type RepoMapSignalType = "read" | "edit" | "write" | "mention";
|
|
14
|
+
|
|
15
|
+
export interface RepoMapSymbol {
|
|
16
|
+
name: string;
|
|
17
|
+
kind:
|
|
18
|
+
| "function"
|
|
19
|
+
| "class"
|
|
20
|
+
| "interface"
|
|
21
|
+
| "type"
|
|
22
|
+
| "enum"
|
|
23
|
+
| "const"
|
|
24
|
+
| "default"
|
|
25
|
+
| "module";
|
|
26
|
+
signature?: string;
|
|
27
|
+
exported: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RepoMapImport {
|
|
31
|
+
specifier: string;
|
|
32
|
+
resolvedPath?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RepoMapFileRecord {
|
|
36
|
+
path: string;
|
|
37
|
+
language: string;
|
|
38
|
+
parserStatus: RepoMapParserStatus;
|
|
39
|
+
size: number;
|
|
40
|
+
mtimeMs: number;
|
|
41
|
+
fingerprint: string;
|
|
42
|
+
indexedAt: string;
|
|
43
|
+
firstIndexedAt: string;
|
|
44
|
+
symbols: RepoMapSymbol[];
|
|
45
|
+
imports: RepoMapImport[];
|
|
46
|
+
outgoingPaths: string[];
|
|
47
|
+
incomingPaths: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface RepoMapState {
|
|
51
|
+
schemaVersion: number;
|
|
52
|
+
indexedAt: string;
|
|
53
|
+
files: Record<string, RepoMapFileRecord>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface RepoMapRankedEntry {
|
|
57
|
+
path: string;
|
|
58
|
+
file: RepoMapFileRecord;
|
|
59
|
+
baseScore: number;
|
|
60
|
+
turnScore: number;
|
|
61
|
+
finalScore: number;
|
|
62
|
+
blastRadius: number;
|
|
63
|
+
tags: string[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface RepoMapSignal {
|
|
67
|
+
type: RepoMapSignalType;
|
|
68
|
+
path: string;
|
|
69
|
+
timestamp: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface RepoMapSessionState {
|
|
73
|
+
signals: RepoMapSignal[];
|
|
74
|
+
dirtyPaths: Set<string>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface RepoMapRenderOptions {
|
|
78
|
+
prompt?: string;
|
|
79
|
+
maxTokens?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RepoMapRefreshResult {
|
|
83
|
+
state: RepoMapState;
|
|
84
|
+
indexedPaths: string[];
|
|
85
|
+
removedPaths: string[];
|
|
86
|
+
reusedPaths: string[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface RepoMapDebugSnapshot {
|
|
90
|
+
state: RepoMapState;
|
|
91
|
+
ranked: RepoMapRankedEntry[];
|
|
92
|
+
rendered: string;
|
|
93
|
+
}
|