@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.
Files changed (156) hide show
  1. package/LICENSE.md +58 -0
  2. package/README.md +256 -0
  3. package/dist/agents/AdapterProfileControls.d.ts +20 -0
  4. package/dist/agents/AdapterProfileControls.js +63 -0
  5. package/dist/agents/AdapterProfileControls.js.map +1 -0
  6. package/dist/agents/AdapterStatePaths.d.ts +12 -0
  7. package/dist/agents/AdapterStatePaths.js +44 -0
  8. package/dist/agents/AdapterStatePaths.js.map +1 -0
  9. package/dist/agents/AgentAdapter.d.ts +32 -0
  10. package/dist/agents/AgentAdapter.js +2 -0
  11. package/dist/agents/AgentAdapter.js.map +1 -0
  12. package/dist/agents/AgentRegistry.d.ts +6 -0
  13. package/dist/agents/AgentRegistry.js +17 -0
  14. package/dist/agents/AgentRegistry.js.map +1 -0
  15. package/dist/agents/LaunchResources.d.ts +13 -0
  16. package/dist/agents/LaunchResources.js +35 -0
  17. package/dist/agents/LaunchResources.js.map +1 -0
  18. package/dist/agents/ResourceIdentity.d.ts +2 -0
  19. package/dist/agents/ResourceIdentity.js +51 -0
  20. package/dist/agents/ResourceIdentity.js.map +1 -0
  21. package/dist/agents/claude/ClaudeAdapter.d.ts +2 -0
  22. package/dist/agents/claude/ClaudeAdapter.js +117 -0
  23. package/dist/agents/claude/ClaudeAdapter.js.map +1 -0
  24. package/dist/agents/claude/ClaudeCompositeProfileWriter.d.ts +5 -0
  25. package/dist/agents/claude/ClaudeCompositeProfileWriter.js +7 -0
  26. package/dist/agents/claude/ClaudeCompositeProfileWriter.js.map +1 -0
  27. package/dist/agents/pi/PiAdapter.d.ts +2 -0
  28. package/dist/agents/pi/PiAdapter.js +229 -0
  29. package/dist/agents/pi/PiAdapter.js.map +1 -0
  30. package/dist/agents/pi/PiCompositeProfileWriter.d.ts +5 -0
  31. package/dist/agents/pi/PiCompositeProfileWriter.js +7 -0
  32. package/dist/agents/pi/PiCompositeProfileWriter.js.map +1 -0
  33. package/dist/agents/pi/PiMcpConfig.d.ts +2 -0
  34. package/dist/agents/pi/PiMcpConfig.js +114 -0
  35. package/dist/agents/pi/PiMcpConfig.js.map +1 -0
  36. package/dist/agents/pi/PiSettingsMergePolicy.d.ts +17 -0
  37. package/dist/agents/pi/PiSettingsMergePolicy.js +59 -0
  38. package/dist/agents/pi/PiSettingsMergePolicy.js.map +1 -0
  39. package/dist/cli/OutfitterCli.d.ts +4 -0
  40. package/dist/cli/OutfitterCli.js +32 -0
  41. package/dist/cli/OutfitterCli.js.map +1 -0
  42. package/dist/cli/commands/CommandObject.d.ts +11 -0
  43. package/dist/cli/commands/CommandObject.js +5 -0
  44. package/dist/cli/commands/CommandObject.js.map +1 -0
  45. package/dist/cli/commands/FirstRunWelcomeProfile.d.ts +11 -0
  46. package/dist/cli/commands/FirstRunWelcomeProfile.js +107 -0
  47. package/dist/cli/commands/FirstRunWelcomeProfile.js.map +1 -0
  48. package/dist/cli/commands/PiLoginLaunch.d.ts +10 -0
  49. package/dist/cli/commands/PiLoginLaunch.js +76 -0
  50. package/dist/cli/commands/PiLoginLaunch.js.map +1 -0
  51. package/dist/cli/commands/RunCommand.d.ts +30 -0
  52. package/dist/cli/commands/RunCommand.js +299 -0
  53. package/dist/cli/commands/RunCommand.js.map +1 -0
  54. package/dist/cli/commands/SetupCommand.d.ts +34 -0
  55. package/dist/cli/commands/SetupCommand.js +379 -0
  56. package/dist/cli/commands/SetupCommand.js.map +1 -0
  57. package/dist/cli/commands/SyncCommand.d.ts +28 -0
  58. package/dist/cli/commands/SyncCommand.js +178 -0
  59. package/dist/cli/commands/SyncCommand.js.map +1 -0
  60. package/dist/cli/commands/WelcomeCommand.d.ts +54 -0
  61. package/dist/cli/commands/WelcomeCommand.js +214 -0
  62. package/dist/cli/commands/WelcomeCommand.js.map +1 -0
  63. package/dist/cli/commands/profile/Command.d.ts +6 -0
  64. package/dist/cli/commands/profile/Command.js +21 -0
  65. package/dist/cli/commands/profile/Command.js.map +1 -0
  66. package/dist/cli/commands/profile/CreateCommand.d.ts +19 -0
  67. package/dist/cli/commands/profile/CreateCommand.js +115 -0
  68. package/dist/cli/commands/profile/CreateCommand.js.map +1 -0
  69. package/dist/cli/commands/profile/ListCommand.d.ts +17 -0
  70. package/dist/cli/commands/profile/ListCommand.js +85 -0
  71. package/dist/cli/commands/profile/ListCommand.js.map +1 -0
  72. package/dist/cli/commands/profile/Shared.d.ts +9 -0
  73. package/dist/cli/commands/profile/Shared.js +10 -0
  74. package/dist/cli/commands/profile/Shared.js.map +1 -0
  75. package/dist/cli.d.ts +3 -0
  76. package/dist/cli.js +22 -0
  77. package/dist/cli.js.map +1 -0
  78. package/dist/compositeProfile/CompositeProfile.d.ts +8 -0
  79. package/dist/compositeProfile/CompositeProfile.js +6 -0
  80. package/dist/compositeProfile/CompositeProfile.js.map +1 -0
  81. package/dist/compositeProfile/CompositeProfileAssembler.d.ts +12 -0
  82. package/dist/compositeProfile/CompositeProfileAssembler.js +32 -0
  83. package/dist/compositeProfile/CompositeProfileAssembler.js.map +1 -0
  84. package/dist/compositeProfile/CompositeProfileFile.d.ts +16 -0
  85. package/dist/compositeProfile/CompositeProfileFile.js +16 -0
  86. package/dist/compositeProfile/CompositeProfileFile.js.map +1 -0
  87. package/dist/compositeProfile/CompositeProfileTemplate.d.ts +15 -0
  88. package/dist/compositeProfile/CompositeProfileTemplate.js +65 -0
  89. package/dist/compositeProfile/CompositeProfileTemplate.js.map +1 -0
  90. package/dist/compositeProfile/CompositeProfileWatcher.d.ts +18 -0
  91. package/dist/compositeProfile/CompositeProfileWatcher.js +46 -0
  92. package/dist/compositeProfile/CompositeProfileWatcher.js.map +1 -0
  93. package/dist/compositeProfile/StatePersistence.d.ts +24 -0
  94. package/dist/compositeProfile/StatePersistence.js +224 -0
  95. package/dist/compositeProfile/StatePersistence.js.map +1 -0
  96. package/dist/merge/ArrayMergePolicy.d.ts +8 -0
  97. package/dist/merge/ArrayMergePolicy.js +45 -0
  98. package/dist/merge/ArrayMergePolicy.js.map +1 -0
  99. package/dist/merge/SettingsValueMerger.d.ts +11 -0
  100. package/dist/merge/SettingsValueMerger.js +34 -0
  101. package/dist/merge/SettingsValueMerger.js.map +1 -0
  102. package/dist/profiles/Profile.d.ts +32 -0
  103. package/dist/profiles/Profile.js +7 -0
  104. package/dist/profiles/Profile.js.map +1 -0
  105. package/dist/profiles/ProfileCache.d.ts +8 -0
  106. package/dist/profiles/ProfileCache.js +36 -0
  107. package/dist/profiles/ProfileCache.js.map +1 -0
  108. package/dist/profiles/ProfileLoader.d.ts +24 -0
  109. package/dist/profiles/ProfileLoader.js +169 -0
  110. package/dist/profiles/ProfileLoader.js.map +1 -0
  111. package/dist/profiles/ProfileMerger.d.ts +20 -0
  112. package/dist/profiles/ProfileMerger.js +97 -0
  113. package/dist/profiles/ProfileMerger.js.map +1 -0
  114. package/dist/profiles/ProfileSource.d.ts +35 -0
  115. package/dist/profiles/ProfileSource.js +13 -0
  116. package/dist/profiles/ProfileSource.js.map +1 -0
  117. package/dist/schemas/profile-source.schema.json +29 -0
  118. package/dist/schemas/profile.schema.json +115 -0
  119. package/dist/schemas/settings.schema.json +37 -0
  120. package/dist/settings/Settings.d.ts +17 -0
  121. package/dist/settings/Settings.js +5 -0
  122. package/dist/settings/Settings.js.map +1 -0
  123. package/dist/settings/SettingsLoader.d.ts +33 -0
  124. package/dist/settings/SettingsLoader.js +129 -0
  125. package/dist/settings/SettingsLoader.js.map +1 -0
  126. package/dist/settings/SettingsMerger.d.ts +2 -0
  127. package/dist/settings/SettingsMerger.js +31 -0
  128. package/dist/settings/SettingsMerger.js.map +1 -0
  129. package/dist/validation/SchemaValidator.d.ts +11 -0
  130. package/dist/validation/SchemaValidator.js +36 -0
  131. package/dist/validation/SchemaValidator.js.map +1 -0
  132. package/dist/validation/YamlDocument.d.ts +13 -0
  133. package/dist/validation/YamlDocument.js +11 -0
  134. package/dist/validation/YamlDocument.js.map +1 -0
  135. package/doc/.deepreview +30 -0
  136. package/doc/architecture.md +834 -0
  137. package/doc/controllable-elements.md +162 -0
  138. package/doc/file_structure.md +133 -0
  139. package/doc/integration_test_system.md +214 -0
  140. package/doc/specs/validating_requirements_with_rules.md +55 -0
  141. package/doc/state_writeback_strategy.md +334 -0
  142. package/package.json +73 -0
  143. package/requirements/OFTR-001-project-foundation.md +53 -0
  144. package/requirements/OFTR-002-settings.md +65 -0
  145. package/requirements/OFTR-003-profiles.md +51 -0
  146. package/requirements/OFTR-004-sync-and-setup.md +57 -0
  147. package/requirements/OFTR-005-run-and-composite-profile.md +60 -0
  148. package/requirements/OFTR-006-agent-adapters.md +64 -0
  149. package/requirements/OFTR-007-controllable-elements.md +32 -0
  150. package/requirements/OFTR-008-requirements-governance.md +42 -0
  151. package/requirements/OFTR-009-release-publishing.md +25 -0
  152. package/requirements/OFTR-010-onboarding-welcome.md +38 -0
  153. package/src/schemas/SchemaDocument.ts +20 -0
  154. package/src/schemas/profile-source.schema.json +29 -0
  155. package/src/schemas/profile.schema.json +115 -0
  156. package/src/schemas/settings.schema.json +37 -0
@@ -0,0 +1,34 @@
1
+ import { mergeArrayByPolicy } from './ArrayMergePolicy.js';
2
+ export const mergeObjectsWithPolicy = (lowerPrecedence, higherPrecedence, options = {}) => mergeObjectValue(lowerPrecedence ?? {}, higherPrecedence, [], options);
3
+ const mergeObjectValue = (lowerPrecedence, higherPrecedence, path, options) => ({
4
+ ...lowerPrecedence,
5
+ ...Object.fromEntries(Object.entries(higherPrecedence)
6
+ .filter((entry) => entry[1] !== undefined)
7
+ .map(([key, value]) => [
8
+ key,
9
+ key in lowerPrecedence
10
+ ? mergeMemberValue(lowerPrecedence[key], value, [...path, key], options)
11
+ : cloneMergeableValue(value),
12
+ ])),
13
+ });
14
+ const mergeMemberValue = (lowerPrecedence, higherPrecedence, path, options) => {
15
+ if (Array.isArray(higherPrecedence)) {
16
+ return mergeArrayByPolicy(isMergeableArray(lowerPrecedence) ? lowerPrecedence : undefined, higherPrecedence, options.arrayPolicyForPath?.(path) ?? 'replace');
17
+ }
18
+ if (isPlainMergeableObject(lowerPrecedence) && isPlainMergeableObject(higherPrecedence)) {
19
+ return mergeObjectValue(lowerPrecedence, higherPrecedence, path, options);
20
+ }
21
+ return cloneMergeableValue(higherPrecedence);
22
+ };
23
+ const cloneMergeableValue = (value) => {
24
+ if (isMergeableArray(value)) {
25
+ return value.map(cloneMergeableValue);
26
+ }
27
+ if (isPlainMergeableObject(value)) {
28
+ return mergeObjectValue({}, value, [], {});
29
+ }
30
+ return value;
31
+ };
32
+ const isPlainMergeableObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
33
+ const isMergeableArray = (value) => Array.isArray(value);
34
+ //# sourceMappingURL=SettingsValueMerger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingsValueMerger.js","sourceRoot":"","sources":["../../src/merge/SettingsValueMerger.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAmB3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,eAA8B,EAC9B,gBAAmB,EACnB,UAA6B,EAAE,EAC5B,EAAE,CAAC,gBAAgB,CAAC,eAAe,IAAI,EAAE,EAAE,gBAAmC,EAAE,EAAE,EAAE,OAAO,CAAM,CAAC;AAEvG,MAAM,gBAAgB,GAAG,CACvB,eAAgC,EAChC,gBAAiC,EACjC,IAAe,EACf,OAA0B,EACT,EAAE,CAAC,CAAC;IACrB,GAAG,eAAe;IAClB,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC;SAC7B,MAAM,CAAC,CAAC,KAAK,EAAqC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;SAC5E,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACrB,GAAG;QACH,GAAG,IAAI,eAAe;YACpB,CAAC,CAAC,gBAAgB,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC;YACxE,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC;KAC/B,CAAC,CACL;CACF,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CACvB,eAA2C,EAC3C,gBAAgC,EAChC,IAAe,EACf,OAA0B,EACV,EAAE;IAClB,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpC,OAAO,kBAAkB,CACvB,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,EAC/D,gBAAgB,EAChB,OAAO,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,SAAS,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,sBAAsB,CAAC,eAAe,CAAC,IAAI,sBAAsB,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACxF,OAAO,gBAAgB,CAAC,eAAe,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,KAAqB,EAAkB,EAAE;IACpE,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,gBAAgB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,KAAc,EAA4B,EAAE,CAC1E,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEvE,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAsC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { StatePersistenceStrategy } from '../compositeProfile/StatePersistence.js';
2
+ export type StatePersistenceOverrides = Readonly<Record<string, StatePersistenceStrategy>>;
3
+ interface BaseProfileControls {
4
+ readonly [controlName: string]: unknown;
5
+ readonly model?: string;
6
+ readonly provider?: string;
7
+ readonly thinking?: string;
8
+ readonly environment?: Readonly<Record<string, string>>;
9
+ readonly args?: readonly string[];
10
+ readonly sessionDirectory?: string;
11
+ readonly extensions?: readonly string[];
12
+ readonly skills?: readonly string[];
13
+ readonly promptTemplate?: string;
14
+ readonly systemPrompt?: string;
15
+ readonly appendSystemPrompt?: string;
16
+ }
17
+ export type AgentSpecificProfileControls = BaseProfileControls;
18
+ export type PiProfileControls = AgentSpecificProfileControls;
19
+ export type ClaudeProfileControls = AgentSpecificProfileControls;
20
+ export interface ProfileControls extends BaseProfileControls {
21
+ readonly pi?: PiProfileControls;
22
+ readonly claude?: ClaudeProfileControls;
23
+ }
24
+ export interface Profile {
25
+ readonly id: string;
26
+ readonly label?: string;
27
+ readonly inherits: readonly string[];
28
+ readonly controls: ProfileControls;
29
+ readonly statePersistence?: StatePersistenceOverrides;
30
+ }
31
+ export declare const createEmptyProfile: (id: string) => Profile;
32
+ export {};
@@ -0,0 +1,7 @@
1
+ export const createEmptyProfile = (id) => ({
2
+ id,
3
+ inherits: [],
4
+ controls: {},
5
+ statePersistence: {},
6
+ });
7
+ //# sourceMappingURL=Profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Profile.js","sourceRoot":"","sources":["../../src/profiles/Profile.ts"],"names":[],"mappings":"AAqCA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAU,EAAW,EAAE,CAAC,CAAC;IAC1D,EAAE;IACF,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,gBAAgB,EAAE,EAAE;CACrB,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type RemoteSourceReference } from './ProfileSource.js';
2
+ export declare const encodeProfileSourceUri: (uri: string) => string;
3
+ export declare const encodeRemoteSource: (source: RemoteSourceReference) => string;
4
+ export declare const createProfileSourceCachePath: (homeDirectory: string, uri: string) => string;
5
+ export declare const createRemoteRepositoryCachePath: (homeDirectory: string, source: RemoteSourceReference) => string;
6
+ export declare const resolveRemoteRepositorySubpath: (repositoryPath: string, subpath?: string) => string;
7
+ export declare const redactProfileSourceUriCredentials: (uri: string) => string;
8
+ export declare const normalizeGitUri: (uri: string) => string;
@@ -0,0 +1,36 @@
1
+ // Encodes remote profile/source cache paths.
2
+ import { isAbsolute, join, relative, resolve } from 'node:path';
3
+ import { normalizeRemoteSourceUri } from './ProfileSource.js';
4
+ export const encodeProfileSourceUri = (uri) => Buffer.from(redactProfileSourceUriCredentials(uri), 'utf8').toString('base64url');
5
+ export const encodeRemoteSource = (source) => encodeProfileSourceUri(`${normalizeRemoteSourceUri(source)}#${source.ref ?? ''}`);
6
+ export const createProfileSourceCachePath = (homeDirectory, uri) => join(homeDirectory, '.outfitter', 'cache', 'profiles', encodeProfileSourceUri(uri));
7
+ export const createRemoteRepositoryCachePath = (homeDirectory, source) => join(homeDirectory, '.outfitter', 'cache', 'repos', encodeRemoteSource(source));
8
+ export const resolveRemoteRepositorySubpath = (repositoryPath, subpath = '') => {
9
+ if (isAbsolute(subpath)) {
10
+ throw new Error(`Remote repository path '${subpath}' must be relative.`);
11
+ }
12
+ const resolvedPath = resolve(repositoryPath, subpath);
13
+ const relativePath = relative(repositoryPath, resolvedPath);
14
+ if (relativePath === '..' || relativePath.startsWith('../') || isAbsolute(relativePath)) {
15
+ throw new Error(`Remote repository path '${subpath}' must stay inside the repository.`);
16
+ }
17
+ return resolvedPath;
18
+ };
19
+ export const redactProfileSourceUriCredentials = (uri) => {
20
+ const prefix = uri.startsWith('git+') ? 'git+' : '';
21
+ const normalizedUri = normalizeGitUri(uri);
22
+ try {
23
+ const parsedUri = new URL(normalizedUri);
24
+ if (parsedUri.username === '' && parsedUri.password === '') {
25
+ return uri;
26
+ }
27
+ parsedUri.username = 'REDACTED';
28
+ parsedUri.password = '';
29
+ return `${prefix}${parsedUri.toString()}`;
30
+ }
31
+ catch {
32
+ return uri.replace(/\/\/[^/@\s]+@/u, '//REDACTED@');
33
+ }
34
+ };
35
+ export const normalizeGitUri = (uri) => (uri.startsWith('git+') ? uri.slice('git+'.length) : uri);
36
+ //# sourceMappingURL=ProfileCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileCache.js","sourceRoot":"","sources":["../../src/profiles/ProfileCache.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,wBAAwB,EAA8B,MAAM,oBAAoB,CAAC;AAE1F,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAU,EAAE,CAC5D,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAEpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAA6B,EAAU,EAAE,CAC1E,sBAAsB,CAAC,GAAG,wBAAwB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC;AAEpF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,aAAqB,EAAE,GAAW,EAAU,EAAE,CACzF,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtF,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,aAAqB,EAAE,MAA6B,EAAU,EAAE,CAC9G,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AAElF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,cAAsB,EAAE,OAAO,GAAG,EAAE,EAAU,EAAE;IAC7F,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,qBAAqB,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAE5D,IAAI,YAAY,KAAK,IAAI,IAAI,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,oCAAoC,CAAC,CAAC;IAC1F,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,GAAW,EAAU,EAAE;IACvE,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,aAAa,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAE3C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QAEzC,IAAI,SAAS,CAAC,QAAQ,KAAK,EAAE,IAAI,SAAS,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;YAC3D,OAAO,GAAG,CAAC;QACb,CAAC;QAED,SAAS,CAAC,QAAQ,GAAG,UAAU,CAAC;QAChC,SAAS,CAAC,QAAQ,GAAG,EAAE,CAAC;QACxB,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { ValidationIssue } from '../validation/SchemaValidator.js';
2
+ import type { Profile } from './Profile.js';
3
+ import type { ProfileSourceReference } from './ProfileSource.js';
4
+ export interface ProfileLoadPlan {
5
+ readonly sources: readonly ProfileSourceReference[];
6
+ }
7
+ export type ProfileLoadIssue = ValidationIssue;
8
+ export interface LoadedProfile {
9
+ readonly source: ProfileSourceReference;
10
+ readonly folderPath: string;
11
+ readonly profilePath: string;
12
+ readonly profile: Profile;
13
+ }
14
+ export interface ProfileLoadResult {
15
+ readonly profiles: readonly LoadedProfile[];
16
+ readonly issues: readonly ProfileLoadIssue[];
17
+ }
18
+ export declare const createProfileLoadPlan: (sources: readonly ProfileSourceReference[]) => ProfileLoadPlan;
19
+ export declare const isValidProfileId: (profileId: string) => boolean;
20
+ export declare const isProfileIncludedBySource: (profileId: string, source: ProfileSourceReference) => boolean;
21
+ export declare const parseProfileDocument: (document: unknown, fallbackId: string) => Profile | ProfileLoadIssue;
22
+ export declare const parseProfileYaml: (content: string, fallbackId: string) => Profile | ProfileLoadIssue;
23
+ export declare const loadLocalProfileSource: (source: ProfileSourceReference) => ProfileLoadResult;
24
+ export declare const readErrorMessage: (error: unknown) => string;
@@ -0,0 +1,169 @@
1
+ // Loads local profile folders and parses profile.yml documents.
2
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { validateSchema } from '../validation/SchemaValidator.js';
5
+ import { parseYamlDocument } from '../validation/YamlDocument.js';
6
+ const profileIdPattern = /^[a-z0-9][a-z0-9._-]*[a-z0-9]$|^[a-z0-9]$/u;
7
+ export const createProfileLoadPlan = (sources) => ({
8
+ sources,
9
+ });
10
+ export const isValidProfileId = (profileId) => profileIdPattern.test(profileId);
11
+ export const isProfileIncludedBySource = (profileId, source) => (source.only === undefined || source.only.includes(profileId)) &&
12
+ (source.except === undefined || !source.except.includes(profileId));
13
+ export const parseProfileDocument = (document, fallbackId) => {
14
+ const record = readObject(document);
15
+ if (record === undefined) {
16
+ return { path: '/', message: 'Profile document must be a mapping.' };
17
+ }
18
+ const id = readString(record.id, fallbackId);
19
+ const validationIssue = validateProfileRecord({ ...record, id });
20
+ if (validationIssue !== undefined) {
21
+ return validationIssue;
22
+ }
23
+ const statePersistence = readStatePersistence(record.state_persistence);
24
+ return omitUndefined({
25
+ id,
26
+ label: readOptionalString(record.label),
27
+ inherits: readStringArray(record.inherits),
28
+ controls: readControls(record.controls),
29
+ statePersistence: Object.keys(statePersistence).length > 0 ? statePersistence : undefined,
30
+ });
31
+ };
32
+ export const parseProfileYaml = (content, fallbackId) => {
33
+ const parsed = parseYamlDocument(content, '/profile.yml');
34
+ if (!parsed.ok) {
35
+ return parsed.issue;
36
+ }
37
+ return parseProfileDocument(parsed.document, fallbackId);
38
+ };
39
+ export const loadLocalProfileSource = (source) => {
40
+ if (source.path === undefined) {
41
+ return {
42
+ profiles: [],
43
+ issues: [{ path: '<uri-source>', message: 'Only local profile sources can be loaded directly.' }],
44
+ };
45
+ }
46
+ if (!existsSync(source.path) || !statSync(source.path).isDirectory()) {
47
+ return { profiles: [], issues: [{ path: source.path, message: 'Profile source must be an existing directory.' }] };
48
+ }
49
+ const profiles = [];
50
+ const issues = [];
51
+ for (const entryName of readdirSync(source.path).sort()) {
52
+ const folderPath = join(source.path, entryName);
53
+ const profilePath = join(folderPath, 'profile.yml');
54
+ if (statSync(folderPath).isDirectory() && existsSync(profilePath)) {
55
+ addProfileFromFolder(source, entryName, folderPath, profilePath, profiles, issues);
56
+ }
57
+ }
58
+ return { profiles, issues };
59
+ };
60
+ const addProfileFromFolder = (source, fallbackId, folderPath, profilePath, profiles, issues) => {
61
+ const profile = parseProfileYaml(readFileSync(profilePath, 'utf8'), fallbackId);
62
+ if ('message' in profile) {
63
+ issues.push({ path: `${profilePath}#${profile.path}`, message: profile.message });
64
+ }
65
+ else if (isProfileIncludedBySource(profile.id, source)) {
66
+ profiles.push({ source, folderPath, profilePath, profile });
67
+ }
68
+ };
69
+ const validateProfileRecord = (record) => {
70
+ const validation = validateSchema('profile', record);
71
+ if (validation.valid) {
72
+ return undefined;
73
+ }
74
+ return validation.issues[0];
75
+ };
76
+ const readObject = (value) => {
77
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
78
+ return undefined;
79
+ }
80
+ return value;
81
+ };
82
+ const readString = (value, fallback) => {
83
+ if (typeof value === 'string') {
84
+ return value;
85
+ }
86
+ return fallback;
87
+ };
88
+ const readOptionalString = (value) => {
89
+ if (typeof value === 'string') {
90
+ return value;
91
+ }
92
+ return undefined;
93
+ };
94
+ const readStringArray = (value) => {
95
+ if (Array.isArray(value)) {
96
+ return value.filter((item) => typeof item === 'string');
97
+ }
98
+ return [];
99
+ };
100
+ const readOptionalStringArray = (value) => {
101
+ if (Array.isArray(value)) {
102
+ return value.filter((item) => typeof item === 'string');
103
+ }
104
+ return undefined;
105
+ };
106
+ const readControls = (value) => {
107
+ const controls = readObject(value);
108
+ if (controls === undefined) {
109
+ return {};
110
+ }
111
+ return omitUndefined({
112
+ ...controls,
113
+ model: readOptionalString(controls.model),
114
+ provider: readOptionalString(controls.provider),
115
+ thinking: readOptionalString(controls.thinking),
116
+ environment: readEnvironment(controls.environment),
117
+ args: readOptionalStringArray(controls.args),
118
+ sessionDirectory: readOptionalString(controls.session_directory),
119
+ extensions: readOptionalStringArray(controls.extensions),
120
+ skills: readOptionalStringArray(controls.skills),
121
+ promptTemplate: readOptionalString(controls.prompt_template),
122
+ systemPrompt: readOptionalString(controls.system_prompt),
123
+ appendSystemPrompt: readOptionalString(controls.append_system_prompt),
124
+ pi: readAgentSpecificControls(controls.pi),
125
+ claude: readAgentSpecificControls(controls.claude),
126
+ });
127
+ };
128
+ const readAgentSpecificControls = (value) => {
129
+ const controls = readObject(value);
130
+ if (controls === undefined) {
131
+ return undefined;
132
+ }
133
+ return omitUndefined({
134
+ ...controls,
135
+ model: readOptionalString(controls.model),
136
+ provider: readOptionalString(controls.provider),
137
+ thinking: readOptionalString(controls.thinking),
138
+ environment: readEnvironment(controls.environment),
139
+ args: readOptionalStringArray(controls.args),
140
+ sessionDirectory: readOptionalString(controls.session_directory),
141
+ extensions: readOptionalStringArray(controls.extensions),
142
+ skills: readOptionalStringArray(controls.skills),
143
+ promptTemplate: readOptionalString(controls.prompt_template),
144
+ systemPrompt: readOptionalString(controls.system_prompt),
145
+ appendSystemPrompt: readOptionalString(controls.append_system_prompt),
146
+ });
147
+ };
148
+ const omitUndefined = (record) => Object.fromEntries(Object.entries(record).filter((entry) => entry[1] !== undefined));
149
+ const readStatePersistence = (value) => {
150
+ const statePersistence = readObject(value);
151
+ if (statePersistence === undefined) {
152
+ return {};
153
+ }
154
+ return Object.fromEntries(Object.entries(statePersistence).filter((entry) => typeof entry[1] === 'string'));
155
+ };
156
+ const readEnvironment = (value) => {
157
+ const environment = readObject(value);
158
+ if (environment === undefined) {
159
+ return undefined;
160
+ }
161
+ return Object.fromEntries(Object.entries(environment).filter((entry) => typeof entry[1] === 'string'));
162
+ };
163
+ export const readErrorMessage = (error) => {
164
+ if (error instanceof Error) {
165
+ return error.message;
166
+ }
167
+ return String(error);
168
+ };
169
+ //# sourceMappingURL=ProfileLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileLoader.js","sourceRoot":"","sources":["../../src/profiles/ProfileLoader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Profile } from './Profile.js';
2
+ import type { LoadedProfile } from './ProfileLoader.js';
3
+ export type NonEmptyProfileStack = readonly [Profile, ...Profile[]];
4
+ export interface ProfileResolutionInput {
5
+ /** Profiles ordered from lowest precedence to highest precedence. */
6
+ readonly profiles: readonly LoadedProfile[];
7
+ readonly profileId: string;
8
+ readonly defaultProfileId?: string;
9
+ }
10
+ export interface ProfileResolutionIssue {
11
+ readonly path: string;
12
+ readonly message: string;
13
+ }
14
+ export interface ProfileResolutionResult {
15
+ readonly profile?: Profile;
16
+ readonly profileStack: readonly Profile[];
17
+ readonly issues: readonly ProfileResolutionIssue[];
18
+ }
19
+ export declare const mergeProfileStack: (profileStack: NonEmptyProfileStack) => Profile;
20
+ export declare const resolveProfile: (input: ProfileResolutionInput) => ProfileResolutionResult;
@@ -0,0 +1,97 @@
1
+ import { mergeObjectsWithPolicy } from '../merge/SettingsValueMerger.js';
2
+ import { normalizeExtensionResourceIdentity, normalizeLaunchResourceIdentity } from '../agents/ResourceIdentity.js';
3
+ export const mergeProfileStack = (profileStack) => {
4
+ const [baseProfile, ...higherPrecedenceProfiles] = profileStack;
5
+ return higherPrecedenceProfiles.reduce((mergedProfile, profile) => mergeObjectsWithPolicy(mergedProfile, profile, { arrayPolicyForPath: profileArrayPolicy }), baseProfile);
6
+ };
7
+ const profileArrayPolicy = (path) => {
8
+ const pathKey = path.join('.');
9
+ if (pathKey === 'inherits') {
10
+ return 'replace';
11
+ }
12
+ if (['controls.args', 'controls.pi.args', 'controls.claude.args'].includes(pathKey)) {
13
+ return 'prepend';
14
+ }
15
+ if (['controls.extensions', 'controls.pi.extensions', 'controls.claude.extensions'].includes(pathKey)) {
16
+ return {
17
+ mode: 'uniqueBy',
18
+ order: 'prepend',
19
+ winner: 'first',
20
+ key: (source) => normalizeExtensionResourceIdentity(String(source)),
21
+ };
22
+ }
23
+ if (['controls.skills', 'controls.pi.skills', 'controls.claude.skills'].includes(pathKey)) {
24
+ return {
25
+ mode: 'uniqueBy',
26
+ order: 'prepend',
27
+ winner: 'first',
28
+ key: (source) => normalizeLaunchResourceIdentity(String(source)),
29
+ };
30
+ }
31
+ return undefined;
32
+ };
33
+ export const resolveProfile = (input) => {
34
+ const definitions = createProfileDefinitions(input.profiles);
35
+ const issues = [];
36
+ const explicitStack = resolveProfileStack(input.profileId, definitions, [], issues);
37
+ const defaultStack = input.defaultProfileId === undefined || input.defaultProfileId === input.profileId
38
+ ? []
39
+ : resolveProfileStack(input.defaultProfileId, definitions, [], issues);
40
+ const profileStack = uniqueProfileStack([
41
+ ...defaultStack.filter((profile) => profile.id !== input.profileId),
42
+ ...explicitStack,
43
+ ]);
44
+ return {
45
+ profile: issues.length === 0 && profileStack.length > 0
46
+ ? mergeProfileStack(profileStack)
47
+ : undefined,
48
+ profileStack,
49
+ issues,
50
+ };
51
+ };
52
+ const createProfileDefinitions = (profiles) => {
53
+ const groupedProfiles = new Map();
54
+ for (const loadedProfile of profiles) {
55
+ const profileStack = groupedProfiles.get(loadedProfile.profile.id);
56
+ groupedProfiles.set(loadedProfile.profile.id, profileStack === undefined ? [loadedProfile.profile] : [...profileStack, loadedProfile.profile]);
57
+ }
58
+ return new Map([...groupedProfiles.entries()].map(([profileId, profileStack]) => [
59
+ profileId,
60
+ mergeSameIdProfileDefinitions(profileStack),
61
+ ]));
62
+ };
63
+ const mergeSameIdProfileDefinitions = (profileStack) => {
64
+ const highestPrecedenceProfile = profileStack[profileStack.length - 1];
65
+ return {
66
+ ...mergeProfileStack(profileStack),
67
+ inherits: highestPrecedenceProfile.inherits,
68
+ };
69
+ };
70
+ const resolveProfileStack = (profileId, definitions, ancestry, issues) => {
71
+ if (ancestry.includes(profileId)) {
72
+ issues.push({
73
+ path: `/profiles/${profileId}/inherits`,
74
+ message: `Profile inheritance cycle detected: ${[...ancestry, profileId].join(' -> ')}`,
75
+ });
76
+ return [];
77
+ }
78
+ const profile = definitions.get(profileId);
79
+ if (profile === undefined) {
80
+ issues.push({ path: `/profiles/${profileId}`, message: `Profile '${profileId}' was not found.` });
81
+ return [];
82
+ }
83
+ const inheritedProfiles = profile.inherits.flatMap((inheritedProfileId) => resolveProfileStack(inheritedProfileId, definitions, [...ancestry, profileId], issues));
84
+ return uniqueProfileStack([...inheritedProfiles, profile]);
85
+ };
86
+ const uniqueProfileStack = (profileStack) => {
87
+ const profilesById = new Set();
88
+ const uniqueProfiles = [];
89
+ for (const profile of profileStack) {
90
+ if (!profilesById.has(profile.id)) {
91
+ profilesById.add(profile.id);
92
+ uniqueProfiles.push(profile);
93
+ }
94
+ }
95
+ return uniqueProfiles;
96
+ };
97
+ //# sourceMappingURL=ProfileMerger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileMerger.js","sourceRoot":"","sources":["../../src/profiles/ProfileMerger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ interface ProfileSourceFilters {
2
+ readonly only?: readonly string[];
3
+ readonly except?: readonly string[];
4
+ }
5
+ export type RemoteSourceReference = {
6
+ readonly uri: string;
7
+ readonly github?: never;
8
+ readonly ref?: string;
9
+ readonly path?: string;
10
+ } | {
11
+ readonly github: string;
12
+ readonly uri?: never;
13
+ readonly ref?: string;
14
+ readonly path?: string;
15
+ };
16
+ export type ProfileSourceReference = (ProfileSourceFilters & {
17
+ readonly path: string;
18
+ readonly uri?: never;
19
+ readonly github?: never;
20
+ readonly ref?: never;
21
+ }) | (ProfileSourceFilters & {
22
+ readonly uri: string;
23
+ readonly github?: never;
24
+ readonly ref?: string;
25
+ readonly path?: string;
26
+ }) | (ProfileSourceFilters & {
27
+ readonly github: string;
28
+ readonly uri?: never;
29
+ readonly ref?: string;
30
+ readonly path?: string;
31
+ });
32
+ export declare const createLocalProfileSource: (path: string) => ProfileSourceReference;
33
+ export declare const createUriProfileSource: (uri: string) => ProfileSourceReference;
34
+ export declare const normalizeRemoteSourceUri: (source: RemoteSourceReference) => string;
35
+ export {};
@@ -0,0 +1,13 @@
1
+ export const createLocalProfileSource = (path) => ({
2
+ path,
3
+ });
4
+ export const createUriProfileSource = (uri) => ({
5
+ uri,
6
+ });
7
+ export const normalizeRemoteSourceUri = (source) => {
8
+ if (source.uri !== undefined) {
9
+ return source.uri;
10
+ }
11
+ return `git+https://github.com/${source.github}.git`;
12
+ };
13
+ //# sourceMappingURL=ProfileSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileSource.js","sourceRoot":"","sources":["../../src/profiles/ProfileSource.ts"],"names":[],"mappings":"AA8BA,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,IAAY,EAA0B,EAAE,CAAC,CAAC;IACjF,IAAI;CACL,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAA0B,EAAE,CAAC,CAAC;IAC9E,GAAG;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAA6B,EAAU,EAAE;IAChF,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,GAAG,CAAC;IACpB,CAAC;IAED,OAAO,0BAA0B,MAAM,CAAC,MAAM,MAAM,CAAC;AACvD,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://outfitter.dev/schemas/profile-source.schema.json",
4
+ "title": "Outfitter profile source",
5
+ "type": "object",
6
+ "oneOf": [
7
+ {
8
+ "required": ["path"],
9
+ "not": { "anyOf": [{ "required": ["uri"] }, { "required": ["github"] }, { "required": ["ref"] }] }
10
+ },
11
+ { "required": ["uri"], "not": { "required": ["github"] } },
12
+ { "required": ["github"], "not": { "required": ["uri"] } }
13
+ ],
14
+ "properties": {
15
+ "path": { "type": "string", "minLength": 1 },
16
+ "uri": { "type": "string", "minLength": 1 },
17
+ "github": { "type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" },
18
+ "ref": { "type": "string", "minLength": 1 },
19
+ "only": {
20
+ "type": "array",
21
+ "items": { "type": "string", "minLength": 1 }
22
+ },
23
+ "except": {
24
+ "type": "array",
25
+ "items": { "type": "string", "minLength": 1 }
26
+ }
27
+ },
28
+ "additionalProperties": false
29
+ }