@silo-code/sdk 0.21.0 → 0.23.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/dist/editor-service.d.ts +135 -3
- package/dist/editor-service.d.ts.map +1 -1
- package/dist/event.d.ts +28 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +2 -0
- package/dist/event.js.map +1 -0
- package/dist/file-service.d.ts +33 -2
- package/dist/file-service.d.ts.map +1 -1
- package/dist/index.d.ts +15 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/dist/network-service.d.ts +46 -2
- package/dist/network-service.d.ts.map +1 -1
- package/dist/path.d.ts +62 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +150 -0
- package/dist/path.js.map +1 -0
- package/dist/process-service.d.ts +24 -4
- package/dist/process-service.d.ts.map +1 -1
- package/dist/processes-service.d.ts +1 -1
- package/dist/search-service.d.ts +11 -0
- package/dist/search-service.d.ts.map +1 -1
- package/dist/system-service.d.ts +2 -2
- package/dist/terminal-service.d.ts +66 -0
- package/dist/terminal-service.d.ts.map +1 -1
- package/dist/types.d.ts +12 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/workspace-service.d.ts +13 -0
- package/dist/workspace-service.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/editor-service.ts +141 -5
- package/src/event.ts +28 -0
- package/src/file-service.ts +33 -2
- package/src/index.ts +24 -5
- package/src/network-service.ts +51 -2
- package/src/path.test.ts +135 -0
- package/src/path.ts +188 -0
- package/src/process-service.ts +24 -4
- package/src/processes-service.ts +1 -1
- package/src/search-service.ts +11 -0
- package/src/system-service.ts +2 -2
- package/src/terminal-service.ts +73 -0
- package/src/types.ts +12 -5
- package/src/workspace-service.ts +13 -0
package/src/path.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Pure path utilities for extensions. A cross-platform replacement for
|
|
2
|
+
// `node:path`, which extensions are banned from importing (platform ban).
|
|
3
|
+
// All outputs use forward-slash separators — the form FileService accepts on
|
|
4
|
+
// every platform. Both "/" and "\" are accepted as inputs.
|
|
5
|
+
|
|
6
|
+
/** Normalize all separators to forward-slash. */
|
|
7
|
+
function normSep(p: string): string {
|
|
8
|
+
return p.replace(/\\/g, "/");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Extract a Windows drive-letter prefix ("C:") from a forward-slash path, or null. */
|
|
12
|
+
function parseDrive(p: string): string | null {
|
|
13
|
+
const m = /^([A-Za-z]):/.exec(p);
|
|
14
|
+
return m ? m[1].toUpperCase() + ":" : null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Normalize segments of a forward-slash path: collapse duplicate slashes,
|
|
19
|
+
* resolve "." and ".." segments. Preserves leading "/" (POSIX absolute),
|
|
20
|
+
* "C:/" (Windows drive-letter), and "//" (UNC paths).
|
|
21
|
+
*/
|
|
22
|
+
function normSegments(s: string): string {
|
|
23
|
+
const drive = parseDrive(s);
|
|
24
|
+
const afterDrive = drive ? s.slice(2) : s;
|
|
25
|
+
const isUnc = afterDrive.startsWith("//");
|
|
26
|
+
const isAbs = isUnc || afterDrive.startsWith("/");
|
|
27
|
+
|
|
28
|
+
const stack: string[] = [];
|
|
29
|
+
for (const seg of afterDrive.split("/")) {
|
|
30
|
+
if (seg === "" || seg === ".") continue;
|
|
31
|
+
if (seg === "..") {
|
|
32
|
+
if (stack.length > 0 && stack[stack.length - 1] !== "..") {
|
|
33
|
+
stack.pop();
|
|
34
|
+
} else if (!isAbs) {
|
|
35
|
+
stack.push("..");
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
stack.push(seg);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let result = stack.join("/");
|
|
43
|
+
if (isUnc) result = "//" + result;
|
|
44
|
+
else if (isAbs) result = "/" + result;
|
|
45
|
+
if (drive) result = drive + result;
|
|
46
|
+
if (!result) return isAbs ? (drive ? drive + "/" : "/") : ".";
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Path utilities for extensions — a cross-platform replacement for
|
|
52
|
+
* `node:path`, which extensions are banned from importing. All output paths
|
|
53
|
+
* use forward-slash separators (the form {@link FileService} accepts on every
|
|
54
|
+
* platform). Both `/` and `\` are accepted as input separators.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { path } from "@silo-code/sdk";
|
|
59
|
+
*
|
|
60
|
+
* const dir = path.dirname(filePath); // "/home/user/docs"
|
|
61
|
+
* const full = path.join(dir, "images/fig.png"); // "/home/user/docs/images/fig.png"
|
|
62
|
+
* const rel = path.relative(dir, full); // "images/fig.png"
|
|
63
|
+
* const ext = path.extname(full); // ".png"
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @category Core Types
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export const path: {
|
|
70
|
+
/**
|
|
71
|
+
* Join path segments and normalize the result. Empty segments are ignored;
|
|
72
|
+
* `\` separators in any segment are treated as `/`.
|
|
73
|
+
*/
|
|
74
|
+
join(...parts: string[]): string;
|
|
75
|
+
/**
|
|
76
|
+
* Return the directory portion of a path — everything up to (not including)
|
|
77
|
+
* the last `/`. Returns `"."` for a bare filename with no directory component.
|
|
78
|
+
*/
|
|
79
|
+
dirname(p: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Return the final component of a path. If `ext` is supplied and the
|
|
82
|
+
* basename ends with that string, it is stripped from the result.
|
|
83
|
+
*/
|
|
84
|
+
basename(p: string, ext?: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Return the extension of a path — the portion from the last `.` of the
|
|
87
|
+
* basename, including the dot. Returns `""` for paths with no extension and
|
|
88
|
+
* for dotfiles with no secondary extension (e.g. `".gitignore"` → `""`).
|
|
89
|
+
*/
|
|
90
|
+
extname(p: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* Compute the relative path from `from` to `to`. Both should be absolute
|
|
93
|
+
* paths on the same drive. When they are on different Windows drive letters,
|
|
94
|
+
* `to` (normalized) is returned unchanged — no relative path exists between
|
|
95
|
+
* drives.
|
|
96
|
+
*/
|
|
97
|
+
relative(from: string, to: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Return `true` if `p` is an absolute path: starts with `/` (POSIX), has a
|
|
100
|
+
* drive letter followed by a slash (`C:/`, `C:\`), or is a UNC path
|
|
101
|
+
* (`\\server\share` / `//server/share`). Note: `C:foo` (drive-relative,
|
|
102
|
+
* no slash) is NOT absolute.
|
|
103
|
+
*/
|
|
104
|
+
isAbsolute(p: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Normalize a path: convert `\` to `/`, collapse duplicate slashes, and
|
|
107
|
+
* resolve `.` and `..` segments.
|
|
108
|
+
*/
|
|
109
|
+
normalize(p: string): string;
|
|
110
|
+
} = {
|
|
111
|
+
normalize(p) {
|
|
112
|
+
return normSegments(normSep(p));
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
join(...parts) {
|
|
116
|
+
const nonEmpty = parts.filter((p) => p.length > 0);
|
|
117
|
+
if (nonEmpty.length === 0) return ".";
|
|
118
|
+
// Concatenate without adding "/" when adjacent parts already supply the
|
|
119
|
+
// boundary, so join("/", "rel") → "/rel" rather than "//rel" (UNC).
|
|
120
|
+
const raw = nonEmpty.map(normSep).reduce((a, b) => {
|
|
121
|
+
if (a.endsWith("/") || b.startsWith("/")) return a + b;
|
|
122
|
+
return a + "/" + b;
|
|
123
|
+
});
|
|
124
|
+
return normSegments(raw);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
dirname(p) {
|
|
128
|
+
const n = normSegments(normSep(p));
|
|
129
|
+
const drive = parseDrive(n);
|
|
130
|
+
const rest = drive ? n.slice(2) : n;
|
|
131
|
+
const i = rest.lastIndexOf("/");
|
|
132
|
+
if (i < 0) return drive ? drive + "." : ".";
|
|
133
|
+
if (i === 0) return drive ? drive + "/" : "/";
|
|
134
|
+
return drive ? drive + rest.slice(0, i) : rest.slice(0, i);
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
basename(p, ext) {
|
|
138
|
+
const n = normSep(p);
|
|
139
|
+
const segs = n.split("/");
|
|
140
|
+
let name = segs[segs.length - 1] ?? "";
|
|
141
|
+
// Trailing slash: "foo/" → last segment is "" → fall back to prior segment
|
|
142
|
+
if (name === "" && segs.length > 1) name = segs[segs.length - 2] ?? "";
|
|
143
|
+
if (ext !== undefined && name.endsWith(ext)) {
|
|
144
|
+
name = name.slice(0, name.length - ext.length);
|
|
145
|
+
}
|
|
146
|
+
return name;
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
extname(p) {
|
|
150
|
+
const base = path.basename(normSep(p));
|
|
151
|
+
const i = base.lastIndexOf(".");
|
|
152
|
+
// i === 0 means a dotfile like ".gitignore" — no extension
|
|
153
|
+
if (i <= 0) return "";
|
|
154
|
+
return base.slice(i);
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
isAbsolute(p) {
|
|
158
|
+
const n = normSep(p);
|
|
159
|
+
if (n.startsWith("//")) return true; // UNC (\\server\share or //server/share)
|
|
160
|
+
if (/^[A-Za-z]:\//.test(n)) return true; // Windows drive with slash (C:/ or C:\)
|
|
161
|
+
return n.startsWith("/"); // POSIX
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
relative(from, to) {
|
|
165
|
+
const nFrom = normSegments(normSep(from));
|
|
166
|
+
const nTo = normSegments(normSep(to));
|
|
167
|
+
const driveFrom = parseDrive(nFrom);
|
|
168
|
+
const driveTo = parseDrive(nTo);
|
|
169
|
+
// Can't express a relative path across different drives
|
|
170
|
+
if (driveFrom !== driveTo) return nTo;
|
|
171
|
+
const segsFrom = (driveFrom ? nFrom.slice(2) : nFrom)
|
|
172
|
+
.split("/")
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
const segsTo = (driveTo ? nTo.slice(2) : nTo).split("/").filter(Boolean);
|
|
175
|
+
let common = 0;
|
|
176
|
+
while (
|
|
177
|
+
common < segsFrom.length &&
|
|
178
|
+
common < segsTo.length &&
|
|
179
|
+
segsFrom[common] === segsTo[common]
|
|
180
|
+
) {
|
|
181
|
+
common++;
|
|
182
|
+
}
|
|
183
|
+
const ups = segsFrom.length - common;
|
|
184
|
+
const downs = segsTo.slice(common);
|
|
185
|
+
const parts = [...Array<string>(ups).fill(".."), ...downs];
|
|
186
|
+
return parts.join("/") || ".";
|
|
187
|
+
},
|
|
188
|
+
};
|
package/src/process-service.ts
CHANGED
|
@@ -67,6 +67,24 @@ export interface ProcessExecOptions {
|
|
|
67
67
|
* {@link Permission}. First-party (bundled) extensions are unscoped.
|
|
68
68
|
*/
|
|
69
69
|
cwd?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Extra environment variables, **merged over** the host's environment (the
|
|
72
|
+
* command inherits the host env; these keys add to or override it). Use it to
|
|
73
|
+
* set things like `GIT_PAGER=cat` or a locale without clobbering `PATH`.
|
|
74
|
+
*/
|
|
75
|
+
env?: Record<string, string>;
|
|
76
|
+
/**
|
|
77
|
+
* Kill the process and reject after this many milliseconds. The whole process
|
|
78
|
+
* group is terminated (not just the direct child), so shell wrappers don't
|
|
79
|
+
* leak orphans. The rejection is an `Error` whose `name` is `"AbortError"`.
|
|
80
|
+
*/
|
|
81
|
+
timeoutMs?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Abort handle. Aborting kills the process (and its group) and rejects the
|
|
84
|
+
* `exec` promise with an `Error` whose `name` is `"AbortError"` — the same
|
|
85
|
+
* shape as a `timeoutMs` expiry, so callers branch on `err.name`.
|
|
86
|
+
*/
|
|
87
|
+
signal?: AbortSignal;
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
/**
|
|
@@ -116,10 +134,12 @@ export interface ProcessService {
|
|
|
116
134
|
* interactive sessions instead.
|
|
117
135
|
*
|
|
118
136
|
* Runs **off the UI thread**, so a slow or network-bound command never
|
|
119
|
-
* stutters the app. The returned promise rejects
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
137
|
+
* stutters the app. The returned promise rejects if the process could not be
|
|
138
|
+
* spawned (e.g. the command was not found), or if a
|
|
139
|
+
* {@link ProcessExecOptions.timeoutMs | timeout} / {@link ProcessExecOptions.signal | abort}
|
|
140
|
+
* fires (an `Error` with `name === "AbortError"`); a command that runs to
|
|
141
|
+
* completion but exits non-zero **resolves** — check
|
|
142
|
+
* {@link ProcessExecResult.code} and {@link ProcessExecResult.stderr}.
|
|
123
143
|
*
|
|
124
144
|
* @param command - Executable to run (resolved via `PATH`), e.g. `"git"`.
|
|
125
145
|
* @param args - Arguments passed verbatim — not shell-interpreted, so no
|
package/src/processes-service.ts
CHANGED
|
@@ -88,7 +88,7 @@ export interface ProcessInfo {
|
|
|
88
88
|
* // Notify when all agents in the workspace are idle.
|
|
89
89
|
* const sub = ctx.processes.subscribe((procs) => {
|
|
90
90
|
* const allIdle = procs.every((p) => p.atPrompt);
|
|
91
|
-
* if (allIdle) ctx.ui.notify(
|
|
91
|
+
* if (allIdle) ctx.ui.notify("info", "All agents finished");
|
|
92
92
|
* });
|
|
93
93
|
* ctx.subscriptions.push(sub);
|
|
94
94
|
*
|
package/src/search-service.ts
CHANGED
|
@@ -43,6 +43,17 @@ export interface SearchOptions {
|
|
|
43
43
|
* is hit, the search stops early and {@link SearchResponse.truncated} is true.
|
|
44
44
|
*/
|
|
45
45
|
maxResults?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Cancel the search. When the signal aborts, the promise returned by
|
|
48
|
+
* {@link SearchService.search} rejects with an `Error` whose `name` is
|
|
49
|
+
* `"AbortError"` (the `fetch` convention — branch on `err.name`).
|
|
50
|
+
*
|
|
51
|
+
* Cancellation is observable immediately, but the native search may still run
|
|
52
|
+
* to completion in the background — its result is simply discarded. Use this
|
|
53
|
+
* to abandon a stale query (e.g. superseded by the next keystroke) rather than
|
|
54
|
+
* to reclaim native CPU the instant you abort.
|
|
55
|
+
*/
|
|
56
|
+
signal?: AbortSignal;
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
/**
|
package/src/system-service.ts
CHANGED
|
@@ -53,13 +53,13 @@ export interface SystemInfo {
|
|
|
53
53
|
* ctx.subscriptions.push(
|
|
54
54
|
* ctx.registerCommand({
|
|
55
55
|
* id: "my.reveal-in-finder",
|
|
56
|
-
*
|
|
56
|
+
* label: "Reveal in Finder",
|
|
57
57
|
* run() { ... },
|
|
58
58
|
* }),
|
|
59
59
|
* );
|
|
60
60
|
* }
|
|
61
61
|
*
|
|
62
|
-
* ctx.ui.notify(
|
|
62
|
+
* ctx.ui.notify("info", `Running Silo ${siloVersion} on ${os}/${arch}`);
|
|
63
63
|
* },
|
|
64
64
|
* };
|
|
65
65
|
* ```
|
package/src/terminal-service.ts
CHANGED
|
@@ -98,11 +98,51 @@ export interface TerminalService {
|
|
|
98
98
|
* Open a new terminal in a workspace (defaults to the active one). Returns the
|
|
99
99
|
* created {@link TerminalRecord}; the PTY session spawns lazily when its tab
|
|
100
100
|
* mounts.
|
|
101
|
+
*
|
|
102
|
+
* Returns `undefined` only when `input.workspaceId` is not given and there is
|
|
103
|
+
* no active workspace at the time of the call — in normal use this does not
|
|
104
|
+
* happen because activating any workspace happens before extensions run.
|
|
101
105
|
*/
|
|
102
106
|
create(input?: CreateTerminalInput): TerminalRecord | undefined;
|
|
103
107
|
/** Close and kill every terminal in a workspace (e.g. on workspace delete). */
|
|
104
108
|
closeWorkspace(workspaceId: string): void;
|
|
105
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Write text to a terminal's PTY as if the user typed it. By default a
|
|
112
|
+
* carriage return is appended so the line executes; pass `addNewline: false`
|
|
113
|
+
* to stage text without running it.
|
|
114
|
+
*
|
|
115
|
+
* Works even if the terminal tab has never been shown: the PTY spawns lazily
|
|
116
|
+
* on first mount, and `sendText` force-spawns it on demand (a later mount then
|
|
117
|
+
* attaches to that same session). No-op for an unknown `terminalId`.
|
|
118
|
+
*
|
|
119
|
+
* @param terminalId - The {@link TerminalRecord.id} to write to.
|
|
120
|
+
* @param text - The text to send.
|
|
121
|
+
* @param addNewline - Append a carriage return to execute. Defaults to `true`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const term = ctx.terminals.create({ cwd: workspaceFolder });
|
|
126
|
+
* if (term) ctx.terminals.sendText(term.id, "npm run build");
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
sendText(terminalId: string, text: string, addNewline?: boolean): void;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Close one terminal tab and kill its PTY session. No-op if the id is unknown.
|
|
133
|
+
* To reap every terminal in a workspace at once use
|
|
134
|
+
* {@link TerminalService.closeWorkspace}.
|
|
135
|
+
*/
|
|
136
|
+
close(terminalId: string): void;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Set a terminal's user-facing name ({@link TerminalRecord.customName}),
|
|
140
|
+
* shown on its tab and persisted across restarts. Passing an empty string
|
|
141
|
+
* clears the custom name, letting the PTY-derived title take over again.
|
|
142
|
+
* No-op for an unknown `terminalId`.
|
|
143
|
+
*/
|
|
144
|
+
rename(terminalId: string, name: string): void;
|
|
145
|
+
|
|
106
146
|
/**
|
|
107
147
|
* Switch to the workspace containing this terminal and activate its tab in
|
|
108
148
|
* the center dock. No-ops if the terminal id is unknown.
|
|
@@ -169,6 +209,39 @@ export interface TerminalService {
|
|
|
169
209
|
handler: (event: OscEvent) => void,
|
|
170
210
|
): Disposable;
|
|
171
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Subscribe to the raw PTY output stream of the terminal identified by
|
|
214
|
+
* `terminalId`. The `handler` is called with every chunk of bytes the PTY
|
|
215
|
+
* produces — including ANSI escape sequences, OSC sequences, and all other
|
|
216
|
+
* control characters — exactly as they arrive, with no parsing or filtering.
|
|
217
|
+
*
|
|
218
|
+
* This fires even when the terminal's panel is not visible, so it is suitable
|
|
219
|
+
* for background monitoring (e.g. detecting output activity to confirm an
|
|
220
|
+
* agent is still running). Keep handlers lightweight: they execute
|
|
221
|
+
* synchronously on every PTY chunk, which can be multiple times per second
|
|
222
|
+
* while a program is active.
|
|
223
|
+
*
|
|
224
|
+
* The subscription is keyed to the **terminal record id** (e.g. `"term_…"`),
|
|
225
|
+
* not the underlying PTY session id, so it survives terminal recreation within
|
|
226
|
+
* the same record.
|
|
227
|
+
*
|
|
228
|
+
* Returns a {@link Disposable} that cancels the subscription.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* // Track the last time any output arrived to confirm agent activity.
|
|
233
|
+
* let lastOutputAt = 0;
|
|
234
|
+
* const sub = ctx.terminals.subscribeOutput(terminalId, () => {
|
|
235
|
+
* lastOutputAt = Date.now();
|
|
236
|
+
* });
|
|
237
|
+
* ctx.subscriptions.push(sub);
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
subscribeOutput(
|
|
241
|
+
terminalId: string,
|
|
242
|
+
handler: (data: string) => void,
|
|
243
|
+
): Disposable;
|
|
244
|
+
|
|
172
245
|
/**
|
|
173
246
|
* The record id of the terminal tab that is currently active in the active
|
|
174
247
|
* workspace's center dock, or `null` when an editor tab (or nothing) is
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Silo extension API — types
|
|
2
|
+
* The Silo extension API — types-first contract plus a small set of blessed
|
|
3
|
+
* runtime helpers.
|
|
3
4
|
*
|
|
4
5
|
* Everything an extension author can see at compile time lives here (plus the
|
|
5
6
|
* service interfaces in the sibling `*-service` files, which this module
|
|
@@ -8,6 +9,12 @@
|
|
|
8
9
|
* never import the host. This is the VS Code (`vscode.d.ts`) / Obsidian
|
|
9
10
|
* (`obsidian-api`) model.
|
|
10
11
|
*
|
|
12
|
+
* **Runtime exports:** the SDK also ships a small set of blessed runtime
|
|
13
|
+
* helpers (`Tooltip`, `useFocusGroup`, `useServiceState`, `DND_MIME`,
|
|
14
|
+
* `PathDeniedError`, `NetworkError`) and peer-depends on React 19. Changes to
|
|
15
|
+
* these can be breaking even when the types are unchanged — treat them with
|
|
16
|
+
* the same care as the type surface.
|
|
17
|
+
*
|
|
11
18
|
* Start with {@link Extension} (the unit you export) and
|
|
12
19
|
* {@link ExtensionContext} (the `ctx` the host hands you).
|
|
13
20
|
*
|
|
@@ -207,10 +214,10 @@ export interface NewFileTemplate {
|
|
|
207
214
|
|
|
208
215
|
/**
|
|
209
216
|
* Declarative metadata about a file extension — the open-ended counterpart to
|
|
210
|
-
*
|
|
211
|
-
* surfaces (and, later, tab/explorer icons) can
|
|
212
|
-
* FileType does not register
|
|
213
|
-
* extension at dispatch time.
|
|
217
|
+
* {@link Editor} (which is purely a presenter/renderer). A single source of
|
|
218
|
+
* truth that "New File" surfaces (and, later, tab/explorer icons) can
|
|
219
|
+
* enumerate. Registering a FileType does not register an Editor; the two are
|
|
220
|
+
* matched independently by extension at dispatch time.
|
|
214
221
|
*
|
|
215
222
|
* @category Registration
|
|
216
223
|
* @public
|
package/src/workspace-service.ts
CHANGED
|
@@ -170,6 +170,12 @@ export interface WorkspaceService {
|
|
|
170
170
|
createFromFolderPicker(): Promise<Workspace | null>;
|
|
171
171
|
create(input: CreateWorkspaceInput): Workspace;
|
|
172
172
|
rename(id: string, name: string): void;
|
|
173
|
+
/**
|
|
174
|
+
* Move a workspace to a new position relative to a reference workspace.
|
|
175
|
+
* @param from - Id of the workspace being dragged / moved.
|
|
176
|
+
* @param to - Id of the reference workspace (the insertion anchor).
|
|
177
|
+
* @param position - Whether to place `from` before or after `to`.
|
|
178
|
+
*/
|
|
173
179
|
reorder(from: string, to: string, position: "before" | "after"): void;
|
|
174
180
|
/** Activate (and reopen if closed). */
|
|
175
181
|
activate(id: string): void;
|
|
@@ -263,6 +269,13 @@ export interface WorkspaceService {
|
|
|
263
269
|
*
|
|
264
270
|
* The Workspaces panel subscribes internally to re-render when providers
|
|
265
271
|
* are added or removed.
|
|
272
|
+
*
|
|
273
|
+
* **No `invalidateSection` by design.** Unlike status rows and badges, a
|
|
274
|
+
* section is a live React component that re-renders on its own internal or
|
|
275
|
+
* context-driven state changes — it is not a snapshot returned from a
|
|
276
|
+
* `provide()` call, so there is nothing for the host to re-query. If a
|
|
277
|
+
* section needs to trigger a full workspace-panel refresh (rare), it should
|
|
278
|
+
* update its own state directly.
|
|
266
279
|
*/
|
|
267
280
|
subscribeSection(listener: () => void): Disposable;
|
|
268
281
|
|