@uniqbit/mate-core 0.17.2-canary.0 → 0.17.2-canary.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/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
|
|
3
4
|
import { FRAMEWORK_NAME } from "../../../framework";
|
|
@@ -26,11 +27,56 @@ export async function launchableAgents(
|
|
|
26
27
|
return TERMINAL_AGENTS.filter((agent) => allowed.includes(agent) && installed(agent));
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
/** Lowercase letters, digits and hyphens, so a name can never carry shell syntax or a flag. */
|
|
31
|
+
export const AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
32
|
+
|
|
33
|
+
const AGENT_DEFINITION_DIRS: Record<TerminalAgent, string> = {
|
|
34
|
+
claude: path.join(".claude", "agents"),
|
|
35
|
+
opencode: path.join(".opencode", "agents"),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface DefaultAgentOutcome {
|
|
39
|
+
agentArgs?: string[];
|
|
40
|
+
notice?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The companion's `studio.terminal.agent` for one provider. Never throws and
|
|
45
|
+
* never echoes the configured value into the notice.
|
|
46
|
+
*/
|
|
47
|
+
export async function defaultAgentFor(
|
|
48
|
+
companionPath: string,
|
|
49
|
+
agent: TerminalAgent,
|
|
50
|
+
): Promise<DefaultAgentOutcome> {
|
|
51
|
+
const configPath = path.join(companionPath, `.${FRAMEWORK_NAME}`, "config", "framework.yaml");
|
|
52
|
+
if (!fs.existsSync(configPath)) return {};
|
|
53
|
+
let name: unknown;
|
|
54
|
+
try {
|
|
55
|
+
name = (await new ConfigStore(configPath).load()).studio?.terminal?.agent;
|
|
56
|
+
} catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
if (name === undefined || name === null) return {};
|
|
60
|
+
if (typeof name !== "string" || !AGENT_NAME_PATTERN.test(name)) {
|
|
61
|
+
return {
|
|
62
|
+
notice: "Default agent not applied: studio.terminal.agent is not a valid agent name.",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const definition = path.join(companionPath, AGENT_DEFINITION_DIRS[agent], `${name}.md`);
|
|
66
|
+
if (!fs.existsSync(definition)) {
|
|
67
|
+
return {
|
|
68
|
+
notice: `Default agent "${name}" not applied: this companion has no ${agent} definition for it.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { agentArgs: ["--agent", name] };
|
|
72
|
+
}
|
|
73
|
+
|
|
29
74
|
export interface LaunchResolverOptions {
|
|
30
75
|
collectInventory: () => Promise<StudioInventory>;
|
|
31
76
|
/** Pinned by `serve --companion`; overrides the page selection. */
|
|
32
77
|
launchCompanion?: string | null;
|
|
33
78
|
launchableAgents?: (companionPath: string) => Promise<TerminalAgent[]>;
|
|
79
|
+
defaultAgent?: (companionPath: string, agent: TerminalAgent) => Promise<DefaultAgentOutcome>;
|
|
34
80
|
}
|
|
35
81
|
|
|
36
82
|
/** The companion a launch targets: the pinned one, else the page's, both read from the current inventory. */
|
|
@@ -50,6 +96,7 @@ export function createLaunchResolver(
|
|
|
50
96
|
options: LaunchResolverOptions,
|
|
51
97
|
): (agent: string, digest: string | null) => Promise<TerminalLaunchResolution> {
|
|
52
98
|
const agents = options.launchableAgents ?? launchableAgents;
|
|
99
|
+
const defaultAgent = options.defaultAgent ?? defaultAgentFor;
|
|
53
100
|
return async (agent, digest) => {
|
|
54
101
|
const companion = await effectiveLaunchCompanion(
|
|
55
102
|
await options.collectInventory(),
|
|
@@ -66,6 +113,9 @@ export function createLaunchResolver(
|
|
|
66
113
|
if (!(await agents(companion.path)).includes(agent as TerminalAgent)) {
|
|
67
114
|
return { reason: `${agent} is not allowed by this companion or is not installed` };
|
|
68
115
|
}
|
|
69
|
-
return {
|
|
116
|
+
return {
|
|
117
|
+
companionPath: companion.path,
|
|
118
|
+
...(await defaultAgent(companion.path, agent as TerminalAgent)),
|
|
119
|
+
};
|
|
70
120
|
};
|
|
71
121
|
}
|
|
@@ -177,7 +177,15 @@ export interface TerminalSessionInfo {
|
|
|
177
177
|
startedAt: number;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
export type TerminalLaunchResolution =
|
|
180
|
+
export type TerminalLaunchResolution =
|
|
181
|
+
| {
|
|
182
|
+
companionPath: string;
|
|
183
|
+
/** Extra argv entries for the managed launch; set only by companion configuration. */
|
|
184
|
+
agentArgs?: string[];
|
|
185
|
+
/** Written to the terminal before the agent starts. */
|
|
186
|
+
notice?: string;
|
|
187
|
+
}
|
|
188
|
+
| { reason: string };
|
|
181
189
|
|
|
182
190
|
export interface TerminalRegistryOptions {
|
|
183
191
|
detachMs: number;
|
|
@@ -388,7 +396,7 @@ export class TerminalRegistry {
|
|
|
388
396
|
void this.finish(detached, { type: "ended", reason: "evicted" });
|
|
389
397
|
}
|
|
390
398
|
|
|
391
|
-
const session = this.launch(agent, resolved.companionPath, size);
|
|
399
|
+
const session = this.launch(agent, resolved.companionPath, size, resolved);
|
|
392
400
|
this.attachTo(connection, session, size);
|
|
393
401
|
}
|
|
394
402
|
|
|
@@ -396,6 +404,7 @@ export class TerminalRegistry {
|
|
|
396
404
|
agent: TerminalAgent,
|
|
397
405
|
companionPath: string,
|
|
398
406
|
size: { cols: number; rows: number },
|
|
407
|
+
extras: { agentArgs?: string[]; notice?: string } = {},
|
|
399
408
|
): Session {
|
|
400
409
|
const env: Record<string, string> = {};
|
|
401
410
|
for (const [key, value] of Object.entries(this.options.env ?? process.env)) {
|
|
@@ -413,6 +422,7 @@ export class TerminalRegistry {
|
|
|
413
422
|
"--companion",
|
|
414
423
|
"--yes",
|
|
415
424
|
...(this.options.noGit ? ["--no-git"] : []),
|
|
425
|
+
...(extras.agentArgs ?? []),
|
|
416
426
|
];
|
|
417
427
|
|
|
418
428
|
const session = {
|
|
@@ -427,6 +437,7 @@ export class TerminalRegistry {
|
|
|
427
437
|
ending: null,
|
|
428
438
|
exited: false,
|
|
429
439
|
} as Omit<Session, "process"> as Session;
|
|
440
|
+
if (extras.notice) session.ring.push(new TextEncoder().encode(`${extras.notice}\r\n`));
|
|
430
441
|
session.process = this.spawn({
|
|
431
442
|
argv,
|
|
432
443
|
cwd: companionPath,
|
|
@@ -120,6 +120,11 @@ export interface PluginDeclaration {
|
|
|
120
120
|
config?: unknown;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
export interface StudioTerminalConfig {
|
|
124
|
+
/** Persona selected with `--agent` when Studio's terminal starts a provider. */
|
|
125
|
+
agent?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
export interface FrameworkConfig {
|
|
124
129
|
type?: FrameworkType;
|
|
125
130
|
git?: GitModeProfile;
|
|
@@ -131,6 +136,7 @@ export interface FrameworkConfig {
|
|
|
131
136
|
cliTools?: CliToolConfig[];
|
|
132
137
|
packageManagers?: string[];
|
|
133
138
|
engines?: EngineConstraints;
|
|
139
|
+
studio?: { terminal?: StudioTerminalConfig };
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
export interface CompanionRegistryConfig {
|