@agimon-ai/doompi 0.0.1-alpha.102 → 0.0.1-alpha.103
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/README.md
CHANGED
|
@@ -51,7 +51,7 @@ releases.
|
|
|
51
51
|
|
|
52
52
|
- Node.js 22.19.0 or newer
|
|
53
53
|
- Release targets: macOS arm64, Linux x64, and Linux arm64
|
|
54
|
-
- Pi 0.
|
|
54
|
+
- Pi 0.99.1 and Pi TUI 0.99.1 for packages that declare them as peer requirements
|
|
55
55
|
|
|
56
56
|
## Try DoomPi without replacing your Pi setup
|
|
57
57
|
|
|
@@ -18,7 +18,11 @@ const MANAGED_KEYS = [
|
|
|
18
18
|
"quietStartup"
|
|
19
19
|
];
|
|
20
20
|
const DPI_MANAGED_SETTINGS = {
|
|
21
|
-
extensions: [
|
|
21
|
+
extensions: [
|
|
22
|
+
"@agimon-ai/doompi",
|
|
23
|
+
"!extensions/**",
|
|
24
|
+
..._agimon_ai_doompi_core_runtimePiSettings.DISABLED_PI_BUILTINS
|
|
25
|
+
],
|
|
22
26
|
themes: ["themes/doom-pi-dark.json"],
|
|
23
27
|
theme: "doom-pi-dark",
|
|
24
28
|
quietStartup: true
|
|
@@ -86,12 +90,16 @@ function resolveDpiManagedSettings(cwd, environment = process.env) {
|
|
|
86
90
|
if (!registration) return DPI_MANAGED_SETTINGS;
|
|
87
91
|
return {
|
|
88
92
|
...DPI_MANAGED_SETTINGS,
|
|
89
|
-
extensions: [
|
|
93
|
+
extensions: [
|
|
94
|
+
registration.package.root,
|
|
95
|
+
"!extensions/**",
|
|
96
|
+
..._agimon_ai_doompi_core_runtimePiSettings.DISABLED_PI_BUILTINS
|
|
97
|
+
]
|
|
90
98
|
};
|
|
91
99
|
} catch {
|
|
92
100
|
return {
|
|
93
101
|
...DPI_MANAGED_SETTINGS,
|
|
94
|
-
extensions: ["!extensions/**"]
|
|
102
|
+
extensions: ["!extensions/**", ..._agimon_ai_doompi_core_runtimePiSettings.DISABLED_PI_BUILTINS]
|
|
95
103
|
};
|
|
96
104
|
}
|
|
97
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dpiSettings.cjs","names":["path","piCliPath","pathToFileURL","findRepositoryRoot","os","readSyncRegistration","piAgentDirectory"],"sources":["../../../../src/builders/cli/dpiSettings.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { piCliPath } from '@agimon-ai/doompi-core/moduleResolution';\nimport { piAgentDirectory } from '@agimon-ai/doompi-core/runtimePiSettings';\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport type { SettingsManager, SettingsManagerCreateOptions } from '@earendil-works/pi-coding-agent';\n\nimport { findRepositoryRoot } from '../../composition/repository';\n\nconst GLOBAL_SCOPE = 'global';\nconst PROJECT_SCOPE = 'project';\nconst MANAGED_KEYS = ['extensions', 'themes', 'theme', 'quietStartup'] as const;\n\nexport interface DpiManagedSettings {\n extensions: string[];\n themes: string[];\n theme: string;\n quietStartup: boolean;\n}\n\nexport const DPI_MANAGED_SETTINGS: DpiManagedSettings = {\n extensions: ['@agimon-ai/doompi', '!extensions/**'],\n themes: ['themes/doom-pi-dark.json'],\n theme: 'doom-pi-dark',\n quietStartup: true,\n};\n\nexport type DpiSettingsScope = typeof GLOBAL_SCOPE | typeof PROJECT_SCOPE;\n\nexport interface DpiSettingsStorageBackend {\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void;\n}\n\ninterface SettingsManagerClass {\n create(this: void, cwd: string, agentDir?: string, options?: SettingsManagerCreateOptions): SettingsManager;\n fromStorage(this: void, storage: DpiSettingsStorageBackend, options?: SettingsManagerCreateOptions): SettingsManager;\n}\n\ninterface FileSettingsStorageConstructor {\n new (cwd: string, agentDir: string): DpiSettingsStorageBackend;\n}\n\nexport interface PiSettingsRuntime {\n FileSettingsStorage: FileSettingsStorageConstructor;\n SettingsManager: SettingsManagerClass;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettings(content: string | undefined): Record<string, unknown> {\n if (content === undefined) return {};\n const parsed: unknown = JSON.parse(content);\n if (!isRecord(parsed)) throw new SyntaxError('Pi settings must contain a JSON object');\n return parsed;\n}\n\nfunction managedView(\n scope: DpiSettingsScope,\n current: string | undefined,\n managedSettings: DpiManagedSettings,\n): string | undefined {\n if (scope === PROJECT_SCOPE && current === undefined) return undefined;\n const settings = parseSettings(current);\n if (scope === GLOBAL_SCOPE) Object.assign(settings, managedSettings);\n else for (const key of MANAGED_KEYS) delete settings[key];\n return JSON.stringify(settings, null, 2);\n}\n\nfunction restorePersistedSettings(current: string | undefined, next: string): string {\n const persisted = parseSettings(current);\n const updated = parseSettings(next);\n for (const key of MANAGED_KEYS) {\n if (Object.hasOwn(persisted, key)) updated[key] = persisted[key];\n else delete updated[key];\n }\n return JSON.stringify(updated, null, 2);\n}\n\n/**\n * Presents DoomPi-owned settings to Pi without allowing that overlay to leak\n * into either the global or project settings file when Pi saves another key.\n */\nexport class DpiSettingsStorage implements DpiSettingsStorageBackend {\n private readonly backend: DpiSettingsStorageBackend;\n private readonly managedSettings: DpiManagedSettings;\n\n constructor(backend: DpiSettingsStorageBackend, managedSettings: DpiManagedSettings = DPI_MANAGED_SETTINGS) {\n this.backend = backend;\n this.managedSettings = managedSettings;\n }\n\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void {\n this.backend.withLock(scope, (current) => {\n const next = callback(managedView(scope, current, this.managedSettings));\n return next === undefined ? undefined : restorePersistedSettings(current, next);\n });\n }\n}\n\nfunction isPiSettingsRuntime(value: unknown): value is PiSettingsRuntime {\n if (!isRecord(value) || typeof value.FileSettingsStorage !== 'function') return false;\n const settingsManager = value.SettingsManager;\n if (typeof settingsManager !== 'function') return false;\n return (\n typeof Reflect.get(settingsManager, 'create') === 'function' &&\n typeof Reflect.get(settingsManager, 'fromStorage') === 'function'\n );\n}\n\n/** Loads Pi's concrete file storage from the same pinned installation as its CLI. */\nexport async function loadPiSettingsRuntime(): Promise<PiSettingsRuntime> {\n const modulePath = path.join(path.dirname(piCliPath()), 'core', 'settings-manager.js');\n const loaded: unknown = await import(pathToFileURL(modulePath).href);\n if (!isPiSettingsRuntime(loaded)) throw new Error(`Unsupported Pi settings runtime: ${modulePath}`);\n return loaded;\n}\n\n/** Selects the package recorded by sync so embedded DPI does not depend on init's global dispatcher. */\nexport function resolveDpiManagedSettings(\n cwd: string,\n environment: NodeJS.ProcessEnv = process.env,\n): DpiManagedSettings {\n try {\n const root = findRepositoryRoot(cwd);\n const homeDirectory = environment.HOME?.trim() || os.homedir();\n const registration = readSyncRegistration(root, homeDirectory);\n if (!registration) return DPI_MANAGED_SETTINGS;\n return {
|
|
1
|
+
{"version":3,"file":"dpiSettings.cjs","names":["DISABLED_PI_BUILTINS","path","piCliPath","pathToFileURL","findRepositoryRoot","os","readSyncRegistration","piAgentDirectory"],"sources":["../../../../src/builders/cli/dpiSettings.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { piCliPath } from '@agimon-ai/doompi-core/moduleResolution';\nimport { DISABLED_PI_BUILTINS, piAgentDirectory } from '@agimon-ai/doompi-core/runtimePiSettings';\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport type { SettingsManager, SettingsManagerCreateOptions } from '@earendil-works/pi-coding-agent';\n\nimport { findRepositoryRoot } from '../../composition/repository';\n\nconst GLOBAL_SCOPE = 'global';\nconst PROJECT_SCOPE = 'project';\nconst MANAGED_KEYS = ['extensions', 'themes', 'theme', 'quietStartup'] as const;\n\nexport interface DpiManagedSettings {\n extensions: string[];\n themes: string[];\n theme: string;\n quietStartup: boolean;\n}\n\nexport const DPI_MANAGED_SETTINGS: DpiManagedSettings = {\n extensions: ['@agimon-ai/doompi', '!extensions/**', ...DISABLED_PI_BUILTINS],\n themes: ['themes/doom-pi-dark.json'],\n theme: 'doom-pi-dark',\n quietStartup: true,\n};\n\nexport type DpiSettingsScope = typeof GLOBAL_SCOPE | typeof PROJECT_SCOPE;\n\nexport interface DpiSettingsStorageBackend {\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void;\n}\n\ninterface SettingsManagerClass {\n create(this: void, cwd: string, agentDir?: string, options?: SettingsManagerCreateOptions): SettingsManager;\n fromStorage(this: void, storage: DpiSettingsStorageBackend, options?: SettingsManagerCreateOptions): SettingsManager;\n}\n\ninterface FileSettingsStorageConstructor {\n new (cwd: string, agentDir: string): DpiSettingsStorageBackend;\n}\n\nexport interface PiSettingsRuntime {\n FileSettingsStorage: FileSettingsStorageConstructor;\n SettingsManager: SettingsManagerClass;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettings(content: string | undefined): Record<string, unknown> {\n if (content === undefined) return {};\n const parsed: unknown = JSON.parse(content);\n if (!isRecord(parsed)) throw new SyntaxError('Pi settings must contain a JSON object');\n return parsed;\n}\n\nfunction managedView(\n scope: DpiSettingsScope,\n current: string | undefined,\n managedSettings: DpiManagedSettings,\n): string | undefined {\n if (scope === PROJECT_SCOPE && current === undefined) return undefined;\n const settings = parseSettings(current);\n if (scope === GLOBAL_SCOPE) Object.assign(settings, managedSettings);\n else for (const key of MANAGED_KEYS) delete settings[key];\n return JSON.stringify(settings, null, 2);\n}\n\nfunction restorePersistedSettings(current: string | undefined, next: string): string {\n const persisted = parseSettings(current);\n const updated = parseSettings(next);\n for (const key of MANAGED_KEYS) {\n if (Object.hasOwn(persisted, key)) updated[key] = persisted[key];\n else delete updated[key];\n }\n return JSON.stringify(updated, null, 2);\n}\n\n/**\n * Presents DoomPi-owned settings to Pi without allowing that overlay to leak\n * into either the global or project settings file when Pi saves another key.\n */\nexport class DpiSettingsStorage implements DpiSettingsStorageBackend {\n private readonly backend: DpiSettingsStorageBackend;\n private readonly managedSettings: DpiManagedSettings;\n\n constructor(backend: DpiSettingsStorageBackend, managedSettings: DpiManagedSettings = DPI_MANAGED_SETTINGS) {\n this.backend = backend;\n this.managedSettings = managedSettings;\n }\n\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void {\n this.backend.withLock(scope, (current) => {\n const next = callback(managedView(scope, current, this.managedSettings));\n return next === undefined ? undefined : restorePersistedSettings(current, next);\n });\n }\n}\n\nfunction isPiSettingsRuntime(value: unknown): value is PiSettingsRuntime {\n if (!isRecord(value) || typeof value.FileSettingsStorage !== 'function') return false;\n const settingsManager = value.SettingsManager;\n if (typeof settingsManager !== 'function') return false;\n return (\n typeof Reflect.get(settingsManager, 'create') === 'function' &&\n typeof Reflect.get(settingsManager, 'fromStorage') === 'function'\n );\n}\n\n/** Loads Pi's concrete file storage from the same pinned installation as its CLI. */\nexport async function loadPiSettingsRuntime(): Promise<PiSettingsRuntime> {\n const modulePath = path.join(path.dirname(piCliPath()), 'core', 'settings-manager.js');\n const loaded: unknown = await import(pathToFileURL(modulePath).href);\n if (!isPiSettingsRuntime(loaded)) throw new Error(`Unsupported Pi settings runtime: ${modulePath}`);\n return loaded;\n}\n\n/** Selects the package recorded by sync so embedded DPI does not depend on init's global dispatcher. */\nexport function resolveDpiManagedSettings(\n cwd: string,\n environment: NodeJS.ProcessEnv = process.env,\n): DpiManagedSettings {\n try {\n const root = findRepositoryRoot(cwd);\n const homeDirectory = environment.HOME?.trim() || os.homedir();\n const registration = readSyncRegistration(root, homeDirectory);\n if (!registration) return DPI_MANAGED_SETTINGS;\n return {\n ...DPI_MANAGED_SETTINGS,\n extensions: [registration.package.root, '!extensions/**', ...DISABLED_PI_BUILTINS],\n };\n } catch {\n return { ...DPI_MANAGED_SETTINGS, extensions: ['!extensions/**', ...DISABLED_PI_BUILTINS] };\n }\n}\n\n/** Installs the process-local create() hook used by upstream Pi startup and reloads. */\nexport function installDpiSettingsOverlay(\n runtime: PiSettingsRuntime,\n environment: NodeJS.ProcessEnv = process.env,\n): () => void {\n const originalCreate = runtime.SettingsManager.create;\n runtime.SettingsManager.create = (cwd, agentDir, options) => {\n const resolvedAgentDirectory = agentDir ?? piAgentDirectory(environment);\n const storage = new runtime.FileSettingsStorage(cwd, resolvedAgentDirectory);\n const managedSettings = resolveDpiManagedSettings(cwd, environment);\n return runtime.SettingsManager.fromStorage(new DpiSettingsStorage(storage, managedSettings), options);\n };\n\n return () => {\n runtime.SettingsManager.create = originalCreate;\n };\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { piCliPath } from "@agimon-ai/doompi-core/moduleResolution";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { piAgentDirectory } from "@agimon-ai/doompi-core/runtimePiSettings";
|
|
6
|
+
import { DISABLED_PI_BUILTINS, piAgentDirectory } from "@agimon-ai/doompi-core/runtimePiSettings";
|
|
7
7
|
import { readSyncRegistration } from "@agimon-ai/doompi-core/syncRegistration";
|
|
8
8
|
//#region src/builders/cli/dpiSettings.ts
|
|
9
9
|
const GLOBAL_SCOPE = "global";
|
|
@@ -15,7 +15,11 @@ const MANAGED_KEYS = [
|
|
|
15
15
|
"quietStartup"
|
|
16
16
|
];
|
|
17
17
|
const DPI_MANAGED_SETTINGS = {
|
|
18
|
-
extensions: [
|
|
18
|
+
extensions: [
|
|
19
|
+
"@agimon-ai/doompi",
|
|
20
|
+
"!extensions/**",
|
|
21
|
+
...DISABLED_PI_BUILTINS
|
|
22
|
+
],
|
|
19
23
|
themes: ["themes/doom-pi-dark.json"],
|
|
20
24
|
theme: "doom-pi-dark",
|
|
21
25
|
quietStartup: true
|
|
@@ -83,12 +87,16 @@ function resolveDpiManagedSettings(cwd, environment = process.env) {
|
|
|
83
87
|
if (!registration) return DPI_MANAGED_SETTINGS;
|
|
84
88
|
return {
|
|
85
89
|
...DPI_MANAGED_SETTINGS,
|
|
86
|
-
extensions: [
|
|
90
|
+
extensions: [
|
|
91
|
+
registration.package.root,
|
|
92
|
+
"!extensions/**",
|
|
93
|
+
...DISABLED_PI_BUILTINS
|
|
94
|
+
]
|
|
87
95
|
};
|
|
88
96
|
} catch {
|
|
89
97
|
return {
|
|
90
98
|
...DPI_MANAGED_SETTINGS,
|
|
91
|
-
extensions: ["!extensions/**"]
|
|
99
|
+
extensions: ["!extensions/**", ...DISABLED_PI_BUILTINS]
|
|
92
100
|
};
|
|
93
101
|
}
|
|
94
102
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dpiSettings.mjs","names":[],"sources":["../../../../src/builders/cli/dpiSettings.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { piCliPath } from '@agimon-ai/doompi-core/moduleResolution';\nimport { piAgentDirectory } from '@agimon-ai/doompi-core/runtimePiSettings';\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport type { SettingsManager, SettingsManagerCreateOptions } from '@earendil-works/pi-coding-agent';\n\nimport { findRepositoryRoot } from '../../composition/repository';\n\nconst GLOBAL_SCOPE = 'global';\nconst PROJECT_SCOPE = 'project';\nconst MANAGED_KEYS = ['extensions', 'themes', 'theme', 'quietStartup'] as const;\n\nexport interface DpiManagedSettings {\n extensions: string[];\n themes: string[];\n theme: string;\n quietStartup: boolean;\n}\n\nexport const DPI_MANAGED_SETTINGS: DpiManagedSettings = {\n extensions: ['@agimon-ai/doompi', '!extensions/**'],\n themes: ['themes/doom-pi-dark.json'],\n theme: 'doom-pi-dark',\n quietStartup: true,\n};\n\nexport type DpiSettingsScope = typeof GLOBAL_SCOPE | typeof PROJECT_SCOPE;\n\nexport interface DpiSettingsStorageBackend {\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void;\n}\n\ninterface SettingsManagerClass {\n create(this: void, cwd: string, agentDir?: string, options?: SettingsManagerCreateOptions): SettingsManager;\n fromStorage(this: void, storage: DpiSettingsStorageBackend, options?: SettingsManagerCreateOptions): SettingsManager;\n}\n\ninterface FileSettingsStorageConstructor {\n new (cwd: string, agentDir: string): DpiSettingsStorageBackend;\n}\n\nexport interface PiSettingsRuntime {\n FileSettingsStorage: FileSettingsStorageConstructor;\n SettingsManager: SettingsManagerClass;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettings(content: string | undefined): Record<string, unknown> {\n if (content === undefined) return {};\n const parsed: unknown = JSON.parse(content);\n if (!isRecord(parsed)) throw new SyntaxError('Pi settings must contain a JSON object');\n return parsed;\n}\n\nfunction managedView(\n scope: DpiSettingsScope,\n current: string | undefined,\n managedSettings: DpiManagedSettings,\n): string | undefined {\n if (scope === PROJECT_SCOPE && current === undefined) return undefined;\n const settings = parseSettings(current);\n if (scope === GLOBAL_SCOPE) Object.assign(settings, managedSettings);\n else for (const key of MANAGED_KEYS) delete settings[key];\n return JSON.stringify(settings, null, 2);\n}\n\nfunction restorePersistedSettings(current: string | undefined, next: string): string {\n const persisted = parseSettings(current);\n const updated = parseSettings(next);\n for (const key of MANAGED_KEYS) {\n if (Object.hasOwn(persisted, key)) updated[key] = persisted[key];\n else delete updated[key];\n }\n return JSON.stringify(updated, null, 2);\n}\n\n/**\n * Presents DoomPi-owned settings to Pi without allowing that overlay to leak\n * into either the global or project settings file when Pi saves another key.\n */\nexport class DpiSettingsStorage implements DpiSettingsStorageBackend {\n private readonly backend: DpiSettingsStorageBackend;\n private readonly managedSettings: DpiManagedSettings;\n\n constructor(backend: DpiSettingsStorageBackend, managedSettings: DpiManagedSettings = DPI_MANAGED_SETTINGS) {\n this.backend = backend;\n this.managedSettings = managedSettings;\n }\n\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void {\n this.backend.withLock(scope, (current) => {\n const next = callback(managedView(scope, current, this.managedSettings));\n return next === undefined ? undefined : restorePersistedSettings(current, next);\n });\n }\n}\n\nfunction isPiSettingsRuntime(value: unknown): value is PiSettingsRuntime {\n if (!isRecord(value) || typeof value.FileSettingsStorage !== 'function') return false;\n const settingsManager = value.SettingsManager;\n if (typeof settingsManager !== 'function') return false;\n return (\n typeof Reflect.get(settingsManager, 'create') === 'function' &&\n typeof Reflect.get(settingsManager, 'fromStorage') === 'function'\n );\n}\n\n/** Loads Pi's concrete file storage from the same pinned installation as its CLI. */\nexport async function loadPiSettingsRuntime(): Promise<PiSettingsRuntime> {\n const modulePath = path.join(path.dirname(piCliPath()), 'core', 'settings-manager.js');\n const loaded: unknown = await import(pathToFileURL(modulePath).href);\n if (!isPiSettingsRuntime(loaded)) throw new Error(`Unsupported Pi settings runtime: ${modulePath}`);\n return loaded;\n}\n\n/** Selects the package recorded by sync so embedded DPI does not depend on init's global dispatcher. */\nexport function resolveDpiManagedSettings(\n cwd: string,\n environment: NodeJS.ProcessEnv = process.env,\n): DpiManagedSettings {\n try {\n const root = findRepositoryRoot(cwd);\n const homeDirectory = environment.HOME?.trim() || os.homedir();\n const registration = readSyncRegistration(root, homeDirectory);\n if (!registration) return DPI_MANAGED_SETTINGS;\n return {
|
|
1
|
+
{"version":3,"file":"dpiSettings.mjs","names":[],"sources":["../../../../src/builders/cli/dpiSettings.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { piCliPath } from '@agimon-ai/doompi-core/moduleResolution';\nimport { DISABLED_PI_BUILTINS, piAgentDirectory } from '@agimon-ai/doompi-core/runtimePiSettings';\nimport { readSyncRegistration } from '@agimon-ai/doompi-core/syncRegistration';\nimport type { SettingsManager, SettingsManagerCreateOptions } from '@earendil-works/pi-coding-agent';\n\nimport { findRepositoryRoot } from '../../composition/repository';\n\nconst GLOBAL_SCOPE = 'global';\nconst PROJECT_SCOPE = 'project';\nconst MANAGED_KEYS = ['extensions', 'themes', 'theme', 'quietStartup'] as const;\n\nexport interface DpiManagedSettings {\n extensions: string[];\n themes: string[];\n theme: string;\n quietStartup: boolean;\n}\n\nexport const DPI_MANAGED_SETTINGS: DpiManagedSettings = {\n extensions: ['@agimon-ai/doompi', '!extensions/**', ...DISABLED_PI_BUILTINS],\n themes: ['themes/doom-pi-dark.json'],\n theme: 'doom-pi-dark',\n quietStartup: true,\n};\n\nexport type DpiSettingsScope = typeof GLOBAL_SCOPE | typeof PROJECT_SCOPE;\n\nexport interface DpiSettingsStorageBackend {\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void;\n}\n\ninterface SettingsManagerClass {\n create(this: void, cwd: string, agentDir?: string, options?: SettingsManagerCreateOptions): SettingsManager;\n fromStorage(this: void, storage: DpiSettingsStorageBackend, options?: SettingsManagerCreateOptions): SettingsManager;\n}\n\ninterface FileSettingsStorageConstructor {\n new (cwd: string, agentDir: string): DpiSettingsStorageBackend;\n}\n\nexport interface PiSettingsRuntime {\n FileSettingsStorage: FileSettingsStorageConstructor;\n SettingsManager: SettingsManagerClass;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettings(content: string | undefined): Record<string, unknown> {\n if (content === undefined) return {};\n const parsed: unknown = JSON.parse(content);\n if (!isRecord(parsed)) throw new SyntaxError('Pi settings must contain a JSON object');\n return parsed;\n}\n\nfunction managedView(\n scope: DpiSettingsScope,\n current: string | undefined,\n managedSettings: DpiManagedSettings,\n): string | undefined {\n if (scope === PROJECT_SCOPE && current === undefined) return undefined;\n const settings = parseSettings(current);\n if (scope === GLOBAL_SCOPE) Object.assign(settings, managedSettings);\n else for (const key of MANAGED_KEYS) delete settings[key];\n return JSON.stringify(settings, null, 2);\n}\n\nfunction restorePersistedSettings(current: string | undefined, next: string): string {\n const persisted = parseSettings(current);\n const updated = parseSettings(next);\n for (const key of MANAGED_KEYS) {\n if (Object.hasOwn(persisted, key)) updated[key] = persisted[key];\n else delete updated[key];\n }\n return JSON.stringify(updated, null, 2);\n}\n\n/**\n * Presents DoomPi-owned settings to Pi without allowing that overlay to leak\n * into either the global or project settings file when Pi saves another key.\n */\nexport class DpiSettingsStorage implements DpiSettingsStorageBackend {\n private readonly backend: DpiSettingsStorageBackend;\n private readonly managedSettings: DpiManagedSettings;\n\n constructor(backend: DpiSettingsStorageBackend, managedSettings: DpiManagedSettings = DPI_MANAGED_SETTINGS) {\n this.backend = backend;\n this.managedSettings = managedSettings;\n }\n\n withLock(scope: DpiSettingsScope, callback: (current: string | undefined) => string | undefined): void {\n this.backend.withLock(scope, (current) => {\n const next = callback(managedView(scope, current, this.managedSettings));\n return next === undefined ? undefined : restorePersistedSettings(current, next);\n });\n }\n}\n\nfunction isPiSettingsRuntime(value: unknown): value is PiSettingsRuntime {\n if (!isRecord(value) || typeof value.FileSettingsStorage !== 'function') return false;\n const settingsManager = value.SettingsManager;\n if (typeof settingsManager !== 'function') return false;\n return (\n typeof Reflect.get(settingsManager, 'create') === 'function' &&\n typeof Reflect.get(settingsManager, 'fromStorage') === 'function'\n );\n}\n\n/** Loads Pi's concrete file storage from the same pinned installation as its CLI. */\nexport async function loadPiSettingsRuntime(): Promise<PiSettingsRuntime> {\n const modulePath = path.join(path.dirname(piCliPath()), 'core', 'settings-manager.js');\n const loaded: unknown = await import(pathToFileURL(modulePath).href);\n if (!isPiSettingsRuntime(loaded)) throw new Error(`Unsupported Pi settings runtime: ${modulePath}`);\n return loaded;\n}\n\n/** Selects the package recorded by sync so embedded DPI does not depend on init's global dispatcher. */\nexport function resolveDpiManagedSettings(\n cwd: string,\n environment: NodeJS.ProcessEnv = process.env,\n): DpiManagedSettings {\n try {\n const root = findRepositoryRoot(cwd);\n const homeDirectory = environment.HOME?.trim() || os.homedir();\n const registration = readSyncRegistration(root, homeDirectory);\n if (!registration) return DPI_MANAGED_SETTINGS;\n return {\n ...DPI_MANAGED_SETTINGS,\n extensions: [registration.package.root, '!extensions/**', ...DISABLED_PI_BUILTINS],\n };\n } catch {\n return { ...DPI_MANAGED_SETTINGS, extensions: ['!extensions/**', ...DISABLED_PI_BUILTINS] };\n }\n}\n\n/** Installs the process-local create() hook used by upstream Pi startup and reloads. */\nexport function installDpiSettingsOverlay(\n runtime: PiSettingsRuntime,\n environment: NodeJS.ProcessEnv = process.env,\n): () => void {\n const originalCreate = runtime.SettingsManager.create;\n runtime.SettingsManager.create = (cwd, agentDir, options) => {\n const resolvedAgentDirectory = agentDir ?? piAgentDirectory(environment);\n const storage = new runtime.FileSettingsStorage(cwd, resolvedAgentDirectory);\n const managedSettings = resolveDpiManagedSettings(cwd, environment);\n return runtime.SettingsManager.fromStorage(new DpiSettingsStorage(storage, managedSettings), options);\n };\n\n return () => {\n runtime.SettingsManager.create = originalCreate;\n };\n}\n"],"mappings":";;;;;;;;AAWA,MAAM,eAAe;AACrB,MAAM,gBAAgB;AACtB,MAAM,eAAe;CAAC;CAAc;CAAU;CAAS;AAAc;AASrE,MAAa,uBAA2C;CACtD,YAAY;EAAC;EAAqB;EAAkB,GAAG;CAAoB;CAC3E,QAAQ,CAAC,0BAA0B;CACnC,OAAO;CACP,cAAc;AAChB;AAsBA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,cAAc,SAAsD;CAC3E,IAAI,YAAY,KAAA,GAAW,OAAO,CAAC;CACnC,MAAM,SAAkB,KAAK,MAAM,OAAO;CAC1C,IAAI,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,YAAY,wCAAwC;CACrF,OAAO;AACT;AAEA,SAAS,YACP,OACA,SACA,iBACoB;CACpB,IAAI,UAAU,iBAAiB,YAAY,KAAA,GAAW,OAAO,KAAA;CAC7D,MAAM,WAAW,cAAc,OAAO;CACtC,IAAI,UAAU,cAAc,OAAO,OAAO,UAAU,eAAe;MAC9D,KAAK,MAAM,OAAO,cAAc,OAAO,SAAS;CACrD,OAAO,KAAK,UAAU,UAAU,MAAM,CAAC;AACzC;AAEA,SAAS,yBAAyB,SAA6B,MAAsB;CACnF,MAAM,YAAY,cAAc,OAAO;CACvC,MAAM,UAAU,cAAc,IAAI;CAClC,KAAK,MAAM,OAAO,cAChB,IAAI,OAAO,OAAO,WAAW,GAAG,GAAG,QAAQ,OAAO,UAAU;MACvD,OAAO,QAAQ;CAEtB,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC;AACxC;;;;;AAMA,IAAa,qBAAb,MAAqE;CACnE;CACA;CAEA,YAAY,SAAoC,kBAAsC,sBAAsB;EAC1G,KAAK,UAAU;EACf,KAAK,kBAAkB;CACzB;CAEA,SAAS,OAAyB,UAAqE;EACrG,KAAK,QAAQ,SAAS,QAAQ,YAAY;GACxC,MAAM,OAAO,SAAS,YAAY,OAAO,SAAS,KAAK,eAAe,CAAC;GACvE,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,yBAAyB,SAAS,IAAI;EAChF,CAAC;CACH;AACF;AAEA,SAAS,oBAAoB,OAA4C;CACvE,IAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,wBAAwB,YAAY,OAAO;CAChF,MAAM,kBAAkB,MAAM;CAC9B,IAAI,OAAO,oBAAoB,YAAY,OAAO;CAClD,OACE,OAAO,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,cAClD,OAAO,QAAQ,IAAI,iBAAiB,aAAa,MAAM;AAE3D;;AAGA,eAAsB,wBAAoD;CACxE,MAAM,aAAa,KAAK,KAAK,KAAK,QAAQ,UAAU,CAAC,GAAG,QAAQ,qBAAqB;CACrF,MAAM,SAAkB,MAAM,OAAO,cAAc,UAAU,CAAC,CAAC;CAC/D,IAAI,CAAC,oBAAoB,MAAM,GAAG,MAAM,IAAI,MAAM,oCAAoC,YAAY;CAClG,OAAO;AACT;;AAGA,SAAgB,0BACd,KACA,cAAiC,QAAQ,KACrB;CACpB,IAAI;EACF,MAAM,OAAO,mBAAmB,GAAG;EACnC,MAAM,gBAAgB,YAAY,MAAM,KAAK,KAAK,GAAG,QAAQ;EAC7D,MAAM,eAAe,qBAAqB,MAAM,aAAa;EAC7D,IAAI,CAAC,cAAc,OAAO;EAC1B,OAAO;GACL,GAAG;GACH,YAAY;IAAC,aAAa,QAAQ;IAAM;IAAkB,GAAG;GAAoB;EACnF;CACF,QAAQ;EACN,OAAO;GAAE,GAAG;GAAsB,YAAY,CAAC,kBAAkB,GAAG,oBAAoB;EAAE;CAC5F;AACF;;AAGA,SAAgB,0BACd,SACA,cAAiC,QAAQ,KAC7B;CACZ,MAAM,iBAAiB,QAAQ,gBAAgB;CAC/C,QAAQ,gBAAgB,UAAU,KAAK,UAAU,YAAY;EAC3D,MAAM,yBAAyB,YAAY,iBAAiB,WAAW;EACvE,MAAM,UAAU,IAAI,QAAQ,oBAAoB,KAAK,sBAAsB;EAC3E,MAAM,kBAAkB,0BAA0B,KAAK,WAAW;EAClE,OAAO,QAAQ,gBAAgB,YAAY,IAAI,mBAAmB,SAAS,eAAe,GAAG,OAAO;CACtG;CAEA,aAAa;EACX,QAAQ,gBAAgB,SAAS;CACnC;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.103",
|
|
4
4
|
"description": "Opinionated, composable Pi distribution for scoped agent tools, skills, MCP servers, and developer workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -277,29 +277,29 @@
|
|
|
277
277
|
"registry": "https://registry.npmjs.org/"
|
|
278
278
|
},
|
|
279
279
|
"dependencies": {
|
|
280
|
-
"@agimon-ai/doompi-autostop": "0.0.1-alpha.
|
|
281
|
-
"@agimon-ai/doompi-cache": "0.0.1-alpha.
|
|
282
|
-
"@agimon-ai/doompi-config": "0.0.1-alpha.
|
|
283
|
-
"@agimon-ai/doompi-core": "0.0.1-alpha.
|
|
284
|
-
"@agimon-ai/doompi-domain": "0.0.1-alpha.
|
|
285
|
-
"@agimon-ai/doompi-major-mode": "0.0.1-alpha.
|
|
286
|
-
"@agimon-ai/doompi-minor-mode": "0.0.1-alpha.
|
|
287
|
-
"@agimon-ai/doompi-notification": "0.0.1-alpha.
|
|
288
|
-
"@agimon-ai/doompi-profile": "0.0.1-alpha.
|
|
289
|
-
"@agimon-ai/doompi-session": "0.0.1-alpha.
|
|
290
|
-
"@agimon-ai/doompi-skill": "0.0.1-alpha.
|
|
291
|
-
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.
|
|
292
|
-
"@agimon-ai/doompi-ui": "0.0.1-alpha.
|
|
293
|
-
"@agimon-ai/doompi-web-components": "0.0.1-alpha.
|
|
294
|
-
"@agimon-ai/doompi-web-security": "0.0.1-alpha.
|
|
280
|
+
"@agimon-ai/doompi-autostop": "0.0.1-alpha.76",
|
|
281
|
+
"@agimon-ai/doompi-cache": "0.0.1-alpha.65",
|
|
282
|
+
"@agimon-ai/doompi-config": "0.0.1-alpha.98",
|
|
283
|
+
"@agimon-ai/doompi-core": "0.0.1-alpha.99",
|
|
284
|
+
"@agimon-ai/doompi-domain": "0.0.1-alpha.77",
|
|
285
|
+
"@agimon-ai/doompi-major-mode": "0.0.1-alpha.77",
|
|
286
|
+
"@agimon-ai/doompi-minor-mode": "0.0.1-alpha.99",
|
|
287
|
+
"@agimon-ai/doompi-notification": "0.0.1-alpha.76",
|
|
288
|
+
"@agimon-ai/doompi-profile": "0.0.1-alpha.77",
|
|
289
|
+
"@agimon-ai/doompi-session": "0.0.1-alpha.23",
|
|
290
|
+
"@agimon-ai/doompi-skill": "0.0.1-alpha.77",
|
|
291
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.89",
|
|
292
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.99",
|
|
293
|
+
"@agimon-ai/doompi-web-components": "0.0.1-alpha.57",
|
|
294
|
+
"@agimon-ai/doompi-web-security": "0.0.1-alpha.52",
|
|
295
295
|
"@agimon-ai/log-sink-mcp": "0.29.35",
|
|
296
296
|
"@deepseek-ai/cordis": "4.0.2",
|
|
297
|
-
"@earendil-works/chord": "0.
|
|
298
|
-
"@earendil-works/pi-agent-core": "0.
|
|
299
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
300
|
-
"@earendil-works/pi-protocol": "0.
|
|
301
|
-
"@earendil-works/pi-server": "0.
|
|
302
|
-
"@earendil-works/pi-session-backend-sqlite-node": "0.
|
|
297
|
+
"@earendil-works/chord": "0.99.1",
|
|
298
|
+
"@earendil-works/pi-agent-core": "0.99.1",
|
|
299
|
+
"@earendil-works/pi-coding-agent": "0.99.1",
|
|
300
|
+
"@earendil-works/pi-protocol": "0.99.1",
|
|
301
|
+
"@earendil-works/pi-server": "0.99.1",
|
|
302
|
+
"@earendil-works/pi-session-backend-sqlite-node": "0.99.1",
|
|
303
303
|
"@hono/node-server": "2.1.1",
|
|
304
304
|
"@simplewebauthn/server": "^14.0.2",
|
|
305
305
|
"@tailwindcss/vite": "4.3.3",
|
|
@@ -317,11 +317,11 @@
|
|
|
317
317
|
"yaml": "2.9.1"
|
|
318
318
|
},
|
|
319
319
|
"devDependencies": {
|
|
320
|
-
"@agimon-ai/doompi-runner": "0.0.1-alpha.
|
|
321
|
-
"@agimon-ai/vibe-lint-plugin-doom-cli": "0.0.1-alpha.
|
|
322
|
-
"@earendil-works/pi-ai": "0.
|
|
323
|
-
"@earendil-works/pi-client": "0.
|
|
324
|
-
"@earendil-works/pi-tui": "0.
|
|
320
|
+
"@agimon-ai/doompi-runner": "0.0.1-alpha.100",
|
|
321
|
+
"@agimon-ai/vibe-lint-plugin-doom-cli": "0.0.1-alpha.24",
|
|
322
|
+
"@earendil-works/pi-ai": "0.99.1",
|
|
323
|
+
"@earendil-works/pi-client": "0.99.1",
|
|
324
|
+
"@earendil-works/pi-tui": "0.99.1",
|
|
325
325
|
"@modelcontextprotocol/ext-apps": "2.0.0",
|
|
326
326
|
"@modelcontextprotocol/server": "2.1.0",
|
|
327
327
|
"@playwright/test": "1.63.0",
|
|
@@ -334,7 +334,7 @@
|
|
|
334
334
|
"vitest": "5.0.1"
|
|
335
335
|
},
|
|
336
336
|
"peerDependencies": {
|
|
337
|
-
"@earendil-works/pi-tui": "0.
|
|
337
|
+
"@earendil-works/pi-tui": "0.99.1"
|
|
338
338
|
},
|
|
339
339
|
"peerDependenciesMeta": {
|
|
340
340
|
"@earendil-works/pi-tui": {
|