@copilot-swarm/core 0.0.13 → 0.0.16
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/defaults/agents/cross-model-reviewer.md +2 -1
- package/dist/analysis-engine.d.ts.map +1 -1
- package/dist/analysis-engine.js +6 -2
- package/dist/analysis-engine.js.map +1 -1
- package/dist/checkpoint.d.ts +9 -0
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js.map +1 -1
- package/dist/checkpoint.test.js +1 -0
- package/dist/checkpoint.test.js.map +1 -1
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -2
- package/dist/config.js.map +1 -1
- package/dist/finish.d.ts +32 -0
- package/dist/finish.d.ts.map +1 -0
- package/dist/finish.js +232 -0
- package/dist/finish.js.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +8 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +9 -0
- package/dist/messages.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +2 -0
- package/dist/orchestrator.js.map +1 -1
- package/dist/paths.d.ts +6 -6
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +17 -10
- package/dist/paths.js.map +1 -1
- package/dist/pipeline-engine.d.ts.map +1 -1
- package/dist/pipeline-engine.js +32 -17
- package/dist/pipeline-engine.js.map +1 -1
- package/dist/planning-engine.d.ts +5 -0
- package/dist/planning-engine.d.ts.map +1 -1
- package/dist/planning-engine.js +78 -22
- package/dist/planning-engine.js.map +1 -1
- package/dist/progress-tracker.d.ts +2 -0
- package/dist/progress-tracker.d.ts.map +1 -1
- package/dist/progress-tracker.js +2 -0
- package/dist/progress-tracker.js.map +1 -1
- package/dist/session-store.d.ts +38 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +158 -0
- package/dist/session-store.js.map +1 -0
- package/dist/session.d.ts +9 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +20 -4
- package/dist/session.js.map +1 -1
- package/dist/textarea.d.ts.map +1 -1
- package/dist/textarea.js +119 -36
- package/dist/textarea.js.map +1 -1
- package/dist/tui-renderer.d.ts.map +1 -1
- package/dist/tui-renderer.js +2 -1
- package/dist/tui-renderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session management for grouping related runs (analyze, plan, run, review)
|
|
3
|
+
* under a single logical feature/project.
|
|
4
|
+
*
|
|
5
|
+
* Structure:
|
|
6
|
+
* .swarm/
|
|
7
|
+
* sessions/
|
|
8
|
+
* <sessionId>/
|
|
9
|
+
* session.json # metadata
|
|
10
|
+
* runs/<runId>/ # run directories (same layout as before)
|
|
11
|
+
* plans/ # plan outputs
|
|
12
|
+
* analysis/ # analysis outputs
|
|
13
|
+
* latest # latest run pointer within session
|
|
14
|
+
* active-session # pointer to the active session ID
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from "node:fs/promises";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
const SESSIONS_DIR = "sessions";
|
|
19
|
+
const ACTIVE_SESSION_FILE = "active-session";
|
|
20
|
+
function sessionsRoot(config) {
|
|
21
|
+
return path.join(config.repoRoot, config.swarmDir, SESSIONS_DIR);
|
|
22
|
+
}
|
|
23
|
+
function activeSessionPath(config) {
|
|
24
|
+
return path.join(config.repoRoot, config.swarmDir, ACTIVE_SESSION_FILE);
|
|
25
|
+
}
|
|
26
|
+
function sessionDir(config, sessionId) {
|
|
27
|
+
return path.join(sessionsRoot(config), sessionId);
|
|
28
|
+
}
|
|
29
|
+
function sessionJsonPath(config, sessionId) {
|
|
30
|
+
return path.join(sessionDir(config, sessionId), "session.json");
|
|
31
|
+
}
|
|
32
|
+
/** Create a new session and set it as active. */
|
|
33
|
+
export async function createSession(config, name, description) {
|
|
34
|
+
const id = generateSessionId();
|
|
35
|
+
const session = {
|
|
36
|
+
id,
|
|
37
|
+
name,
|
|
38
|
+
created: new Date().toISOString(),
|
|
39
|
+
description,
|
|
40
|
+
};
|
|
41
|
+
const dir = sessionDir(config, id);
|
|
42
|
+
await fs.mkdir(dir, { recursive: true });
|
|
43
|
+
await fs.writeFile(sessionJsonPath(config, id), JSON.stringify(session, null, 2));
|
|
44
|
+
// Set as active
|
|
45
|
+
await setActiveSession(config, id);
|
|
46
|
+
return session;
|
|
47
|
+
}
|
|
48
|
+
/** List all sessions, sorted by creation date (newest first). */
|
|
49
|
+
export async function listSessions(config) {
|
|
50
|
+
const root = sessionsRoot(config);
|
|
51
|
+
try {
|
|
52
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
53
|
+
const sessions = [];
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (!entry.isDirectory())
|
|
56
|
+
continue;
|
|
57
|
+
const jsonPath = path.join(root, entry.name, "session.json");
|
|
58
|
+
try {
|
|
59
|
+
const content = await fs.readFile(jsonPath, "utf-8");
|
|
60
|
+
sessions.push(JSON.parse(content));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Skip invalid session directories
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
sessions.sort((a, b) => b.created.localeCompare(a.created));
|
|
67
|
+
return sessions;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Get a session by ID. */
|
|
74
|
+
export async function getSession(config, sessionId) {
|
|
75
|
+
try {
|
|
76
|
+
const content = await fs.readFile(sessionJsonPath(config, sessionId), "utf-8");
|
|
77
|
+
return JSON.parse(content);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Get the active session ID. */
|
|
84
|
+
export async function getActiveSessionId(config) {
|
|
85
|
+
try {
|
|
86
|
+
return (await fs.readFile(activeSessionPath(config), "utf-8")).trim();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Set the active session. */
|
|
93
|
+
export async function setActiveSession(config, sessionId) {
|
|
94
|
+
const root = path.join(config.repoRoot, config.swarmDir);
|
|
95
|
+
await fs.mkdir(root, { recursive: true });
|
|
96
|
+
await fs.writeFile(activeSessionPath(config), sessionId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolve the effective session ID for the current command.
|
|
100
|
+
* Priority: CLI --session flag > active-session file > auto-create default.
|
|
101
|
+
*/
|
|
102
|
+
export async function resolveSessionId(config) {
|
|
103
|
+
// 1. Explicit CLI flag
|
|
104
|
+
if (config.sessionId) {
|
|
105
|
+
const session = await getSession(config, config.sessionId);
|
|
106
|
+
if (!session) {
|
|
107
|
+
throw new Error(`Session not found: ${config.sessionId}`);
|
|
108
|
+
}
|
|
109
|
+
return config.sessionId;
|
|
110
|
+
}
|
|
111
|
+
// 2. Active session pointer
|
|
112
|
+
const activeId = await getActiveSessionId(config);
|
|
113
|
+
if (activeId) {
|
|
114
|
+
const session = await getSession(config, activeId);
|
|
115
|
+
if (session)
|
|
116
|
+
return activeId;
|
|
117
|
+
}
|
|
118
|
+
// 3. Auto-create a default session, migrating legacy runs if present
|
|
119
|
+
return migrateOrCreateDefault(config);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* If legacy .swarm/runs/ exists, migrate into a "default" session.
|
|
123
|
+
* Otherwise, create a fresh default session.
|
|
124
|
+
*/
|
|
125
|
+
async function migrateOrCreateDefault(config) {
|
|
126
|
+
const swarmRootPath = path.join(config.repoRoot, config.swarmDir);
|
|
127
|
+
const legacyRunsDir = path.join(swarmRootPath, "runs");
|
|
128
|
+
const legacyPlansDir = path.join(swarmRootPath, "plans");
|
|
129
|
+
const legacyAnalysisDir = path.join(swarmRootPath, "analysis");
|
|
130
|
+
const legacyLatest = path.join(swarmRootPath, "latest");
|
|
131
|
+
const session = await createSession(config, "default", "Auto-created default session");
|
|
132
|
+
// Migrate legacy directories if they exist
|
|
133
|
+
const sDir = sessionDir(config, session.id);
|
|
134
|
+
for (const [src, dest] of [
|
|
135
|
+
[legacyRunsDir, path.join(sDir, "runs")],
|
|
136
|
+
[legacyPlansDir, path.join(sDir, "plans")],
|
|
137
|
+
[legacyAnalysisDir, path.join(sDir, "analysis")],
|
|
138
|
+
[legacyLatest, path.join(sDir, "latest")],
|
|
139
|
+
]) {
|
|
140
|
+
try {
|
|
141
|
+
await fs.access(src);
|
|
142
|
+
await fs.rename(src, dest);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Source doesn't exist — skip
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return session.id;
|
|
149
|
+
}
|
|
150
|
+
function generateSessionId() {
|
|
151
|
+
// Short readable ID: 8 hex chars
|
|
152
|
+
const bytes = new Uint8Array(4);
|
|
153
|
+
crypto.getRandomValues(bytes);
|
|
154
|
+
return Array.from(bytes)
|
|
155
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
156
|
+
.join("");
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CopilotSession } from "@github/copilot-sdk";
|
|
2
|
+
import type { SessionRecord } from "./checkpoint.js";
|
|
2
3
|
import type { SwarmConfig } from "./config.js";
|
|
3
4
|
import type { Logger } from "./logger.js";
|
|
4
5
|
import type { PipelineConfig } from "./pipeline-types.js";
|
|
@@ -8,7 +9,12 @@ export declare class SessionManager {
|
|
|
8
9
|
private readonly logger;
|
|
9
10
|
private readonly client;
|
|
10
11
|
private readonly instructionCache;
|
|
12
|
+
private readonly _sessionLog;
|
|
11
13
|
constructor(config: SwarmConfig, pipeline: PipelineConfig, logger: Logger);
|
|
14
|
+
/** All Copilot SDK sessions created during this run, keyed by context. */
|
|
15
|
+
get sessionLog(): Record<string, SessionRecord>;
|
|
16
|
+
/** Record a session with a context key (e.g. "spec-0", "implement-3/stream-1"). */
|
|
17
|
+
recordSession(key: string, session: CopilotSession, agent: string, role: string): void;
|
|
12
18
|
start(): Promise<void>;
|
|
13
19
|
stop(): Promise<void>;
|
|
14
20
|
/**
|
|
@@ -18,10 +24,10 @@ export declare class SessionManager {
|
|
|
18
24
|
* - Undefined → fall back to `<agentsDir>/<agentName>.md`
|
|
19
25
|
*/
|
|
20
26
|
loadAgentInstructions(agentName: string): Promise<string>;
|
|
21
|
-
createAgentSession(agentName: string, model?: string): Promise<CopilotSession>;
|
|
27
|
+
createAgentSession(agentName: string, model?: string, sessionKey?: string): Promise<CopilotSession>;
|
|
22
28
|
createSessionWithInstructions(instructions: string, model?: string): Promise<CopilotSession>;
|
|
23
29
|
send(session: CopilotSession, prompt: string, spinnerLabel?: string): Promise<string>;
|
|
24
|
-
callIsolated(agentName: string, prompt: string, model?: string): Promise<string>;
|
|
25
|
-
callIsolatedWithInstructions(instructions: string, prompt: string, spinnerLabel: string, model?: string): Promise<string>;
|
|
30
|
+
callIsolated(agentName: string, prompt: string, model?: string, sessionKey?: string): Promise<string>;
|
|
31
|
+
callIsolatedWithInstructions(instructions: string, prompt: string, spinnerLabel: string, model?: string, sessionKey?: string): Promise<string>;
|
|
26
32
|
}
|
|
27
33
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,qBAAa,cAAc;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;gBAG9C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM;IAOjC,0EAA0E;IAC1E,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAE9C;IAED,mFAAmF;IACnF,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;;;OAKG;IACG,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6CzD,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAOnG,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAqB5F,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQrF,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBrG,4BAA4B,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;CAuBnB"}
|
package/dist/session.js
CHANGED
|
@@ -12,6 +12,7 @@ export class SessionManager {
|
|
|
12
12
|
logger;
|
|
13
13
|
client;
|
|
14
14
|
instructionCache = new Map();
|
|
15
|
+
_sessionLog = {};
|
|
15
16
|
constructor(config, pipeline, logger) {
|
|
16
17
|
this.config = config;
|
|
17
18
|
this.pipeline = pipeline;
|
|
@@ -20,6 +21,14 @@ export class SessionManager {
|
|
|
20
21
|
logLevel: config.verbose ? "debug" : "warning",
|
|
21
22
|
});
|
|
22
23
|
}
|
|
24
|
+
/** All Copilot SDK sessions created during this run, keyed by context. */
|
|
25
|
+
get sessionLog() {
|
|
26
|
+
return this._sessionLog;
|
|
27
|
+
}
|
|
28
|
+
/** Record a session with a context key (e.g. "spec-0", "implement-3/stream-1"). */
|
|
29
|
+
recordSession(key, session, agent, role) {
|
|
30
|
+
this._sessionLog[key] = { sessionId: session.sessionId, agent, role };
|
|
31
|
+
}
|
|
23
32
|
async start() {
|
|
24
33
|
await this.client.start();
|
|
25
34
|
}
|
|
@@ -74,9 +83,12 @@ export class SessionManager {
|
|
|
74
83
|
}
|
|
75
84
|
throw new Error(`Failed to load agent instructions for "${agentName}": not found in repo (${repoFilePath}) or bundled defaults`);
|
|
76
85
|
}
|
|
77
|
-
async createAgentSession(agentName, model) {
|
|
86
|
+
async createAgentSession(agentName, model, sessionKey) {
|
|
78
87
|
const instructions = await this.loadAgentInstructions(agentName);
|
|
79
|
-
|
|
88
|
+
const session = await this.createSessionWithInstructions(instructions, model);
|
|
89
|
+
if (sessionKey)
|
|
90
|
+
this.recordSession(sessionKey, session, agentName, agentName);
|
|
91
|
+
return session;
|
|
80
92
|
}
|
|
81
93
|
async createSessionWithInstructions(instructions, model) {
|
|
82
94
|
const session = await this.client.createSession({
|
|
@@ -104,10 +116,12 @@ export class SessionManager {
|
|
|
104
116
|
this.logger.newline();
|
|
105
117
|
return response?.data.content ?? "";
|
|
106
118
|
}
|
|
107
|
-
async callIsolated(agentName, prompt, model) {
|
|
119
|
+
async callIsolated(agentName, prompt, model, sessionKey) {
|
|
108
120
|
const maxAttempts = this.config.maxRetries;
|
|
109
121
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
110
122
|
const session = await this.createAgentSession(agentName, model);
|
|
123
|
+
if (sessionKey)
|
|
124
|
+
this.recordSession(sessionKey, session, agentName, agentName);
|
|
111
125
|
try {
|
|
112
126
|
const content = await this.send(session, prompt, `${agentName} is working…`);
|
|
113
127
|
if (!content && attempt < maxAttempts) {
|
|
@@ -128,10 +142,12 @@ export class SessionManager {
|
|
|
128
142
|
}
|
|
129
143
|
return "";
|
|
130
144
|
}
|
|
131
|
-
async callIsolatedWithInstructions(instructions, prompt, spinnerLabel, model) {
|
|
145
|
+
async callIsolatedWithInstructions(instructions, prompt, spinnerLabel, model, sessionKey) {
|
|
132
146
|
const maxAttempts = this.config.maxRetries;
|
|
133
147
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
134
148
|
const session = await this.createSessionWithInstructions(instructions, model);
|
|
149
|
+
if (sessionKey)
|
|
150
|
+
this.recordSession(sessionKey, session, "inline-agent", "inline-agent");
|
|
135
151
|
try {
|
|
136
152
|
const content = await this.send(session, prompt, spinnerLabel);
|
|
137
153
|
if (!content && attempt < maxAttempts) {
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/textarea.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../src/textarea.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../src/textarea.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkRH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkLhE;AAID,MAAM,WAAW,kBAAkB;IACjC,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA8SpH"}
|
package/dist/textarea.js
CHANGED
|
@@ -62,22 +62,64 @@ function wrapText(text, width) {
|
|
|
62
62
|
return [""];
|
|
63
63
|
const result = [];
|
|
64
64
|
for (const rawLine of text.split("\n")) {
|
|
65
|
-
|
|
66
|
-
result.push(
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
let remaining = rawLine;
|
|
70
|
-
while (remaining.length > width) {
|
|
71
|
-
let cut = remaining.lastIndexOf(" ", width);
|
|
72
|
-
if (cut <= 0)
|
|
73
|
-
cut = width;
|
|
74
|
-
result.push(remaining.substring(0, cut));
|
|
75
|
-
remaining = remaining.substring(cut).trimStart();
|
|
76
|
-
}
|
|
77
|
-
result.push(remaining);
|
|
65
|
+
for (const vr of wrapLine(rawLine, width))
|
|
66
|
+
result.push(vr);
|
|
78
67
|
}
|
|
79
68
|
return result;
|
|
80
69
|
}
|
|
70
|
+
/** Wrap a single line into visual rows at word boundaries. */
|
|
71
|
+
function wrapLine(line, width) {
|
|
72
|
+
if (width <= 0)
|
|
73
|
+
return [line];
|
|
74
|
+
if (line.length <= width)
|
|
75
|
+
return [line];
|
|
76
|
+
const rows = [];
|
|
77
|
+
let remaining = line;
|
|
78
|
+
while (remaining.length > width) {
|
|
79
|
+
let cut = remaining.lastIndexOf(" ", width);
|
|
80
|
+
if (cut <= 0)
|
|
81
|
+
cut = width;
|
|
82
|
+
rows.push(remaining.substring(0, cut));
|
|
83
|
+
remaining = remaining.substring(cut === width ? cut : cut + 1);
|
|
84
|
+
}
|
|
85
|
+
rows.push(remaining);
|
|
86
|
+
return rows;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Compute the visual row count for a set of lines at a given width.
|
|
90
|
+
* Also builds a map from logical line index to starting visual row.
|
|
91
|
+
*/
|
|
92
|
+
function computeVisualLayout(lines, width) {
|
|
93
|
+
const lineStartRow = [];
|
|
94
|
+
const wrappedLines = [];
|
|
95
|
+
let total = 0;
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
lineStartRow.push(total);
|
|
98
|
+
const wrapped = wrapLine(line, width);
|
|
99
|
+
wrappedLines.push(wrapped);
|
|
100
|
+
total += wrapped.length;
|
|
101
|
+
}
|
|
102
|
+
return { totalVisualRows: total, lineStartRow, wrappedLines };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Convert a logical cursor position (row, col) to a visual row offset and
|
|
106
|
+
* visual column within the wrapped layout.
|
|
107
|
+
*/
|
|
108
|
+
function logicalToVisual(lineStartRow, wrappedLines, logRow, logCol) {
|
|
109
|
+
const wrapped = wrappedLines[logRow];
|
|
110
|
+
let remaining = logCol;
|
|
111
|
+
for (let i = 0; i < wrapped.length; i++) {
|
|
112
|
+
const rowLen = wrapped[i].length;
|
|
113
|
+
// Account for removed space at word-wrap boundary
|
|
114
|
+
const isLastWrapRow = i === wrapped.length - 1;
|
|
115
|
+
if (remaining <= rowLen || isLastWrapRow) {
|
|
116
|
+
return { visualRow: lineStartRow[logRow] + i, visualCol: remaining };
|
|
117
|
+
}
|
|
118
|
+
// +1 for the space that was consumed as the wrap point
|
|
119
|
+
remaining -= rowLen + 1;
|
|
120
|
+
}
|
|
121
|
+
return { visualRow: lineStartRow[logRow], visualCol: logCol };
|
|
122
|
+
}
|
|
81
123
|
function renderMenuOverlay(items, selectedIdx, rows, cols) {
|
|
82
124
|
process.stdout.write("\x1b[?25l");
|
|
83
125
|
const boxW = 30;
|
|
@@ -143,6 +185,15 @@ function handleEditorKey(ch, i, data, state) {
|
|
|
143
185
|
state.curCol = r.col;
|
|
144
186
|
}
|
|
145
187
|
}
|
|
188
|
+
// Shift+Enter (ESC[1;2B) → insert newline
|
|
189
|
+
if (mod === 50 && dir === 66) {
|
|
190
|
+
const after = state.lines[state.curRow].substring(state.curCol);
|
|
191
|
+
state.lines[state.curRow] = state.lines[state.curRow].substring(0, state.curCol);
|
|
192
|
+
state.lines.splice(state.curRow + 1, 0, after);
|
|
193
|
+
state.curRow++;
|
|
194
|
+
state.curCol = 0;
|
|
195
|
+
return { handled: true, newI: i + 5, needsFullRender: true, needsCursorUpdate: false };
|
|
196
|
+
}
|
|
146
197
|
return { handled: true, newI: i + 5, needsFullRender: false, needsCursorUpdate: true };
|
|
147
198
|
}
|
|
148
199
|
if (code === 65)
|
|
@@ -210,13 +261,16 @@ export async function openTextarea() {
|
|
|
210
261
|
const innerWidth = cols - 4;
|
|
211
262
|
const title = " Task Description ";
|
|
212
263
|
const state = { lines: [""], curRow: 0, curCol: 0 };
|
|
213
|
-
let scroll = 0;
|
|
264
|
+
let scroll = 0; // scroll in visual rows
|
|
214
265
|
let menuOpen = false;
|
|
215
266
|
let menuIdx = 0;
|
|
216
267
|
const menuItems = [
|
|
217
268
|
{ label: "Submit", value: "submit" },
|
|
218
269
|
{ label: "Cancel", value: "cancel" },
|
|
219
270
|
];
|
|
271
|
+
function getLayout() {
|
|
272
|
+
return computeVisualLayout(state.lines, innerWidth);
|
|
273
|
+
}
|
|
220
274
|
function clamp() {
|
|
221
275
|
if (state.curRow < 0)
|
|
222
276
|
state.curRow = 0;
|
|
@@ -226,13 +280,25 @@ export async function openTextarea() {
|
|
|
226
280
|
state.curCol = 0;
|
|
227
281
|
if (state.curCol > state.lines[state.curRow].length)
|
|
228
282
|
state.curCol = state.lines[state.curRow].length;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
scroll =
|
|
283
|
+
const layout = getLayout();
|
|
284
|
+
const vis = logicalToVisual(layout.lineStartRow, layout.wrappedLines, state.curRow, state.curCol);
|
|
285
|
+
if (vis.visualRow < scroll)
|
|
286
|
+
scroll = vis.visualRow;
|
|
287
|
+
if (vis.visualRow >= scroll + editorHeight)
|
|
288
|
+
scroll = vis.visualRow - editorHeight + 1;
|
|
233
289
|
}
|
|
234
|
-
function
|
|
235
|
-
const
|
|
290
|
+
function renderVisualRow(screenRow, visualRowIdx) {
|
|
291
|
+
const layout = getLayout();
|
|
292
|
+
// Find which logical line + wrap row this visual row belongs to
|
|
293
|
+
let text = "";
|
|
294
|
+
for (let li = 0; li < state.lines.length; li++) {
|
|
295
|
+
const startVR = layout.lineStartRow[li];
|
|
296
|
+
const wrapped = layout.wrappedLines[li];
|
|
297
|
+
if (visualRowIdx >= startVR && visualRowIdx < startVR + wrapped.length) {
|
|
298
|
+
text = wrapped[visualRowIdx - startVR];
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
236
302
|
const display = text.substring(0, innerWidth);
|
|
237
303
|
const pad = Math.max(0, innerWidth - display.length);
|
|
238
304
|
process.stdout.write(`\x1b[${screenRow};1H\x1b[2K\u2502 ${display}${" ".repeat(pad)} \u2502`);
|
|
@@ -245,14 +311,16 @@ export async function openTextarea() {
|
|
|
245
311
|
process.stdout.write("\x1b[?25l");
|
|
246
312
|
process.stdout.write(`\x1b[1;1H\x1b[2K${top}`);
|
|
247
313
|
for (let i = 0; i < editorHeight; i++)
|
|
248
|
-
|
|
314
|
+
renderVisualRow(2 + i, scroll + i);
|
|
249
315
|
process.stdout.write(`\x1b[${2 + editorHeight};1H\x1b[2K${bottom}`);
|
|
250
316
|
placeCursor();
|
|
251
317
|
process.stdout.write("\x1b[?25h");
|
|
252
318
|
}
|
|
253
319
|
function placeCursor() {
|
|
254
|
-
const
|
|
255
|
-
const
|
|
320
|
+
const layout = getLayout();
|
|
321
|
+
const vis = logicalToVisual(layout.lineStartRow, layout.wrappedLines, state.curRow, state.curCol);
|
|
322
|
+
const screenRow = 2 + (vis.visualRow - scroll);
|
|
323
|
+
const screenCol = 3 + Math.min(vis.visualCol, innerWidth);
|
|
256
324
|
process.stdout.write(`\x1b[${screenRow};${screenCol}H`);
|
|
257
325
|
}
|
|
258
326
|
return new Promise((resolve) => {
|
|
@@ -347,8 +415,7 @@ export async function openTextarea() {
|
|
|
347
415
|
state.lines[state.curRow].substring(state.curCol);
|
|
348
416
|
state.curCol++;
|
|
349
417
|
clamp();
|
|
350
|
-
|
|
351
|
-
placeCursor();
|
|
418
|
+
needsFullRender = true;
|
|
352
419
|
}
|
|
353
420
|
}
|
|
354
421
|
if (needsFullRender)
|
|
@@ -387,7 +454,7 @@ export async function openSplitEditor(contextText, options) {
|
|
|
387
454
|
const contextTitle = ` ${options?.contextTitle ?? "Agent Questions"} `;
|
|
388
455
|
// Editor state (left panel)
|
|
389
456
|
const state = { lines: [""], curRow: 0, curCol: 0 };
|
|
390
|
-
let edScroll = 0;
|
|
457
|
+
let edScroll = 0; // scroll in visual rows
|
|
391
458
|
// Context state (right panel)
|
|
392
459
|
const ctxLines = wrapText(contextText, rightInner);
|
|
393
460
|
let ctxScroll = 0;
|
|
@@ -400,6 +467,9 @@ export async function openSplitEditor(contextText, options) {
|
|
|
400
467
|
{ label: "Skip (use AI judgment)", value: "skip" },
|
|
401
468
|
{ label: "Cancel", value: "cancel" },
|
|
402
469
|
];
|
|
470
|
+
function getEdLayout() {
|
|
471
|
+
return computeVisualLayout(state.lines, leftInner);
|
|
472
|
+
}
|
|
403
473
|
function clampEditor() {
|
|
404
474
|
if (state.curRow < 0)
|
|
405
475
|
state.curRow = 0;
|
|
@@ -409,10 +479,12 @@ export async function openSplitEditor(contextText, options) {
|
|
|
409
479
|
state.curCol = 0;
|
|
410
480
|
if (state.curCol > state.lines[state.curRow].length)
|
|
411
481
|
state.curCol = state.lines[state.curRow].length;
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (
|
|
415
|
-
edScroll =
|
|
482
|
+
const layout = getEdLayout();
|
|
483
|
+
const vis = logicalToVisual(layout.lineStartRow, layout.wrappedLines, state.curRow, state.curCol);
|
|
484
|
+
if (vis.visualRow < edScroll)
|
|
485
|
+
edScroll = vis.visualRow;
|
|
486
|
+
if (vis.visualRow >= edScroll + bodyHeight)
|
|
487
|
+
edScroll = vis.visualRow - bodyHeight + 1;
|
|
416
488
|
}
|
|
417
489
|
function clampCtx() {
|
|
418
490
|
if (ctxScroll < 0)
|
|
@@ -421,8 +493,18 @@ export async function openSplitEditor(contextText, options) {
|
|
|
421
493
|
ctxScroll = ctxMaxScroll;
|
|
422
494
|
}
|
|
423
495
|
function renderRow(screenRow, bodyIdx) {
|
|
424
|
-
|
|
425
|
-
const
|
|
496
|
+
// Left panel: get visual row from wrapped editor layout
|
|
497
|
+
const edVisIdx = edScroll + bodyIdx;
|
|
498
|
+
const layout = getEdLayout();
|
|
499
|
+
let edText = "";
|
|
500
|
+
for (let li = 0; li < state.lines.length; li++) {
|
|
501
|
+
const startVR = layout.lineStartRow[li];
|
|
502
|
+
const wrapped = layout.wrappedLines[li];
|
|
503
|
+
if (edVisIdx >= startVR && edVisIdx < startVR + wrapped.length) {
|
|
504
|
+
edText = wrapped[edVisIdx - startVR];
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
426
508
|
const edDisplay = edText.substring(0, leftInner);
|
|
427
509
|
const edPad = Math.max(0, leftInner - edDisplay.length);
|
|
428
510
|
const leftDim = focus === "right" ? "\x1b[2m" : "";
|
|
@@ -462,8 +544,10 @@ export async function openSplitEditor(contextText, options) {
|
|
|
462
544
|
}
|
|
463
545
|
function placeCursorSplit() {
|
|
464
546
|
if (focus === "left") {
|
|
465
|
-
const
|
|
466
|
-
const
|
|
547
|
+
const layout = getEdLayout();
|
|
548
|
+
const vis = logicalToVisual(layout.lineStartRow, layout.wrappedLines, state.curRow, state.curCol);
|
|
549
|
+
const screenRow = 2 + (vis.visualRow - edScroll);
|
|
550
|
+
const screenCol = 3 + Math.min(vis.visualCol, leftInner);
|
|
467
551
|
process.stdout.write(`\x1b[?25h\x1b[${screenRow};${screenCol}H`);
|
|
468
552
|
}
|
|
469
553
|
else {
|
|
@@ -632,8 +716,7 @@ export async function openSplitEditor(contextText, options) {
|
|
|
632
716
|
state.lines[state.curRow].substring(state.curCol);
|
|
633
717
|
state.curCol++;
|
|
634
718
|
clampEditor();
|
|
635
|
-
|
|
636
|
-
placeCursorSplit();
|
|
719
|
+
needsFullRender = true;
|
|
637
720
|
}
|
|
638
721
|
}
|
|
639
722
|
if (needsFullRender)
|