@chengchenccc/oh-my-agent 0.2.0-rc.2 → 0.2.0-rc.3
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 +11 -6
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -2
- package/dist/cli/gateway-commands.d.ts.map +1 -1
- package/dist/cli/gateway-commands.js +35 -5
- package/dist/cli/initial-input.d.ts +3 -2
- package/dist/cli/initial-input.d.ts.map +1 -1
- package/dist/core/coordination/registry.d.ts +11 -0
- package/dist/core/coordination/registry.d.ts.map +1 -1
- package/dist/core/coordination/registry.js +23 -0
- package/dist/core/gateway/artifact.d.ts +0 -1
- package/dist/core/gateway/artifact.d.ts.map +1 -1
- package/dist/core/gateway/artifact.js +1 -1
- package/dist/core/goals/index.d.ts +8 -0
- package/dist/core/goals/index.d.ts.map +1 -0
- package/dist/core/goals/index.js +7 -0
- package/dist/core/goals/runtime.d.ts +112 -0
- package/dist/core/goals/runtime.d.ts.map +1 -0
- package/dist/core/goals/runtime.js +241 -0
- package/dist/core/goals/state.d.ts +82 -0
- package/dist/core/goals/state.d.ts.map +1 -0
- package/dist/core/goals/state.js +225 -0
- package/dist/core/goals/tool.d.ts +10 -0
- package/dist/core/goals/tool.d.ts.map +1 -0
- package/dist/core/goals/tool.js +87 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -3
- package/dist/core/loops/condition.d.ts +57 -0
- package/dist/core/loops/condition.d.ts.map +1 -0
- package/dist/core/loops/condition.js +153 -0
- package/dist/core/loops/index.d.ts +9 -0
- package/dist/core/loops/index.d.ts.map +1 -0
- package/dist/core/loops/index.js +8 -0
- package/dist/core/loops/limits.d.ts +43 -0
- package/dist/core/loops/limits.d.ts.map +1 -0
- package/dist/core/loops/limits.js +219 -0
- package/dist/core/loops/ralph.d.ts +37 -0
- package/dist/core/loops/ralph.d.ts.map +1 -0
- package/dist/core/loops/ralph.js +72 -0
- package/dist/core/loops/runtime.d.ts +95 -0
- package/dist/core/loops/runtime.d.ts.map +1 -0
- package/dist/core/loops/runtime.js +222 -0
- package/dist/core/memory/managed-skills.d.ts +0 -11
- package/dist/core/memory/managed-skills.d.ts.map +1 -1
- package/dist/core/memory/managed-skills.js +2 -2
- package/dist/core/memory/vector-store.d.ts +0 -1
- package/dist/core/memory/vector-store.d.ts.map +1 -1
- package/dist/core/memory/vector-store.js +0 -3
- package/dist/core/plans/index.d.ts +7 -0
- package/dist/core/plans/index.d.ts.map +1 -0
- package/dist/core/plans/index.js +6 -0
- package/dist/core/plans/prompts.d.ts +20 -0
- package/dist/core/plans/prompts.d.ts.map +1 -0
- package/dist/core/plans/prompts.js +72 -0
- package/dist/core/plans/runtime.d.ts +89 -0
- package/dist/core/plans/runtime.d.ts.map +1 -0
- package/dist/core/plans/runtime.js +170 -0
- package/dist/core/plans/state.d.ts +55 -0
- package/dist/core/plans/state.d.ts.map +1 -0
- package/dist/core/plans/state.js +88 -0
- package/dist/core/runtime/agent-loop-messages.d.ts +6 -0
- package/dist/core/runtime/agent-loop-messages.d.ts.map +1 -1
- package/dist/core/runtime/agent-loop-messages.js +40 -15
- package/dist/core/runtime/agent-loop-run.d.ts.map +1 -1
- package/dist/core/runtime/agent-loop-run.js +18 -27
- package/dist/core/runtime/agent-loop-runner.d.ts +1 -23
- package/dist/core/runtime/agent-loop-runner.d.ts.map +1 -1
- package/dist/core/runtime/agent-loop-runner.js +84 -30
- package/dist/core/runtime/agent-loop-types.d.ts +4 -0
- package/dist/core/runtime/agent-loop-types.d.ts.map +1 -1
- package/dist/core/runtime/compaction.d.ts +9 -0
- package/dist/core/runtime/compaction.d.ts.map +1 -1
- package/dist/core/runtime/compaction.js +28 -0
- package/dist/core/runtime/context-estimate.d.ts +37 -4
- package/dist/core/runtime/context-estimate.d.ts.map +1 -1
- package/dist/core/runtime/context-estimate.js +70 -0
- package/dist/core/runtime/create-runtime.d.ts +27 -5
- package/dist/core/runtime/create-runtime.d.ts.map +1 -1
- package/dist/core/runtime/create-runtime.js +22 -2
- package/dist/core/runtime/permission-classifier.d.ts.map +1 -1
- package/dist/core/runtime/permission-classifier.js +83 -12
- package/dist/core/runtime/plugin.d.ts +7 -0
- package/dist/core/runtime/plugin.d.ts.map +1 -1
- package/dist/core/runtime/plugin.js +13 -0
- package/dist/core/runtime/process-tree.d.ts +0 -9
- package/dist/core/runtime/process-tree.d.ts.map +1 -1
- package/dist/core/runtime/process-tree.js +1 -1
- package/dist/core/runtime/run-runtime.d.ts.map +1 -1
- package/dist/core/runtime/run-runtime.js +88 -49
- package/dist/core/runtime/runtime-catalog.d.ts +0 -4
- package/dist/core/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/core/runtime/runtime-catalog.js +1 -1
- package/dist/core/runtime/stream-rules.d.ts +9 -2
- package/dist/core/runtime/stream-rules.d.ts.map +1 -1
- package/dist/core/runtime/stream-rules.js +19 -5
- package/dist/core/runtime/title.d.ts +13 -1
- package/dist/core/runtime/title.d.ts.map +1 -1
- package/dist/core/runtime/title.js +51 -17
- package/dist/core/runtime/tool-pruning.d.ts.map +1 -1
- package/dist/core/runtime/tool-pruning.js +8 -16
- package/dist/core/session/session-file.d.ts +91 -5
- package/dist/core/session/session-file.d.ts.map +1 -1
- package/dist/core/session/session-file.js +206 -24
- package/dist/core/session/session-loop.d.ts +3 -1
- package/dist/core/session/session-loop.d.ts.map +1 -1
- package/dist/core/session/session-loop.js +8 -4
- package/dist/core/settings/project-settings.d.ts +63 -9
- package/dist/core/settings/project-settings.d.ts.map +1 -1
- package/dist/core/settings/project-settings.js +43 -2
- package/dist/core/settings/workspace-context.js +4 -4
- package/dist/core/store/in-memory-session-store.d.ts.map +1 -1
- package/dist/core/store/in-memory-session-store.js +3 -2
- package/dist/core/store/session-store.contract.test-helper.d.ts +7 -5
- package/dist/core/store/session-store.contract.test-helper.d.ts.map +1 -1
- package/dist/core/store/session-store.contract.test-helper.js +7 -5
- package/dist/core/store/session-store.d.ts +4 -2
- package/dist/core/store/session-store.d.ts.map +1 -1
- package/dist/core/store/session-store.js +4 -2
- package/dist/core/tools/ask-question.d.ts.map +1 -1
- package/dist/core/tools/ask-question.js +51 -5
- package/dist/core/tools/bash-pty.d.ts +13 -4
- package/dist/core/tools/bash-pty.d.ts.map +1 -1
- package/dist/core/tools/bash-pty.js +15 -8
- package/dist/core/tools/bash-sandbox.d.ts +1 -1
- package/dist/core/tools/bash.d.ts +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +18 -8
- package/dist/core/tools/browser.d.ts +54 -0
- package/dist/core/tools/browser.d.ts.map +1 -1
- package/dist/core/tools/browser.js +138 -1
- package/dist/core/tools/file-fingerprint.d.ts +24 -0
- package/dist/core/tools/file-fingerprint.d.ts.map +1 -0
- package/dist/core/tools/file-fingerprint.js +61 -0
- package/dist/core/tools/file-tools.d.ts +26 -0
- package/dist/core/tools/file-tools.d.ts.map +1 -1
- package/dist/core/tools/file-tools.js +113 -17
- package/dist/core/tools/index.d.ts +2 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/mcp-mount.d.ts +1 -1
- package/dist/core/tools/mcp-mount.d.ts.map +1 -1
- package/dist/core/tools/mcp-mount.js +72 -26
- package/dist/core/tools/url-guard.d.ts +15 -0
- package/dist/core/tools/url-guard.d.ts.map +1 -1
- package/dist/core/tools/url-guard.js +54 -14
- package/dist/core/tools/web-ports-std.d.ts.map +1 -1
- package/dist/core/tools/web-ports-std.js +5 -2
- package/dist/modes/print-mode.d.ts +3 -2
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/modes/shared.d.ts +12 -0
- package/dist/modes/shared.d.ts.map +1 -1
- package/dist/modes/shared.js +23 -6
- package/dist/modes/tui/agent-status.d.ts +20 -0
- package/dist/modes/tui/agent-status.d.ts.map +1 -0
- package/dist/modes/tui/agent-status.js +35 -0
- package/dist/modes/tui/ask-panel.d.ts +166 -0
- package/dist/modes/tui/ask-panel.d.ts.map +1 -0
- package/dist/modes/tui/ask-panel.js +888 -0
- package/dist/modes/tui/pty-console.d.ts +3 -0
- package/dist/modes/tui/pty-console.d.ts.map +1 -1
- package/dist/modes/tui/pty-console.js +19 -0
- package/dist/modes/tui/settings-overlay.d.ts +19 -0
- package/dist/modes/tui/settings-overlay.d.ts.map +1 -1
- package/dist/modes/tui/settings-overlay.js +46 -10
- package/dist/modes/tui/tui-commands-session.d.ts.map +1 -1
- package/dist/modes/tui/tui-commands-session.js +20 -6
- package/dist/modes/tui/tui-commands.d.ts +44 -3
- package/dist/modes/tui/tui-commands.d.ts.map +1 -1
- package/dist/modes/tui/tui-commands.js +380 -6
- package/dist/modes/tui/tui-components.d.ts +10 -0
- package/dist/modes/tui/tui-components.d.ts.map +1 -1
- package/dist/modes/tui/tui-components.js +26 -0
- package/dist/modes/tui/tui-format.d.ts +53 -4
- package/dist/modes/tui/tui-format.d.ts.map +1 -1
- package/dist/modes/tui/tui-format.js +137 -42
- package/dist/modes/tui/tui-frame-provider.d.ts +11 -3
- package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -1
- package/dist/modes/tui/tui-frame-provider.js +14 -5
- package/dist/modes/tui/tui-interactive.d.ts.map +1 -1
- package/dist/modes/tui/tui-interactive.js +14 -0
- package/dist/modes/tui/tui-io.d.ts.map +1 -1
- package/dist/modes/tui/tui-io.js +150 -55
- package/dist/modes/tui/tui-mode.d.ts.map +1 -1
- package/dist/modes/tui/tui-mode.js +428 -23
- package/dist/modes/tui/tui-overlays.d.ts +6 -10
- package/dist/modes/tui/tui-overlays.d.ts.map +1 -1
- package/dist/modes/tui/tui-overlays.js +0 -43
- package/dist/modes/tui/tui-render.d.ts +10 -0
- package/dist/modes/tui/tui-render.d.ts.map +1 -1
- package/dist/modes/tui/tui-render.js +73 -38
- package/dist/modes/tui/tui-seam.d.ts +28 -6
- package/dist/modes/tui/tui-seam.d.ts.map +1 -1
- package/dist/modes/tui/tui-slash.d.ts.map +1 -1
- package/dist/modes/tui/tui-slash.js +3 -1
- package/dist/modes/tui/tui-tool-render.d.ts +14 -1
- package/dist/modes/tui/tui-tool-render.d.ts.map +1 -1
- package/dist/modes/tui/tui-tool-render.js +158 -50
- package/dist/modes/tui/tui-transcript-reconciler.d.ts +4 -0
- package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -1
- package/dist/modes/tui/tui-transcript-reconciler.js +12 -2
- package/dist/modes/tui/view-state.d.ts.map +1 -1
- package/dist/modes/tui/view-state.js +4 -1
- package/dist/protocol/transport.d.ts +10 -0
- package/dist/protocol/transport.d.ts.map +1 -1
- package/dist/protocol/transport.js +1 -0
- package/package.json +11 -11
|
@@ -31,22 +31,63 @@ export function sessionDirFor(workspaceRoot) {
|
|
|
31
31
|
export function sessionDir() {
|
|
32
32
|
return process.env.OMA_SESSION_DIR ?? sessionDirFor(process.cwd());
|
|
33
33
|
}
|
|
34
|
+
/** Session ids reach the FILESYSTEM, and callers supply them (RPC resume,
|
|
35
|
+
* TUI rename/delete): validate at this boundary. A path-shaped id
|
|
36
|
+
* ("../x", "/abs", "a\\b", "..", trailing dots) would otherwise escape the
|
|
37
|
+
* session directory and read/append/rename/delete outside it. Legit ids
|
|
38
|
+
* are newSessionId() UUIDs (hex + dashes). */
|
|
39
|
+
export function assertSafeSessionId(id) {
|
|
40
|
+
if (!/^[A-Za-z0-9_-]+$/.test(id)) {
|
|
41
|
+
throw new Error(`invalid session id: ${JSON.stringify(id.slice(0, 40))}`);
|
|
42
|
+
}
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
45
|
+
/** The single place a session id becomes a path. */
|
|
46
|
+
function sessionFilePath(id, dir) {
|
|
47
|
+
return join(dir, `${assertSafeSessionId(id)}.jsonl`);
|
|
48
|
+
}
|
|
34
49
|
export function sessionPath(id) {
|
|
35
|
-
return
|
|
50
|
+
return sessionFilePath(id, sessionDir());
|
|
36
51
|
}
|
|
37
52
|
export function newSessionId() {
|
|
38
53
|
return crypto.randomUUID();
|
|
39
54
|
}
|
|
40
55
|
/** Load the transcript messages of a session file (wire-loose shape).
|
|
41
|
-
* Missing/corrupt files yield [] (the caller falls back to a fresh
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
56
|
+
* Missing/corrupt files yield [] (the caller falls back to a fresh session).
|
|
57
|
+
*
|
|
58
|
+
* A compaction event carries `replacesEarlierMessages`: whether its summary
|
|
59
|
+
* describes everything written before it. Only then is folding lossless —
|
|
60
|
+
* the summary becomes one context message and later turns stay live.
|
|
61
|
+
*
|
|
62
|
+
* Why a flag and not a count: the count would have to be expressed in THIS
|
|
63
|
+
* file's message-event space, but the run that produces the summary counts
|
|
64
|
+
* coverage over its own session branch, and the two spaces do not align —
|
|
65
|
+
* the branch also holds entries that never reach the file (re-seeded
|
|
66
|
+
* `product_history`, the `meta` entry) and folds a prior summary into a
|
|
67
|
+
* single entry. A count in the wrong space lands past the real boundary and
|
|
68
|
+
* DELETES messages the summary never described. The flag cannot be
|
|
69
|
+
* mis-indexed: when the summary does not describe the whole file, the
|
|
70
|
+
* transcript is simply left intact (a resume may re-summarize, never lose).
|
|
71
|
+
*
|
|
72
|
+
* Events without the field (files written before it existed) keep the
|
|
73
|
+
* historical behavior: the summary replaces everything before it.
|
|
74
|
+
*
|
|
75
|
+
* The LAST event that says "replaces" decides the fold, and a later event
|
|
76
|
+
* saying otherwise does NOT cancel it. That distinction is what makes manual
|
|
77
|
+
* /compact stick: /compact folds the transcript to one summary, a later
|
|
78
|
+
* automatic compaction covers only part of what follows, and "latest event
|
|
79
|
+
* wins" would resurrect every message the user deliberately compacted away.
|
|
80
|
+
* Ignoring a partial summary is always safe — its content is either already
|
|
81
|
+
* summarized or still present as messages. */
|
|
45
82
|
export function loadSessionMessages(id, dir = sessionDir()) {
|
|
46
|
-
const path =
|
|
83
|
+
const path = sessionFilePath(id, dir);
|
|
47
84
|
if (!existsSync(path))
|
|
48
85
|
return [];
|
|
49
86
|
const messages = [];
|
|
87
|
+
/** The latest summary that MAY fold, with the index it folds from. A later
|
|
88
|
+
* non-folding summary must not overwrite these. */
|
|
89
|
+
let foldSummary;
|
|
90
|
+
let foldFrom;
|
|
50
91
|
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
51
92
|
if (!line.trim())
|
|
52
93
|
continue;
|
|
@@ -57,18 +98,28 @@ export function loadSessionMessages(id, dir = sessionDir()) {
|
|
|
57
98
|
if (evt.type === "message" && evt.message?.role)
|
|
58
99
|
messages.push(evt.message);
|
|
59
100
|
else if (evt.type === "compaction" && typeof evt.summary === "string") {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
101
|
+
// Evaluated in this file's own index space: everything parsed before
|
|
102
|
+
// it. Only a replacing event re-points the fold; a partial summary
|
|
103
|
+
// leaves an earlier fold in place (see the header note on /compact).
|
|
104
|
+
if (evt.replacesEarlierMessages !== false) {
|
|
105
|
+
foldSummary = evt.summary;
|
|
106
|
+
foldFrom = messages.length;
|
|
107
|
+
}
|
|
65
108
|
}
|
|
66
109
|
}
|
|
67
110
|
catch {
|
|
68
111
|
/* skip malformed line */
|
|
69
112
|
}
|
|
70
113
|
}
|
|
71
|
-
|
|
114
|
+
if (foldSummary === undefined || foldFrom === undefined)
|
|
115
|
+
return messages;
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
role: "user",
|
|
119
|
+
text: `<previous_session_summary>\n${foldSummary}\n</previous_session_summary>`,
|
|
120
|
+
},
|
|
121
|
+
...messages.slice(foldFrom),
|
|
122
|
+
];
|
|
72
123
|
}
|
|
73
124
|
/** Scan one session directory (all *.jsonl) into summaries. */
|
|
74
125
|
function scanSessionDir(dir, workspace) {
|
|
@@ -82,6 +133,7 @@ function scanSessionDir(dir, workspace) {
|
|
|
82
133
|
const path = join(dir, entry);
|
|
83
134
|
let preview = "";
|
|
84
135
|
let title;
|
|
136
|
+
let summaryText;
|
|
85
137
|
let headerCwd;
|
|
86
138
|
let forkOf;
|
|
87
139
|
try {
|
|
@@ -98,6 +150,10 @@ function scanSessionDir(dir, workspace) {
|
|
|
98
150
|
title = evt.title;
|
|
99
151
|
continue;
|
|
100
152
|
}
|
|
153
|
+
if (evt.type === "summary" && typeof evt.summary === "string") {
|
|
154
|
+
summaryText = evt.summary;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
101
157
|
if (evt.type === "fork_of" && typeof evt.parentId === "string") {
|
|
102
158
|
forkOf = evt.parentId;
|
|
103
159
|
continue;
|
|
@@ -115,6 +171,8 @@ function scanSessionDir(dir, workspace) {
|
|
|
115
171
|
const summary = { id, modifiedAt: statSync(path).mtimeMs, preview };
|
|
116
172
|
if (title !== undefined)
|
|
117
173
|
summary.title = title;
|
|
174
|
+
if (summaryText !== undefined)
|
|
175
|
+
summary.summary = summaryText;
|
|
118
176
|
if (workspace !== undefined)
|
|
119
177
|
summary.workspace = workspace;
|
|
120
178
|
else if (headerCwd !== undefined)
|
|
@@ -155,7 +213,7 @@ export function listAllSessions() {
|
|
|
155
213
|
* the TUI to mark a session titled so the loop stops re-generating one on
|
|
156
214
|
* every completed turn. */
|
|
157
215
|
export function readSessionTitle(id, dir = sessionDir()) {
|
|
158
|
-
const path =
|
|
216
|
+
const path = sessionFilePath(id, dir);
|
|
159
217
|
let raw;
|
|
160
218
|
try {
|
|
161
219
|
raw = readFileSync(path, "utf-8");
|
|
@@ -183,7 +241,7 @@ export function readSessionTitle(id, dir = sessionDir()) {
|
|
|
183
241
|
* loop after each completed run. Last one wins in listings. Also the
|
|
184
242
|
* primitive for /rename: appending a new title overrides the display. */
|
|
185
243
|
export function appendSessionTitle(id, title, dir = sessionDir()) {
|
|
186
|
-
const path =
|
|
244
|
+
const path = sessionFilePath(id, dir);
|
|
187
245
|
if (!existsSync(path))
|
|
188
246
|
return;
|
|
189
247
|
appendFileSync(path, `${JSON.stringify({
|
|
@@ -192,9 +250,22 @@ export function appendSessionTitle(id, title, dir = sessionDir()) {
|
|
|
192
250
|
title,
|
|
193
251
|
})}\n`);
|
|
194
252
|
}
|
|
253
|
+
/** Append a summary event: a one-sentence description of what the session is
|
|
254
|
+
* about, produced by the same ephemeral call as the title. Last one wins in
|
|
255
|
+
* listings (the resume list shows it next to the title). */
|
|
256
|
+
export function appendSessionSummary(id, summary, dir = sessionDir()) {
|
|
257
|
+
const path = sessionFilePath(id, dir);
|
|
258
|
+
if (!existsSync(path))
|
|
259
|
+
return;
|
|
260
|
+
appendFileSync(path, `${JSON.stringify({
|
|
261
|
+
type: "summary",
|
|
262
|
+
timestamp: new Date().toISOString(),
|
|
263
|
+
summary,
|
|
264
|
+
})}\n`);
|
|
265
|
+
}
|
|
195
266
|
/** Delete a session file. Returns false when it did not exist. */
|
|
196
267
|
export function deleteSession(id, dir = sessionDir()) {
|
|
197
|
-
const path =
|
|
268
|
+
const path = sessionFilePath(id, dir);
|
|
198
269
|
if (!existsSync(path))
|
|
199
270
|
return false;
|
|
200
271
|
rmSync(path, { force: true });
|
|
@@ -203,30 +274,141 @@ export function deleteSession(id, dir = sessionDir()) {
|
|
|
203
274
|
/** Rename a session's display title (last-wins title event). Returns false
|
|
204
275
|
* when the session file does not exist. */
|
|
205
276
|
export function renameSession(id, title, dir = sessionDir()) {
|
|
206
|
-
const path =
|
|
277
|
+
const path = sessionFilePath(id, dir);
|
|
207
278
|
if (!existsSync(path))
|
|
208
279
|
return false;
|
|
209
280
|
appendSessionTitle(id, title, dir);
|
|
210
281
|
return true;
|
|
211
282
|
}
|
|
283
|
+
/** Append a goal-mode event (omp mode-change analogue): the latest goal
|
|
284
|
+
* state transition for the session. Replay reconstructs the current goal
|
|
285
|
+
* (active/paused/complete/dropped); a goal:null event means dropped. */
|
|
286
|
+
export function appendSessionGoalEvent(id, state, dir = sessionDir()) {
|
|
287
|
+
const path = sessionFilePath(id, dir);
|
|
288
|
+
if (!existsSync(path))
|
|
289
|
+
return;
|
|
290
|
+
appendFileSync(path, `${JSON.stringify({
|
|
291
|
+
type: "goal",
|
|
292
|
+
timestamp: new Date().toISOString(),
|
|
293
|
+
goalMode: state,
|
|
294
|
+
})}\n`);
|
|
295
|
+
}
|
|
296
|
+
/** Append a goal COMPLETION record: the objective and the tracked usage at the
|
|
297
|
+
* moment the model declared the goal done. Separate from the mode-change
|
|
298
|
+
* events so a completed goal reads as a durable achievement rather than a
|
|
299
|
+
* status flip (and so resumed sessions can report what was finished). */
|
|
300
|
+
export function appendSessionGoalCompletion(id, record, dir = sessionDir()) {
|
|
301
|
+
const path = sessionFilePath(id, dir);
|
|
302
|
+
if (!existsSync(path))
|
|
303
|
+
return;
|
|
304
|
+
appendFileSync(path, `${JSON.stringify({
|
|
305
|
+
type: "goal_completed",
|
|
306
|
+
timestamp: new Date().toISOString(),
|
|
307
|
+
...record,
|
|
308
|
+
})}
|
|
309
|
+
`);
|
|
310
|
+
}
|
|
311
|
+
/** Append a plan-mode event (same mode-change shape as the goal one): the
|
|
312
|
+
* mode plus whether it is paused. The draft itself is a FILE, so the journal
|
|
313
|
+
* only needs the mode; resume restores "planning, paused" and never
|
|
314
|
+
* re-enters a read-only planning turn on its own. */
|
|
315
|
+
export function appendSessionPlanEvent(id, state, paused, dir = sessionDir()) {
|
|
316
|
+
const path = sessionFilePath(id, dir);
|
|
317
|
+
if (!existsSync(path))
|
|
318
|
+
return;
|
|
319
|
+
appendFileSync(path, `${JSON.stringify({
|
|
320
|
+
type: "plan",
|
|
321
|
+
timestamp: new Date().toISOString(),
|
|
322
|
+
planMode: state ? { planPath: state.planPath, paused } : null,
|
|
323
|
+
})}\n`);
|
|
324
|
+
}
|
|
325
|
+
/** Replay plan-mode events: the latest one wins (null = plan mode off). */
|
|
326
|
+
export function loadSessionPlanState(id, dir = sessionDir()) {
|
|
327
|
+
const path = sessionFilePath(id, dir);
|
|
328
|
+
if (!existsSync(path))
|
|
329
|
+
return null;
|
|
330
|
+
let latest = null;
|
|
331
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
332
|
+
if (!line.trim() || !line.includes('"plan"'))
|
|
333
|
+
continue;
|
|
334
|
+
try {
|
|
335
|
+
const evt = JSON.parse(line);
|
|
336
|
+
if (evt.type !== "plan")
|
|
337
|
+
continue;
|
|
338
|
+
const mode = evt.planMode;
|
|
339
|
+
if (mode === null || mode === undefined || typeof mode.planPath !== "string") {
|
|
340
|
+
latest = null;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
latest = { planPath: mode.planPath, paused: mode.paused === true };
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
/* skip malformed line */
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return latest;
|
|
350
|
+
}
|
|
351
|
+
/** Reconstruct the current goal-mode state by replaying goal events (last
|
|
352
|
+
* one wins; malformed entries are skipped like every other scan here). */
|
|
353
|
+
export function loadSessionGoalState(id, dir = sessionDir()) {
|
|
354
|
+
const path = sessionFilePath(id, dir);
|
|
355
|
+
if (!existsSync(path))
|
|
356
|
+
return null;
|
|
357
|
+
let latest = null;
|
|
358
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
359
|
+
if (!line.trim() || !line.includes('"goal"'))
|
|
360
|
+
continue;
|
|
361
|
+
try {
|
|
362
|
+
const evt = JSON.parse(line);
|
|
363
|
+
if (evt.type !== "goal")
|
|
364
|
+
continue;
|
|
365
|
+
const mode = evt.goalMode;
|
|
366
|
+
if (mode === null || mode === undefined || mode.goal == null) {
|
|
367
|
+
latest = null; // explicit drop/clear wins from here on
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const g = mode.goal;
|
|
371
|
+
if (typeof g.objective !== "string" ||
|
|
372
|
+
typeof g.status !== "string" ||
|
|
373
|
+
typeof g.id !== "string") {
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
latest = {
|
|
377
|
+
enabled: mode.enabled === true,
|
|
378
|
+
mode: mode.mode === "exiting" ? "exiting" : "active",
|
|
379
|
+
...(mode.reason === "completed" ? { reason: "completed" } : {}),
|
|
380
|
+
goal: g,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
/* skip malformed line */
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return latest;
|
|
388
|
+
}
|
|
212
389
|
/** Append a compaction event: records that the run compacted everything
|
|
213
390
|
* recorded so far in this file into `summary`. Must be called AFTER the
|
|
214
391
|
* turn's messages are appended. */
|
|
215
|
-
export function appendSessionCompaction(id, summary, dir = sessionDir()
|
|
216
|
-
|
|
392
|
+
export function appendSessionCompaction(id, summary, dir = sessionDir(),
|
|
393
|
+
/** Whether this summary describes EVERYTHING already in the file, which is
|
|
394
|
+
* what makes folding on load lossless. Omit when unknown: the load path
|
|
395
|
+
* then keeps the transcript intact instead of folding it. */
|
|
396
|
+
replacesEarlierMessages) {
|
|
397
|
+
const path = sessionFilePath(id, dir);
|
|
217
398
|
if (!existsSync(path))
|
|
218
399
|
return;
|
|
219
400
|
appendFileSync(path, `${JSON.stringify({
|
|
220
401
|
type: "compaction",
|
|
221
402
|
timestamp: new Date().toISOString(),
|
|
222
403
|
summary,
|
|
404
|
+
...(replacesEarlierMessages !== undefined ? { replacesEarlierMessages } : {}),
|
|
223
405
|
})}\n`);
|
|
224
406
|
}
|
|
225
407
|
/** Read the durable event tree of one session as parentId-chained message
|
|
226
408
|
* nodes (used by the TUI branch-tree fork overlay). Only message events
|
|
227
409
|
* carry an id; corrupt lines are skipped. */
|
|
228
410
|
export function loadSessionBranchNodes(id, dir = sessionDir()) {
|
|
229
|
-
const path =
|
|
411
|
+
const path = sessionFilePath(id, dir);
|
|
230
412
|
if (!existsSync(path))
|
|
231
413
|
return [];
|
|
232
414
|
const lines = readFileSync(path, "utf8")
|
|
@@ -281,7 +463,7 @@ export function loadSessionBranchNodes(id, dir = sessionDir()) {
|
|
|
281
463
|
/** Copy a session file through the line at `cutIndex` into a NEW file with a
|
|
282
464
|
* fork_of marker. Shared by the ordinal and event-id fork paths. */
|
|
283
465
|
function copySessionThrough(id, cutIndex, dir, markerFields) {
|
|
284
|
-
const path =
|
|
466
|
+
const path = sessionFilePath(id, dir);
|
|
285
467
|
if (!existsSync(path))
|
|
286
468
|
return null;
|
|
287
469
|
const lines = readFileSync(path, "utf8")
|
|
@@ -303,13 +485,13 @@ function copySessionThrough(id, cutIndex, dir, markerFields) {
|
|
|
303
485
|
/* keep the original header line */
|
|
304
486
|
}
|
|
305
487
|
const marker = JSON.stringify({ type: "fork_of", parentId: id, ...markerFields });
|
|
306
|
-
writeFileSync(
|
|
488
|
+
writeFileSync(sessionFilePath(newId, dir), `${[...kept, marker].join("\n")}\n`);
|
|
307
489
|
return newId;
|
|
308
490
|
}
|
|
309
491
|
/** Fork a session at the Nth user message (1-based) — the existing /fork
|
|
310
492
|
* semantics. */
|
|
311
493
|
export function forkSession(id, ordinal, dir = sessionDir()) {
|
|
312
|
-
const path =
|
|
494
|
+
const path = sessionFilePath(id, dir);
|
|
313
495
|
if (!existsSync(path))
|
|
314
496
|
return null;
|
|
315
497
|
const lines = readFileSync(path, "utf8")
|
|
@@ -340,7 +522,7 @@ export function forkSession(id, ordinal, dir = sessionDir()) {
|
|
|
340
522
|
/** Fork a session through a specific branch node (message event id). The new
|
|
341
523
|
* session contains every event up to and INCLUDING that node. */
|
|
342
524
|
export function forkSessionAtEvent(id, eventId, dir = sessionDir()) {
|
|
343
|
-
const path =
|
|
525
|
+
const path = sessionFilePath(id, dir);
|
|
344
526
|
if (!existsSync(path))
|
|
345
527
|
return null;
|
|
346
528
|
const lines = readFileSync(path, "utf8")
|
|
@@ -389,7 +571,7 @@ function readLastMessageId(path) {
|
|
|
389
571
|
}
|
|
390
572
|
export function appendSessionMessages(id, cwd, messages, dir = sessionDir()) {
|
|
391
573
|
mkdirSync(dir, { recursive: true });
|
|
392
|
-
const path =
|
|
574
|
+
const path = sessionFilePath(id, dir);
|
|
393
575
|
const cacheKey = `${dir}:${id}`;
|
|
394
576
|
if (!existsSync(path)) {
|
|
395
577
|
writeFileSync(path, `${JSON.stringify({
|
|
@@ -5,7 +5,7 @@ import type { OmaRuntime } from "../runtime/create-runtime.js";
|
|
|
5
5
|
* stores only the session id. A completed turn (input + assistant/tool
|
|
6
6
|
* messages + compaction summaries) is appended after the run. */
|
|
7
7
|
/** Finalize a turn in the session file: writes compaction summaries and the
|
|
8
|
-
* auto title. Conversational messages are written in REAL TIME via
|
|
8
|
+
* auto title/summary. Conversational messages are written in REAL TIME via
|
|
9
9
|
* createOmaRuntime's onPersistMessages (pi appendMessage) when the caller
|
|
10
10
|
* wires it; `messages` is the fallback batch for one-shot modes (print)
|
|
11
11
|
* that do not use real-time persistence. */
|
|
@@ -17,6 +17,8 @@ export declare function persistSessionTurn(opts: {
|
|
|
17
17
|
messages?: readonly unknown[];
|
|
18
18
|
/** The run's auto-generated title (outcome.title), when present. */
|
|
19
19
|
title?: string;
|
|
20
|
+
/** The run's one-sentence session summary (outcome.summary), when present. */
|
|
21
|
+
summary?: string;
|
|
20
22
|
/** Session directory; defaults to the current workspace. Cross-workspace
|
|
21
23
|
* resumes pass the source workspace's dir so new turns append there. */
|
|
22
24
|
dir?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-loop.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"session-loop.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAW/D;;;;kEAIkE;AAElE;;;;6CAI6C;AAC7C,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,UAAU,CAAC;IACpB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;6EACyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAED;;;sEAGsE;AACtE,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,MAAM,GACX;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;CACb,CAIA"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { appendSessionCompaction, appendSessionMessages, appendSessionTitle, loadSessionMessages, newSessionId, sessionDir, } from "./session-file.js";
|
|
1
|
+
import { appendSessionCompaction, appendSessionMessages, appendSessionSummary, appendSessionTitle, loadSessionMessages, newSessionId, sessionDir, } from "./session-file.js";
|
|
2
2
|
/** Shared session persistence for the interactive CLI modes (TUI) and the
|
|
3
3
|
* one-shot modes (print). Mirrors the RPC mode's session semantics
|
|
4
4
|
* (ADR 0003 decision 6): the CLI owns its session file; the product
|
|
5
5
|
* stores only the session id. A completed turn (input + assistant/tool
|
|
6
6
|
* messages + compaction summaries) is appended after the run. */
|
|
7
7
|
/** Finalize a turn in the session file: writes compaction summaries and the
|
|
8
|
-
* auto title. Conversational messages are written in REAL TIME via
|
|
8
|
+
* auto title/summary. Conversational messages are written in REAL TIME via
|
|
9
9
|
* createOmaRuntime's onPersistMessages (pi appendMessage) when the caller
|
|
10
10
|
* wires it; `messages` is the fallback batch for one-shot modes (print)
|
|
11
11
|
* that do not use real-time persistence. */
|
|
@@ -13,11 +13,15 @@ export async function persistSessionTurn(opts) {
|
|
|
13
13
|
if (opts.messages && opts.messages.length > 0) {
|
|
14
14
|
appendSessionMessages(opts.sessionId, opts.cwd, opts.messages, opts.dir);
|
|
15
15
|
}
|
|
16
|
-
for (const
|
|
17
|
-
|
|
16
|
+
for (const compaction of await opts.runtime.compactions()) {
|
|
17
|
+
// The flag rides the event: a summary that does NOT describe the whole
|
|
18
|
+
// file must not fold it, or a resume drops the messages it never saw.
|
|
19
|
+
appendSessionCompaction(opts.sessionId, compaction.summary, opts.dir, compaction.replacesEarlierMessages);
|
|
18
20
|
}
|
|
19
21
|
if (opts.title)
|
|
20
22
|
appendSessionTitle(opts.sessionId, opts.title, opts.dir);
|
|
23
|
+
if (opts.summary)
|
|
24
|
+
appendSessionSummary(opts.sessionId, opts.summary, opts.dir);
|
|
21
25
|
}
|
|
22
26
|
/** Resolve the session for a new TUI turn: a --session id resumes that
|
|
23
27
|
* file (missing/corrupt file degrades to fresh); otherwise a new id.
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/** Project-level oma settings (`.oma/settings.json` in the workspace root).
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
*
|
|
3
|
+
* Every mode reads this file, but what a mode HONORS differs on purpose: a
|
|
4
|
+
* standalone run (TUI / print / json) takes it whole, while a product run
|
|
5
|
+
* (rpc) takes only `bashSandbox` — a workspace file must never steer the
|
|
6
|
+
* product's permission classifier, web access, step budget or timeouts. The
|
|
7
|
+
* product backend keeps agent.yml as its model truth and passes per-run
|
|
8
|
+
* values in the run snapshot, so this file cannot conflict with agent.yml in
|
|
9
|
+
* the backend -> oma chain. */
|
|
5
10
|
export interface ProjectSettings {
|
|
6
11
|
/** Canonical `<provider>/<model>` id chosen in the TUI. */
|
|
7
12
|
model?: string;
|
|
@@ -21,6 +26,11 @@ export interface ProjectSettings {
|
|
|
21
26
|
modelTimeoutMs?: number;
|
|
22
27
|
/** MCP call timeout ms (env OMA_MCP_TIMEOUT_MS). */
|
|
23
28
|
mcpTimeoutMs?: number;
|
|
29
|
+
/** HITL ask inactivity timeout ms (env OMA_ASK_TIMEOUT_MS, omp ask.timeout
|
|
30
|
+
* which is in SECONDS): when a question sits untouched this long, the
|
|
31
|
+
* unanswered ones are auto-answered with their recommended option and the
|
|
32
|
+
* answer is marked timedOut. 0 / absent = disabled (omp's default). */
|
|
33
|
+
askTimeoutMs?: number;
|
|
24
34
|
/** Disable web tools (env OMA_DISABLE_WEB=1). */
|
|
25
35
|
disableWeb?: boolean;
|
|
26
36
|
/** Generate auto titles (env OMA_TITLE_ENABLED=0 disables). */
|
|
@@ -52,15 +62,50 @@ export interface ProjectSettings {
|
|
|
52
62
|
model?: string;
|
|
53
63
|
};
|
|
54
64
|
/** Standalone permission gate (ADR 0020): "ask" cards every high-risk
|
|
55
|
-
* tool, "auto" runs the classifier, "deny" blocks them
|
|
56
|
-
* (
|
|
57
|
-
*
|
|
58
|
-
|
|
65
|
+
* tool, "auto" runs the classifier, "deny" blocks them, "yolo" runs
|
|
66
|
+
* ungated (the industry's skip-permissions mode — judgment gates off,
|
|
67
|
+
* STATIC boundaries stay: workspace containment, protected files,
|
|
68
|
+
* secret stripping, egress rules, write freshness; the OS bash sandbox
|
|
69
|
+
* is force-enabled when the platform has one). Absent = ungated (legacy
|
|
70
|
+
* default). The product RPC path never reads this — its permissionMode
|
|
71
|
+
* arrives frozen in the run snapshot. */
|
|
72
|
+
permissionMode?: "ask" | "auto" | "deny" | "yolo";
|
|
73
|
+
/** Plan mode master switch (default ON). Turn it off in a workspace that
|
|
74
|
+
* should never enter the read-only planning loop. */
|
|
75
|
+
planEnabled?: boolean;
|
|
76
|
+
/** Model used while planning ("provider/model"); absent = the session's
|
|
77
|
+
* model. Planning benefits from a stronger reader than the implementer,
|
|
78
|
+
* and the modes are separate so the two can differ. */
|
|
79
|
+
planModel?: string;
|
|
80
|
+
/** Goal mode master switch (default ON). A workspace that does not want an
|
|
81
|
+
* autonomous multi-turn objective driver can turn it off; /goal and
|
|
82
|
+
* /guided-goal then refuse with a hint. */
|
|
83
|
+
goalEnabled?: boolean;
|
|
84
|
+
/** Loop mode between-iteration action (`/loop`): "prompt" re-submits the
|
|
85
|
+
* prompt, "compact" summarizes the context first, "reset" starts a fresh
|
|
86
|
+
* session first, "ralph" runs the build loop (one work-queue item per fresh
|
|
87
|
+
* session). Absent = "prompt". */
|
|
88
|
+
loopAction?: "prompt" | "compact" | "reset" | "ralph";
|
|
59
89
|
/** Read-side tool-result pruning: old tool output outside the protect
|
|
60
90
|
* window is replaced by a short summary before each model call (a lighter
|
|
61
91
|
* touch than compaction). Absent = pruning OFF — the loop only prunes when
|
|
62
92
|
* a run was explicitly configured for it. */
|
|
63
93
|
prune?: PruneKnobs;
|
|
94
|
+
/** Let the browser tool open loopback/RFC1918 targets, so a local dev server
|
|
95
|
+
* can be inspected (env OMA_BROWSER_LOCAL_NETWORK=1). Cloud metadata
|
|
96
|
+
* endpoints stay refused either way. Opt-IN because it loosens a boundary;
|
|
97
|
+
* like permissionMode it is standalone-only — a backend RPC run ignores the
|
|
98
|
+
* workspace file and takes the value from its frozen run snapshot. */
|
|
99
|
+
browserLocalNetwork?: boolean;
|
|
100
|
+
/** Write freshness policy for the file tools (env OMA_EDIT_FRESHNESS).
|
|
101
|
+
* "require" = edit/write must echo the [fingerprint ...] a read reported, so
|
|
102
|
+
* a write can never land on content the caller has not seen; "off" restores
|
|
103
|
+
* the pre-fingerprint behaviour. ABSENT MEANS "require": the gate is on
|
|
104
|
+
* unless a workspace deliberately downgrades it, and a workspace can only do
|
|
105
|
+
* that for itself (`read_only` file tools cannot edit `.oma/settings.json` —
|
|
106
|
+
* it is in PROTECTED_FILES). A backend RPC run ignores the workspace value
|
|
107
|
+
* entirely and keeps the default. */
|
|
108
|
+
editFreshness?: "off" | "require";
|
|
64
109
|
}
|
|
65
110
|
/** Tool-output pruning knobs (see tool-pruning.ts for the mechanics). */
|
|
66
111
|
export interface PruneKnobs {
|
|
@@ -86,6 +131,7 @@ export interface RuntimeKnobs {
|
|
|
86
131
|
maxSteps?: number;
|
|
87
132
|
modelTimeoutMs?: number;
|
|
88
133
|
mcpTimeoutMs?: number;
|
|
134
|
+
askTimeoutMs?: number;
|
|
89
135
|
maxToolTimeoutMs?: number;
|
|
90
136
|
bashTimeoutMs?: number;
|
|
91
137
|
evalTimeoutMs?: number;
|
|
@@ -93,6 +139,11 @@ export interface RuntimeKnobs {
|
|
|
93
139
|
permissionClassifierModel?: string;
|
|
94
140
|
permissionClassifierTimeoutMs?: number;
|
|
95
141
|
disableWeb?: boolean;
|
|
142
|
+
/** Browser tool: allow loopback/RFC1918 targets (metadata stays refused). */
|
|
143
|
+
browserLocalNetwork?: boolean;
|
|
144
|
+
/** File-tool write freshness: "require" (fingerprint echo) or "off".
|
|
145
|
+
* The assembly treats absence as "require". */
|
|
146
|
+
editFreshness?: "off" | "require";
|
|
96
147
|
titleEnabled?: boolean;
|
|
97
148
|
conversationTitled?: boolean;
|
|
98
149
|
memoryExtract?: boolean;
|
|
@@ -107,6 +158,9 @@ export interface RuntimeKnobs {
|
|
|
107
158
|
export declare function resolveRuntimeKnobs(settings: ProjectSettings | undefined, env?: Readonly<Record<string, string | undefined>>): RuntimeKnobs;
|
|
108
159
|
/** Effective standalone permission mode: an explicit choice (CLI flag,
|
|
109
160
|
* /permission override) wins; the workspace setting is the default.
|
|
110
|
-
* "off" (a TUI override) and absent both resolve to undefined = ungated.
|
|
111
|
-
|
|
161
|
+
* "off" (a TUI override) and absent both resolve to undefined = ungated.
|
|
162
|
+
* "yolo" stays DISTINCT from undefined: both are ungated at the gate, but
|
|
163
|
+
* yolo additionally force-enables the OS bash sandbox — collapsing it into
|
|
164
|
+
* undefined would silently drop that compensating control. */
|
|
165
|
+
export declare function resolvePermissionMode(explicit?: "ask" | "auto" | "deny" | "yolo" | "off", workspaceRoot?: string): "ask" | "auto" | "deny" | "yolo" | undefined;
|
|
112
166
|
//# sourceMappingURL=project-settings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-settings.d.ts","sourceRoot":"","sources":["../../../src/core/settings/project-settings.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"project-settings.d.ts","sourceRoot":"","sources":["../../../src/core/settings/project-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,9 @@ export function loadProjectSettings(root) {
|
|
|
34
34
|
if ("mcpTimeoutMs" in parsed && typeof parsed.mcpTimeoutMs === "number") {
|
|
35
35
|
result.mcpTimeoutMs = parsed.mcpTimeoutMs;
|
|
36
36
|
}
|
|
37
|
+
if ("askTimeoutMs" in parsed && typeof parsed.askTimeoutMs === "number") {
|
|
38
|
+
result.askTimeoutMs = parsed.askTimeoutMs;
|
|
39
|
+
}
|
|
37
40
|
if ("disableWeb" in parsed && typeof parsed.disableWeb === "boolean") {
|
|
38
41
|
result.disableWeb = parsed.disableWeb;
|
|
39
42
|
}
|
|
@@ -59,6 +62,29 @@ export function loadProjectSettings(root) {
|
|
|
59
62
|
if ("bashSandbox" in parsed && typeof parsed.bashSandbox === "boolean") {
|
|
60
63
|
result.bashSandbox = parsed.bashSandbox;
|
|
61
64
|
}
|
|
65
|
+
if ("browserLocalNetwork" in parsed && typeof parsed.browserLocalNetwork === "boolean") {
|
|
66
|
+
result.browserLocalNetwork = parsed.browserLocalNetwork;
|
|
67
|
+
}
|
|
68
|
+
if ("editFreshness" in parsed &&
|
|
69
|
+
(parsed.editFreshness === "off" || parsed.editFreshness === "require")) {
|
|
70
|
+
result.editFreshness = parsed.editFreshness;
|
|
71
|
+
}
|
|
72
|
+
if ("planEnabled" in parsed && typeof parsed.planEnabled === "boolean") {
|
|
73
|
+
result.planEnabled = parsed.planEnabled;
|
|
74
|
+
}
|
|
75
|
+
if ("planModel" in parsed && typeof parsed.planModel === "string" && parsed.planModel.trim()) {
|
|
76
|
+
result.planModel = parsed.planModel.trim();
|
|
77
|
+
}
|
|
78
|
+
if ("goalEnabled" in parsed && typeof parsed.goalEnabled === "boolean") {
|
|
79
|
+
result.goalEnabled = parsed.goalEnabled;
|
|
80
|
+
}
|
|
81
|
+
if ("loopAction" in parsed &&
|
|
82
|
+
(parsed.loopAction === "prompt" ||
|
|
83
|
+
parsed.loopAction === "compact" ||
|
|
84
|
+
parsed.loopAction === "reset" ||
|
|
85
|
+
parsed.loopAction === "ralph")) {
|
|
86
|
+
result.loopAction = parsed.loopAction;
|
|
87
|
+
}
|
|
62
88
|
if ("memoryVector" in parsed &&
|
|
63
89
|
typeof parsed.memoryVector === "object" &&
|
|
64
90
|
parsed.memoryVector !== null) {
|
|
@@ -74,7 +100,8 @@ export function loadProjectSettings(root) {
|
|
|
74
100
|
if ("permissionMode" in parsed &&
|
|
75
101
|
(parsed.permissionMode === "ask" ||
|
|
76
102
|
parsed.permissionMode === "auto" ||
|
|
77
|
-
parsed.permissionMode === "deny"
|
|
103
|
+
parsed.permissionMode === "deny" ||
|
|
104
|
+
parsed.permissionMode === "yolo")) {
|
|
78
105
|
result.permissionMode = parsed.permissionMode;
|
|
79
106
|
}
|
|
80
107
|
if ("maxToolTimeoutMs" in parsed && typeof parsed.maxToolTimeoutMs === "number") {
|
|
@@ -161,6 +188,9 @@ export function resolveRuntimeKnobs(settings, env = process.env) {
|
|
|
161
188
|
const bashTimeoutMs = s.bashTimeoutMs ?? envPositive(env, "OMA_BASH_TIMEOUT_MS");
|
|
162
189
|
if (bashTimeoutMs !== undefined)
|
|
163
190
|
knobs.bashTimeoutMs = bashTimeoutMs;
|
|
191
|
+
const askTimeoutMs = s.askTimeoutMs ?? envNumber(env, "OMA_ASK_TIMEOUT_MS");
|
|
192
|
+
if (askTimeoutMs !== undefined)
|
|
193
|
+
knobs.askTimeoutMs = askTimeoutMs;
|
|
164
194
|
const evalTimeoutMs = envNumber(env, "OMA_EVAL_TIMEOUT_MS");
|
|
165
195
|
if (evalTimeoutMs !== undefined)
|
|
166
196
|
knobs.evalTimeoutMs = evalTimeoutMs;
|
|
@@ -196,11 +226,22 @@ export function resolveRuntimeKnobs(settings, env = process.env) {
|
|
|
196
226
|
knobs.memoryModel = s.memoryModel;
|
|
197
227
|
if (s.prune)
|
|
198
228
|
knobs.prune = s.prune;
|
|
229
|
+
const browserLocalNetwork = s.browserLocalNetwork ?? (env.OMA_BROWSER_LOCAL_NETWORK === "1" ? true : undefined);
|
|
230
|
+
if (browserLocalNetwork !== undefined)
|
|
231
|
+
knobs.browserLocalNetwork = browserLocalNetwork;
|
|
232
|
+
// Only an explicit "off" resolves here; absence stays undefined so the
|
|
233
|
+
// assembly can apply its "require" default in one visible place.
|
|
234
|
+
const editFreshness = s.editFreshness ?? (env.OMA_EDIT_FRESHNESS === "off" ? "off" : undefined);
|
|
235
|
+
if (editFreshness !== undefined)
|
|
236
|
+
knobs.editFreshness = editFreshness;
|
|
199
237
|
return knobs;
|
|
200
238
|
}
|
|
201
239
|
/** Effective standalone permission mode: an explicit choice (CLI flag,
|
|
202
240
|
* /permission override) wins; the workspace setting is the default.
|
|
203
|
-
* "off" (a TUI override) and absent both resolve to undefined = ungated.
|
|
241
|
+
* "off" (a TUI override) and absent both resolve to undefined = ungated.
|
|
242
|
+
* "yolo" stays DISTINCT from undefined: both are ungated at the gate, but
|
|
243
|
+
* yolo additionally force-enables the OS bash sandbox — collapsing it into
|
|
244
|
+
* undefined would silently drop that compensating control. */
|
|
204
245
|
export function resolvePermissionMode(explicit, workspaceRoot) {
|
|
205
246
|
if (explicit)
|
|
206
247
|
return explicit === "off" ? undefined : explicit;
|
|
@@ -8,10 +8,10 @@ import { agentDir } from "../session/session-file.js";
|
|
|
8
8
|
* values (Loop scopes still pass their own LOOP.md config).
|
|
9
9
|
*
|
|
10
10
|
* Context-file discovery absorbs oh-my-pi's context-files.md semantics,
|
|
11
|
-
* ponytail cut: AGENTS.md only (no multi-provider discovery), no @
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* ponytail cut: AGENTS.md only (no multi-provider discovery), no @ imports
|
|
12
|
+
* (the agent has read tools), and no sticky-rule file (the prompt lands in
|
|
13
|
+
* the SYSTEM role, which is sticky by construction — omp needs a separate
|
|
14
|
+
* RULES.md because it injects into the opening message instead). */
|
|
15
15
|
function readTextOrNull(path) {
|
|
16
16
|
try {
|
|
17
17
|
return readFileSync(path, "utf-8");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-session-store.d.ts","sourceRoot":"","sources":["../../../src/core/store/in-memory-session-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuC,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAS5F,wBAAgB,0BAA0B,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"in-memory-session-store.d.ts","sourceRoot":"","sources":["../../../src/core/store/in-memory-session-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuC,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAS5F,wBAAgB,0BAA0B,IAAI,YAAY,CAiIzD"}
|