@almadar/workspace 0.11.3 → 0.11.5
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/index.d.ts +1 -1
- package/dist/index.js +56 -7
- package/dist/index.js.map +1 -1
- package/dist/internal/path-layout.d.ts +5 -1
- package/dist/service.d.ts +10 -1
- package/dist/types.d.ts +22 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export { openWorkspace } from './open-workspace.js';
|
|
|
10
10
|
export { listWorkspaces } from './list-workspaces.js';
|
|
11
11
|
export { deleteWorkspace } from './delete-workspace.js';
|
|
12
12
|
export { openAccount } from './account.js';
|
|
13
|
-
export type { WorkspaceService, InstantiateWorkspaceSeed, WorkspaceObserver, WorkspaceWriteEvent, WorkspaceWatchEvent, OpenWorkspaceOptions, ListWorkspacesOptions, WorkspaceSummary, RestoreBackend, GitHubConfig, GitStatusInfo, SnapshotMeta, WorkspaceArchiveBackend, FileTreeNode, AccountService, AccountConfig, ProviderCredential, AuthToken, AccountIdentity, OpenAccountOptions, } from './types.js';
|
|
13
|
+
export type { WorkspaceService, InstantiateWorkspaceSeed, WorkspaceObserver, WorkspaceWriteEvent, WorkspaceWatchEvent, OpenWorkspaceOptions, MountEntry, ListWorkspacesOptions, WorkspaceSummary, RestoreBackend, GitHubConfig, GitStatusInfo, SnapshotMeta, WorkspaceArchiveBackend, FileTreeNode, AccountService, AccountConfig, ProviderCredential, AuthToken, AccountIdentity, OpenAccountOptions, } from './types.js';
|
|
14
14
|
export type { WorkspaceIndex, EmbedderPort, ResolveResult, ResolveOptions, TraitRefEmit, WorkspaceIndexStats, OrbitalIndexEntry, ExtraTraitIdentity, RetrievalResult, RetrievalOptions, RecentlyEditedOptions, EventEdge, EntityBinding, RuleBinding, RecencyEntry, IntentMaps, ComposedMaps, BM25Document, BM25Table, BM25Options, WorkspaceIndexManifest, } from './workspace-index/types.js';
|
|
15
15
|
export { DEFAULT_COERCION_THRESHOLD, DEFAULT_RETRIEVAL_TOP_K, RRF_K, WORKSPACE_INDEX_SCHEMA_VERSION, } from './workspace-index/types.js';
|
package/dist/index.js
CHANGED
|
@@ -293,7 +293,7 @@ function appMarkerFile(workDir) {
|
|
|
293
293
|
function workspaceIndexManifestFile(workDir) {
|
|
294
294
|
return path2.join(workDir, WORKSPACE_LAYOUT.ALMADAR_DIR, "index.json");
|
|
295
295
|
}
|
|
296
|
-
function sandboxedPath(workDir, relPath) {
|
|
296
|
+
function sandboxedPath(workDir, relPath, mounts) {
|
|
297
297
|
if (typeof relPath !== "string" || relPath.length === 0) {
|
|
298
298
|
throw new Error("sandbox: empty relative path");
|
|
299
299
|
}
|
|
@@ -303,6 +303,20 @@ function sandboxedPath(workDir, relPath) {
|
|
|
303
303
|
if (/^[a-zA-Z]:[\\/]/.test(relPath)) {
|
|
304
304
|
throw new Error(`sandbox: drive-letter paths are not allowed (${relPath})`);
|
|
305
305
|
}
|
|
306
|
+
if (mounts) {
|
|
307
|
+
for (const [prefix, mountRoot] of mounts) {
|
|
308
|
+
const prefixSep = prefix + "/";
|
|
309
|
+
if (relPath === prefix || relPath.startsWith(prefixSep)) {
|
|
310
|
+
const mountAbs = path2.resolve(mountRoot);
|
|
311
|
+
const rest = relPath === prefix ? "." : relPath.slice(prefixSep.length);
|
|
312
|
+
const target2 = path2.resolve(mountAbs, rest);
|
|
313
|
+
if (target2 !== mountAbs && !target2.startsWith(mountAbs + path2.sep)) {
|
|
314
|
+
throw new Error(`sandbox: mount path escapes mount root (${relPath})`);
|
|
315
|
+
}
|
|
316
|
+
return target2;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
306
320
|
const rootAbs = path2.resolve(workDir);
|
|
307
321
|
const target = path2.resolve(rootAbs, relPath);
|
|
308
322
|
if (target !== rootAbs && !target.startsWith(rootAbs + path2.sep)) {
|
|
@@ -1770,6 +1784,8 @@ var WorkspaceServiceImpl = class {
|
|
|
1770
1784
|
constructor(args) {
|
|
1771
1785
|
/** Per-absolute-path serial queue. */
|
|
1772
1786
|
this.writeQueue = /* @__PURE__ */ new Map();
|
|
1787
|
+
/** Mount prefix → resolved absolute directory. Built from constructor `mounts` + runtime `mountReadonly`. */
|
|
1788
|
+
this.mountMap = /* @__PURE__ */ new Map();
|
|
1773
1789
|
this.workDir = args.workDir;
|
|
1774
1790
|
this.backend = args.backend;
|
|
1775
1791
|
this.sinks = args.sinks;
|
|
@@ -1787,6 +1803,9 @@ var WorkspaceServiceImpl = class {
|
|
|
1787
1803
|
readSchema: () => this.readSchema(),
|
|
1788
1804
|
readHistory: (orbital) => this.readHistory(orbital)
|
|
1789
1805
|
});
|
|
1806
|
+
if (args.mounts) {
|
|
1807
|
+
for (const m of args.mounts) this.mountMap.set(m.prefix, path2.resolve(m.absPath));
|
|
1808
|
+
}
|
|
1790
1809
|
}
|
|
1791
1810
|
// === Identity ===
|
|
1792
1811
|
get appId() {
|
|
@@ -2109,7 +2128,7 @@ var WorkspaceServiceImpl = class {
|
|
|
2109
2128
|
}
|
|
2110
2129
|
// === Sandboxed generic file I/O ===
|
|
2111
2130
|
async readFile(relPath) {
|
|
2112
|
-
const abs =
|
|
2131
|
+
const abs = this.sandbox(relPath);
|
|
2113
2132
|
if (!this.backend.exists(abs)) return null;
|
|
2114
2133
|
try {
|
|
2115
2134
|
return await this.backend.readFile(abs);
|
|
@@ -2118,7 +2137,8 @@ var WorkspaceServiceImpl = class {
|
|
|
2118
2137
|
}
|
|
2119
2138
|
}
|
|
2120
2139
|
async writeFile(relPath, content) {
|
|
2121
|
-
|
|
2140
|
+
this.assertNotMounted(relPath);
|
|
2141
|
+
const abs = this.sandbox(relPath);
|
|
2122
2142
|
await this.withLock(abs, async () => {
|
|
2123
2143
|
await this.ensureParent(abs);
|
|
2124
2144
|
await this.backend.writeFile(abs, content);
|
|
@@ -2126,7 +2146,8 @@ var WorkspaceServiceImpl = class {
|
|
|
2126
2146
|
await this.emit({ kind: "file", relPath, content });
|
|
2127
2147
|
}
|
|
2128
2148
|
async removeFile(relPath) {
|
|
2129
|
-
|
|
2149
|
+
this.assertNotMounted(relPath);
|
|
2150
|
+
const abs = this.sandbox(relPath);
|
|
2130
2151
|
let removed = false;
|
|
2131
2152
|
await this.withLock(abs, async () => {
|
|
2132
2153
|
if (!this.backend.exists(abs)) return;
|
|
@@ -2136,7 +2157,7 @@ var WorkspaceServiceImpl = class {
|
|
|
2136
2157
|
if (removed) await this.emit({ kind: "file-removed", relPath });
|
|
2137
2158
|
}
|
|
2138
2159
|
async listTree(relPath) {
|
|
2139
|
-
const base = relPath === void 0 ? this.workDir :
|
|
2160
|
+
const base = relPath === void 0 ? this.workDir : this.sandbox(relPath);
|
|
2140
2161
|
if (!this.backend.exists(base)) return [];
|
|
2141
2162
|
const out = [];
|
|
2142
2163
|
await walk(this.backend, base, this.workDir, out);
|
|
@@ -2145,12 +2166,39 @@ var WorkspaceServiceImpl = class {
|
|
|
2145
2166
|
async exists(relPath) {
|
|
2146
2167
|
let abs;
|
|
2147
2168
|
try {
|
|
2148
|
-
abs =
|
|
2169
|
+
abs = this.sandbox(relPath);
|
|
2149
2170
|
} catch {
|
|
2150
2171
|
return false;
|
|
2151
2172
|
}
|
|
2152
2173
|
return this.backend.exists(abs);
|
|
2153
2174
|
}
|
|
2175
|
+
// === Read-only mounts ===
|
|
2176
|
+
mountReadonly(prefix, absPath) {
|
|
2177
|
+
if (this.mountMap.has(prefix)) {
|
|
2178
|
+
throw new Error(`mount: prefix "${prefix}" already registered`);
|
|
2179
|
+
}
|
|
2180
|
+
this.mountMap.set(prefix, path2.resolve(absPath));
|
|
2181
|
+
}
|
|
2182
|
+
isMounted(relPath) {
|
|
2183
|
+
try {
|
|
2184
|
+
for (const [prefix] of this.mountMap) {
|
|
2185
|
+
if (relPath === prefix || relPath.startsWith(prefix + "/")) return true;
|
|
2186
|
+
}
|
|
2187
|
+
return false;
|
|
2188
|
+
} catch {
|
|
2189
|
+
return false;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
/** Resolve a sandboxed path through mounts. */
|
|
2193
|
+
sandbox(relPath) {
|
|
2194
|
+
return sandboxedPath(this.workDir, relPath, this.mountMap.size > 0 ? this.mountMap : void 0);
|
|
2195
|
+
}
|
|
2196
|
+
/** Throw if relPath resolves to a mount (write/remove are blocked). */
|
|
2197
|
+
assertNotMounted(relPath) {
|
|
2198
|
+
if (this.isMounted(relPath)) {
|
|
2199
|
+
throw new Error(`sandbox: cannot write to read-only mount (${relPath})`);
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2154
2202
|
// === Git ===
|
|
2155
2203
|
async commitAndPush(opts) {
|
|
2156
2204
|
if (!this.git) return null;
|
|
@@ -2405,7 +2453,8 @@ async function openWorkspaceInternal(opts) {
|
|
|
2405
2453
|
appId: resolved.appId,
|
|
2406
2454
|
git,
|
|
2407
2455
|
github: opts.github,
|
|
2408
|
-
archiveBackend: opts.archiveBackend
|
|
2456
|
+
archiveBackend: opts.archiveBackend,
|
|
2457
|
+
mounts: opts.mounts
|
|
2409
2458
|
});
|
|
2410
2459
|
if (!bare) {
|
|
2411
2460
|
await service.index.warm();
|