@omercnet/paseo-context-mode 3.1.3 → 3.1.4-next.434.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OVERVIEW.md +3 -3
- package/README.md +13 -15
- package/client/analytics-dashboard.tsx +745 -613
- package/client/controls.tsx +295 -0
- package/client/diagnostics-section.tsx +178 -0
- package/client/{context-mode-footer.tsx → footer.tsx} +22 -20
- package/client/knowledge-section.tsx +725 -697
- package/client/{context-mode-pill.tsx → pill.tsx} +5 -5
- package/client/scoped-knowledge-section.tsx +14 -20
- package/client/screen-scope.ts +12 -6
- package/client/settings-screen.tsx +94 -97
- package/client/surface.tsx +377 -0
- package/index.client.tsx +3 -3
- package/index.server.ts +18 -27
- package/npm-shrinkwrap.json +8 -1747
- package/package.json +7 -7
- package/server/actions.ts +91 -102
- package/server/analytics.ts +257 -308
- package/server/binary.ts +119 -94
- package/server/database.ts +463 -0
- package/server/handlers.ts +40 -95
- package/server/integration.ts +230 -361
- package/server/knowledge.ts +65 -137
- package/server/mcp-process.ts +135 -86
- package/server/storage-discovery.ts +46 -199
- package/shared/actions.ts +2 -27
- package/shared/analytics.ts +60 -33
- package/shared/contracts.ts +16 -47
- package/shared/knowledge.ts +62 -65
- package/shared/providers.ts +62 -0
- package/shared/settings.ts +33 -18
- package/client/actions-section.tsx +0 -621
- package/client/context-mode-surface.tsx +0 -444
- package/server/context-mode-db.ts +0 -481
- package/shared/index.ts +0 -5
package/shared/knowledge.ts
CHANGED
|
@@ -6,32 +6,29 @@ const MAX_PATH_LENGTH = 4_096;
|
|
|
6
6
|
const MAX_LABEL_LENGTH = 512;
|
|
7
7
|
const MAX_QUERY_LENGTH = 1_024;
|
|
8
8
|
|
|
9
|
-
export const ContextModeProviderSchema = z.enum([
|
|
10
|
-
"claude",
|
|
11
|
-
"codex",
|
|
12
|
-
"copilot",
|
|
13
|
-
"cursor",
|
|
14
|
-
"opencode",
|
|
15
|
-
"pi",
|
|
16
|
-
"omp",
|
|
17
|
-
"omp-plugin",
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
export const ContextModePlatformSchema = z.enum([
|
|
21
|
-
"claude-code",
|
|
22
|
-
"codex",
|
|
23
|
-
"copilot-cli",
|
|
24
|
-
"cursor",
|
|
25
|
-
"opencode",
|
|
26
|
-
"pi",
|
|
27
|
-
"omp",
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
9
|
/** A Paseo provider id: a built-in or one configured in `agents.providers`. */
|
|
31
10
|
export const KnowledgeProviderSchema = z.string().trim().min(1).max(128);
|
|
32
11
|
|
|
12
|
+
/** The project store a knowledge action writes to, and the agent it is recorded as. */
|
|
13
|
+
export interface KnowledgeDestination {
|
|
14
|
+
provider: string;
|
|
15
|
+
projectPath: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A finished action's result belongs to the destination it ran against, not to a later one. */
|
|
19
|
+
export function sameDestination(
|
|
20
|
+
ran: KnowledgeDestination | undefined,
|
|
21
|
+
current: KnowledgeDestination | null,
|
|
22
|
+
): boolean {
|
|
23
|
+
return (
|
|
24
|
+
ran !== undefined &&
|
|
25
|
+
current !== null &&
|
|
26
|
+
ran.provider === current.provider &&
|
|
27
|
+
ran.projectPath === current.projectPath
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
33
31
|
const boundedLabel = z.string().trim().min(1).max(MAX_LABEL_LENGTH);
|
|
34
|
-
const boundedPattern = z.string().trim().min(1).max(256);
|
|
35
32
|
const absoluteLocalPath = z
|
|
36
33
|
.string()
|
|
37
34
|
.trim()
|
|
@@ -64,65 +61,64 @@ export const KnowledgeToolResultSchema = z
|
|
|
64
61
|
})
|
|
65
62
|
.strict();
|
|
66
63
|
|
|
64
|
+
const pageCursor = z.number().int().nonnegative();
|
|
65
|
+
|
|
66
|
+
/** Where the next page starts: `offset` for relevance order, `after` (epoch ms) for timeline. */
|
|
67
|
+
export const SearchPageSchema = z.union([
|
|
68
|
+
z.object({ offset: pageCursor }).strict(),
|
|
69
|
+
z.object({ after: pageCursor }).strict(),
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
export const SearchKnowledgeResultSchema = KnowledgeToolResultSchema.extend({
|
|
73
|
+
next: SearchPageSchema.nullable(),
|
|
74
|
+
}).strict();
|
|
75
|
+
|
|
67
76
|
export const SearchKnowledgeInputSchema = providerScope
|
|
68
77
|
.extend({
|
|
69
78
|
queries: z.array(z.string().trim().min(1).max(MAX_QUERY_LENGTH)).min(1).max(8),
|
|
70
|
-
|
|
79
|
+
scope: z.enum(["worktree", "project"]).default("worktree"),
|
|
71
80
|
source: boundedLabel.optional(),
|
|
72
|
-
contentType: z.enum(["code", "prose"]).optional(),
|
|
73
81
|
sort: z.enum(["relevance", "timeline"]).default("relevance"),
|
|
82
|
+
page: SearchPageSchema.optional(),
|
|
74
83
|
})
|
|
75
84
|
.strict();
|
|
76
85
|
|
|
77
|
-
export const IndexPathInputSchema = providerScope
|
|
78
|
-
.extend({
|
|
79
|
-
path: absoluteLocalPath,
|
|
80
|
-
source: boundedLabel.optional(),
|
|
81
|
-
include: z.array(boundedPattern).max(32).optional(),
|
|
82
|
-
exclude: z.array(boundedPattern).max(32).optional(),
|
|
83
|
-
maxDepth: z.number().int().min(0).max(20).optional(),
|
|
84
|
-
maxFiles: z.number().int().min(1).max(1_000).optional(),
|
|
85
|
-
extensions: z.array(boundedPattern).max(32).optional(),
|
|
86
|
-
respectGitignore: z.boolean().optional(),
|
|
87
|
-
followSymlinks: z.boolean().optional(),
|
|
88
|
-
})
|
|
89
|
-
.strict();
|
|
86
|
+
export const IndexPathInputSchema = providerScope.extend({ path: absoluteLocalPath }).strict();
|
|
90
87
|
|
|
91
|
-
export const FetchAndIndexInputSchema = providerScope
|
|
92
|
-
.extend({
|
|
93
|
-
url: httpUrl,
|
|
94
|
-
source: boundedLabel.optional(),
|
|
95
|
-
force: z.boolean().default(false),
|
|
96
|
-
ttl: z.number().int().min(0).max(1_209_600_000).optional(),
|
|
97
|
-
})
|
|
98
|
-
.strict();
|
|
88
|
+
export const FetchAndIndexInputSchema = providerScope.extend({ url: httpUrl }).strict();
|
|
99
89
|
|
|
100
|
-
const
|
|
101
|
-
.
|
|
102
|
-
provider: KnowledgeProviderSchema,
|
|
103
|
-
projectPath: absoluteLocalPath,
|
|
104
|
-
confirm: z.literal(true),
|
|
105
|
-
scope: z.literal("project"),
|
|
106
|
-
})
|
|
107
|
-
.strict();
|
|
108
|
-
const sessionPurge = z
|
|
109
|
-
.object({
|
|
110
|
-
provider: KnowledgeProviderSchema,
|
|
111
|
-
projectPath: absoluteLocalPath,
|
|
112
|
-
confirm: z.literal(true),
|
|
113
|
-
scope: z.literal("session"),
|
|
114
|
-
sessionId: z.string().trim().min(1).max(256),
|
|
115
|
-
})
|
|
90
|
+
export const ResumeSessionInputSchema = providerScope
|
|
91
|
+
.extend({ sessionId: z.string().trim().min(1).max(256) })
|
|
116
92
|
.strict();
|
|
117
93
|
|
|
94
|
+
const purgeBase = {
|
|
95
|
+
provider: KnowledgeProviderSchema,
|
|
96
|
+
projectPath: absoluteLocalPath,
|
|
97
|
+
confirm: z.literal(true),
|
|
98
|
+
};
|
|
99
|
+
|
|
118
100
|
export const PurgeKnowledgeInputSchema = z.discriminatedUnion("scope", [
|
|
119
|
-
|
|
120
|
-
|
|
101
|
+
z.object({ ...purgeBase, scope: z.literal("project") }).strict(),
|
|
102
|
+
z
|
|
103
|
+
.object({
|
|
104
|
+
...purgeBase,
|
|
105
|
+
scope: z.literal("session"),
|
|
106
|
+
sessionId: z.string().trim().min(1).max(256),
|
|
107
|
+
})
|
|
108
|
+
.strict(),
|
|
109
|
+
z.object({ ...purgeBase, scope: z.literal("source"), source: boundedLabel }).strict(),
|
|
121
110
|
]);
|
|
122
111
|
|
|
123
112
|
export const searchContextModeKnowledge = defineRpc({
|
|
124
113
|
name: "context-mode.knowledge.search",
|
|
125
114
|
input: SearchKnowledgeInputSchema,
|
|
115
|
+
output: SearchKnowledgeResultSchema,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/** `ctx_resume` for one recorded session: the state block an agent gets after a compact or restart. */
|
|
119
|
+
export const resumeContextModeSession = defineRpc({
|
|
120
|
+
name: "context-mode.knowledge.resume",
|
|
121
|
+
input: ResumeSessionInputSchema,
|
|
126
122
|
output: KnowledgeToolResultSchema,
|
|
127
123
|
});
|
|
128
124
|
|
|
@@ -144,10 +140,11 @@ export const purgeContextModeKnowledge = defineRpc({
|
|
|
144
140
|
output: KnowledgeToolResultSchema,
|
|
145
141
|
});
|
|
146
142
|
|
|
147
|
-
export type ContextModeProvider = z.infer<typeof ContextModeProviderSchema>;
|
|
148
|
-
export type ContextModePlatform = z.infer<typeof ContextModePlatformSchema>;
|
|
149
143
|
export type KnowledgeToolResult = z.infer<typeof KnowledgeToolResultSchema>;
|
|
144
|
+
export type SearchPage = z.infer<typeof SearchPageSchema>;
|
|
145
|
+
export type SearchKnowledgeResult = z.infer<typeof SearchKnowledgeResultSchema>;
|
|
150
146
|
export type SearchKnowledgeInput = z.infer<typeof SearchKnowledgeInputSchema>;
|
|
151
147
|
export type IndexPathInput = z.infer<typeof IndexPathInputSchema>;
|
|
152
148
|
export type FetchAndIndexInput = z.infer<typeof FetchAndIndexInputSchema>;
|
|
149
|
+
export type ResumeSessionInput = z.infer<typeof ResumeSessionInputSchema>;
|
|
153
150
|
export type PurgeKnowledgeInput = z.infer<typeof PurgeKnowledgeInputSchema>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/** Paseo providers Context Mode 2 serves over MCP. */
|
|
4
|
+
export const ContextModeProviderSchema = z.enum(["claude", "codex", "copilot", "opencode"]);
|
|
5
|
+
|
|
6
|
+
/** Context Mode 2 `--agent` ids for those providers. */
|
|
7
|
+
export const ContextModePlatformSchema = z.enum([
|
|
8
|
+
"claude-code",
|
|
9
|
+
"codex",
|
|
10
|
+
"copilot-cli",
|
|
11
|
+
"opencode",
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export type ContextModeProvider = z.infer<typeof ContextModeProviderSchema>;
|
|
15
|
+
export type ContextModePlatform = z.infer<typeof ContextModePlatformSchema>;
|
|
16
|
+
|
|
17
|
+
interface ProviderEntry {
|
|
18
|
+
provider: ContextModeProvider;
|
|
19
|
+
platform: ContextModePlatform;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The one mapping between Paseo providers, Context Mode agent ids, and display labels. */
|
|
24
|
+
export const CONTEXT_MODE_PROVIDERS: readonly ProviderEntry[] = [
|
|
25
|
+
{ provider: "claude", platform: "claude-code", label: "Claude" },
|
|
26
|
+
{ provider: "codex", platform: "codex", label: "Codex" },
|
|
27
|
+
{ provider: "copilot", platform: "copilot-cli", label: "Copilot" },
|
|
28
|
+
{ provider: "opencode", platform: "opencode", label: "OpenCode" },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export function contextModePlatformFor(provider: ContextModeProvider): ContextModePlatform {
|
|
32
|
+
const entry = CONTEXT_MODE_PROVIDERS.find((candidate) => candidate.provider === provider);
|
|
33
|
+
if (!entry) throw new Error(`No Context Mode agent id for provider ${provider}.`);
|
|
34
|
+
return entry.platform;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface InProcessEntry {
|
|
38
|
+
provider: string;
|
|
39
|
+
agent: string;
|
|
40
|
+
label: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Context Mode runs inside these hosts as an extension, so Paseo cannot inject it, but they record
|
|
45
|
+
* sessions in the same store under their own agent id.
|
|
46
|
+
*/
|
|
47
|
+
export const IN_PROCESS_PROVIDERS: readonly InProcessEntry[] = [
|
|
48
|
+
{ provider: "pi", agent: "pi", label: "Pi" },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Agent id of the panel's own Context Mode process when no injectable agent applies: `--agent pi`
|
|
53
|
+
* cannot resolve a project over MCP, and the panel's calls are its own session anyway.
|
|
54
|
+
*/
|
|
55
|
+
export const PANEL_PLATFORM: ContextModePlatform = "claude-code";
|
|
56
|
+
|
|
57
|
+
/** The Paseo provider that owns a Context Mode agent id recorded in a database, if any. */
|
|
58
|
+
export function providerForPlatform(platform: string): { provider: string; label: string } | null {
|
|
59
|
+
const injected = CONTEXT_MODE_PROVIDERS.find((candidate) => candidate.platform === platform);
|
|
60
|
+
if (injected) return injected;
|
|
61
|
+
return IN_PROCESS_PROVIDERS.find((candidate) => candidate.agent === platform) ?? null;
|
|
62
|
+
}
|
package/shared/settings.ts
CHANGED
|
@@ -4,10 +4,8 @@ import { z } from "zod";
|
|
|
4
4
|
export const REFRESH_INTERVALS = [5_000, 15_000, 30_000, 60_000] as const;
|
|
5
5
|
|
|
6
6
|
export const DEFAULT_CONTEXT_MODE_SETTINGS = {
|
|
7
|
-
|
|
8
|
-
binaryPath: "",
|
|
7
|
+
binaryPath: null,
|
|
9
8
|
refreshIntervalMs: 15_000,
|
|
10
|
-
showDoctorByDefault: false,
|
|
11
9
|
autoInject: true,
|
|
12
10
|
preferNativeIntegrations: true,
|
|
13
11
|
} as const;
|
|
@@ -18,34 +16,51 @@ function isAbsolutePath(value: string): boolean {
|
|
|
18
16
|
|
|
19
17
|
export const ContextModeSettingsSchema = z
|
|
20
18
|
.object({
|
|
21
|
-
|
|
22
|
-
binaryPath: z
|
|
19
|
+
/** Your own Context Mode executable; null runs the runtime bundled with the plugin. */
|
|
20
|
+
binaryPath: z
|
|
21
|
+
.string()
|
|
22
|
+
.trim()
|
|
23
|
+
.min(1)
|
|
24
|
+
.max(4_096)
|
|
25
|
+
.refine(isAbsolutePath, "The Context Mode binary path must be absolute.")
|
|
26
|
+
.nullable()
|
|
27
|
+
.default(DEFAULT_CONTEXT_MODE_SETTINGS.binaryPath),
|
|
23
28
|
refreshIntervalMs: z
|
|
24
29
|
.union([z.literal(5_000), z.literal(15_000), z.literal(30_000), z.literal(60_000)])
|
|
25
30
|
.default(DEFAULT_CONTEXT_MODE_SETTINGS.refreshIntervalMs),
|
|
26
|
-
showDoctorByDefault: z.boolean().default(DEFAULT_CONTEXT_MODE_SETTINGS.showDoctorByDefault),
|
|
27
31
|
autoInject: z.boolean().default(DEFAULT_CONTEXT_MODE_SETTINGS.autoInject),
|
|
28
32
|
preferNativeIntegrations: z
|
|
29
33
|
.boolean()
|
|
30
34
|
.default(DEFAULT_CONTEXT_MODE_SETTINGS.preferNativeIntegrations),
|
|
31
35
|
})
|
|
32
|
-
.strict()
|
|
33
|
-
.superRefine((settings, context) => {
|
|
34
|
-
if (settings.binaryMode !== "path" || settings.binaryPath.length === 0) return;
|
|
35
|
-
if (!isAbsolutePath(settings.binaryPath)) {
|
|
36
|
-
context.addIssue({
|
|
37
|
-
code: "custom",
|
|
38
|
-
path: ["binaryPath"],
|
|
39
|
-
message: "The Context Mode binary path must be absolute.",
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
});
|
|
36
|
+
.strict();
|
|
43
37
|
|
|
44
38
|
export type ContextModeSettings = z.infer<typeof ContextModeSettingsSchema>;
|
|
45
39
|
|
|
40
|
+
const VersionOneSettingsSchema = z.looseObject({
|
|
41
|
+
binaryMode: z.string().optional(),
|
|
42
|
+
binaryPath: z.string().optional(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Version 1 searched PATH when no path was set and kept a `showDoctorByDefault` flag nothing read.
|
|
47
|
+
* Only an explicitly configured absolute path survives as the user's own binary.
|
|
48
|
+
*/
|
|
49
|
+
function migrate(values: unknown): unknown {
|
|
50
|
+
const {
|
|
51
|
+
binaryMode,
|
|
52
|
+
binaryPath,
|
|
53
|
+
showDoctorByDefault: _unused,
|
|
54
|
+
...rest
|
|
55
|
+
} = VersionOneSettingsSchema.parse(values ?? {});
|
|
56
|
+
const configured = binaryMode !== "automatic" ? binaryPath?.trim() : undefined;
|
|
57
|
+
return { ...rest, binaryPath: configured || null };
|
|
58
|
+
}
|
|
59
|
+
|
|
46
60
|
export const contextModeSettings = defineSettings({
|
|
47
61
|
id: "context-mode",
|
|
48
62
|
scope: "host",
|
|
49
|
-
version:
|
|
63
|
+
version: 2,
|
|
50
64
|
schema: ContextModeSettingsSchema,
|
|
65
|
+
migrate,
|
|
51
66
|
});
|