@caupulican/pi-adaptative 0.80.7 → 0.80.9
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 +8 -0
- package/README.md +1 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +16 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +17 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -3
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/export-html/template.js +19 -6
- package/dist/core/package-manager.d.ts +3 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +47 -13
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/reload-blockers.d.ts +2 -0
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +8 -2
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +30 -22
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +71 -30
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +7 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/trust-manager.d.ts +9 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +134 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +65 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -12
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +20 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +86 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +127 -26
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +55 -8
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/docs/adaptive-extension-shared-state-audit.md +43 -0
- package/docs/settings.md +2 -2
- package/docs/skills.md +3 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -26,6 +26,7 @@ import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../cor
|
|
|
26
26
|
import { isAutoLearnSessionId, SessionManager } from "../../core/session-manager.js";
|
|
27
27
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
28
28
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
29
|
+
import { hasProjectTrustInputs, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
29
30
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
30
31
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
31
32
|
import { readClipboardImage } from "../../utils/clipboard-image.js";
|
|
@@ -63,6 +64,7 @@ import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
|
63
64
|
import { ToolGroupComponent } from "./components/tool-group.js";
|
|
64
65
|
import { getToolPanelActionKey, ToolPanelRegistry } from "./components/tool-panel-registry.js";
|
|
65
66
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
67
|
+
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
66
68
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
67
69
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
68
70
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
@@ -158,6 +160,14 @@ function definedStringSet(values) {
|
|
|
158
160
|
}
|
|
159
161
|
return set;
|
|
160
162
|
}
|
|
163
|
+
function sanitizeAutoLearnPathPart(input, fallback) {
|
|
164
|
+
const cleaned = (input || fallback)
|
|
165
|
+
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
166
|
+
.replace(/-+/g, "-")
|
|
167
|
+
.replace(/^-+|-+$/g, "")
|
|
168
|
+
.slice(0, 80);
|
|
169
|
+
return cleaned || fallback;
|
|
170
|
+
}
|
|
161
171
|
function isOldAutoLearnArtifact(filePath, now, retentionMs) {
|
|
162
172
|
const stats = fs.lstatSync(filePath);
|
|
163
173
|
return stats.isFile() && now - stats.mtimeMs > retentionMs;
|
|
@@ -171,6 +181,22 @@ function removeOldAutoLearnArtifact(filePath, result, counter) {
|
|
|
171
181
|
result.errors++;
|
|
172
182
|
}
|
|
173
183
|
}
|
|
184
|
+
function isPathInside(target, root) {
|
|
185
|
+
const resolvedTarget = path.resolve(target);
|
|
186
|
+
const resolvedRoot = path.resolve(root);
|
|
187
|
+
return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(`${resolvedRoot}${path.sep}`);
|
|
188
|
+
}
|
|
189
|
+
function removeAutoLearnArtifactPath(filePath, root) {
|
|
190
|
+
if (!isPathInside(filePath, root))
|
|
191
|
+
return false;
|
|
192
|
+
try {
|
|
193
|
+
fs.rmSync(filePath, { recursive: true, force: true });
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
174
200
|
function readAutoLearnSessionIdFromFile(filePath) {
|
|
175
201
|
let fd;
|
|
176
202
|
try {
|
|
@@ -232,24 +258,20 @@ function pruneAutoLearnSessionFiles(dir, activeSessionIds, now, retentionMs, res
|
|
|
232
258
|
removeOldAutoLearnArtifact(filePath, result, "sessionFiles");
|
|
233
259
|
}
|
|
234
260
|
}
|
|
235
|
-
|
|
236
|
-
const result = { promptFiles: 0, logFiles: 0, sessionFiles: 0, errors: 0 };
|
|
237
|
-
const dataDir = path.resolve(options.dataDir);
|
|
238
|
-
const now = options.now ?? Date.now();
|
|
239
|
-
const retentionMs = options.retentionMs ?? AUTO_LEARN_HISTORY_RETENTION_MS;
|
|
240
|
-
const activeRunIds = definedStringSet(options.activeRunIds);
|
|
241
|
-
const activeSessionIds = definedStringSet(options.activeSessionIds);
|
|
242
|
-
if (retentionMs <= 0 || !fs.existsSync(dataDir))
|
|
243
|
-
return result;
|
|
261
|
+
function pruneAutoLearnRunArtifacts(dir, activeRunIds, now, retentionMs, result) {
|
|
244
262
|
let entries;
|
|
245
263
|
try {
|
|
246
|
-
entries = fs.readdirSync(
|
|
264
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
247
265
|
}
|
|
248
266
|
catch {
|
|
249
|
-
|
|
250
|
-
return result;
|
|
267
|
+
return;
|
|
251
268
|
}
|
|
252
269
|
for (const entry of entries) {
|
|
270
|
+
const filePath = path.join(dir, entry.name);
|
|
271
|
+
if (entry.isDirectory()) {
|
|
272
|
+
pruneAutoLearnRunArtifacts(filePath, activeRunIds, now, retentionMs, result);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
253
275
|
if (!entry.isFile())
|
|
254
276
|
continue;
|
|
255
277
|
const promptRunId = entry.name.endsWith(".prompt.md") ? entry.name.slice(0, -".prompt.md".length) : undefined;
|
|
@@ -257,7 +279,6 @@ export function pruneAutoLearnConversationHistory(options) {
|
|
|
257
279
|
const runId = promptRunId ?? logRunId;
|
|
258
280
|
if (!runId || activeRunIds.has(runId))
|
|
259
281
|
continue;
|
|
260
|
-
const filePath = path.join(dataDir, entry.name);
|
|
261
282
|
let shouldPrune = false;
|
|
262
283
|
try {
|
|
263
284
|
shouldPrune = isOldAutoLearnArtifact(filePath, now, retentionMs);
|
|
@@ -270,7 +291,18 @@ export function pruneAutoLearnConversationHistory(options) {
|
|
|
270
291
|
continue;
|
|
271
292
|
removeOldAutoLearnArtifact(filePath, result, promptRunId ? "promptFiles" : "logFiles");
|
|
272
293
|
}
|
|
273
|
-
|
|
294
|
+
}
|
|
295
|
+
export function pruneAutoLearnConversationHistory(options) {
|
|
296
|
+
const result = { promptFiles: 0, logFiles: 0, sessionFiles: 0, errors: 0 };
|
|
297
|
+
const dataDir = path.resolve(options.dataDir);
|
|
298
|
+
const now = options.now ?? Date.now();
|
|
299
|
+
const retentionMs = options.retentionMs ?? AUTO_LEARN_HISTORY_RETENTION_MS;
|
|
300
|
+
const activeRunIds = definedStringSet(options.activeRunIds);
|
|
301
|
+
const activeSessionIds = definedStringSet(options.activeSessionIds);
|
|
302
|
+
if (retentionMs <= 0 || !fs.existsSync(dataDir))
|
|
303
|
+
return result;
|
|
304
|
+
pruneAutoLearnRunArtifacts(dataDir, activeRunIds, now, retentionMs, result);
|
|
305
|
+
pruneAutoLearnSessionFiles(dataDir, activeSessionIds, now, retentionMs, result);
|
|
274
306
|
return result;
|
|
275
307
|
}
|
|
276
308
|
export function buildAutoLearnSpawnArgs(spawnTarget, options) {
|
|
@@ -704,6 +736,7 @@ export class InteractiveMode {
|
|
|
704
736
|
await this.rebindCurrentSession();
|
|
705
737
|
// Render initial messages AFTER showing loaded resources
|
|
706
738
|
this.renderInitialMessages();
|
|
739
|
+
this.renderProjectTrustWarningIfNeeded();
|
|
707
740
|
// Set up theme file watcher
|
|
708
741
|
onThemeChange(() => {
|
|
709
742
|
this.ui.invalidate();
|
|
@@ -718,6 +751,15 @@ export class InteractiveMode {
|
|
|
718
751
|
await this.updateAvailableProviderCount();
|
|
719
752
|
this.updateAutoLearnFooter();
|
|
720
753
|
}
|
|
754
|
+
renderProjectTrustWarningIfNeeded() {
|
|
755
|
+
if (this.settingsManager.isProjectTrusted() || !hasProjectTrustInputs(this.sessionManager.getCwd())) {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (this.chatContainer.children.length > 0) {
|
|
759
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
760
|
+
}
|
|
761
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", "This project is not trusted. Project instructions (AGENTS.md/CLAUDE.md/GEMINI.md), .pi resources, and project packages are ignored. Use /trust to save a trust decision, then restart pi."), 1, 0));
|
|
762
|
+
}
|
|
721
763
|
/**
|
|
722
764
|
* Update terminal title with session name and cwd.
|
|
723
765
|
*/
|
|
@@ -2389,6 +2431,11 @@ export class InteractiveMode {
|
|
|
2389
2431
|
this.editor.setText("");
|
|
2390
2432
|
return;
|
|
2391
2433
|
}
|
|
2434
|
+
if (text === "/trust") {
|
|
2435
|
+
this.showTrustSelector();
|
|
2436
|
+
this.editor.setText("");
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2392
2439
|
if (text === "/login" || text.startsWith("/login ")) {
|
|
2393
2440
|
await this.showOAuthSelector("login", text.slice("/login".length).trim() || undefined);
|
|
2394
2441
|
this.editor.setText("");
|
|
@@ -3759,13 +3806,21 @@ export class InteractiveMode {
|
|
|
3759
3806
|
getAutoLearnTenantKey() {
|
|
3760
3807
|
return `${this.sessionManager.getCwd()}::${this.session.sessionId}`;
|
|
3761
3808
|
}
|
|
3809
|
+
getAutoLearnTenantId() {
|
|
3810
|
+
const cwdHash = crypto.createHash("sha256").update(this.sessionManager.getCwd()).digest("hex").slice(0, 8);
|
|
3811
|
+
const sessionPart = sanitizeAutoLearnPathPart(this.session.sessionId, "session");
|
|
3812
|
+
return `${sessionPart}-${cwdHash}`;
|
|
3813
|
+
}
|
|
3814
|
+
getAutoLearnTenantDataDir() {
|
|
3815
|
+
return path.join(this.getAutoLearnDataDir(), "tenants", this.getAutoLearnTenantId());
|
|
3816
|
+
}
|
|
3762
3817
|
getAutoLearnMessageCount() {
|
|
3763
3818
|
return this.sessionManager.getBranch().filter((entry) => entry.type === "message").length;
|
|
3764
3819
|
}
|
|
3765
3820
|
buildAutoLearnDecisionFromState(state, settings, force = false) {
|
|
3766
3821
|
const now = Date.now();
|
|
3767
3822
|
const tenant = this.getAutoLearnTenantKey();
|
|
3768
|
-
const runningCount = Object.
|
|
3823
|
+
const runningCount = Object.values(state.runs ?? {}).filter((run) => run.tenant === tenant).length;
|
|
3769
3824
|
const lastLaunch = state.lastLaunchByTenant?.[tenant] ?? 0;
|
|
3770
3825
|
const cooldownMs = settings.cooldownMinutes * 60 * 1000;
|
|
3771
3826
|
const cooldownRemainingMs = Math.max(0, lastLaunch + cooldownMs - now);
|
|
@@ -3784,7 +3839,7 @@ export class InteractiveMode {
|
|
|
3784
3839
|
if (runningCount >= settings.maxConcurrentLearners) {
|
|
3785
3840
|
return {
|
|
3786
3841
|
shouldRun: false,
|
|
3787
|
-
reason: `max learners running (${runningCount}/${settings.maxConcurrentLearners})`,
|
|
3842
|
+
reason: `max tenant learners running (${runningCount}/${settings.maxConcurrentLearners})`,
|
|
3788
3843
|
messageCount,
|
|
3789
3844
|
contextPercent,
|
|
3790
3845
|
cooldownRemainingMs,
|
|
@@ -3926,7 +3981,7 @@ export class InteractiveMode {
|
|
|
3926
3981
|
const objective = options.kind === "reflection"
|
|
3927
3982
|
? "review the latest completed turn for durable memory, skill, validation, and tooling-improvement cues, then run one bounded continuous-learning pass if the learning tools are available"
|
|
3928
3983
|
: "run one bounded continuous-learning pass for this Pi tenant";
|
|
3929
|
-
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}.\n3. Treat the latest-turn digest as current-session evidence only; do not auto-commit one-off cues unless deterministic tooling
|
|
3984
|
+
return `You are Pi Auto Learn running as a background learner.\n\nObjective: ${objective}.\nTrigger: ${reason}.\n\n${authorityBlock}\n\nRequired workflow:\n1. Query existing durable memory/rules first when tools allow it. Memory confrontation is mandatory before accepting, merging, upgrading, or rejecting learning candidates.\n2. Run the available Auto Learn tooling, preferably learning_run_auto, with applyHighConfidence=${settings.applyHighConfidence}. Process candidate validation in vectorized chunks/batches; avoid scalar per-candidate memory queries except for final selected writes.\n3. Apply the learning validation tree to each candidate chunk: (a) Why is this good for the user? (b) Is it unique, or similar to existing memory/skills/agents so it should merge or upgrade existing knowledge? (c) Will this make Pi a better agent? Candidates that cannot answer all three are noise.\n4. Treat the latest-turn digest as current-session evidence only; do not auto-commit one-off cues unless deterministic tooling and memory confrontation corroborate them.\n5. In mode=full, apply safe memory/skill/user-extension/authorized-source improvements under the standing grant above; otherwise keep them proposal-gated.\n6. Never cross hard-stop boundaries from the authority policy.\n7. If the learning tools are unavailable, report BLOCKED with the missing tool names and do not improvise.\n8. Finish with PASS, BLOCKED, or FAIL and concise evidence, including chunk counts, merge/upgrade decisions, and cleanup/purge status.${reflectionBlock}`;
|
|
3930
3985
|
}
|
|
3931
3986
|
reserveAutoLearnRun(params) {
|
|
3932
3987
|
return this.withAutoLearnStateLock((current) => {
|
|
@@ -3993,6 +4048,20 @@ export class InteractiveMode {
|
|
|
3993
4048
|
return { result: undefined, next };
|
|
3994
4049
|
});
|
|
3995
4050
|
}
|
|
4051
|
+
cleanupCompletedAutoLearnRun(runId, artifactPaths) {
|
|
4052
|
+
const dataDir = this.getAutoLearnDataDir();
|
|
4053
|
+
const removed = artifactPaths.filter((filePath) => removeAutoLearnArtifactPath(filePath, dataDir)).length;
|
|
4054
|
+
this.withAutoLearnStateLock((current) => {
|
|
4055
|
+
const state = this.pruneAutoLearnState(current);
|
|
4056
|
+
const runs = { ...(state.runs ?? {}) };
|
|
4057
|
+
delete runs[runId];
|
|
4058
|
+
return { result: undefined, next: { ...state, runs } };
|
|
4059
|
+
});
|
|
4060
|
+
if (removed > 0) {
|
|
4061
|
+
this.autoLearnLastStatus = `cleaned ${removed} artifact(s)`;
|
|
4062
|
+
this.updateAutoLearnFooter();
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
3996
4065
|
markAutoLearnReservationRunning(reservation, pid, settings) {
|
|
3997
4066
|
this.withAutoLearnStateLock((current) => {
|
|
3998
4067
|
const now = Date.now();
|
|
@@ -4028,14 +4097,14 @@ export class InteractiveMode {
|
|
|
4028
4097
|
if (!spawnTarget) {
|
|
4029
4098
|
return "Auto Learn not started: could not resolve current pi CLI path.";
|
|
4030
4099
|
}
|
|
4031
|
-
const dir = this.
|
|
4100
|
+
const dir = this.getAutoLearnTenantDataDir();
|
|
4032
4101
|
fs.mkdirSync(dir, { recursive: true });
|
|
4033
4102
|
const runId = `${Date.now()}-${crypto.randomUUID().slice(0, 8)}`;
|
|
4034
4103
|
const logPath = path.join(dir, `${runId}.log`);
|
|
4035
4104
|
const promptPath = path.join(dir, `${runId}.prompt.md`);
|
|
4036
4105
|
const kind = options.promptKind ?? "auto";
|
|
4037
|
-
const sessionDir = path.join(dir, "sessions");
|
|
4038
|
-
const sessionId = `auto-learn-${kind}-${runId}`;
|
|
4106
|
+
const sessionDir = path.join(dir, "sessions", runId);
|
|
4107
|
+
const sessionId = `auto-learn-${kind}-${this.getAutoLearnTenantId()}-${runId}`;
|
|
4039
4108
|
fs.mkdirSync(sessionDir, { recursive: true });
|
|
4040
4109
|
const prompt = this.buildAutoLearnPrompt(reason, settings, {
|
|
4041
4110
|
kind,
|
|
@@ -4129,6 +4198,10 @@ export class InteractiveMode {
|
|
|
4129
4198
|
return `Auto Learn not started: failed to spawn background learner. Log: ${logPath}`;
|
|
4130
4199
|
}
|
|
4131
4200
|
const childPid = child.pid;
|
|
4201
|
+
child.once("exit", (code) => {
|
|
4202
|
+
if (code === 0)
|
|
4203
|
+
this.cleanupCompletedAutoLearnRun(reservation.runId, [promptPath, logPath, sessionDir]);
|
|
4204
|
+
});
|
|
4132
4205
|
child.unref();
|
|
4133
4206
|
this.markAutoLearnReservationRunning(reservation, childPid, settings);
|
|
4134
4207
|
this.autoLearnLastStatus = `running ${modelPattern}`;
|
|
@@ -4212,7 +4285,7 @@ export class InteractiveMode {
|
|
|
4212
4285
|
});
|
|
4213
4286
|
const now = Date.now();
|
|
4214
4287
|
const tenant = this.getAutoLearnTenantKey();
|
|
4215
|
-
const runningCount = Object.
|
|
4288
|
+
const runningCount = Object.values(state.runs ?? {}).filter((run) => run.tenant === tenant).length;
|
|
4216
4289
|
const lastReflection = state.lastReflectionByTenant?.[tenant] ?? 0;
|
|
4217
4290
|
const cooldownMs = settings.reflectionCooldownMinutes * 60 * 1000;
|
|
4218
4291
|
const cooldownRemainingMs = Math.max(0, lastReflection + cooldownMs - now);
|
|
@@ -4233,7 +4306,7 @@ export class InteractiveMode {
|
|
|
4233
4306
|
return {
|
|
4234
4307
|
...base,
|
|
4235
4308
|
shouldRun: false,
|
|
4236
|
-
reason: `max learners running (${runningCount}/${settings.maxConcurrentLearners})`,
|
|
4309
|
+
reason: `max tenant learners running (${runningCount}/${settings.maxConcurrentLearners})`,
|
|
4237
4310
|
};
|
|
4238
4311
|
}
|
|
4239
4312
|
if (cooldownRemainingMs > 0)
|
|
@@ -4305,7 +4378,9 @@ export class InteractiveMode {
|
|
|
4305
4378
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
4306
4379
|
const decision = this.evaluateAutoLearn(false);
|
|
4307
4380
|
const state = this.getPrunedAutoLearnState();
|
|
4308
|
-
const
|
|
4381
|
+
const tenant = this.getAutoLearnTenantKey();
|
|
4382
|
+
const runs = Object.entries(state.runs ?? {}).filter(([, run]) => run.tenant === tenant);
|
|
4383
|
+
const otherTenantRuns = Object.values(state.runs ?? {}).filter((run) => run.tenant !== tenant).length;
|
|
4309
4384
|
const contextText = decision.contextPercent === null ? "unknown" : `${decision.contextPercent.toFixed(1)}%`;
|
|
4310
4385
|
const cooldownText = decision.cooldownRemainingMs > 0 ? `${Math.ceil(decision.cooldownRemainingMs / 60000)}m remaining` : "ready";
|
|
4311
4386
|
const runLines = runs.length
|
|
@@ -4333,13 +4408,15 @@ export class InteractiveMode {
|
|
|
4333
4408
|
const reflectionLast = state.lastReflectionByTenant?.[this.getAutoLearnTenantKey()] ?? 0;
|
|
4334
4409
|
const reflectionCooldownRemainingMs = Math.max(0, reflectionLast + settings.reflectionCooldownMinutes * 60 * 1000 - Date.now());
|
|
4335
4410
|
const reflectionCooldownText = reflectionCooldownRemainingMs > 0 ? `${Math.ceil(reflectionCooldownRemainingMs / 60000)}m remaining` : "ready";
|
|
4336
|
-
return `Auto Learn status\nEnabled: ${settings.enabled}\nModel: ${settings.model}\nNext decision: ${decision.shouldRun ? "ready" : decision.reason}\nMessages: ${decision.messageCount}/${settings.longSessionMessages}\nContext: ${contextText}/${settings.longSessionContextPercent}%\nCooldown: ${cooldownText}\nReflection review: ${settings.reflectionReview ? "enabled" : "disabled"} (tool trigger ${settings.reflectionMinToolCalls}, cooldown ${reflectionCooldownText})\nHistory retention: 7 days for internal Auto Learn prompts/logs/sessions\nRunning leases: ${runs.length}/${settings.maxConcurrentLearners}\nPi auto-reload blockers: ${reloadBlockers.pending ? reloadBlockers.reason : "none"}\n${reloadBlockerLines}\nRuns:\n${runLines}`;
|
|
4411
|
+
return `Auto Learn status\nEnabled: ${settings.enabled}\nModel: ${settings.model}\nNext decision: ${decision.shouldRun ? "ready" : decision.reason}\nMessages: ${decision.messageCount}/${settings.longSessionMessages}\nContext: ${contextText}/${settings.longSessionContextPercent}%\nCooldown: ${cooldownText}\nReflection review: ${settings.reflectionReview ? "enabled" : "disabled"} (tool trigger ${settings.reflectionMinToolCalls}, cooldown ${reflectionCooldownText})\nHistory retention: 7 days for internal Auto Learn prompts/logs/sessions\nRunning tenant leases: ${runs.length}/${settings.maxConcurrentLearners}\nOther tenant leases: ${otherTenantRuns}\nTenant artifact dir: ${this.getAutoLearnTenantDataDir()}\nPi auto-reload blockers: ${reloadBlockers.pending ? reloadBlockers.reason : "none"}\n${reloadBlockerLines}\nRuns:\n${runLines}`;
|
|
4337
4412
|
}
|
|
4338
4413
|
formatAutonomyStatus() {
|
|
4339
4414
|
const autonomy = this.settingsManager.getAutonomySettings();
|
|
4340
4415
|
const settings = this.getEffectiveAutoLearnSettings();
|
|
4341
4416
|
const autoLearnState = this.getPrunedAutoLearnState();
|
|
4342
|
-
const
|
|
4417
|
+
const tenant = this.getAutoLearnTenantKey();
|
|
4418
|
+
const running = Object.entries(autoLearnState.runs ?? {}).filter(([, run]) => run.tenant === tenant);
|
|
4419
|
+
const otherTenantRunning = Object.values(autoLearnState.runs ?? {}).filter((run) => run.tenant !== tenant).length;
|
|
4343
4420
|
const safety = autonomy.mode === "full"
|
|
4344
4421
|
? "standing grant for memory, skills, user/project extensions, autonomy/autoLearn tuning, and authorized selfModification.sourcePath edits; hard stops still require explicit foreground approval"
|
|
4345
4422
|
: "proposal-gated outside configured high-confidence memory policy";
|
|
@@ -4352,10 +4429,12 @@ export class InteractiveMode {
|
|
|
4352
4429
|
`Auto Learn: ${settings.enabled ? "enabled" : "disabled"}; model=${settings.model}; applyHighConfidence=${settings.applyHighConfidence}`,
|
|
4353
4430
|
`Long-session trigger: ${settings.longSessionMessages} messages or ${settings.longSessionContextPercent}% context; cooldown=${settings.cooldownMinutes}m`,
|
|
4354
4431
|
reflectionLine,
|
|
4355
|
-
`Running learners: ${running.length}/${settings.maxConcurrentLearners}`,
|
|
4432
|
+
`Running tenant learners: ${running.length}/${settings.maxConcurrentLearners}`,
|
|
4433
|
+
`Other tenant learners: ${otherTenantRunning}`,
|
|
4356
4434
|
"History retention: 7 days for internal Auto Learn prompts/logs/sessions",
|
|
4357
4435
|
`Standing authority: ${safety}`,
|
|
4358
4436
|
`Audit/log dir: ${this.getAutoLearnDataDir()}`,
|
|
4437
|
+
`Tenant artifact dir: ${this.getAutoLearnTenantDataDir()}`,
|
|
4359
4438
|
"Use /autonomy off|safe|balanced|full to switch presets. Advanced overrides remain in /settings → Auto Learn Advanced.",
|
|
4360
4439
|
].join("\n");
|
|
4361
4440
|
}
|
|
@@ -4918,6 +4997,28 @@ export class InteractiveMode {
|
|
|
4918
4997
|
return { component: selector, focus: selector };
|
|
4919
4998
|
});
|
|
4920
4999
|
}
|
|
5000
|
+
showTrustSelector() {
|
|
5001
|
+
const cwd = this.sessionManager.getCwd();
|
|
5002
|
+
const trustStore = new ProjectTrustStore(this.runtimeHost.services.agentDir);
|
|
5003
|
+
const savedDecision = trustStore.get(cwd);
|
|
5004
|
+
this.showSelector((done) => {
|
|
5005
|
+
const selector = new TrustSelectorComponent({
|
|
5006
|
+
cwd,
|
|
5007
|
+
savedDecision,
|
|
5008
|
+
projectTrusted: this.settingsManager.isProjectTrusted(),
|
|
5009
|
+
onSelect: (trusted) => {
|
|
5010
|
+
trustStore.set(cwd, trusted);
|
|
5011
|
+
done();
|
|
5012
|
+
this.showStatus(`Saved trust decision: ${trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
|
|
5013
|
+
},
|
|
5014
|
+
onCancel: () => {
|
|
5015
|
+
done();
|
|
5016
|
+
this.ui.requestRender();
|
|
5017
|
+
},
|
|
5018
|
+
});
|
|
5019
|
+
return { component: selector, focus: selector };
|
|
5020
|
+
});
|
|
5021
|
+
}
|
|
4921
5022
|
showSessionSelector() {
|
|
4922
5023
|
this.showSelector((done) => {
|
|
4923
5024
|
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), (onProgress) => this.sessionManager.usesDefaultSessionDir()
|