@agentlip/workspace 0.1.0 → 0.1.1-rc.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/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +146 -0
- package/dist/index.js.map +1 -0
- package/package.json +8 -2
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentlip/workspace - Workspace discovery + initialization
|
|
3
|
+
*
|
|
4
|
+
* Provides upward workspace discovery with security boundaries:
|
|
5
|
+
* - Starts at cwd (or provided path)
|
|
6
|
+
* - Walks upward until .agentlip/db.sqlite3 exists
|
|
7
|
+
* - Stops at filesystem boundary OR user home directory
|
|
8
|
+
* - Initializes workspace at starting directory if not found
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Result of workspace discovery
|
|
12
|
+
*/
|
|
13
|
+
export interface WorkspaceDiscoveryResult {
|
|
14
|
+
/** Absolute path to workspace root directory */
|
|
15
|
+
root: string;
|
|
16
|
+
/** Absolute path to db.sqlite3 file */
|
|
17
|
+
dbPath: string;
|
|
18
|
+
/** Whether workspace was discovered (true) or needs initialization (false) */
|
|
19
|
+
discovered: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Result of workspace initialization
|
|
23
|
+
*/
|
|
24
|
+
export interface WorkspaceInitResult {
|
|
25
|
+
/** Absolute path to workspace root directory */
|
|
26
|
+
root: string;
|
|
27
|
+
/** Absolute path to db.sqlite3 file */
|
|
28
|
+
dbPath: string;
|
|
29
|
+
/** Whether workspace was newly created (true) or already existed (false) */
|
|
30
|
+
created: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Discover workspace root by walking upward from startPath.
|
|
34
|
+
*
|
|
35
|
+
* Stops at:
|
|
36
|
+
* - Filesystem boundary (device ID change)
|
|
37
|
+
* - User home directory (never traverse above home)
|
|
38
|
+
*
|
|
39
|
+
* @param startPath - Directory to start search from (defaults to cwd)
|
|
40
|
+
* @returns Discovery result or null if no workspace found within boundary
|
|
41
|
+
*/
|
|
42
|
+
export declare function discoverWorkspaceRoot(startPath?: string): Promise<WorkspaceDiscoveryResult | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Ensure workspace is initialized at workspaceRoot.
|
|
45
|
+
* Creates .agentlip/ directory and empty db.sqlite3 file if they don't exist.
|
|
46
|
+
*
|
|
47
|
+
* @param workspaceRoot - Directory to initialize workspace in
|
|
48
|
+
* @returns Init result indicating whether workspace was newly created
|
|
49
|
+
*/
|
|
50
|
+
export declare function ensureWorkspaceInitialized(workspaceRoot: string): Promise<WorkspaceInitResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Discover workspace or initialize if not found.
|
|
53
|
+
*
|
|
54
|
+
* Combines discovery + initialization:
|
|
55
|
+
* - First tries to discover workspace by walking upward
|
|
56
|
+
* - If not found, initializes workspace at startPath
|
|
57
|
+
*
|
|
58
|
+
* @param startPath - Directory to start search from (defaults to cwd)
|
|
59
|
+
* @returns Discovery result (never null)
|
|
60
|
+
*/
|
|
61
|
+
export declare function discoverOrInitWorkspace(startPath?: string): Promise<WorkspaceDiscoveryResult>;
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAsD1C;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAyC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,wBAAwB,CAAC,CAiBnC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentlip/workspace - Workspace discovery + initialization
|
|
3
|
+
*
|
|
4
|
+
* Provides upward workspace discovery with security boundaries:
|
|
5
|
+
* - Starts at cwd (or provided path)
|
|
6
|
+
* - Walks upward until .agentlip/db.sqlite3 exists
|
|
7
|
+
* - Stops at filesystem boundary OR user home directory
|
|
8
|
+
* - Initializes workspace at starting directory if not found
|
|
9
|
+
*/
|
|
10
|
+
import { promises as fs } from 'node:fs';
|
|
11
|
+
import { join, dirname, resolve } from 'node:path';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
const WORKSPACE_MARKER = '.agentlip';
|
|
14
|
+
const DB_FILENAME = 'db.sqlite3';
|
|
15
|
+
/**
|
|
16
|
+
* Discover workspace root by walking upward from startPath.
|
|
17
|
+
*
|
|
18
|
+
* Stops at:
|
|
19
|
+
* - Filesystem boundary (device ID change)
|
|
20
|
+
* - User home directory (never traverse above home)
|
|
21
|
+
*
|
|
22
|
+
* @param startPath - Directory to start search from (defaults to cwd)
|
|
23
|
+
* @returns Discovery result or null if no workspace found within boundary
|
|
24
|
+
*/
|
|
25
|
+
export async function discoverWorkspaceRoot(startPath) {
|
|
26
|
+
const start = resolve(startPath ?? process.cwd());
|
|
27
|
+
const home = resolve(homedir());
|
|
28
|
+
// Get initial filesystem device ID
|
|
29
|
+
const startStat = await fs.lstat(start);
|
|
30
|
+
const startDevice = startStat.dev;
|
|
31
|
+
let current = start;
|
|
32
|
+
while (true) {
|
|
33
|
+
// Check if .agentlip/db.sqlite3 exists at current level
|
|
34
|
+
const workspaceDir = join(current, WORKSPACE_MARKER);
|
|
35
|
+
const dbPath = join(workspaceDir, DB_FILENAME);
|
|
36
|
+
try {
|
|
37
|
+
await fs.access(dbPath);
|
|
38
|
+
// Found it!
|
|
39
|
+
return {
|
|
40
|
+
root: current,
|
|
41
|
+
dbPath,
|
|
42
|
+
discovered: true
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Not found, continue upward
|
|
47
|
+
}
|
|
48
|
+
// Check boundary conditions before going up
|
|
49
|
+
const parent = dirname(current);
|
|
50
|
+
// Reached filesystem root (parent === current)
|
|
51
|
+
if (parent === current) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
// Stop traversal at user home directory (security boundary)
|
|
55
|
+
if (current === home) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// Check filesystem boundary (device ID change)
|
|
59
|
+
try {
|
|
60
|
+
const parentStat = await fs.lstat(parent);
|
|
61
|
+
if (parentStat.dev !== startDevice) {
|
|
62
|
+
// Crossed filesystem boundary
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Can't stat parent - stop here
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
current = parent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Ensure workspace is initialized at workspaceRoot.
|
|
75
|
+
* Creates .agentlip/ directory and empty db.sqlite3 file if they don't exist.
|
|
76
|
+
*
|
|
77
|
+
* @param workspaceRoot - Directory to initialize workspace in
|
|
78
|
+
* @returns Init result indicating whether workspace was newly created
|
|
79
|
+
*/
|
|
80
|
+
export async function ensureWorkspaceInitialized(workspaceRoot) {
|
|
81
|
+
const root = resolve(workspaceRoot);
|
|
82
|
+
const workspaceDir = join(root, WORKSPACE_MARKER);
|
|
83
|
+
const dbPath = join(workspaceDir, DB_FILENAME);
|
|
84
|
+
let created = false;
|
|
85
|
+
// Check if db already exists
|
|
86
|
+
try {
|
|
87
|
+
await fs.access(dbPath);
|
|
88
|
+
// Already initialized
|
|
89
|
+
return { root, dbPath, created: false };
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Need to initialize
|
|
93
|
+
}
|
|
94
|
+
// Create .agentlip directory with mode 0700 (owner rwx only)
|
|
95
|
+
try {
|
|
96
|
+
await fs.mkdir(workspaceDir, { mode: 0o700, recursive: true });
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
// If directory already exists, that's fine
|
|
100
|
+
if (err.code !== 'EEXIST') {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Create empty db.sqlite3 with mode 0600 (owner rw only)
|
|
105
|
+
try {
|
|
106
|
+
const handle = await fs.open(dbPath, 'wx', 0o600); // x = fail if exists
|
|
107
|
+
await handle.close();
|
|
108
|
+
created = true;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err.code === 'EEXIST') {
|
|
112
|
+
// File was created between our check and now - that's fine
|
|
113
|
+
created = false;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { root, dbPath, created };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Discover workspace or initialize if not found.
|
|
123
|
+
*
|
|
124
|
+
* Combines discovery + initialization:
|
|
125
|
+
* - First tries to discover workspace by walking upward
|
|
126
|
+
* - If not found, initializes workspace at startPath
|
|
127
|
+
*
|
|
128
|
+
* @param startPath - Directory to start search from (defaults to cwd)
|
|
129
|
+
* @returns Discovery result (never null)
|
|
130
|
+
*/
|
|
131
|
+
export async function discoverOrInitWorkspace(startPath) {
|
|
132
|
+
const start = resolve(startPath ?? process.cwd());
|
|
133
|
+
// Try discovery first
|
|
134
|
+
const discovered = await discoverWorkspaceRoot(start);
|
|
135
|
+
if (discovered) {
|
|
136
|
+
return discovered;
|
|
137
|
+
}
|
|
138
|
+
// No workspace found - initialize at start path
|
|
139
|
+
const initialized = await ensureWorkspaceInitialized(start);
|
|
140
|
+
return {
|
|
141
|
+
root: initialized.root,
|
|
142
|
+
dbPath: initialized.dbPath,
|
|
143
|
+
discovered: false
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentlip/workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1-rc.1",
|
|
4
4
|
"description": "Workspace discovery and initialization for Agentlip",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,13 +17,19 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
+
"dist/**/*",
|
|
20
21
|
"src/**/*.ts",
|
|
21
22
|
"!src/**/*.test.ts"
|
|
22
23
|
],
|
|
23
24
|
"exports": {
|
|
24
|
-
".":
|
|
25
|
+
".": {
|
|
26
|
+
"bun": "./src/index.ts",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
}
|
|
25
30
|
},
|
|
26
31
|
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.build.json",
|
|
27
33
|
"test": "bun test",
|
|
28
34
|
"verify": "bun verify.ts"
|
|
29
35
|
}
|