@ai-outfitter/outfitter 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/LICENSE.md +58 -0
- package/README.md +256 -0
- package/dist/agents/AdapterProfileControls.d.ts +20 -0
- package/dist/agents/AdapterProfileControls.js +63 -0
- package/dist/agents/AdapterProfileControls.js.map +1 -0
- package/dist/agents/AdapterStatePaths.d.ts +12 -0
- package/dist/agents/AdapterStatePaths.js +44 -0
- package/dist/agents/AdapterStatePaths.js.map +1 -0
- package/dist/agents/AgentAdapter.d.ts +32 -0
- package/dist/agents/AgentAdapter.js +2 -0
- package/dist/agents/AgentAdapter.js.map +1 -0
- package/dist/agents/AgentRegistry.d.ts +6 -0
- package/dist/agents/AgentRegistry.js +17 -0
- package/dist/agents/AgentRegistry.js.map +1 -0
- package/dist/agents/LaunchResources.d.ts +13 -0
- package/dist/agents/LaunchResources.js +35 -0
- package/dist/agents/LaunchResources.js.map +1 -0
- package/dist/agents/ResourceIdentity.d.ts +2 -0
- package/dist/agents/ResourceIdentity.js +51 -0
- package/dist/agents/ResourceIdentity.js.map +1 -0
- package/dist/agents/claude/ClaudeAdapter.d.ts +2 -0
- package/dist/agents/claude/ClaudeAdapter.js +117 -0
- package/dist/agents/claude/ClaudeAdapter.js.map +1 -0
- package/dist/agents/claude/ClaudeCompositeProfileWriter.d.ts +5 -0
- package/dist/agents/claude/ClaudeCompositeProfileWriter.js +7 -0
- package/dist/agents/claude/ClaudeCompositeProfileWriter.js.map +1 -0
- package/dist/agents/pi/PiAdapter.d.ts +2 -0
- package/dist/agents/pi/PiAdapter.js +229 -0
- package/dist/agents/pi/PiAdapter.js.map +1 -0
- package/dist/agents/pi/PiCompositeProfileWriter.d.ts +5 -0
- package/dist/agents/pi/PiCompositeProfileWriter.js +7 -0
- package/dist/agents/pi/PiCompositeProfileWriter.js.map +1 -0
- package/dist/agents/pi/PiMcpConfig.d.ts +2 -0
- package/dist/agents/pi/PiMcpConfig.js +114 -0
- package/dist/agents/pi/PiMcpConfig.js.map +1 -0
- package/dist/agents/pi/PiSettingsMergePolicy.d.ts +17 -0
- package/dist/agents/pi/PiSettingsMergePolicy.js +59 -0
- package/dist/agents/pi/PiSettingsMergePolicy.js.map +1 -0
- package/dist/cli/OutfitterCli.d.ts +4 -0
- package/dist/cli/OutfitterCli.js +32 -0
- package/dist/cli/OutfitterCli.js.map +1 -0
- package/dist/cli/commands/CommandObject.d.ts +11 -0
- package/dist/cli/commands/CommandObject.js +5 -0
- package/dist/cli/commands/CommandObject.js.map +1 -0
- package/dist/cli/commands/FirstRunWelcomeProfile.d.ts +11 -0
- package/dist/cli/commands/FirstRunWelcomeProfile.js +107 -0
- package/dist/cli/commands/FirstRunWelcomeProfile.js.map +1 -0
- package/dist/cli/commands/PiLoginLaunch.d.ts +10 -0
- package/dist/cli/commands/PiLoginLaunch.js +76 -0
- package/dist/cli/commands/PiLoginLaunch.js.map +1 -0
- package/dist/cli/commands/RunCommand.d.ts +30 -0
- package/dist/cli/commands/RunCommand.js +299 -0
- package/dist/cli/commands/RunCommand.js.map +1 -0
- package/dist/cli/commands/SetupCommand.d.ts +34 -0
- package/dist/cli/commands/SetupCommand.js +379 -0
- package/dist/cli/commands/SetupCommand.js.map +1 -0
- package/dist/cli/commands/SyncCommand.d.ts +28 -0
- package/dist/cli/commands/SyncCommand.js +178 -0
- package/dist/cli/commands/SyncCommand.js.map +1 -0
- package/dist/cli/commands/WelcomeCommand.d.ts +54 -0
- package/dist/cli/commands/WelcomeCommand.js +214 -0
- package/dist/cli/commands/WelcomeCommand.js.map +1 -0
- package/dist/cli/commands/profile/Command.d.ts +6 -0
- package/dist/cli/commands/profile/Command.js +21 -0
- package/dist/cli/commands/profile/Command.js.map +1 -0
- package/dist/cli/commands/profile/CreateCommand.d.ts +19 -0
- package/dist/cli/commands/profile/CreateCommand.js +115 -0
- package/dist/cli/commands/profile/CreateCommand.js.map +1 -0
- package/dist/cli/commands/profile/ListCommand.d.ts +17 -0
- package/dist/cli/commands/profile/ListCommand.js +85 -0
- package/dist/cli/commands/profile/ListCommand.js.map +1 -0
- package/dist/cli/commands/profile/Shared.d.ts +9 -0
- package/dist/cli/commands/profile/Shared.js +10 -0
- package/dist/cli/commands/profile/Shared.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +22 -0
- package/dist/cli.js.map +1 -0
- package/dist/compositeProfile/CompositeProfile.d.ts +8 -0
- package/dist/compositeProfile/CompositeProfile.js +6 -0
- package/dist/compositeProfile/CompositeProfile.js.map +1 -0
- package/dist/compositeProfile/CompositeProfileAssembler.d.ts +12 -0
- package/dist/compositeProfile/CompositeProfileAssembler.js +32 -0
- package/dist/compositeProfile/CompositeProfileAssembler.js.map +1 -0
- package/dist/compositeProfile/CompositeProfileFile.d.ts +16 -0
- package/dist/compositeProfile/CompositeProfileFile.js +16 -0
- package/dist/compositeProfile/CompositeProfileFile.js.map +1 -0
- package/dist/compositeProfile/CompositeProfileTemplate.d.ts +15 -0
- package/dist/compositeProfile/CompositeProfileTemplate.js +65 -0
- package/dist/compositeProfile/CompositeProfileTemplate.js.map +1 -0
- package/dist/compositeProfile/CompositeProfileWatcher.d.ts +18 -0
- package/dist/compositeProfile/CompositeProfileWatcher.js +46 -0
- package/dist/compositeProfile/CompositeProfileWatcher.js.map +1 -0
- package/dist/compositeProfile/StatePersistence.d.ts +24 -0
- package/dist/compositeProfile/StatePersistence.js +224 -0
- package/dist/compositeProfile/StatePersistence.js.map +1 -0
- package/dist/merge/ArrayMergePolicy.d.ts +8 -0
- package/dist/merge/ArrayMergePolicy.js +45 -0
- package/dist/merge/ArrayMergePolicy.js.map +1 -0
- package/dist/merge/SettingsValueMerger.d.ts +11 -0
- package/dist/merge/SettingsValueMerger.js +34 -0
- package/dist/merge/SettingsValueMerger.js.map +1 -0
- package/dist/profiles/Profile.d.ts +32 -0
- package/dist/profiles/Profile.js +7 -0
- package/dist/profiles/Profile.js.map +1 -0
- package/dist/profiles/ProfileCache.d.ts +8 -0
- package/dist/profiles/ProfileCache.js +36 -0
- package/dist/profiles/ProfileCache.js.map +1 -0
- package/dist/profiles/ProfileLoader.d.ts +24 -0
- package/dist/profiles/ProfileLoader.js +169 -0
- package/dist/profiles/ProfileLoader.js.map +1 -0
- package/dist/profiles/ProfileMerger.d.ts +20 -0
- package/dist/profiles/ProfileMerger.js +97 -0
- package/dist/profiles/ProfileMerger.js.map +1 -0
- package/dist/profiles/ProfileSource.d.ts +35 -0
- package/dist/profiles/ProfileSource.js +13 -0
- package/dist/profiles/ProfileSource.js.map +1 -0
- package/dist/schemas/profile-source.schema.json +29 -0
- package/dist/schemas/profile.schema.json +115 -0
- package/dist/schemas/settings.schema.json +37 -0
- package/dist/settings/Settings.d.ts +17 -0
- package/dist/settings/Settings.js +5 -0
- package/dist/settings/Settings.js.map +1 -0
- package/dist/settings/SettingsLoader.d.ts +33 -0
- package/dist/settings/SettingsLoader.js +129 -0
- package/dist/settings/SettingsLoader.js.map +1 -0
- package/dist/settings/SettingsMerger.d.ts +2 -0
- package/dist/settings/SettingsMerger.js +31 -0
- package/dist/settings/SettingsMerger.js.map +1 -0
- package/dist/validation/SchemaValidator.d.ts +11 -0
- package/dist/validation/SchemaValidator.js +36 -0
- package/dist/validation/SchemaValidator.js.map +1 -0
- package/dist/validation/YamlDocument.d.ts +13 -0
- package/dist/validation/YamlDocument.js +11 -0
- package/dist/validation/YamlDocument.js.map +1 -0
- package/doc/.deepreview +30 -0
- package/doc/architecture.md +834 -0
- package/doc/controllable-elements.md +162 -0
- package/doc/file_structure.md +133 -0
- package/doc/integration_test_system.md +214 -0
- package/doc/specs/validating_requirements_with_rules.md +55 -0
- package/doc/state_writeback_strategy.md +334 -0
- package/package.json +73 -0
- package/requirements/OFTR-001-project-foundation.md +53 -0
- package/requirements/OFTR-002-settings.md +65 -0
- package/requirements/OFTR-003-profiles.md +51 -0
- package/requirements/OFTR-004-sync-and-setup.md +57 -0
- package/requirements/OFTR-005-run-and-composite-profile.md +60 -0
- package/requirements/OFTR-006-agent-adapters.md +64 -0
- package/requirements/OFTR-007-controllable-elements.md +32 -0
- package/requirements/OFTR-008-requirements-governance.md +42 -0
- package/requirements/OFTR-009-release-publishing.md +25 -0
- package/requirements/OFTR-010-onboarding-welcome.md +38 -0
- package/src/schemas/SchemaDocument.ts +20 -0
- package/src/schemas/profile-source.schema.json +29 -0
- package/src/schemas/profile.schema.json +115 -0
- package/src/schemas/settings.schema.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeProfile.js","sourceRoot":"","sources":["../../src/compositeProfile/CompositeProfile.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,aAAqB,EACrB,KAAsC,EACtC,aAAmD,EAAE,EACnC,EAAE,CAAC,CAAC;IACtB,aAAa;IACb,KAAK;IACL,UAAU;CACX,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CompositeProfile } from './CompositeProfile.js';
|
|
2
|
+
import type { CompositeProfileFile } from './CompositeProfileFile.js';
|
|
3
|
+
export interface CompositeProfileAssemblyInput {
|
|
4
|
+
readonly rootDirectory?: string;
|
|
5
|
+
readonly files: readonly CompositeProfileFile[];
|
|
6
|
+
}
|
|
7
|
+
export interface CompositeProfileWriteOptions {
|
|
8
|
+
readonly materializeStatePaths?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const createCompositeProfileRootDirectory: (profileId: string, agentId: string) => string;
|
|
11
|
+
export declare const assembleCompositeProfile: (input: CompositeProfileAssemblyInput) => CompositeProfile;
|
|
12
|
+
export declare const writeCompositeProfile: (compositeProfile: CompositeProfile, options?: CompositeProfileWriteOptions) => void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Provides composite profile assembly and disk writing for generated logical files.
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
5
|
+
import { createCompositeProfile } from './CompositeProfile.js';
|
|
6
|
+
import { materializeCompositeProfileStatePath } from './StatePersistence.js';
|
|
7
|
+
export const createCompositeProfileRootDirectory = (profileId, agentId) => mkdtempSync(join(tmpdir(), `outfitter-${profileId}-${agentId}-`));
|
|
8
|
+
export const assembleCompositeProfile = (input) => createCompositeProfile(input.rootDirectory ?? createCompositeProfileRootDirectory('profile', 'agent'), input.files);
|
|
9
|
+
export const writeCompositeProfile = (compositeProfile, options = {}) => {
|
|
10
|
+
mkdirSync(compositeProfile.rootDirectory, { recursive: true });
|
|
11
|
+
for (const file of compositeProfile.files) {
|
|
12
|
+
const outputPath = resolveCompositeProfileFileOutputPath(compositeProfile.rootDirectory, file.outputPath);
|
|
13
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
14
|
+
writeFileSync(outputPath, file.content);
|
|
15
|
+
}
|
|
16
|
+
if (options.materializeStatePaths === false) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const statePath of compositeProfile.statePaths.filter((statePath) => statePath.relativePath !== 'unknown')) {
|
|
20
|
+
materializeCompositeProfileStatePath(compositeProfile.rootDirectory, statePath);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const resolveCompositeProfileFileOutputPath = (rootDirectory, outputPath) => {
|
|
24
|
+
const resolvedRootDirectory = resolve(rootDirectory);
|
|
25
|
+
const resolvedOutputPath = isAbsolute(outputPath) ? resolve(outputPath) : resolve(rootDirectory, outputPath);
|
|
26
|
+
const relativeOutputPath = relative(resolvedRootDirectory, resolvedOutputPath);
|
|
27
|
+
if (relativeOutputPath.startsWith('..') || isAbsolute(relativeOutputPath)) {
|
|
28
|
+
throw new Error(`CompositeProfile file output path '${outputPath}' must stay under compositeProfile root '${rootDirectory}'.`);
|
|
29
|
+
}
|
|
30
|
+
return resolvedOutputPath;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=CompositeProfileAssembler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeProfileAssembler.js","sourceRoot":"","sources":["../../src/compositeProfile/CompositeProfileAssembler.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oCAAoC,EAAE,MAAM,uBAAuB,CAAC;AAY7E,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,SAAiB,EAAE,OAAe,EAAU,EAAE,CAChG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;AAEpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAoC,EAAoB,EAAE,CACjG,sBAAsB,CAAC,KAAK,CAAC,aAAa,IAAI,mCAAmC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AAEtH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,gBAAkC,EAClC,UAAwC,EAAE,EACpC,EAAE;IACR,SAAS,CAAC,gBAAgB,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,qCAAqC,CAAC,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1G,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,OAAO,CAAC,qBAAqB,KAAK,KAAK,EAAE,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,EAAE,CAAC;QAChH,oCAAoC,CAAC,gBAAgB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAClF,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,qCAAqC,GAAG,CAAC,aAAqB,EAAE,UAAkB,EAAU,EAAE;IAClG,MAAM,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACrD,MAAM,kBAAkB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAC7G,MAAM,kBAAkB,GAAG,QAAQ,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAAC;IAE/E,IAAI,kBAAkB,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CACb,sCAAsC,UAAU,4CAA4C,aAAa,IAAI,CAC9G,CAAC;IACJ,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type CompositeProfileFileStrategy = 'copy' | 'merge' | 'transform' | 'generate';
|
|
2
|
+
export interface CompositeProfileFile {
|
|
3
|
+
readonly relativePath: string;
|
|
4
|
+
readonly content: string;
|
|
5
|
+
readonly sourceInputs: readonly string[];
|
|
6
|
+
readonly outputPath: string;
|
|
7
|
+
readonly strategy: CompositeProfileFileStrategy;
|
|
8
|
+
}
|
|
9
|
+
export interface CompositeProfileFileInput {
|
|
10
|
+
readonly relativePath: string;
|
|
11
|
+
readonly content: string;
|
|
12
|
+
readonly rootDirectory?: string;
|
|
13
|
+
readonly sourceInputs?: readonly string[];
|
|
14
|
+
readonly strategy?: CompositeProfileFileStrategy;
|
|
15
|
+
}
|
|
16
|
+
export declare const createCompositeProfileFile: (input: CompositeProfileFileInput | string, content?: string) => CompositeProfileFile;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Defines a logical file generated into a temporary Outfitter compositeProfile directory.
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export const createCompositeProfileFile = (input, content) => {
|
|
4
|
+
if (typeof input === 'string') {
|
|
5
|
+
return createCompositeProfileFileFromInput({ relativePath: input, content: content ?? '' });
|
|
6
|
+
}
|
|
7
|
+
return createCompositeProfileFileFromInput(input);
|
|
8
|
+
};
|
|
9
|
+
const createCompositeProfileFileFromInput = (input) => ({
|
|
10
|
+
relativePath: input.relativePath,
|
|
11
|
+
content: input.content,
|
|
12
|
+
sourceInputs: input.sourceInputs ?? [],
|
|
13
|
+
outputPath: input.rootDirectory === undefined ? input.relativePath : join(input.rootDirectory, input.relativePath),
|
|
14
|
+
strategy: input.strategy ?? 'generate',
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=CompositeProfileFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeProfileFile.js","sourceRoot":"","sources":["../../src/compositeProfile/CompositeProfileFile.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoBjC,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,KAAyC,EACzC,OAAgB,EACM,EAAE;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,mCAAmC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,OAAO,mCAAmC,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,mCAAmC,GAAG,CAAC,KAAgC,EAAwB,EAAE,CAAC,CAAC;IACvG,YAAY,EAAE,KAAK,CAAC,YAAY;IAChC,OAAO,EAAE,KAAK,CAAC,OAAO;IACtB,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;IACtC,UAAU,EAAE,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC;IAClH,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,UAAU;CACvC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Profile } from '../profiles/Profile.js';
|
|
2
|
+
import type { Settings } from '../settings/Settings.js';
|
|
3
|
+
import type { CompositeProfile } from './CompositeProfile.js';
|
|
4
|
+
export interface CompositeProfileTemplateContextInput {
|
|
5
|
+
readonly settings: Settings;
|
|
6
|
+
readonly profile: Profile;
|
|
7
|
+
readonly agentId: string;
|
|
8
|
+
readonly projectDirectory: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CompositeProfileTemplateRenderInput extends CompositeProfileTemplateContextInput {
|
|
11
|
+
readonly compositeProfile: CompositeProfile;
|
|
12
|
+
readonly settingsPaths: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export declare const createCompositeProfileTemplateContext: (input: CompositeProfileTemplateContextInput) => Readonly<Record<string, unknown>>;
|
|
15
|
+
export declare const renderCompositeProfileTemplates: (input: CompositeProfileTemplateRenderInput) => CompositeProfile;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Renders Outfitter-time templates in generated compositeProfile files.
|
|
2
|
+
import { Liquid } from 'liquidjs';
|
|
3
|
+
import { createCompositeProfile } from './CompositeProfile.js';
|
|
4
|
+
const outfitterTemplateEngine = new Liquid({
|
|
5
|
+
outputDelimiterLeft: '[[=',
|
|
6
|
+
outputDelimiterRight: ']]',
|
|
7
|
+
tagDelimiterLeft: '[[%',
|
|
8
|
+
tagDelimiterRight: '%]]',
|
|
9
|
+
strictFilters: true,
|
|
10
|
+
strictVariables: true,
|
|
11
|
+
lenientIf: true,
|
|
12
|
+
ownPropertyOnly: true,
|
|
13
|
+
jekyllInclude: false,
|
|
14
|
+
dynamicPartials: false,
|
|
15
|
+
});
|
|
16
|
+
export const createCompositeProfileTemplateContext = (input) => ({
|
|
17
|
+
outfitter: {
|
|
18
|
+
custom_settings: input.settings.customSettings ?? {},
|
|
19
|
+
settings: createTemplateSettings(input.settings),
|
|
20
|
+
profile: input.profile,
|
|
21
|
+
agent: input.agentId,
|
|
22
|
+
project: {
|
|
23
|
+
root: input.projectDirectory,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
export const renderCompositeProfileTemplates = (input) => {
|
|
28
|
+
const context = createCompositeProfileTemplateContext(input);
|
|
29
|
+
return createCompositeProfile(input.compositeProfile.rootDirectory, input.compositeProfile.files.map((file) => renderCompositeProfileFile(file, context, input.settingsPaths)), input.compositeProfile.statePaths);
|
|
30
|
+
};
|
|
31
|
+
const renderCompositeProfileFile = (file, context, settingsPaths) => {
|
|
32
|
+
if (!containsOutfitterTemplate(file.content)) {
|
|
33
|
+
return file;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return {
|
|
37
|
+
...file,
|
|
38
|
+
content: renderTemplateContent(file.content, context),
|
|
39
|
+
sourceInputs: [...file.sourceInputs, ...settingsPaths.filter((path) => !file.sourceInputs.includes(path))],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new Error(`Cannot render Outfitter template in compositeProfile file '${file.relativePath}': ${formatTemplateError(error)}`, {
|
|
44
|
+
cause: error,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const renderTemplateContent = (content, context) => {
|
|
49
|
+
const renderedContent = outfitterTemplateEngine.parseAndRenderSync(content, context);
|
|
50
|
+
/* v8 ignore next -- LiquidJS renders string content to strings; this guards future API regressions. */
|
|
51
|
+
if (typeof renderedContent !== 'string') {
|
|
52
|
+
throw new Error('LiquidJS returned non-string template output.');
|
|
53
|
+
}
|
|
54
|
+
return renderedContent;
|
|
55
|
+
};
|
|
56
|
+
const containsOutfitterTemplate = (content) => content.includes('[[=') || content.includes('[[%');
|
|
57
|
+
const createTemplateSettings = (settings) => ({
|
|
58
|
+
default_profile: settings.defaultProfile,
|
|
59
|
+
profile_sources: settings.profileSources,
|
|
60
|
+
remote_settings: settings.remoteSettings,
|
|
61
|
+
cache_directory: settings.cacheDirectory,
|
|
62
|
+
custom_settings: settings.customSettings ?? {},
|
|
63
|
+
});
|
|
64
|
+
const formatTemplateError = (error) => String(error);
|
|
65
|
+
//# sourceMappingURL=CompositeProfileTemplate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeProfileTemplate.js","sourceRoot":"","sources":["../../src/compositeProfile/CompositeProfileTemplate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CompositeProfile } from './CompositeProfile.js';
|
|
2
|
+
export interface CompositeProfileWatchPlan {
|
|
3
|
+
readonly paths: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
export interface CompositeProfileWatcherHandle {
|
|
6
|
+
close(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface WatchCompositeProfileInput {
|
|
9
|
+
readonly compositeProfile: CompositeProfile;
|
|
10
|
+
readonly warn: (message: string) => void;
|
|
11
|
+
readonly refreshCompositeProfile?: () => CompositeProfile;
|
|
12
|
+
readonly onCompositeProfileWritten?: (compositeProfile: CompositeProfile) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const createCompositeProfileWatchPlan: (paths: readonly string[]) => CompositeProfileWatchPlan;
|
|
15
|
+
export declare const createCompositeProfileWatchPlanForCompositeProfile: (compositeProfile: CompositeProfile) => CompositeProfileWatchPlan;
|
|
16
|
+
export declare const watchCompositeProfileInputs: (input: WatchCompositeProfileInput) => CompositeProfileWatcherHandle;
|
|
17
|
+
export declare const createProfileWatchPaths: (profilePaths: readonly string[]) => readonly string[];
|
|
18
|
+
export declare const compositeProfileFileOutputPath: (compositeProfile: CompositeProfile, relativePath: string) => string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Watches composite profile inputs while an agent process runs and rewrites generated compositeProfile files.
|
|
2
|
+
import { watch } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { writeCompositeProfile } from './CompositeProfileAssembler.js';
|
|
5
|
+
export const createCompositeProfileWatchPlan = (paths) => ({
|
|
6
|
+
paths,
|
|
7
|
+
});
|
|
8
|
+
export const createCompositeProfileWatchPlanForCompositeProfile = (compositeProfile) => createCompositeProfileWatchPlan([...new Set(compositeProfile.files.flatMap((file) => file.sourceInputs))]);
|
|
9
|
+
export const watchCompositeProfileInputs = (input) => {
|
|
10
|
+
const watchPaths = createCompositeProfileWatchPlanForCompositeProfile(input.compositeProfile).paths;
|
|
11
|
+
const watchers = [];
|
|
12
|
+
for (const watchPath of watchPaths) {
|
|
13
|
+
try {
|
|
14
|
+
watchers.push(watch(watchPath,
|
|
15
|
+
/* v8 ignore next -- fs.watch delivery is platform-timed; the static watch plan is covered deterministically. */
|
|
16
|
+
() => updateCompositeProfileFromWatchedInput(input, watchPath)));
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
input.warn(`Could not watch composite profile input ${watchPath}: ${formatError(error)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
close() {
|
|
24
|
+
for (const watcher of watchers) {
|
|
25
|
+
watcher.close();
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export const createProfileWatchPaths = (profilePaths) => [
|
|
31
|
+
...new Set(profilePaths.map((profilePath) => dirname(profilePath))),
|
|
32
|
+
];
|
|
33
|
+
export const compositeProfileFileOutputPath = (compositeProfile, relativePath) => join(compositeProfile.rootDirectory, relativePath);
|
|
34
|
+
const updateCompositeProfileFromWatchedInput = (input, watchPath) => {
|
|
35
|
+
try {
|
|
36
|
+
const compositeProfile = input.refreshCompositeProfile?.() ?? input.compositeProfile;
|
|
37
|
+
writeCompositeProfile(compositeProfile, { materializeStatePaths: false });
|
|
38
|
+
input.onCompositeProfileWritten?.(compositeProfile);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
/* v8 ignore next -- unsafe live-update failures are reported defensively; normal refresh behavior is covered. */
|
|
42
|
+
input.warn(`Could not safely update compositeProfile from ${watchPath}: ${formatError(error)}`);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const formatError = (error) => String(error);
|
|
46
|
+
//# sourceMappingURL=CompositeProfileWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompositeProfileWatcher.js","sourceRoot":"","sources":["../../src/compositeProfile/CompositeProfileWatcher.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAiBvE,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,KAAwB,EAA6B,EAAE,CAAC,CAAC;IACvG,KAAK;CACN,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kDAAkD,GAAG,CAChE,gBAAkC,EACP,EAAE,CAC7B,+BAA+B,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7G,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,KAAiC,EAAiC,EAAE;IAC9G,MAAM,UAAU,GAAG,kDAAkD,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC;IACpG,MAAM,QAAQ,GAAgB,EAAE,CAAC;IAEjC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CACX,KAAK,CACH,SAAS;YACT,gHAAgH;YAChH,GAAG,EAAE,CAAC,sCAAsC,CAAC,KAAK,EAAE,SAAS,CAAC,CAC/D,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,2CAA2C,SAAS,KAAK,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;YACH,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,YAA+B,EAAqB,EAAE,CAAC;IAC7F,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;CACpE,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,gBAAkC,EAAE,YAAoB,EAAU,EAAE,CACjH,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;AAErD,MAAM,sCAAsC,GAAG,CAAC,KAAiC,EAAE,SAAiB,EAAQ,EAAE;IAC5G,IAAI,CAAC;QACH,MAAM,gBAAgB,GAAG,KAAK,CAAC,uBAAuB,EAAE,EAAE,IAAI,KAAK,CAAC,gBAAgB,CAAC;QACrF,qBAAqB,CAAC,gBAAgB,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,KAAK,CAAC,yBAAyB,EAAE,CAAC,gBAAgB,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,iHAAiH;QACjH,KAAK,CAAC,IAAI,CAAC,iDAAiD,SAAS,KAAK,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type StatePersistenceStrategy = 'symlink' | 'discard' | 'warn' | 'error' | 'prompt';
|
|
2
|
+
export interface StatePathDeclaration {
|
|
3
|
+
readonly defaultStrategy?: StatePersistenceStrategy;
|
|
4
|
+
readonly allowedStrategies: readonly StatePersistenceStrategy[];
|
|
5
|
+
}
|
|
6
|
+
export interface CompositeProfileStatePath {
|
|
7
|
+
readonly relativePath: string;
|
|
8
|
+
readonly strategy: StatePersistenceStrategy;
|
|
9
|
+
readonly sourcePath?: string;
|
|
10
|
+
readonly directory: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface CompositeProfileStateBaseline {
|
|
13
|
+
readonly fingerprints: ReadonlyMap<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export interface CompositeProfileStateWriteIssue {
|
|
16
|
+
readonly relativePath: string;
|
|
17
|
+
readonly strategy: StatePersistenceStrategy;
|
|
18
|
+
readonly unknown: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare const materializeCompositeProfileStatePath: (rootDirectory: string, statePath: CompositeProfileStatePath) => void;
|
|
21
|
+
export declare const createCompositeProfileStateBaseline: (rootDirectory: string, statePaths?: readonly CompositeProfileStatePath[]) => CompositeProfileStateBaseline;
|
|
22
|
+
export declare const updateCompositeProfileStateBaselinePaths: (rootDirectory: string, baseline: CompositeProfileStateBaseline, outputPaths: readonly string[]) => CompositeProfileStateBaseline;
|
|
23
|
+
export declare const detectCompositeProfileStateWrites: (rootDirectory: string, statePaths: readonly CompositeProfileStatePath[], baseline: CompositeProfileStateBaseline) => readonly CompositeProfileStateWriteIssue[];
|
|
24
|
+
export declare const ensureStateSourcePath: (sourcePath: string, directory: boolean) => string;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Defines composite profile state persistence declarations, strategies, and write detection helpers.
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, readlinkSync, statSync, symlinkSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { sep as posixSeparator } from 'node:path/posix';
|
|
5
|
+
export const materializeCompositeProfileStatePath = (rootDirectory, statePath) => {
|
|
6
|
+
if (statePath.strategy === 'symlink') {
|
|
7
|
+
if (statePath.sourcePath === undefined) {
|
|
8
|
+
throw new Error(`State path '${statePath.relativePath}' uses symlink without a source path.`);
|
|
9
|
+
}
|
|
10
|
+
materializeSymlink(rootDirectory, statePath.relativePath, statePath.sourcePath, statePath.directory);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const outputPath = resolveCompositeProfileStateOutputPath(rootDirectory, statePath.relativePath);
|
|
14
|
+
if (statePath.directory) {
|
|
15
|
+
mkdirSync(outputPath, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export const createCompositeProfileStateBaseline = (rootDirectory, statePaths = []) => ({
|
|
22
|
+
fingerprints: fingerprintTree(rootDirectory, createDiscardStatePathSet(statePaths)),
|
|
23
|
+
});
|
|
24
|
+
export const updateCompositeProfileStateBaselinePaths = (rootDirectory, baseline, outputPaths) => {
|
|
25
|
+
const fingerprints = new Map(baseline.fingerprints);
|
|
26
|
+
for (const outputPath of outputPaths) {
|
|
27
|
+
const relativePath = normalizeCompositeProfileRelativePath(rootDirectory, outputPath);
|
|
28
|
+
deleteFingerprintSubtree(fingerprints, relativePath);
|
|
29
|
+
addPathFingerprints(rootDirectory, relativePath, fingerprints, new Set());
|
|
30
|
+
}
|
|
31
|
+
return { fingerprints };
|
|
32
|
+
};
|
|
33
|
+
export const detectCompositeProfileStateWrites = (rootDirectory, statePaths, baseline) => {
|
|
34
|
+
const current = fingerprintTree(rootDirectory, createDiscardStatePathSet(statePaths));
|
|
35
|
+
const changedPaths = [...new Set([...current.keys(), ...baseline.fingerprints.keys()])].filter((path) => current.get(path) !== baseline.fingerprints.get(path));
|
|
36
|
+
const issues = new Map();
|
|
37
|
+
const declaredPaths = statePaths.filter((statePath) => statePath.relativePath !== 'unknown');
|
|
38
|
+
const unknownStatePath = statePaths.find((statePath) => statePath.relativePath === 'unknown');
|
|
39
|
+
for (const changedPath of changedPaths) {
|
|
40
|
+
const statePath = declaredPaths.find((candidate) => isWithinStatePath(changedPath, candidate));
|
|
41
|
+
if (statePath !== undefined) {
|
|
42
|
+
if (shouldReportStatePathChange(changedPath, statePath)) {
|
|
43
|
+
issues.set(statePath.relativePath, {
|
|
44
|
+
relativePath: statePath.relativePath,
|
|
45
|
+
strategy: statePath.strategy,
|
|
46
|
+
unknown: false,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (unknownStatePath !== undefined &&
|
|
51
|
+
unknownStatePath.strategy !== 'discard' &&
|
|
52
|
+
isUserWritePath(changedPath)) {
|
|
53
|
+
issues.set(changedPath, { relativePath: changedPath, strategy: unknownStatePath.strategy, unknown: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...issues.values()].sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
57
|
+
};
|
|
58
|
+
export const ensureStateSourcePath = (sourcePath, directory) => {
|
|
59
|
+
const sourceType = getExistingSourceType(sourcePath);
|
|
60
|
+
if (sourceType === undefined) {
|
|
61
|
+
if (directory) {
|
|
62
|
+
mkdirSync(sourcePath, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
mkdirSync(dirname(sourcePath), { recursive: true });
|
|
66
|
+
writeFileSync(sourcePath, createInitialStateSourceFileContent(sourcePath));
|
|
67
|
+
}
|
|
68
|
+
return sourcePath;
|
|
69
|
+
}
|
|
70
|
+
initializeEmptyJsonStateSourceFile(sourcePath, directory, sourceType);
|
|
71
|
+
if (directory && sourceType !== 'directory') {
|
|
72
|
+
throw new Error(`State source path '${sourcePath}' must be a directory.`);
|
|
73
|
+
}
|
|
74
|
+
if (!directory && sourceType !== 'file') {
|
|
75
|
+
throw new Error(`State source path '${sourcePath}' must be a file.`);
|
|
76
|
+
}
|
|
77
|
+
return sourcePath;
|
|
78
|
+
};
|
|
79
|
+
const initializeEmptyJsonStateSourceFile = (sourcePath, directory, sourceType) => {
|
|
80
|
+
const defaultFileContent = getJsonStateFileDefault(sourcePath);
|
|
81
|
+
if (!directory && sourceType === 'file' && defaultFileContent !== undefined && isEmptyTextFile(sourcePath)) {
|
|
82
|
+
writeFileSync(sourcePath, defaultFileContent);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const createInitialStateSourceFileContent = (sourcePath) => getJsonStateFileDefault(sourcePath) ?? '';
|
|
86
|
+
const isEmptyTextFile = (sourcePath) => readFileSync(sourcePath, 'utf8').trim() === '';
|
|
87
|
+
const getJsonStateFileDefault = (sourcePath) => {
|
|
88
|
+
if (isStateSourceFileName(sourcePath, 'mcp.json')) {
|
|
89
|
+
return '{}\n';
|
|
90
|
+
}
|
|
91
|
+
if (isStateSourceFileName(sourcePath, 'models.json')) {
|
|
92
|
+
return '{"providers":{}}\n';
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
};
|
|
96
|
+
const isStateSourceFileName = (sourcePath, fileName) => sourcePath.endsWith(`${sep}${fileName}`) || sourcePath === fileName;
|
|
97
|
+
const getExistingSourceType = (sourcePath) => {
|
|
98
|
+
try {
|
|
99
|
+
const stat = statSync(sourcePath);
|
|
100
|
+
return stat.isDirectory() ? 'directory' : 'file';
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
/* v8 ignore next -- non-ENOENT stat failures should surface as actionable filesystem errors. */
|
|
104
|
+
if (isNodeError(error) && error.code === 'ENOENT') {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
/* v8 ignore next -- non-ENOENT stat failures should surface as actionable filesystem errors. */
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const materializeSymlink = (rootDirectory, relativePath, sourcePath, directory) => {
|
|
112
|
+
const outputPath = resolveCompositeProfileStateOutputPath(rootDirectory, relativePath);
|
|
113
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
114
|
+
if (pathLexicallyExists(outputPath)) {
|
|
115
|
+
unlinkSync(outputPath);
|
|
116
|
+
}
|
|
117
|
+
ensureStateSourcePath(sourcePath, directory);
|
|
118
|
+
symlinkSync(sourcePath, outputPath, directory ? 'dir' : 'file');
|
|
119
|
+
};
|
|
120
|
+
const pathLexicallyExists = (path) => {
|
|
121
|
+
try {
|
|
122
|
+
lstatSync(path);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
/* v8 ignore next -- non-ENOENT lstat failures should surface as actionable filesystem errors. */
|
|
127
|
+
if (isNodeError(error) && error.code === 'ENOENT') {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
/* v8 ignore next -- non-ENOENT lstat failures should surface as actionable filesystem errors. */
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const fingerprintTree = (rootDirectory, skippedRelativePaths = new Set()) => {
|
|
135
|
+
const fingerprints = new Map();
|
|
136
|
+
addPathFingerprints(rootDirectory, '', fingerprints, skippedRelativePaths);
|
|
137
|
+
return fingerprints;
|
|
138
|
+
};
|
|
139
|
+
const addPathFingerprints = (rootDirectory, relativePath, fingerprints, skippedRelativePaths) => {
|
|
140
|
+
const absolutePath = relativePath === ''
|
|
141
|
+
? rootDirectory
|
|
142
|
+
: resolveCompositeProfileRelativePath(rootDirectory, relativePath, 'CompositeProfile path');
|
|
143
|
+
if (existsSync(absolutePath)) {
|
|
144
|
+
addFingerprint(absolutePath, relativePath, fingerprints, skippedRelativePaths);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const addFingerprint = (absolutePath, relativePath, fingerprints, skippedRelativePaths) => {
|
|
148
|
+
if (shouldSkipFingerprint(relativePath, skippedRelativePaths)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const stat = lstatSync(absolutePath);
|
|
152
|
+
if (stat.isSymbolicLink()) {
|
|
153
|
+
fingerprints.set(relativePath, `symlink:${readlinkSync(absolutePath)}`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (relativePath !== '') {
|
|
157
|
+
fingerprints.set(relativePath, createEntryFingerprint(absolutePath, stat));
|
|
158
|
+
}
|
|
159
|
+
if (stat.isDirectory()) {
|
|
160
|
+
for (const entryName of readdirSync(absolutePath).sort()) {
|
|
161
|
+
addFingerprint(join(absolutePath, entryName), relativePath === '' ? entryName : `${relativePath}${posixSeparator}${entryName}`, fingerprints, skippedRelativePaths);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const createEntryFingerprint = (absolutePath, stat) => {
|
|
166
|
+
if (stat.isDirectory()) {
|
|
167
|
+
return 'dir';
|
|
168
|
+
}
|
|
169
|
+
if (stat.isFile()) {
|
|
170
|
+
return `file:${readFileSync(absolutePath).toString('base64')}`;
|
|
171
|
+
}
|
|
172
|
+
return `special:${stat.mode}:${stat.rdev}`;
|
|
173
|
+
};
|
|
174
|
+
const shouldSkipFingerprint = (relativePath, skippedRelativePaths) => relativePath !== '' &&
|
|
175
|
+
[...skippedRelativePaths].some((skippedRelativePath) => relativePath === skippedRelativePath || relativePath.startsWith(`${skippedRelativePath}${posixSeparator}`));
|
|
176
|
+
const createDiscardStatePathSet = (statePaths) => new Set(statePaths
|
|
177
|
+
.filter((statePath) => statePath.strategy === 'discard' && statePath.relativePath !== 'unknown')
|
|
178
|
+
.map((statePath) => normalizeStateRelativePath(statePath.relativePath)));
|
|
179
|
+
const deleteFingerprintSubtree = (fingerprints, relativePath) => {
|
|
180
|
+
for (const fingerprintPath of [...fingerprints.keys()]) {
|
|
181
|
+
if (fingerprintPath === relativePath || fingerprintPath.startsWith(`${relativePath}${posixSeparator}`)) {
|
|
182
|
+
fingerprints.delete(fingerprintPath);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const resolveCompositeProfileStateOutputPath = (rootDirectory, relativePath) => {
|
|
187
|
+
const normalizedRelativePath = relativePath.endsWith('/') ? relativePath.slice(0, -1) : relativePath;
|
|
188
|
+
return resolveCompositeProfileRelativePath(rootDirectory, normalizedRelativePath, `State path '${relativePath}'`);
|
|
189
|
+
};
|
|
190
|
+
const normalizeCompositeProfileRelativePath = (rootDirectory, outputPath) => {
|
|
191
|
+
const resolvedOutputPath = isAbsolute(outputPath) ? resolve(outputPath) : resolve(rootDirectory, outputPath);
|
|
192
|
+
const relativeOutputPath = relative(resolve(rootDirectory), resolvedOutputPath);
|
|
193
|
+
assertCompositeProfileRelativePath(rootDirectory, relativeOutputPath, `CompositeProfile file output path '${outputPath}'`);
|
|
194
|
+
return relativeOutputPath.split(sep).join(posixSeparator);
|
|
195
|
+
};
|
|
196
|
+
const resolveCompositeProfileRelativePath = (rootDirectory, relativePath, label) => {
|
|
197
|
+
const resolvedRootDirectory = resolve(rootDirectory);
|
|
198
|
+
const resolvedOutputPath = resolve(rootDirectory, relativePath);
|
|
199
|
+
const relativeOutputPath = relative(resolvedRootDirectory, resolvedOutputPath);
|
|
200
|
+
assertCompositeProfileRelativePath(rootDirectory, relativeOutputPath, label);
|
|
201
|
+
return resolvedOutputPath;
|
|
202
|
+
};
|
|
203
|
+
const assertCompositeProfileRelativePath = (rootDirectory, relativePath, label) => {
|
|
204
|
+
if (relativePath === '..' || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {
|
|
205
|
+
throw new Error(`${label} must stay under compositeProfile root '${rootDirectory}'.`);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const shouldReportStatePathChange = (changedPath, statePath) => {
|
|
209
|
+
if (statePath.strategy === 'discard') {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
if (statePath.strategy === 'symlink') {
|
|
213
|
+
return changedPath === normalizeStateRelativePath(statePath.relativePath);
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
};
|
|
217
|
+
const isWithinStatePath = (changedPath, statePath) => {
|
|
218
|
+
const stateRelativePath = normalizeStateRelativePath(statePath.relativePath);
|
|
219
|
+
return changedPath === stateRelativePath || changedPath.startsWith(`${stateRelativePath}${posixSeparator}`);
|
|
220
|
+
};
|
|
221
|
+
const normalizeStateRelativePath = (relativePath) => relativePath.endsWith('/') ? relativePath.slice(0, -1) : relativePath;
|
|
222
|
+
const isUserWritePath = (relativePath) => relativePath !== 'outfitter' && !relativePath.startsWith(`outfitter${posixSeparator}`);
|
|
223
|
+
const isNodeError = (error) => error instanceof Error && 'code' in error;
|
|
224
|
+
//# sourceMappingURL=StatePersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatePersistence.js","sourceRoot":"","sources":["../../src/compositeProfile/StatePersistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ArrayMergeKey<T> = (item: T) => string;
|
|
2
|
+
export type ArrayMergePolicy<T = unknown> = 'replace' | 'append' | 'prepend' | 'appendUnique' | 'prependUnique' | {
|
|
3
|
+
readonly mode: 'uniqueBy';
|
|
4
|
+
readonly key: ArrayMergeKey<T>;
|
|
5
|
+
readonly order: 'append' | 'prepend';
|
|
6
|
+
readonly winner: 'first' | 'last';
|
|
7
|
+
};
|
|
8
|
+
export declare const mergeArrayByPolicy: <T>(lowerPrecedence: readonly T[] | undefined, higherPrecedence: readonly T[], policy?: ArrayMergePolicy<T>) => readonly T[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const mergeArrayByPolicy = (lowerPrecedence, higherPrecedence, policy = 'replace') => {
|
|
2
|
+
const lower = lowerPrecedence ?? [];
|
|
3
|
+
if (policy === 'replace') {
|
|
4
|
+
return [...higherPrecedence];
|
|
5
|
+
}
|
|
6
|
+
if (policy === 'append') {
|
|
7
|
+
return [...lower, ...higherPrecedence];
|
|
8
|
+
}
|
|
9
|
+
if (policy === 'prepend') {
|
|
10
|
+
return [...higherPrecedence, ...lower];
|
|
11
|
+
}
|
|
12
|
+
if (policy === 'appendUnique') {
|
|
13
|
+
return uniqueBy([...lower, ...higherPrecedence], defaultArrayMergeKey, 'first');
|
|
14
|
+
}
|
|
15
|
+
if (policy === 'prependUnique') {
|
|
16
|
+
return uniqueBy([...higherPrecedence, ...lower], defaultArrayMergeKey, 'first');
|
|
17
|
+
}
|
|
18
|
+
const ordered = policy.order === 'append' ? [...lower, ...higherPrecedence] : [...higherPrecedence, ...lower];
|
|
19
|
+
return uniqueBy(ordered, policy.key, policy.winner);
|
|
20
|
+
};
|
|
21
|
+
const uniqueBy = (items, key, winner) => {
|
|
22
|
+
if (winner === 'first') {
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
const result = [];
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
const itemKey = key(item);
|
|
27
|
+
if (!seen.has(itemKey)) {
|
|
28
|
+
seen.add(itemKey);
|
|
29
|
+
result.push(item);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
return [...uniqueBy([...items].reverse(), key, 'first')].reverse();
|
|
35
|
+
};
|
|
36
|
+
const defaultArrayMergeKey = (item) => {
|
|
37
|
+
if (typeof item === 'string') {
|
|
38
|
+
return item;
|
|
39
|
+
}
|
|
40
|
+
if (item === null || typeof item !== 'object') {
|
|
41
|
+
return JSON.stringify(item);
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify(item, Object.keys(item).sort());
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=ArrayMergePolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArrayMergePolicy.js","sourceRoot":"","sources":["../../src/merge/ArrayMergePolicy.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,eAAyC,EACzC,gBAA8B,EAC9B,SAA8B,SAAS,EACzB,EAAE;IAChB,MAAM,KAAK,GAAG,eAAe,IAAI,EAAE,CAAC;IAEpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,gBAAgB,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,gBAAgB,EAAE,GAAG,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,OAAO,QAAQ,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,KAAK,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,KAAK,CAAC,CAAC;IAE9G,OAAO,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAI,KAAmB,EAAE,GAAqB,EAAE,MAAwB,EAAgB,EAAE;IACzG,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,MAAM,GAAQ,EAAE,CAAC;QAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;YAE1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AACrE,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAI,IAAO,EAAU,EAAE;IAClD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ArrayMergePolicy } from './ArrayMergePolicy.js';
|
|
2
|
+
export type MergePath = readonly string[];
|
|
3
|
+
export type ArrayMergePolicyResolver = (path: MergePath) => ArrayMergePolicy<MergeableValue> | undefined;
|
|
4
|
+
export interface MergeValueOptions {
|
|
5
|
+
readonly arrayPolicyForPath?: ArrayMergePolicyResolver;
|
|
6
|
+
}
|
|
7
|
+
export type MergeableValue = string | number | boolean | null | readonly MergeableValue[] | {
|
|
8
|
+
readonly [key: string]: MergeableValue | undefined;
|
|
9
|
+
};
|
|
10
|
+
export type MergeableObject = Readonly<Record<string, MergeableValue | undefined>>;
|
|
11
|
+
export declare const mergeObjectsWithPolicy: <T extends object>(lowerPrecedence: T | undefined, higherPrecedence: T, options?: MergeValueOptions) => T;
|