@principles/install-layout 0.2.6 → 0.3.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/index.d.ts +18 -1
- package/dist/index.js +15 -2
- package/package.json +4 -2
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -69
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const INSTALL_LAYOUT_VERSION: 1;
|
|
2
2
|
export declare const INSTALL_LAYOUT_MODES: readonly ['canonical', 'legacy'];
|
|
3
3
|
export type InstallLayoutMode = (typeof INSTALL_LAYOUT_MODES)[number];
|
|
4
|
-
export declare const INSTALL_HOSTS: readonly ['codex', 'openclaw'];
|
|
4
|
+
export declare const INSTALL_HOSTS: readonly ['codex', 'openclaw', 'workbuddy'];
|
|
5
5
|
export type InstallHost = (typeof INSTALL_HOSTS)[number];
|
|
6
6
|
export interface InstallManifest {
|
|
7
7
|
layoutVersion: typeof INSTALL_LAYOUT_VERSION;
|
|
@@ -44,6 +44,13 @@ export interface InstallLayoutPaths {
|
|
|
44
44
|
* links like any other runtime component.
|
|
45
45
|
*/
|
|
46
46
|
codexAdapterDir: string;
|
|
47
|
+
/**
|
|
48
|
+
* WorkBuddy host adapter component (payload dir workbuddy-adapter/, npm
|
|
49
|
+
* name @principles/workbuddy-adapter; SPEC workbuddy-host-adapter §4.1).
|
|
50
|
+
* The WorkBuddy plugin wrapper resolves this dir to load the adapter entry
|
|
51
|
+
* the same way the Codex hook resolves the canonical runtime.
|
|
52
|
+
*/
|
|
53
|
+
workbuddyAdapterDir: string;
|
|
47
54
|
}
|
|
48
55
|
export interface LayoutResolution {
|
|
49
56
|
mode: InstallLayoutMode | 'missing';
|
|
@@ -65,6 +72,16 @@ export declare function parseInstallManifest(value: unknown): {
|
|
|
65
72
|
error?: string;
|
|
66
73
|
};
|
|
67
74
|
export declare function getInstallLayoutPaths(homeDir: string): InstallLayoutPaths;
|
|
75
|
+
/**
|
|
76
|
+
* WorkBuddy governance workspace (SPEC workbuddy-host-adapter §4.1 OD-07,
|
|
77
|
+
* frozen by Phase 0 probe P06 2026-10-12): an explicit user-level directory
|
|
78
|
+
* under the WorkBuddy config root, shared across projects, never auto-reused
|
|
79
|
+
* from Codex/OpenClaw state. projectDir stays the host cwd; this dir owns
|
|
80
|
+
* governance state (state.db / trajectory). The dir is CREATED only by the
|
|
81
|
+
* explicit setup flow — its absence means "not initialized", never a silent
|
|
82
|
+
* fallback to another host's database.
|
|
83
|
+
*/
|
|
84
|
+
export declare function getWorkbuddyWorkspaceDir(homeDir: string): string;
|
|
68
85
|
export declare function resolveInstallLayout(options: ResolveInstallLayoutOptions): LayoutResolution;
|
|
69
86
|
export declare function getConsoleServerEntry(paths: InstallLayoutPaths, mode: InstallLayoutMode): string;
|
|
70
87
|
export declare function getConsoleWebIndex(paths: InstallLayoutPaths, mode: InstallLayoutMode): string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
2
|
export const INSTALL_LAYOUT_VERSION = 1;
|
|
3
3
|
export const INSTALL_LAYOUT_MODES = ['canonical', 'legacy'];
|
|
4
|
-
export const INSTALL_HOSTS = ['codex', 'openclaw'];
|
|
4
|
+
export const INSTALL_HOSTS = ['codex', 'openclaw', 'workbuddy'];
|
|
5
5
|
function isRecord(value) {
|
|
6
6
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
7
|
}
|
|
@@ -48,7 +48,7 @@ export function parseInstallManifest(value) {
|
|
|
48
48
|
return { error: 'install_manifest_malformed: mode must be canonical or legacy' };
|
|
49
49
|
}
|
|
50
50
|
if (!Array.isArray(value.hosts) || value.hosts.length === 0 || !value.hosts.every(isHost)) {
|
|
51
|
-
return { error: 'install_manifest_malformed: hosts must contain codex and/or
|
|
51
|
+
return { error: 'install_manifest_malformed: hosts must contain codex, openclaw and/or workbuddy' };
|
|
52
52
|
}
|
|
53
53
|
const hosts = [...new Set(value.hosts)];
|
|
54
54
|
const workspaces = parseWorkspaceList(value.workspaces);
|
|
@@ -78,8 +78,21 @@ export function getInstallLayoutPaths(homeDir) {
|
|
|
78
78
|
openClawExtensionDir: path.join(openClawDir, 'extensions', 'principles-disciple'),
|
|
79
79
|
releaseManagerDir: path.join(runtimeDir, 'release-manager'),
|
|
80
80
|
codexAdapterDir: path.join(runtimeDir, 'codex-adapter'),
|
|
81
|
+
workbuddyAdapterDir: path.join(runtimeDir, 'workbuddy-adapter'),
|
|
81
82
|
};
|
|
82
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* WorkBuddy governance workspace (SPEC workbuddy-host-adapter §4.1 OD-07,
|
|
86
|
+
* frozen by Phase 0 probe P06 2026-10-12): an explicit user-level directory
|
|
87
|
+
* under the WorkBuddy config root, shared across projects, never auto-reused
|
|
88
|
+
* from Codex/OpenClaw state. projectDir stays the host cwd; this dir owns
|
|
89
|
+
* governance state (state.db / trajectory). The dir is CREATED only by the
|
|
90
|
+
* explicit setup flow — its absence means "not initialized", never a silent
|
|
91
|
+
* fallback to another host's database.
|
|
92
|
+
*/
|
|
93
|
+
export function getWorkbuddyWorkspaceDir(homeDir) {
|
|
94
|
+
return path.join(path.resolve(homeDir), '.workbuddy', 'pd-workspace');
|
|
95
|
+
}
|
|
83
96
|
export function resolveInstallLayout(options) {
|
|
84
97
|
const paths = getInstallLayoutPaths(options.homeDir);
|
|
85
98
|
const parsed = parseInstallManifest(options.manifest);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/install-layout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build": "tsc",
|
|
25
|
+
"build": "npm run clean && tsc -p tsconfig.build.json && node ../../scripts/build/check-dist-hygiene.mjs",
|
|
26
|
+
"clean": "node ../../scripts/build/clean-dist.mjs",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
26
28
|
"test": "npm run build && vitest run"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
package/dist/index.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/index.test.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import { getInstallLayoutPaths, getConsoleServerEntry, parseInstallManifest, resolveInstallLayout, mergeInstallManifestWorkspaces, } from './index.js';
|
|
4
|
-
describe('install layout', () => {
|
|
5
|
-
it('resolves a canonical Codex-only install without OpenClaw', () => {
|
|
6
|
-
const paths = getInstallLayoutPaths('C:/Users/alice');
|
|
7
|
-
const result = resolveInstallLayout({
|
|
8
|
-
homeDir: 'C:/Users/alice',
|
|
9
|
-
manifest: { layoutVersion: 1, mode: 'canonical', hosts: ['codex'] },
|
|
10
|
-
canonicalRuntimeExists: true,
|
|
11
|
-
legacyExtensionExists: false,
|
|
12
|
-
});
|
|
13
|
-
expect(result.mode).toBe('canonical');
|
|
14
|
-
expect(result.manifest?.hosts).toEqual(['codex']);
|
|
15
|
-
expect(paths.openClawExtensionDir).toContain('.openclaw');
|
|
16
|
-
expect(paths.pluginDir).toContain('plugin');
|
|
17
|
-
expect(paths.installLayoutDir).toContain('install-layout');
|
|
18
|
-
expect(getConsoleServerEntry(result.paths, 'canonical')).toContain('.pd');
|
|
19
|
-
});
|
|
20
|
-
it('falls back to legacy only when the old extension exists', () => {
|
|
21
|
-
const result = resolveInstallLayout({
|
|
22
|
-
homeDir: '/home/alice',
|
|
23
|
-
manifest: undefined,
|
|
24
|
-
canonicalRuntimeExists: false,
|
|
25
|
-
legacyExtensionExists: true,
|
|
26
|
-
});
|
|
27
|
-
expect(result.mode).toBe('legacy');
|
|
28
|
-
expect(result.nextAction).toContain('migrate');
|
|
29
|
-
});
|
|
30
|
-
it('rejects malformed manifests instead of silently treating them as canonical', () => {
|
|
31
|
-
expect(parseInstallManifest({ layoutVersion: 1, mode: 'canonical', hosts: ['wat'] })).toEqual({
|
|
32
|
-
error: 'install_manifest_malformed: hosts must contain codex and/or openclaw',
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
it('accepts a manifest without workspaces (pre-PRI-624 manifests stay valid)', () => {
|
|
36
|
-
const { manifest, error } = parseInstallManifest({ layoutVersion: 1, mode: 'canonical', hosts: ['codex'] });
|
|
37
|
-
expect(error).toBeUndefined();
|
|
38
|
-
expect(manifest?.workspaces).toEqual([]);
|
|
39
|
-
});
|
|
40
|
-
it('parses workspaces as canonical absolute paths, deduped in insertion order', () => {
|
|
41
|
-
const { manifest, error } = parseInstallManifest({
|
|
42
|
-
layoutVersion: 1,
|
|
43
|
-
mode: 'canonical',
|
|
44
|
-
hosts: ['codex'],
|
|
45
|
-
workspaces: ['D:/Code/ws-a', 'D:\\Code\\ws-a', 'C:/work/ws b'],
|
|
46
|
-
});
|
|
47
|
-
expect(error).toBeUndefined();
|
|
48
|
-
expect(manifest?.workspaces?.length).toBe(2);
|
|
49
|
-
expect(manifest?.workspaces?.[0]).toBe(path.resolve('D:/Code/ws-a'));
|
|
50
|
-
expect(manifest?.workspaces).toContain(path.resolve('C:/work/ws b'));
|
|
51
|
-
});
|
|
52
|
-
it('rejects malformed workspace entries loudly', () => {
|
|
53
|
-
expect(parseInstallManifest({ layoutVersion: 1, mode: 'canonical', hosts: ['codex'], workspaces: [''] })).toEqual({
|
|
54
|
-
error: 'install_manifest_malformed: workspaces must be non-empty absolute paths',
|
|
55
|
-
});
|
|
56
|
-
expect(parseInstallManifest({ layoutVersion: 1, mode: 'canonical', hosts: ['codex'], workspaces: ['ws-a'] })).toEqual({
|
|
57
|
-
error: 'install_manifest_malformed: workspaces must be non-empty absolute paths',
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
it('merges a workspace into an existing manifest without duplicates', () => {
|
|
61
|
-
const merged = mergeInstallManifestWorkspaces({ layoutVersion: 1, mode: 'canonical', hosts: ['codex'], workspaces: ['D:/Code/ws-a'] }, 'D:\\Code\\ws-a');
|
|
62
|
-
expect(merged.length).toBe(1);
|
|
63
|
-
expect(merged[0]).toBe(path.resolve('D:/Code/ws-a'));
|
|
64
|
-
});
|
|
65
|
-
it('merge accepts unknown current manifests and starts a fresh list', () => {
|
|
66
|
-
const merged = mergeInstallManifestWorkspaces(undefined, 'D:/Code/ws-b');
|
|
67
|
-
expect(merged).toEqual([path.resolve('D:/Code/ws-b')]);
|
|
68
|
-
});
|
|
69
|
-
});
|