@cjhyy/code-shell-core 0.6.0-rc.9 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +206 -0
- package/dist/automation/scheduler.d.ts +13 -7
- package/dist/automation/scheduler.js +116 -37
- package/dist/capability-control/service.d.ts +2 -0
- package/dist/capability-control/service.js +4 -2
- package/dist/cc-orchestrator/agent-adapter.d.ts +4 -0
- package/dist/cc-orchestrator/agent-adapter.js +11 -1
- package/dist/cc-orchestrator/codex-session-history.d.ts +14 -1
- package/dist/cc-orchestrator/codex-session-history.js +65 -5
- package/dist/cc-orchestrator/cwd-normalize.d.ts +2 -0
- package/dist/cc-orchestrator/cwd-normalize.js +19 -0
- package/dist/cc-orchestrator/external-agent-bindings.d.ts +27 -0
- package/dist/cc-orchestrator/external-agent-bindings.js +150 -0
- package/dist/cc-orchestrator/external-agent-changes.js +22 -5
- package/dist/cc-orchestrator/external-agent-driver.d.ts +1 -0
- package/dist/cc-orchestrator/external-agent-driver.js +265 -50
- package/dist/cc-orchestrator/external-agent-session-store.d.ts +23 -0
- package/dist/cc-orchestrator/external-agent-session-store.js +146 -0
- package/dist/cc-orchestrator/session-history.d.ts +35 -0
- package/dist/cc-orchestrator/session-history.js +98 -15
- package/dist/cli/agent-server-stdio.js +9 -2
- package/dist/context/compaction.d.ts +8 -1
- package/dist/context/compaction.js +49 -4
- package/dist/context/manager.d.ts +16 -2
- package/dist/context/manager.js +103 -19
- package/dist/credentials/access.d.ts +57 -0
- package/dist/credentials/access.js +185 -0
- package/dist/credentials/index.d.ts +3 -1
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/inject-credential-tool.d.ts +3 -1
- package/dist/credentials/inject-credential-tool.js +30 -11
- package/dist/credentials/oauth.d.ts +20 -0
- package/dist/credentials/oauth.js +114 -0
- package/dist/credentials/store.d.ts +1 -0
- package/dist/credentials/store.js +3 -1
- package/dist/credentials/types.d.ts +49 -3
- package/dist/credentials/use-credential-tool.d.ts +9 -1
- package/dist/credentials/use-credential-tool.js +58 -45
- package/dist/engine/engine.d.ts +23 -3
- package/dist/engine/engine.js +380 -255
- package/dist/engine/goal.d.ts +17 -0
- package/dist/engine/goal.js +16 -6
- package/dist/engine/image-policy.d.ts +6 -0
- package/dist/engine/image-policy.js +17 -6
- package/dist/engine/input-attachments.d.ts +13 -0
- package/dist/engine/input-attachments.js +398 -0
- package/dist/engine/model-facade.d.ts +5 -2
- package/dist/engine/model-facade.js +4 -4
- package/dist/engine/parse-task.d.ts +10 -0
- package/dist/engine/parse-task.js +5 -0
- package/dist/engine/run-image-input.d.ts +22 -0
- package/dist/engine/run-image-input.js +195 -0
- package/dist/engine/steer-queue.d.ts +3 -1
- package/dist/engine/steer-queue.js +10 -2
- package/dist/engine/streaming-tool-queue.d.ts +11 -7
- package/dist/engine/streaming-tool-queue.js +11 -7
- package/dist/engine/turn-loop.d.ts +37 -2
- package/dist/engine/turn-loop.js +228 -43
- package/dist/engine/types.d.ts +8 -0
- package/dist/git/worktree/crud.d.ts +69 -0
- package/dist/git/worktree/crud.js +206 -0
- package/dist/git/worktree/diff.d.ts +14 -0
- package/dist/git/worktree/diff.js +82 -0
- package/dist/git/worktree/git-exec.d.ts +7 -0
- package/dist/git/worktree/git-exec.js +51 -0
- package/dist/git/worktree/index.d.ts +5 -0
- package/dist/git/worktree/index.js +5 -0
- package/dist/git/worktree/query.d.ts +42 -0
- package/dist/git/worktree/query.js +121 -0
- package/dist/git/worktree/slug.d.ts +11 -0
- package/dist/git/worktree/slug.js +58 -0
- package/dist/git/worktree.d.ts +1 -84
- package/dist/git/worktree.js +5 -230
- package/dist/hooks/goal-stop-hook.d.ts +33 -1
- package/dist/hooks/goal-stop-hook.js +202 -34
- package/dist/index.d.ts +31 -28
- package/dist/index.js +27 -25
- package/dist/logging/logger.js +6 -6
- package/dist/logging/sanitize-messages.d.ts +10 -2
- package/dist/logging/sanitize-messages.js +21 -6
- package/dist/plugins/installer/checkUpdate.d.ts +4 -1
- package/dist/plugins/installer/checkUpdate.js +4 -2
- package/dist/plugins/installer/install.js +2 -0
- package/dist/plugins/installer/installFromSource.js +9 -1
- package/dist/plugins/installer/parseSource.d.ts +4 -1
- package/dist/plugins/installer/parseSource.js +28 -10
- package/dist/plugins/installer/sourcePath.d.ts +9 -0
- package/dist/plugins/installer/sourcePath.js +50 -0
- package/dist/plugins/installer/update.d.ts +4 -1
- package/dist/plugins/installer/update.js +5 -3
- package/dist/plugins/parseMarketplaceInput.d.ts +4 -1
- package/dist/plugins/parseMarketplaceInput.js +4 -3
- package/dist/plugins/pluginInstaller.js +24 -22
- package/dist/preset/index.d.ts +1 -0
- package/dist/preset/index.js +30 -13
- package/dist/prompt/sections/base.md +1 -1
- package/dist/protocol/chat-session-manager.d.ts +2 -0
- package/dist/protocol/chat-session-manager.js +38 -2
- package/dist/protocol/chat-session.d.ts +3 -0
- package/dist/protocol/chat-session.js +1 -0
- package/dist/protocol/client.d.ts +9 -4
- package/dist/protocol/client.js +18 -1
- package/dist/protocol/server.d.ts +30 -0
- package/dist/protocol/server.js +247 -47
- package/dist/protocol/types.d.ts +49 -0
- package/dist/protocol/types.js +6 -0
- package/dist/run/FileRunStore.js +10 -1
- package/dist/run/Heartbeat.js +12 -0
- package/dist/run/RunApprovalBackend.d.ts +3 -0
- package/dist/run/RunApprovalBackend.js +41 -6
- package/dist/run/RunLock.js +2 -0
- package/dist/run/RunManager.d.ts +2 -0
- package/dist/run/RunManager.js +64 -24
- package/dist/run/ids.d.ts +2 -0
- package/dist/run/ids.js +23 -0
- package/dist/runtime/background-shell.d.ts +1 -0
- package/dist/runtime/background-shell.js +23 -13
- package/dist/runtime/spawn-common.js +10 -0
- package/dist/services/auto-dream.d.ts +15 -4
- package/dist/services/auto-dream.js +20 -20
- package/dist/services/dream-consolidation.d.ts +2 -3
- package/dist/services/dream-consolidation.js +65 -15
- package/dist/services/extract-memories.d.ts +14 -5
- package/dist/services/extract-memories.js +20 -3
- package/dist/services/global-dream-promotion.d.ts +23 -0
- package/dist/services/global-dream-promotion.js +112 -0
- package/dist/services/memory-orchestrator.js +347 -34
- package/dist/session/memory.d.ts +61 -18
- package/dist/session/memory.js +342 -79
- package/dist/session/session-manager.d.ts +35 -1
- package/dist/session/session-manager.js +224 -4
- package/dist/session/transcript.d.ts +1 -1
- package/dist/session/transcript.js +17 -5
- package/dist/settings/manager.d.ts +1 -0
- package/dist/settings/manager.js +87 -37
- package/dist/settings/schema-export.d.ts +2 -3
- package/dist/settings/schema-export.js +2 -3
- package/dist/settings/schema.d.ts +21 -0
- package/dist/settings/schema.js +12 -0
- package/dist/skills/scanner.d.ts +3 -2
- package/dist/skills/scanner.js +12 -9
- package/dist/tool-system/builtin/agent-notifications.d.ts +11 -4
- package/dist/tool-system/builtin/agent-notifications.js +19 -7
- package/dist/tool-system/builtin/background-jobs.d.ts +35 -6
- package/dist/tool-system/builtin/background-jobs.js +116 -7
- package/dist/tool-system/builtin/background-work.d.ts +17 -18
- package/dist/tool-system/builtin/background-work.js +51 -5
- package/dist/tool-system/builtin/config.d.ts +2 -1
- package/dist/tool-system/builtin/config.js +16 -11
- package/dist/tool-system/builtin/cron-list.definition.d.ts +3 -0
- package/dist/tool-system/builtin/cron-list.definition.js +6 -0
- package/dist/tool-system/builtin/cron.d.ts +1 -2
- package/dist/tool-system/builtin/cron.js +9 -7
- package/dist/tool-system/builtin/drive-claude-code.d.ts +23 -2
- package/dist/tool-system/builtin/drive-claude-code.js +589 -48
- package/dist/tool-system/builtin/edit.js +5 -2
- package/dist/tool-system/builtin/generate-video.d.ts +1 -0
- package/dist/tool-system/builtin/generate-video.js +13 -4
- package/dist/tool-system/builtin/index.d.ts +8 -3
- package/dist/tool-system/builtin/index.js +50 -22
- package/dist/tool-system/builtin/lsp.d.ts +2 -1
- package/dist/tool-system/builtin/lsp.js +6 -3
- package/dist/tool-system/builtin/memory.js +40 -8
- package/dist/tool-system/builtin/notebook-edit.js +5 -2
- package/dist/tool-system/builtin/powershell.d.ts +5 -2
- package/dist/tool-system/builtin/powershell.js +11 -7
- package/dist/tool-system/builtin/read.js +118 -6
- package/dist/tool-system/builtin/sleep.d.ts +1 -2
- package/dist/tool-system/builtin/sleep.definition.d.ts +8 -0
- package/dist/tool-system/builtin/sleep.definition.js +28 -0
- package/dist/tool-system/builtin/sleep.js +1 -22
- package/dist/tool-system/builtin/view-image.d.ts +2 -2
- package/dist/tool-system/builtin/view-image.js +109 -19
- package/dist/tool-system/builtin/worktree.d.ts +4 -4
- package/dist/tool-system/builtin/worktree.js +297 -74
- package/dist/tool-system/builtin/write.js +5 -3
- package/dist/tool-system/context.d.ts +41 -1
- package/dist/tool-system/executor.d.ts +1 -5
- package/dist/tool-system/executor.js +94 -115
- package/dist/tool-system/mcp-manager.d.ts +31 -6
- package/dist/tool-system/mcp-manager.js +193 -78
- package/dist/tool-system/path-policy.d.ts +2 -0
- package/dist/tool-system/path-policy.js +41 -12
- package/dist/tool-system/permission.d.ts +28 -7
- package/dist/tool-system/permission.js +130 -49
- package/dist/tool-system/registry.js +11 -4
- package/dist/tool-system/tool-result-redaction.d.ts +7 -0
- package/dist/tool-system/tool-result-redaction.js +48 -0
- package/dist/tool-system/workspace-bridge.d.ts +11 -0
- package/dist/tool-system/workspace-bridge.js +1 -0
- package/dist/types.d.ts +78 -11
- package/dist/utils/toolDisplay.js +1 -1
- package/package.json +4 -3
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
* The loop is intentionally small and offline:
|
|
14
14
|
* - No streaming, no UI events — it runs in the background.
|
|
15
15
|
* - No permission prompts — there is no interactive backend on this path, so
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* freely.
|
|
16
|
+
* Save/Delete goes through an origin guard before dispatching. Dream may
|
|
17
|
+
* maintain origin:dream/auto entries but never touches origin:manual.
|
|
19
18
|
* - Capped at MAX_TURNS LLM round-trips and MAX_WRITES total mutations to
|
|
20
19
|
* bound damage on misbehavior.
|
|
21
20
|
*/
|
|
22
21
|
import { MemoryManager } from "../session/memory.js";
|
|
23
|
-
import { buildDreamSystemPrompt, buildDreamUserPrompt
|
|
22
|
+
import { buildDreamSystemPrompt, buildDreamUserPrompt } from "./auto-dream.js";
|
|
24
23
|
import { logger } from "../logging/logger.js";
|
|
25
24
|
const MAX_TURNS = 8;
|
|
26
25
|
const MAX_WRITES = 10;
|
|
26
|
+
const FRESH_ENTRY_GRACE_MS = 10 * 60 * 1000;
|
|
27
27
|
const MEMORY_TOOL_NAMES = ["MemoryList", "MemoryRead", "MemorySave", "MemoryDelete"];
|
|
28
28
|
/**
|
|
29
29
|
* Drive the dream-scope consolidation tool-call loop.
|
|
@@ -37,9 +37,7 @@ const MEMORY_TOOL_NAMES = ["MemoryList", "MemoryRead", "MemorySave", "MemoryDele
|
|
|
37
37
|
*/
|
|
38
38
|
export async function runDreamConsolidation(input) {
|
|
39
39
|
const { llmClient, toolRegistry, projectDir, sessionId } = input;
|
|
40
|
-
const memoryTools = MEMORY_TOOL_NAMES
|
|
41
|
-
.map((n) => toolRegistry.getTool(n))
|
|
42
|
-
.filter((t) => t != null);
|
|
40
|
+
const memoryTools = MEMORY_TOOL_NAMES.map((n) => toolRegistry.getTool(n)).filter((t) => t != null);
|
|
43
41
|
if (memoryTools.length < MEMORY_TOOL_NAMES.length) {
|
|
44
42
|
logger.warn("memory.dream_missing_tools", {
|
|
45
43
|
sessionId,
|
|
@@ -52,8 +50,9 @@ export async function runDreamConsolidation(input) {
|
|
|
52
50
|
const mm = new MemoryManager({ projectDir });
|
|
53
51
|
const userMems = mm.loadScope("user");
|
|
54
52
|
const dreamMems = mm.loadScope("dream");
|
|
53
|
+
const globalDreamMems = projectDir ? new MemoryManager({ scope: "dream" }).loadAll() : [];
|
|
55
54
|
const systemPrompt = buildDreamSystemPrompt();
|
|
56
|
-
const userPrompt = buildDreamUserPrompt(userMems, dreamMems);
|
|
55
|
+
const userPrompt = buildDreamUserPrompt(userMems, dreamMems, globalDreamMems);
|
|
57
56
|
// Strip RegisteredTool down to the shape createMessage expects.
|
|
58
57
|
const toolDefs = memoryTools.map((t) => ({
|
|
59
58
|
name: t.name,
|
|
@@ -120,8 +119,8 @@ export async function runDreamConsolidation(input) {
|
|
|
120
119
|
* Execute one memory tool call inside the dream loop. Enforces the two
|
|
121
120
|
* dream-loop invariants the prompt also states:
|
|
122
121
|
* - Only the 4 memory tools are dispatchable.
|
|
123
|
-
* - Save/Delete
|
|
124
|
-
*
|
|
122
|
+
* - Save/Delete is allowed only for origin:auto/origin:dream owned entries.
|
|
123
|
+
* Missing origin is manual, and manual is always protected.
|
|
125
124
|
*/
|
|
126
125
|
async function dispatchDreamTool(tc, toolRegistry, ctx, consumeWriteBudget) {
|
|
127
126
|
const allowed = new Set(MEMORY_TOOL_NAMES);
|
|
@@ -130,17 +129,17 @@ async function dispatchDreamTool(tc, toolRegistry, ctx, consumeWriteBudget) {
|
|
|
130
129
|
}
|
|
131
130
|
const isWrite = tc.toolName === "MemorySave" || tc.toolName === "MemoryDelete";
|
|
132
131
|
if (isWrite) {
|
|
133
|
-
const
|
|
134
|
-
if (
|
|
135
|
-
return
|
|
136
|
-
`User-scope changes require interactive permission, which is not available here.`);
|
|
132
|
+
const guard = checkDreamWriteGuard(tc, ctx);
|
|
133
|
+
if (!guard.ok) {
|
|
134
|
+
return guard.error;
|
|
137
135
|
}
|
|
138
136
|
if (!consumeWriteBudget()) {
|
|
139
137
|
return "Error: dream write budget exhausted — stop calling write tools and summarize instead.";
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
140
|
try {
|
|
143
|
-
const
|
|
141
|
+
const dreamCtx = { ...ctx, __dreamLoop: true };
|
|
142
|
+
const result = await toolRegistry.executeTool(tc.toolName, tc.args, { ctx: dreamCtx });
|
|
144
143
|
if (result.isError)
|
|
145
144
|
return result.error ?? `Error executing ${tc.toolName}`;
|
|
146
145
|
return result.result ?? "";
|
|
@@ -149,3 +148,54 @@ async function dispatchDreamTool(tc, toolRegistry, ctx, consumeWriteBudget) {
|
|
|
149
148
|
return `Error executing ${tc.toolName}: ${err.message}`;
|
|
150
149
|
}
|
|
151
150
|
}
|
|
151
|
+
function checkDreamWriteGuard(tc, ctx) {
|
|
152
|
+
const scope = tc.args?.scope;
|
|
153
|
+
if (scope !== "dream" && scope !== "user") {
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
error: `Error: dream loop may only write to scope "dream" or "user", got "${scope}".`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const location = tc.args?.location === "global" ? "global" : "project";
|
|
160
|
+
const mm = new MemoryManager({
|
|
161
|
+
projectDir: location === "project" ? ctx.cwd : undefined,
|
|
162
|
+
scope,
|
|
163
|
+
});
|
|
164
|
+
const id = typeof tc.args?.id === "string" ? tc.args.id : undefined;
|
|
165
|
+
const name = typeof tc.args?.name === "string" ? tc.args.name : undefined;
|
|
166
|
+
const targetById = id ? mm.findById(id) : undefined;
|
|
167
|
+
const targetByName = name ? mm.find(name) : undefined;
|
|
168
|
+
const targets = [targetById, targetByName].filter((target, index, all) => Boolean(target) && all.findIndex((item) => item?.id === target?.id) === index);
|
|
169
|
+
const protectedTarget = targets.find((target) => target.origin === "manual" || !target.origin);
|
|
170
|
+
if (protectedTarget) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
error: `Error: dream loop cannot modify origin:manual memory "${protectedTarget.name}" ` +
|
|
174
|
+
`(${location}/${scope}/${protectedTarget.id ?? protectedTarget.fileName}).`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const target = targetById ?? targetByName;
|
|
178
|
+
if (!target)
|
|
179
|
+
return { ok: true };
|
|
180
|
+
if (target.origin !== "auto" && target.origin !== "dream") {
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
error: `Error: dream loop can only modify origin:auto or origin:dream memories; ` +
|
|
184
|
+
`"${target.name}" has origin:${target.origin}.`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (tc.toolName === "MemoryDelete" && isFreshEntry(target.createdAt)) {
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
error: `Error: dream loop cannot delete freshly-created memory "${target.name}" yet; ` +
|
|
191
|
+
"leave it for the next consolidation pass.",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return { ok: true };
|
|
195
|
+
}
|
|
196
|
+
function isFreshEntry(createdAt) {
|
|
197
|
+
if (!createdAt)
|
|
198
|
+
return false;
|
|
199
|
+
const createdMs = new Date(createdAt).getTime();
|
|
200
|
+
return Number.isFinite(createdMs) && Date.now() - createdMs < FRESH_ENTRY_GRACE_MS;
|
|
201
|
+
}
|
|
@@ -18,17 +18,26 @@ export interface ExtractedMemory {
|
|
|
18
18
|
description: string;
|
|
19
19
|
content: string;
|
|
20
20
|
}
|
|
21
|
+
export interface ExistingMemorySummary {
|
|
22
|
+
id?: string;
|
|
23
|
+
name: string;
|
|
24
|
+
type: string;
|
|
25
|
+
description: string;
|
|
26
|
+
location?: "project" | "global";
|
|
27
|
+
memoryScope?: "user" | "dream";
|
|
28
|
+
origin?: "manual" | "auto" | "dream";
|
|
29
|
+
pinned?: boolean;
|
|
30
|
+
useCount?: number;
|
|
31
|
+
updateCount?: number;
|
|
32
|
+
updatedAt?: string;
|
|
33
|
+
}
|
|
21
34
|
/**
|
|
22
35
|
* Build the prompt for extracting memories from a conversation.
|
|
23
36
|
*/
|
|
24
37
|
export declare function buildExtractionPrompt(transcript: Array<{
|
|
25
38
|
role: string;
|
|
26
39
|
content: string;
|
|
27
|
-
}>, existingMemories:
|
|
28
|
-
name: string;
|
|
29
|
-
type: string;
|
|
30
|
-
description: string;
|
|
31
|
-
}>): string;
|
|
40
|
+
}>, existingMemories: ExistingMemorySummary[]): string;
|
|
32
41
|
/** Max memories to accept from a single extraction pass. Code-side cap that
|
|
33
42
|
* enforces the same limit the prompt asks for — the model occasionally
|
|
34
43
|
* ignores prompt rules, but this guarantees the cap. */
|
|
@@ -12,7 +12,21 @@ export function buildExtractionPrompt(transcript, existingMemories) {
|
|
|
12
12
|
.map((m) => `[${m.role}]: ${m.content.slice(0, 3000)}`)
|
|
13
13
|
.join("\n\n");
|
|
14
14
|
const existingList = existingMemories.length > 0
|
|
15
|
-
? existingMemories
|
|
15
|
+
? existingMemories
|
|
16
|
+
.map((m) => {
|
|
17
|
+
const meta = [
|
|
18
|
+
m.id ? `id:${m.id}` : null,
|
|
19
|
+
m.location ? `location:${m.location}` : null,
|
|
20
|
+
m.memoryScope ? `scope:${m.memoryScope}` : null,
|
|
21
|
+
m.origin ? `origin:${m.origin}` : null,
|
|
22
|
+
typeof m.useCount === "number" ? `use:${m.useCount}` : null,
|
|
23
|
+
typeof m.updateCount === "number" ? `updates:${m.updateCount}` : null,
|
|
24
|
+
]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(", ");
|
|
27
|
+
return ` - [${m.type}] ${m.name}${meta ? ` (${meta})` : ""}: ${m.description}`;
|
|
28
|
+
})
|
|
29
|
+
.join("\n")
|
|
16
30
|
: " (none)";
|
|
17
31
|
return `Analyze the following conversation and extract any information worth remembering for future sessions.
|
|
18
32
|
|
|
@@ -23,7 +37,7 @@ ${existingList}
|
|
|
23
37
|
${conversationText.slice(0, 30000)}
|
|
24
38
|
|
|
25
39
|
## Instructions
|
|
26
|
-
Identify
|
|
40
|
+
Identify candidate information that may be saved as persistent memories. The extractor only proposes candidates; code will route automatic candidates into dream memory first, never directly into user memory. Categories (type):
|
|
27
41
|
- **user**: Information about the user's role, preferences, or expertise
|
|
28
42
|
- **feedback**: Guidance about how to approach work (corrections or confirmations)
|
|
29
43
|
- **project**: Non-obvious facts about ongoing work, goals, or decisions
|
|
@@ -39,7 +53,10 @@ Rules:
|
|
|
39
53
|
- Extract AT MOST 2 memories per session. Prefer 0 to a marginal one — most sessions are noise.
|
|
40
54
|
- AT MOST 1 of the extracted memories may be "global". The global layer is injected every session, so keep it tiny and high-value. If two candidates both seem global, keep the single most universal one global and make the other "project".
|
|
41
55
|
- Only extract information that would be useful in FUTURE conversations
|
|
42
|
-
- Do not duplicate existing memories (re-read the "Existing Memories" list above carefully)
|
|
56
|
+
- Do not duplicate existing memories (re-read the "Existing Memories" list above carefully).
|
|
57
|
+
- If an existing auto/dream memory has the same durable topic, reuse that topic in the candidate instead of creating a date-stamped variant; the write decision layer will update the existing id.
|
|
58
|
+
- Manual user memories are read-only curated memories. Do not re-extract the same topic just because the wording or date differs.
|
|
59
|
+
- Avoid dates, version stamps, batch names, and progress-snapshot suffixes in names. Names should be stable topic identifiers, not "today" variants.
|
|
43
60
|
- Do not extract code patterns, file structures, or git history (derivable from code)
|
|
44
61
|
- Do not extract ephemeral task details, progress snapshots, or in-flight work state — those belong in the conversation, not memory
|
|
45
62
|
- Do not extract one-off research products (news reports, AI industry summaries, slide deck content, daily progress dumps) — they're done and not "durable, reusable information"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExtractedMemory } from "./extract-memories.js";
|
|
2
|
+
export interface GlobalDreamPromotionInput {
|
|
3
|
+
candidate: ExtractedMemory;
|
|
4
|
+
projectDir?: string;
|
|
5
|
+
baseDir?: string;
|
|
6
|
+
userDirectGlobal?: boolean;
|
|
7
|
+
now?: Date;
|
|
8
|
+
}
|
|
9
|
+
export interface GlobalDreamPromotionResult {
|
|
10
|
+
/** No automatic write to global dream is performed; approval is required. */
|
|
11
|
+
promoted: false;
|
|
12
|
+
/** True when this call created a new pending approval item. */
|
|
13
|
+
pendingSuggested: boolean;
|
|
14
|
+
originProjects: string[];
|
|
15
|
+
evidenceCount: number;
|
|
16
|
+
projectEvidenceSaved: boolean;
|
|
17
|
+
promotionReason: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function detectUserDirectGlobalPreference(transcript: Array<{
|
|
20
|
+
role: string;
|
|
21
|
+
content: string;
|
|
22
|
+
}>): boolean;
|
|
23
|
+
export declare function applyGlobalDreamPromotionGate(input: GlobalDreamPromotionInput): GlobalDreamPromotionResult;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { MemoryManager, resolveMemoryBaseDir } from "../session/memory.js";
|
|
2
|
+
export function detectUserDirectGlobalPreference(transcript) {
|
|
3
|
+
const userText = transcript
|
|
4
|
+
.filter((m) => m.role === "user")
|
|
5
|
+
.map((m) => m.content)
|
|
6
|
+
.join("\n")
|
|
7
|
+
.toLowerCase();
|
|
8
|
+
return (/(?:全局记住|全局保存|所有项目|全部项目|以后所有项目|今后所有项目|以后都|以后默认|我偏好|我的偏好)/u.test(userText) ||
|
|
9
|
+
/(?:remember globally|global memory|all projects|every project|my preference|i prefer|always remember)/i.test(userText));
|
|
10
|
+
}
|
|
11
|
+
export function applyGlobalDreamPromotionGate(input) {
|
|
12
|
+
const baseDir = resolveMemoryBaseDir(input.baseDir);
|
|
13
|
+
const now = input.now ?? new Date();
|
|
14
|
+
const nowIso = now.toISOString();
|
|
15
|
+
const promotionReason = input.userDirectGlobal
|
|
16
|
+
? "user-direct global preference suggested global dream approval"
|
|
17
|
+
: "candidate suggested global dream approval";
|
|
18
|
+
const projectEvidence = input.projectDir
|
|
19
|
+
? saveProjectDreamCandidate({
|
|
20
|
+
baseDir,
|
|
21
|
+
projectDir: input.projectDir,
|
|
22
|
+
candidate: input.candidate,
|
|
23
|
+
nowIso,
|
|
24
|
+
promotionReason,
|
|
25
|
+
})
|
|
26
|
+
: undefined;
|
|
27
|
+
const originProjects = projectEvidence?.originProjects ?? (input.projectDir ? [input.projectDir] : []);
|
|
28
|
+
const rejected = projectEvidence?.promotionStatus === "rejected";
|
|
29
|
+
const pendingSuggested = !rejected &&
|
|
30
|
+
savePendingGlobalSuggestion({
|
|
31
|
+
baseDir,
|
|
32
|
+
projectDir: input.projectDir,
|
|
33
|
+
candidate: input.candidate,
|
|
34
|
+
source: projectEvidence,
|
|
35
|
+
originProjects,
|
|
36
|
+
nowIso,
|
|
37
|
+
promotionReason,
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
promoted: false,
|
|
41
|
+
pendingSuggested,
|
|
42
|
+
originProjects,
|
|
43
|
+
evidenceCount: originProjects.length,
|
|
44
|
+
projectEvidenceSaved: Boolean(projectEvidence),
|
|
45
|
+
promotionReason,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function saveProjectDreamCandidate(input) {
|
|
49
|
+
const mm = new MemoryManager({
|
|
50
|
+
baseDir: input.baseDir,
|
|
51
|
+
projectDir: input.projectDir,
|
|
52
|
+
scope: "dream",
|
|
53
|
+
});
|
|
54
|
+
const existing = mm
|
|
55
|
+
.loadAll()
|
|
56
|
+
.find((entry) => entry.name === input.candidate.name &&
|
|
57
|
+
(entry.origin === "auto" || entry.origin === "dream"));
|
|
58
|
+
const originProjects = unique([...(existing?.originProjects ?? []), input.projectDir]);
|
|
59
|
+
const promotionStatus = existing?.promotionStatus === "rejected" ? "rejected" : "pending";
|
|
60
|
+
const fileName = mm.save({
|
|
61
|
+
id: existing?.id,
|
|
62
|
+
name: input.candidate.name,
|
|
63
|
+
description: input.candidate.description,
|
|
64
|
+
type: input.candidate.type,
|
|
65
|
+
content: input.candidate.content,
|
|
66
|
+
origin: existing?.origin ?? "auto",
|
|
67
|
+
pinned: existing?.pinned,
|
|
68
|
+
createdAt: existing?.createdAt,
|
|
69
|
+
useCount: existing?.useCount,
|
|
70
|
+
updateCount: existing?.updateCount,
|
|
71
|
+
lastUsedAt: existing?.lastUsedAt,
|
|
72
|
+
originProject: input.projectDir,
|
|
73
|
+
originProjects,
|
|
74
|
+
evidenceCount: originProjects.length,
|
|
75
|
+
firstSeenAt: existing?.firstSeenAt ?? existing?.createdAt ?? input.nowIso,
|
|
76
|
+
lastSeenAt: input.nowIso,
|
|
77
|
+
promotionReason: input.promotionReason,
|
|
78
|
+
promotionStatus,
|
|
79
|
+
}, { forceOrigin: existing?.origin ?? "auto" });
|
|
80
|
+
return mm.find(fileName);
|
|
81
|
+
}
|
|
82
|
+
function savePendingGlobalSuggestion(input) {
|
|
83
|
+
const globalDream = new MemoryManager({ baseDir: input.baseDir, scope: "dream" });
|
|
84
|
+
if (globalDream.loadAll().some((entry) => entry.name === input.candidate.name))
|
|
85
|
+
return false;
|
|
86
|
+
const pending = new MemoryManager({ baseDir: input.baseDir, scope: "pending" });
|
|
87
|
+
const duplicate = pending
|
|
88
|
+
.loadAll()
|
|
89
|
+
.some((entry) => entry.name === input.candidate.name &&
|
|
90
|
+
(entry.originProject ?? "") === (input.projectDir ?? ""));
|
|
91
|
+
if (duplicate)
|
|
92
|
+
return false;
|
|
93
|
+
pending.save({
|
|
94
|
+
name: input.candidate.name,
|
|
95
|
+
description: input.candidate.description,
|
|
96
|
+
type: input.candidate.type,
|
|
97
|
+
content: input.candidate.content,
|
|
98
|
+
origin: "dream",
|
|
99
|
+
originProject: input.projectDir,
|
|
100
|
+
originProjects: input.originProjects,
|
|
101
|
+
evidenceCount: input.originProjects.length,
|
|
102
|
+
firstSeenAt: input.source?.firstSeenAt ?? input.source?.createdAt ?? input.nowIso,
|
|
103
|
+
lastSeenAt: input.nowIso,
|
|
104
|
+
promotionReason: input.promotionReason,
|
|
105
|
+
promotionStatus: "pending",
|
|
106
|
+
promotionSourceId: input.source?.id,
|
|
107
|
+
}, { forceOrigin: "dream" });
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
function unique(values) {
|
|
111
|
+
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
112
|
+
}
|