om-memory-system 4.13.3 → 4.14.1
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 +105 -154
- package/dist/importer/claude-import.js +1 -0
- package/dist/importer/import-sessions.d.ts +5 -0
- package/dist/importer/import-sessions.js +15 -3
- package/dist/importer/importer.d.ts +1 -0
- package/dist/importer/importer.js +1 -0
- package/dist/importer/opencode-import.d.ts +1 -0
- package/dist/importer/opencode-import.js +1 -0
- package/dist/importer/profile-import.d.ts +2 -0
- package/dist/importer/profile-import.js +4 -0
- package/dist/importer/run-import.d.ts +2 -0
- package/dist/importer/run-import.js +11 -2
- package/dist/importer/web-import-group.d.ts +57 -0
- package/dist/importer/web-import-group.js +355 -0
- package/dist/importer/web-import-jobs.d.ts +12 -6
- package/dist/importer/web-import-jobs.js +48 -2
- package/dist/importer/web-import-profile-estimate.d.ts +14 -0
- package/dist/importer/web-import-profile-estimate.js +37 -0
- package/dist/services/web-server.js +1 -1
- package/dist/web/assets/index-C9EubnKm.js +127 -0
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/assets/index-BH1QAU9V.js +0 -125
package/README.md
CHANGED
|
@@ -1,197 +1,148 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src=".github/screenshots/omms-logo.png" alt="OMMS logo" width="96" height="96" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# OMMS: Opinionated Modular Memory System
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/om-memory-system)
|
|
4
8
|
[](https://www.npmjs.com/package/om-memory-system)
|
|
5
|
-
[](LICENSE.md)
|
|
10
|
+
|
|
11
|
+
OMMS gives AI coding agents long-term project memory. It captures technical
|
|
12
|
+
work, recalls relevant notes in later sessions and learns your working
|
|
13
|
+
preferences. One shared engine serves **OpenCode**, **Pi** and **Claude Code**,
|
|
14
|
+
so each host can retrieve memories captured by the others in the same project.
|
|
6
15
|
|
|
7
|
-
|
|
16
|
+
Memories are stored locally, by default in `~/.omms/data`. Embeddings run
|
|
17
|
+
locally by default; the first use downloads a search model. Capture and profile
|
|
18
|
+
learning make additional model calls that can send conversation content to your
|
|
19
|
+
chosen provider and incur costs. Remote embeddings are optional. OMMS removes
|
|
20
|
+
text inside `<private>` tags before storage. See [Configuration](docs/configuration.md)
|
|
21
|
+
for model choices and privacy controls.
|
|
8
22
|
|
|
9
|
-
|
|
10
|
-
short notes about what was done and decided in each project: fixes, design
|
|
11
|
-
choices, things that did not work. It brings the relevant notes back in later
|
|
12
|
-
sessions, so the agent does not start from zero every time. It also learns how
|
|
13
|
-
you like to work and keeps that as a user profile.
|
|
23
|
+
## Set up
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
Use Node.js **22.14 or later** for the terminal command and Claude Code hooks.
|
|
26
|
+
OpenCode v1 needs **1.18.29 or later**. OMMS also supports OpenCode v2 and the
|
|
16
27
|
[Pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent).
|
|
17
|
-
Both share one memory per project, so a note written in one is available in
|
|
18
|
-
the other. Everything is stored locally on your machine.
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
[
|
|
29
|
+
> Automatic history import is enabled by default and makes model calls.
|
|
30
|
+
> To disable it before your first session, set `"autoBackfill": false` in
|
|
31
|
+
> `~/.config/omms/omms.jsonc`. See [Automatic import](docs/web-ui-memory.md#automatic-import).
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
### OpenCode
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- **Recalls when relevant.** Matching memories are added to the agent's
|
|
29
|
-
context: on every prompt in OpenCode v2 and Pi, at the start of a session in
|
|
30
|
-
OpenCode v1.
|
|
31
|
-
- **Learns your preferences.** A user profile of your habits builds up over
|
|
32
|
-
time and follows you across projects.
|
|
33
|
-
- **Imports your past sessions.** Pi and OpenCode import older history after
|
|
34
|
-
startup. A command gives you a preview and manual control.
|
|
35
|
-
- **Lets you look and edit.** A local web page shows every memory and your
|
|
36
|
-
profile.
|
|
37
|
-
- **Keeps private things private.** Text inside `<private>` tags is never
|
|
38
|
-
stored.
|
|
35
|
+
Add the package to `~/.config/opencode/opencode.json`. Keep your existing settings.
|
|
36
|
+
On Windows, use `%USERPROFILE%\.config\opencode\opencode.json`.
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
**OpenCode v2:**
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
```json
|
|
41
|
+
{ "plugins": ["om-memory-system"] }
|
|
42
|
+
```
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
**OpenCode v1:**
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
```json
|
|
47
|
+
{ "plugin": ["om-memory-system"] }
|
|
48
|
+
```
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
- **Pi coding agent**
|
|
50
|
-
- **Claude Code**, through a plugin of hooks. Capture needs your own external API. See
|
|
51
|
-
the [Claude Code adapter](docs/claude-code-adapter.md) guide for setup.
|
|
50
|
+
OpenCode v2 also supports:
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Node.js 22.14 or later.
|
|
52
|
+
```bash
|
|
53
|
+
opencode plugin add om-memory-system
|
|
54
|
+
```
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
> check, so it gets less testing. If something breaks on Windows,
|
|
61
|
-
> [open an issue](https://github.com/cmdaltctr/omms/issues). If you fix it,
|
|
62
|
-
> a pull request is welcome.
|
|
56
|
+
Restart OpenCode. The [OpenCode guide](docs/opencode-adapter.md#installation)
|
|
57
|
+
covers plugin management and its additional `cli.json` configuration.
|
|
63
58
|
|
|
64
|
-
|
|
59
|
+
### Pi
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
```bash
|
|
62
|
+
pi install npm:om-memory-system
|
|
63
|
+
```
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
(on Windows, `%USERPROFILE%\.config\opencode\opencode.json`):
|
|
65
|
+
Restart Pi. See the [Pi guide](docs/pi-adapter.md).
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
// OpenCode v2
|
|
73
|
-
{ "plugins": ["om-memory-system"] }
|
|
67
|
+
### Claude Code
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
Install the OMMS plugin using the [Claude Code guide](docs/claude-code-adapter.md#installation).
|
|
70
|
+
Capture and profile learning require a configured external API; retrieval and
|
|
71
|
+
manual memory operations remain available without it. A global npm install is optional.
|
|
78
72
|
|
|
79
|
-
|
|
80
|
-
Restart OpenCode.
|
|
73
|
+
### Model and web app
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
With no model settings, OpenCode and Pi use the session model. You can choose a
|
|
76
|
+
host model or configure an external API under **Settings**. Claude Code uses
|
|
77
|
+
only the external API. See [Choosing the model](docs/configuration.md#choosing-the-model)
|
|
78
|
+
for the selection order and credentials.
|
|
83
79
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
Start a host session, then open [http://127.0.0.1:4747](http://127.0.0.1:4747).
|
|
81
|
+
Each host starts the shared web app when needed, unless it is disabled. Browse
|
|
82
|
+
captured notes on **Project memories**, or ask your agent to search memory for
|
|
83
|
+
an earlier decision.
|
|
87
84
|
|
|
88
|
-
|
|
85
|
+
### Terminal command (optional)
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
command on your `PATH`. You do not need it. OMMS runs the newest copy it finds on
|
|
92
|
-
the machine, so updating one host is enough. A global install from 4.3 or earlier
|
|
93
|
-
needs one update. See
|
|
94
|
-
[Updating and upgrading](docs/upgrading.md#one-update-updates-every-host).
|
|
95
|
-
To install it:
|
|
87
|
+
A global install puts `om-memory-system` on your `PATH`:
|
|
96
88
|
|
|
97
89
|
```bash
|
|
98
|
-
npm
|
|
90
|
+
npm install -g om-memory-system
|
|
99
91
|
om-memory-system --version
|
|
100
92
|
```
|
|
101
93
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
With no settings, OMMS uses the model of the session you are working in. To
|
|
105
|
-
use a different one, add it to `~/.config/omms/omms.jsonc`. If you have no
|
|
106
|
-
config file yet, OMMS creates this one with comments on first start.
|
|
107
|
-
|
|
108
|
-
```jsonc
|
|
109
|
-
{
|
|
110
|
-
// A model you are already signed in to in OpenCode or Pi.
|
|
111
|
-
// Use "inherit" to always follow the session's model.
|
|
112
|
-
"opencodeProvider": "openai",
|
|
113
|
-
"opencodeModel": "gpt-5.6-luna",
|
|
114
|
-
"piProvider": "openai-codex",
|
|
115
|
-
"piModel": "gpt-5.6-luna",
|
|
116
|
-
}
|
|
117
|
-
```
|
|
94
|
+
See the [CLI reference](docs/cli.md) for manual memory operations and history imports.
|
|
118
95
|
|
|
119
|
-
|
|
120
|
-
up on the Settings page's **External API** card, and choose `"external"` as a
|
|
121
|
-
host's model. See [Configuration](docs/configuration.md#choosing-the-model).
|
|
96
|
+
## Inside OMMS
|
|
122
97
|
|
|
123
|
-
|
|
98
|
+
These screenshots use synthetic examples and configuration. All visible prompts,
|
|
99
|
+
code snippets and outcomes are made up for the demonstration.
|
|
124
100
|
|
|
125
|
-
|
|
126
|
-
browser. OpenCode or the login web app serves this page. New memories appear
|
|
127
|
-
on the timeline. You can also ask the agent: "search memory for what we changed today".
|
|
101
|
+
### Project memories
|
|
128
102
|
|
|
129
|
-
|
|
103
|
+
Browse captured notes alongside example user input and technical outcomes.
|
|
130
104
|
|
|
131
|
-
|
|
132
|
-
calls. To turn it off, set `"autoBackfill": false` in
|
|
133
|
-
`~/.config/omms/omms.jsonc` before you start the agent. For a manual import or
|
|
134
|
-
a custom source, preview it inside the agent:
|
|
105
|
+

|
|
135
106
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
107
|
+
### Memory
|
|
108
|
+
|
|
109
|
+
Review history imports, manage profile learning and set memory limits. This page
|
|
110
|
+
also helps resolve missing project folders.
|
|
111
|
+
|
|
112
|
+

|
|
113
|
+
|
|
114
|
+
### Settings
|
|
115
|
+
|
|
116
|
+
Choose models and manage access. Diagnostics show capture outcomes and component health.
|
|
140
117
|
|
|
141
|
-
|
|
142
|
-
session's model; add `--model provider/id` for a cheaper one. There is also a
|
|
143
|
-
terminal version, `npx om-memory-system`, that uses an API key. See the
|
|
144
|
-
[OpenCode](docs/opencode-history-import.md) and [Pi](docs/pi-history-import.md)
|
|
145
|
-
import guides, and the [CLI reference](docs/cli.md).
|
|
146
|
-
|
|
147
|
-
## Keeping OMMS up to date
|
|
148
|
-
|
|
149
|
-
Pi shows a notice when a new version is out; update with
|
|
150
|
-
`pi update npm:om-memory-system`. On OpenCode v2, the footer shows when a new version is out;
|
|
151
|
-
run `opencode plugin update om-memory-system`. Restart the agent afterwards.
|
|
152
|
-
[UPDATES.md](UPDATES.md) explains how updates work on every host.
|
|
153
|
-
To stay on one version, install it with the number, for example
|
|
154
|
-
`pi install npm:om-memory-system@3.1.1` or
|
|
155
|
-
`opencode plugin add om-memory-system@3.1.1`; a pinned install is never
|
|
156
|
-
updated. Coming from `opencode-mem`? Your memories move over automatically, with a
|
|
157
|
-
backup first. See [Updating and upgrading](docs/upgrading.md) and
|
|
158
|
-
[CHANGELOG.md](CHANGELOG.md).
|
|
118
|
+

|
|
159
119
|
|
|
160
120
|
## Documentation
|
|
161
121
|
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
| [Using memory
|
|
165
|
-
| [
|
|
166
|
-
| [
|
|
167
|
-
| [Settings page](docs/web-ui-settings.md)
|
|
168
|
-
| [
|
|
169
|
-
| [
|
|
170
|
-
| [
|
|
171
|
-
| [
|
|
172
|
-
| [
|
|
173
|
-
| [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
##
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
[
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
## License and links
|
|
190
|
-
|
|
191
|
-
MIT License. See [LICENSE.md](LICENSE.md).
|
|
192
|
-
|
|
193
|
-
- Repository: https://github.com/cmdaltctr/omms
|
|
194
|
-
- Upstream: https://github.com/tickernelz/opencode-mem
|
|
195
|
-
- Issues: https://github.com/cmdaltctr/omms/issues
|
|
196
|
-
|
|
197
|
-
Inspired by [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory).
|
|
122
|
+
| Guide | Covers |
|
|
123
|
+
| ------------------------------------------- | ------------------------------------------------------------ |
|
|
124
|
+
| [Using memory](docs/using-memory.md) | Daily use, capture, recall and the user profile |
|
|
125
|
+
| [Web UI](docs/web-ui.md) | Starting the app, browsing memories and safe network access |
|
|
126
|
+
| [Memory page](docs/web-ui-memory.md) | History imports, profile actions, limits and missing folders |
|
|
127
|
+
| [Settings page](docs/web-ui-settings.md) | Models, credentials, diagnostics and profile identities |
|
|
128
|
+
| [Configuration](docs/configuration.md) | Config files, model selection, privacy and embeddings |
|
|
129
|
+
| [Moving projects](docs/moving-projects.md) | Folder moves, backup and restore |
|
|
130
|
+
| [Updating and upgrading](docs/upgrading.md) | Updates, version pinning and older stores |
|
|
131
|
+
| [CLI reference](docs/cli.md) | Terminal commands |
|
|
132
|
+
| [For developers](docs/developers.md) | Building, testing and architecture |
|
|
133
|
+
| [Contributing](CONTRIBUTING.md) | Development workflow and pull requests |
|
|
134
|
+
|
|
135
|
+
History import guides: [OpenCode](docs/opencode-history-import.md),
|
|
136
|
+
[Pi](docs/pi-history-import.md) and [Claude Code](docs/claude-code-history-import.md).
|
|
137
|
+
See [UPDATES.md](UPDATES.md) for host update commands and
|
|
138
|
+
[CHANGELOG.md](CHANGELOG.md) for release changes. Existing `opencode-mem` users
|
|
139
|
+
can follow the [migration guide](docs/omms-migration.md).
|
|
140
|
+
|
|
141
|
+
## Licence
|
|
142
|
+
|
|
143
|
+
MIT. See [LICENSE.md](LICENSE.md) for copyright and attribution, and
|
|
144
|
+
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for bundled dependencies.
|
|
145
|
+
|
|
146
|
+
[Repository](https://github.com/cmdaltctr/omms) ·
|
|
147
|
+
[Issues](https://github.com/cmdaltctr/omms/issues) ·
|
|
148
|
+
[Documentation index](docs/README.md)
|
|
@@ -58,6 +58,7 @@ export async function importClaudeHistory(deps, filters) {
|
|
|
58
58
|
model: deps.profile.model,
|
|
59
59
|
batchSize: deps.profile.batchSize,
|
|
60
60
|
...(deps.profile.onProgress ? { onProgress: deps.profile.onProgress } : {}),
|
|
61
|
+
...(deps.profile.onEligiblePrompt ? { onEligiblePrompt: deps.profile.onEligiblePrompt } : {}),
|
|
61
62
|
});
|
|
62
63
|
}
|
|
63
64
|
return report;
|
|
@@ -27,6 +27,9 @@ export interface ImportMatchOptions {
|
|
|
27
27
|
project?: string;
|
|
28
28
|
pathMaps: ImportPathMap[];
|
|
29
29
|
cwd: string;
|
|
30
|
+
/** Grouped imports can retain a valid source with no matching sessions as no-work. */
|
|
31
|
+
allowEmpty?: boolean;
|
|
32
|
+
signal?: AbortSignal;
|
|
30
33
|
}
|
|
31
34
|
export declare class StaleSelectionError extends Error {
|
|
32
35
|
readonly status = 409;
|
|
@@ -91,6 +94,8 @@ export interface ResolvedImportSelection {
|
|
|
91
94
|
identity: ImportSourceIdentity;
|
|
92
95
|
keys: string[];
|
|
93
96
|
cutoff: number;
|
|
97
|
+
/** Source sessions still missing a project, excluding ignored directories; never import keys. */
|
|
98
|
+
unresolvedCount?: number;
|
|
94
99
|
}
|
|
95
100
|
/**
|
|
96
101
|
* Re-resolve a selection against the source right before a job. New sessions
|
|
@@ -39,7 +39,10 @@ async function readRows(identity, options, snapshotMode) {
|
|
|
39
39
|
}));
|
|
40
40
|
}
|
|
41
41
|
const { openOpencodeHistory } = await import("./opencode-reader.js");
|
|
42
|
-
const history = await openOpencodeHistory(identity.realPath, {}, {
|
|
42
|
+
const history = await openOpencodeHistory(identity.realPath, {}, {
|
|
43
|
+
shared: { key: importSourceKey(identity), mode: snapshotMode },
|
|
44
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
45
|
+
});
|
|
43
46
|
try {
|
|
44
47
|
return history.sessions.map((session) => ({
|
|
45
48
|
key: session.sessionId,
|
|
@@ -71,6 +74,7 @@ function revisionOf(identity, options, projectTag, keys) {
|
|
|
71
74
|
.digest("hex");
|
|
72
75
|
}
|
|
73
76
|
export async function matchImportSessions(identity, options, snapshotMode) {
|
|
77
|
+
options.signal?.throwIfAborted();
|
|
74
78
|
assertImportSourceUnchanged(identity);
|
|
75
79
|
const { projectFilterTag } = await import("./importer.js");
|
|
76
80
|
const projectTag = options.scope === "current-project"
|
|
@@ -207,6 +211,7 @@ export function validateImportSelection(value) {
|
|
|
207
211
|
* "ids" selection stale. Neither ever imports a session the user did not see.
|
|
208
212
|
*/
|
|
209
213
|
export async function resolveImportSelection(sourceToken, selection, options) {
|
|
214
|
+
options.signal?.throwIfAborted();
|
|
210
215
|
const identity = readImportSourceToken(sourceToken, options.host);
|
|
211
216
|
const matched = await matchImportSessions(identity, options, "reuse").catch((error) => {
|
|
212
217
|
if (error.code === "expired")
|
|
@@ -228,7 +233,14 @@ export async function resolveImportSelection(sourceToken, selection, options) {
|
|
|
228
233
|
}
|
|
229
234
|
keys = selection.sessions.map((item) => item.key);
|
|
230
235
|
}
|
|
231
|
-
if (keys.length === 0)
|
|
236
|
+
if (keys.length === 0 && !options.allowEmpty)
|
|
232
237
|
throw new Error("Choose sessions to import");
|
|
233
|
-
|
|
238
|
+
const { CONFIG } = await import("../config.js");
|
|
239
|
+
const { visibleUnresolvedCount } = await import("../services/backfill-state.js");
|
|
240
|
+
return {
|
|
241
|
+
identity,
|
|
242
|
+
keys,
|
|
243
|
+
cutoff: selection.listedAt,
|
|
244
|
+
unresolvedCount: visibleUnresolvedCount(matched.unresolved.length, matched.unresolved.map((row) => ({ directory: row.recordedDirectory ?? "", sessions: 1 })), CONFIG.importIgnoredDirectories ?? []),
|
|
245
|
+
};
|
|
234
246
|
}
|
|
@@ -392,6 +392,7 @@ export async function importPiHistory(deps, filters) {
|
|
|
392
392
|
model: deps.profile.model,
|
|
393
393
|
batchSize: deps.profile.batchSize,
|
|
394
394
|
...(deps.profile.onProgress ? { onProgress: deps.profile.onProgress } : {}),
|
|
395
|
+
...(deps.profile.onEligiblePrompt ? { onEligiblePrompt: deps.profile.onEligiblePrompt } : {}),
|
|
395
396
|
});
|
|
396
397
|
}
|
|
397
398
|
return report;
|
|
@@ -28,6 +28,7 @@ export interface OpencodeImportOptions {
|
|
|
28
28
|
profileModel?: ModelPort;
|
|
29
29
|
/** Profile batches done and planned, during the profile step. */
|
|
30
30
|
onProfileProgress?: (done: number, total: number) => void;
|
|
31
|
+
onProfilePrompt?: (identity: string) => void;
|
|
31
32
|
/** `alreadyHandled`: units found already done so far, which need no model call. */
|
|
32
33
|
onProgress?: (processed: number, total: number, promptPreview: string, alreadyHandled?: number) => void;
|
|
33
34
|
signal?: AbortSignal;
|
|
@@ -143,6 +143,7 @@ export async function importOpencodeHistory(options) {
|
|
|
143
143
|
batchSize: options.profileBatch,
|
|
144
144
|
model: options.profileModel,
|
|
145
145
|
...(options.onProfileProgress ? { onProgress: options.onProfileProgress } : {}),
|
|
146
|
+
...(options.onProfilePrompt ? { onEligiblePrompt: options.onProfilePrompt } : {}),
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
return report;
|
|
@@ -28,6 +28,8 @@ export interface ProfileImportOptions {
|
|
|
28
28
|
profileStore?: ProfileStore;
|
|
29
29
|
/** Profile batches done and planned; called before the first batch and after each one. */
|
|
30
30
|
onProgress?: (done: number, total: number) => void;
|
|
31
|
+
/** Dry-run estimate input only; no prompt content leaves this pipeline. */
|
|
32
|
+
onEligiblePrompt?: (identity: string) => void;
|
|
31
33
|
}
|
|
32
34
|
/** Record historical prompts and build or update the user profile in batches. */
|
|
33
35
|
export declare function importProfileFromHistory(source: AsyncIterable<ImportSourceSession> | Iterable<ImportSourceSession>, options: ProfileImportOptions): Promise<ProfileImportReport>;
|
|
@@ -7,6 +7,8 @@ import { buildImportKey } from "./importer.js";
|
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
import { ImportLedger, importLedgerDbPath } from "./ledger.js";
|
|
9
9
|
import { drainProfileBacklog } from "./profile-backlog.js";
|
|
10
|
+
import { isTrivialPrompt } from "../core/trivial-prompt.js";
|
|
11
|
+
import { profilePromptIdentity } from "./web-import-profile-estimate.js";
|
|
10
12
|
/** Record historical prompts and build or update the user profile in batches. */
|
|
11
13
|
export async function importProfileFromHistory(source, options) {
|
|
12
14
|
if (!options.dryRun && !options.model)
|
|
@@ -62,6 +64,8 @@ export async function importProfileFromHistory(source, options) {
|
|
|
62
64
|
continue;
|
|
63
65
|
}
|
|
64
66
|
if (options.dryRun) {
|
|
67
|
+
if (!isTrivialPrompt(prompt))
|
|
68
|
+
options.onEligiblePrompt?.(profilePromptIdentity(session.sessionId, unit.userEntryId));
|
|
65
69
|
report.promptsWouldRecord++;
|
|
66
70
|
continue;
|
|
67
71
|
}
|
|
@@ -18,6 +18,8 @@ export interface HistoryImportRun {
|
|
|
18
18
|
signal?: AbortSignal;
|
|
19
19
|
/** Profile batches done and planned, during the profile step after the exchanges. */
|
|
20
20
|
onProfileProgress?: (done: number, total: number) => void;
|
|
21
|
+
/** Eligible dry-run profile prompt identities, kept out of public reports. */
|
|
22
|
+
onProfilePrompt?: (identity: string) => void;
|
|
21
23
|
/** Record progress and take the host's lock for a run that calls models. */
|
|
22
24
|
track?: {
|
|
23
25
|
surface: ImportSurface;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import { profileFailureCode } from "../core/profile-failure.js";
|
|
2
3
|
import { hostLabel } from "../types/host-label.js";
|
|
3
4
|
const dryRunCapture = {
|
|
4
5
|
summarize: async () => {
|
|
@@ -55,14 +56,20 @@ export async function runHistoryImport(host, args, run) {
|
|
|
55
56
|
},
|
|
56
57
|
});
|
|
57
58
|
const handled = report.unitsImported + report.unitsSkipped + report.unitsFailed;
|
|
58
|
-
await recorder.finish(recorder.pauseRequested
|
|
59
|
+
await recorder.finish(recorder.pauseRequested
|
|
60
|
+
? "paused"
|
|
61
|
+
: controller.signal.aborted
|
|
62
|
+
? "stopped"
|
|
63
|
+
: report.profile?.error
|
|
64
|
+
? "failed"
|
|
65
|
+
: "done", {
|
|
59
66
|
// The total stays the one progress last reported; a real run has no
|
|
60
67
|
// "would import" count of its own.
|
|
61
68
|
done: handled,
|
|
62
69
|
imported: report.unitsImported,
|
|
63
70
|
skipped: report.unitsSkipped,
|
|
64
71
|
failed: report.unitsFailed,
|
|
65
|
-
});
|
|
72
|
+
}, report.profile?.error ? profileFailureCode(report.profile.error) : undefined);
|
|
66
73
|
// Only a run over every project and every session sees the full list.
|
|
67
74
|
if (args.scope === "all-projects" && !run.selection)
|
|
68
75
|
await recordUnresolved(host, report);
|
|
@@ -126,6 +133,7 @@ async function runUntracked(host, args, run) {
|
|
|
126
133
|
...(run.models.capture ? { provider: capture } : {}),
|
|
127
134
|
...(run.models.profile ? { profileModel: run.models.profile } : {}),
|
|
128
135
|
...(run.onProfileProgress ? { onProfileProgress: run.onProfileProgress } : {}),
|
|
136
|
+
...(run.onProfilePrompt ? { onProfilePrompt: run.onProfilePrompt } : {}),
|
|
129
137
|
});
|
|
130
138
|
}
|
|
131
139
|
const deps = {
|
|
@@ -138,6 +146,7 @@ async function runUntracked(host, args, run) {
|
|
|
138
146
|
...(run.models.profile ? { model: run.models.profile } : {}),
|
|
139
147
|
...(args.profileBatch ? { batchSize: args.profileBatch } : {}),
|
|
140
148
|
...(run.onProfileProgress ? { onProgress: run.onProfileProgress } : {}),
|
|
149
|
+
...(run.onProfilePrompt ? { onEligiblePrompt: run.onProfilePrompt } : {}),
|
|
141
150
|
},
|
|
142
151
|
}
|
|
143
152
|
: {}),
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ImportHost } from "./import-args.js";
|
|
2
|
+
import { type ImportReadiness } from "./import-readiness.js";
|
|
3
|
+
import { resolveImportSelection } from "./import-sessions.js";
|
|
4
|
+
import { type ImportSourceIdentity } from "./import-sources.js";
|
|
5
|
+
import { runHistoryImport, summarizeHistoryImportReport, type HistoryImportRun } from "./run-import.js";
|
|
6
|
+
import { type GroupImportRequest } from "./web-import-jobs.js";
|
|
7
|
+
import { type ProfileEstimate } from "./web-import-profile-estimate.js";
|
|
8
|
+
export type GroupHostState = "queued" | "running" | "done" | "failed" | "cancelled" | "no-work" | "not-run";
|
|
9
|
+
type LegacySummary = ReturnType<typeof summarizeHistoryImportReport>;
|
|
10
|
+
export type GroupImportSummary = Omit<LegacySummary, "profile"> & {
|
|
11
|
+
profile?: NonNullable<LegacySummary["profile"]> & {
|
|
12
|
+
promptsAlreadyHandled: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
type Summary = GroupImportSummary;
|
|
16
|
+
export interface GroupHostJob {
|
|
17
|
+
host: ImportHost;
|
|
18
|
+
state: GroupHostState;
|
|
19
|
+
sessions: number;
|
|
20
|
+
phase: "preparing" | "memory" | "profile";
|
|
21
|
+
processed: number;
|
|
22
|
+
total: number;
|
|
23
|
+
profileProcessed: number;
|
|
24
|
+
profileTotal: number;
|
|
25
|
+
summary?: Summary;
|
|
26
|
+
profileEstimate?: ProfileEstimate;
|
|
27
|
+
/** Model readiness for a real run, also visible in a read-only preview. */
|
|
28
|
+
blocker?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface GroupImportJob {
|
|
32
|
+
id: string;
|
|
33
|
+
dryRun: boolean;
|
|
34
|
+
state: "running" | "cancelling" | "cancelled" | "done" | "failed";
|
|
35
|
+
activeHost?: ImportHost;
|
|
36
|
+
hosts: GroupHostJob[];
|
|
37
|
+
sessions: number;
|
|
38
|
+
processed: number;
|
|
39
|
+
total: number;
|
|
40
|
+
summary?: Summary;
|
|
41
|
+
profileEstimate?: ProfileEstimate;
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface GroupImportDeps {
|
|
45
|
+
/** Model construction and store warmup, never invoked by a preview. */
|
|
46
|
+
prepareModels?: (choice: string, directory: string, signal: AbortSignal, host: ImportHost) => Promise<HistoryImportRun["models"]>;
|
|
47
|
+
discardSelection?: (identity: ImportSourceIdentity) => Promise<void>;
|
|
48
|
+
waitingPrompts?: () => Promise<Set<string>>;
|
|
49
|
+
}
|
|
50
|
+
type Deps = GroupImportDeps & {
|
|
51
|
+
runner: typeof runHistoryImport;
|
|
52
|
+
resolveSelection: typeof resolveImportSelection;
|
|
53
|
+
readiness: () => Promise<ImportReadiness>;
|
|
54
|
+
};
|
|
55
|
+
/** Preflight every child before launching a bounded sequential group in the existing slot. */
|
|
56
|
+
export declare function startImportGroup(input: GroupImportRequest, directory: string, deps: Deps, publish: (job: GroupImportJob, controller: AbortController) => void): Promise<GroupImportJob>;
|
|
57
|
+
export {};
|