pi-model-profiles 0.3.2 → 0.3.4

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.
@@ -1,105 +1,105 @@
1
- import { multiProfilesDebugLogger } from "./debug-logger.js";
2
- import { loadMultiProfilesConfig, saveMultiProfilesConfig } from "./config.js";
3
- import type { ProfileSortResult, ProfilesFile, SavedProfile } from "./types.js";
4
- import type { ProfileSortOrder } from "./types.js";
5
-
6
- /**
7
- * Compare two profile names using locale-aware string comparison.
8
- */
9
- function compareByName(left: SavedProfile, right: SavedProfile): number {
10
- return left.name.localeCompare(right.name);
11
- }
12
-
13
- /**
14
- * Compare two profiles by their createdAt timestamp.
15
- */
16
- function compareByDate(left: SavedProfile, right: SavedProfile): number {
17
- const leftDate = new Date(left.createdAt).getTime();
18
- const rightDate = new Date(right.createdAt).getTime();
19
- return leftDate - rightDate;
20
- }
21
-
22
- /**
23
- * Sort profiles based on the specified order.
24
- * Returns a new array (immutable pattern), preserving the original data.profiles.
25
- *
26
- * @param data - The profiles file containing the profiles array
27
- * @param order - The sort order to apply
28
- * @returns ProfileSortResult with sorted profiles and applied sort order
29
- */
30
- export function sortProfiles(data: ProfilesFile, order: ProfileSortOrder): ProfileSortResult {
31
- const comparator = getSortComparator(order);
32
- const sortedProfiles = [...data.profiles].sort(comparator);
33
-
34
- return {
35
- sortedProfiles,
36
- sortOrder: order,
37
- };
38
- }
39
-
40
- /**
41
- * Get the comparator function for a given sort order.
42
- */
43
- function getSortComparator(order: ProfileSortOrder): (left: SavedProfile, right: SavedProfile) => number {
44
- switch (order) {
45
- case "name-asc":
46
- return compareByName;
47
- case "name-desc":
48
- return (left, right) => compareByName(right, left);
49
- case "date-asc":
50
- return compareByDate;
51
- case "date-desc":
52
- return (left, right) => compareByDate(right, left);
53
- }
54
- }
55
-
56
- /**
57
- * Get the current sort order from config.
58
- */
59
- export function getCurrentSortOrder(): ProfileSortOrder {
60
- const result = loadMultiProfilesConfig();
61
- return result.config.sorting.defaultSort;
62
- }
63
-
64
- /**
65
- * Persist the sort order to config.
66
- */
67
- export function persistSortOrder(order: ProfileSortOrder): void {
68
- const result = loadMultiProfilesConfig();
69
- const config = result.config;
70
- config.sorting.defaultSort = order;
71
- saveMultiProfilesConfig(config);
72
-
73
- multiProfilesDebugLogger.log("config", {
74
- event: "sort_order_persisted",
75
- order,
76
- });
77
- }
78
-
79
- /**
80
- * Get display label for a sort order.
81
- */
82
- export function getSortOrderLabel(order: ProfileSortOrder): string {
83
- switch (order) {
84
- case "name-asc":
85
- return "Name (A-Z)";
86
- case "name-desc":
87
- return "Name (Z-A)";
88
- case "date-asc":
89
- return "Date (Oldest)";
90
- case "date-desc":
91
- return "Date (Newest)";
92
- }
93
- }
94
-
95
- /**
96
- * Get all available sort orders with their labels.
97
- */
98
- export function getAvailableSortOrders(): Array<{ order: ProfileSortOrder; label: string }> {
99
- return [
100
- { order: "name-asc", label: "Name (A-Z)" },
101
- { order: "name-desc", label: "Name (Z-A)" },
102
- { order: "date-asc", label: "Date (Oldest)" },
103
- { order: "date-desc", label: "Date (Newest)" },
104
- ];
105
- }
1
+ import { multiProfilesDebugLogger } from "./debug-logger.js";
2
+ import { loadMultiProfilesConfig, saveMultiProfilesConfig } from "./config.js";
3
+ import type { ProfileSortResult, ProfilesFile, SavedProfile } from "./types.js";
4
+ import type { ProfileSortOrder } from "./types.js";
5
+
6
+ /**
7
+ * Compare two profile names using locale-aware string comparison.
8
+ */
9
+ function compareByName(left: SavedProfile, right: SavedProfile): number {
10
+ return left.name.localeCompare(right.name);
11
+ }
12
+
13
+ /**
14
+ * Compare two profiles by their createdAt timestamp.
15
+ */
16
+ function compareByDate(left: SavedProfile, right: SavedProfile): number {
17
+ const leftDate = new Date(left.createdAt).getTime();
18
+ const rightDate = new Date(right.createdAt).getTime();
19
+ return leftDate - rightDate;
20
+ }
21
+
22
+ /**
23
+ * Sort profiles based on the specified order.
24
+ * Returns a new array (immutable pattern), preserving the original data.profiles.
25
+ *
26
+ * @param data - The profiles file containing the profiles array
27
+ * @param order - The sort order to apply
28
+ * @returns ProfileSortResult with sorted profiles and applied sort order
29
+ */
30
+ export function sortProfiles(data: ProfilesFile, order: ProfileSortOrder): ProfileSortResult {
31
+ const comparator = getSortComparator(order);
32
+ const sortedProfiles = [...data.profiles].sort(comparator);
33
+
34
+ return {
35
+ sortedProfiles,
36
+ sortOrder: order,
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Get the comparator function for a given sort order.
42
+ */
43
+ function getSortComparator(order: ProfileSortOrder): (left: SavedProfile, right: SavedProfile) => number {
44
+ switch (order) {
45
+ case "name-asc":
46
+ return compareByName;
47
+ case "name-desc":
48
+ return (left, right) => compareByName(right, left);
49
+ case "date-asc":
50
+ return compareByDate;
51
+ case "date-desc":
52
+ return (left, right) => compareByDate(right, left);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Get the current sort order from config.
58
+ */
59
+ export function getCurrentSortOrder(): ProfileSortOrder {
60
+ const result = loadMultiProfilesConfig();
61
+ return result.config.sorting.defaultSort;
62
+ }
63
+
64
+ /**
65
+ * Persist the sort order to config.
66
+ */
67
+ export function persistSortOrder(order: ProfileSortOrder): void {
68
+ const result = loadMultiProfilesConfig();
69
+ const config = result.config;
70
+ config.sorting.defaultSort = order;
71
+ saveMultiProfilesConfig(config);
72
+
73
+ multiProfilesDebugLogger.log("config", {
74
+ event: "sort_order_persisted",
75
+ order,
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Get display label for a sort order.
81
+ */
82
+ export function getSortOrderLabel(order: ProfileSortOrder): string {
83
+ switch (order) {
84
+ case "name-asc":
85
+ return "Name (A-Z)";
86
+ case "name-desc":
87
+ return "Name (Z-A)";
88
+ case "date-asc":
89
+ return "Date (Oldest)";
90
+ case "date-desc":
91
+ return "Date (Newest)";
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Get all available sort orders with their labels.
97
+ */
98
+ export function getAvailableSortOrders(): Array<{ order: ProfileSortOrder; label: string }> {
99
+ return [
100
+ { order: "name-asc", label: "Name (A-Z)" },
101
+ { order: "name-desc", label: "Name (Z-A)" },
102
+ { order: "date-asc", label: "Date (Oldest)" },
103
+ { order: "date-desc", label: "Date (Newest)" },
104
+ ];
105
+ }
@@ -1,134 +1,134 @@
1
- import { multiProfilesDebugLogger } from "./debug-logger.js";
2
- import { ModelProfilesError } from "./errors.js";
3
- import { captureAgentSnapshots, type AgentSelectionOptions } from "./agent-writer.js";
4
- import type { ProfilesFile, ProfileUpdateResult, SavedProfile } from "./types.js";
5
-
6
- /**
7
- * Error code for profile not found during update.
8
- */
9
- export const PROFILE_NOT_FOUND_CODE = "PROFILE_NOT_FOUND";
10
-
11
- export interface ProfileUpdateDataResult {
12
- data: ProfilesFile;
13
- result: ProfileUpdateResult;
14
- }
15
-
16
- interface ProfileUpdatePlan {
17
- updatedData: ProfilesFile;
18
- updatedProfile: SavedProfile;
19
- previousProfile: SavedProfile;
20
- result: ProfileUpdateResult;
21
- }
22
-
23
- function createProfileNotFoundError(profileId: string): ModelProfilesError {
24
- return new ModelProfilesError(
25
- `Profile '${profileId}' not found. It may have been removed already.`,
26
- PROFILE_NOT_FOUND_CODE,
27
- );
28
- }
29
-
30
- function buildUpdatePlan(
31
- data: ProfilesFile,
32
- profileId: string,
33
- agentOptions: AgentSelectionOptions,
34
- ): ProfileUpdatePlan {
35
- const profileIndex = data.profiles.findIndex((profile) => profile.id === profileId);
36
- const profile = data.profiles[profileIndex];
37
-
38
- if (profileIndex === -1 || !profile) {
39
- multiProfilesDebugLogger.log("profile-update", {
40
- event: "update_failed",
41
- profileId,
42
- reason: "profile_not_found",
43
- profileCount: data.profiles.length,
44
- });
45
- throw createProfileNotFoundError(profileId);
46
- }
47
-
48
- const snapshot = captureAgentSnapshots(agentOptions);
49
- const updatedProfile: SavedProfile = {
50
- id: profile.id,
51
- name: profile.name,
52
- agents: snapshot.agents,
53
- createdAt: profile.createdAt,
54
- updatedAt: new Date().toISOString(),
55
- };
56
- const updatedProfiles = [
57
- ...data.profiles.slice(0, profileIndex),
58
- updatedProfile,
59
- ...data.profiles.slice(profileIndex + 1),
60
- ];
61
-
62
- return {
63
- updatedData: {
64
- version: data.version,
65
- importedAt: data.importedAt,
66
- profiles: updatedProfiles,
67
- },
68
- updatedProfile,
69
- previousProfile: profile,
70
- result: {
71
- updatedProfileId: profile.id,
72
- updatedProfileName: profile.name,
73
- updatedAgents: snapshot.agents.length,
74
- warnings: snapshot.warnings,
75
- },
76
- };
77
- }
78
-
79
- function logProfileUpdated(plan: ProfileUpdatePlan): void {
80
- multiProfilesDebugLogger.log("profile-update", {
81
- event: "profile_updated",
82
- profileId: plan.updatedProfile.id,
83
- profileName: plan.updatedProfile.name,
84
- beforeAgentCount: plan.previousProfile.agents.length,
85
- afterAgentCount: plan.updatedProfile.agents.length,
86
- warnings: plan.result.warnings,
87
- });
88
- }
89
-
90
- /**
91
- * Update a profile with the current agent state.
92
- *
93
- * Captures the current agent snapshots and replaces the profile's agents array.
94
- * Preserves profile.id, profile.name, and profile.createdAt.
95
- * Updates profile.updatedAt timestamp to current time.
96
- * Logs update event with before/after agent counts via debug logger.
97
- *
98
- * @param data - The profiles file data
99
- * @param profileId - The ID of the profile to update
100
- * @param agentOptions - Options for capturing agent snapshots
101
- * @returns ProfileUpdateResult with updated profile info and agent counts
102
- * @throws ModelProfilesError with code PROFILE_NOT_FOUND if profile doesn't exist
103
- */
104
- export function updateProfile(
105
- data: ProfilesFile,
106
- profileId: string,
107
- agentOptions: AgentSelectionOptions,
108
- ): ProfileUpdateResult {
109
- const plan = buildUpdatePlan(data, profileId, agentOptions);
110
- logProfileUpdated(plan);
111
- return plan.result;
112
- }
113
-
114
- /**
115
- * Update a profile and return the updated profiles file with update metadata.
116
- *
117
- * @param data - The profiles file data
118
- * @param profileId - The ID of the profile to update
119
- * @param agentOptions - Options for capturing agent snapshots
120
- * @returns New ProfilesFile with the profile updated and update metadata
121
- * @throws ModelProfilesError with code PROFILE_NOT_FOUND if profile doesn't exist
122
- */
123
- export function updateProfileAndReturn(
124
- data: ProfilesFile,
125
- profileId: string,
126
- agentOptions: AgentSelectionOptions,
127
- ): ProfileUpdateDataResult {
128
- const plan = buildUpdatePlan(data, profileId, agentOptions);
129
- logProfileUpdated(plan);
130
- return {
131
- data: plan.updatedData,
132
- result: plan.result,
133
- };
134
- }
1
+ import { multiProfilesDebugLogger } from "./debug-logger.js";
2
+ import { ModelProfilesError } from "./errors.js";
3
+ import { captureAgentSnapshots, type AgentSelectionOptions } from "./agent-writer.js";
4
+ import type { ProfilesFile, ProfileUpdateResult, SavedProfile } from "./types.js";
5
+
6
+ /**
7
+ * Error code for profile not found during update.
8
+ */
9
+ export const PROFILE_NOT_FOUND_CODE = "PROFILE_NOT_FOUND";
10
+
11
+ export interface ProfileUpdateDataResult {
12
+ data: ProfilesFile;
13
+ result: ProfileUpdateResult;
14
+ }
15
+
16
+ interface ProfileUpdatePlan {
17
+ updatedData: ProfilesFile;
18
+ updatedProfile: SavedProfile;
19
+ previousProfile: SavedProfile;
20
+ result: ProfileUpdateResult;
21
+ }
22
+
23
+ function createProfileNotFoundError(profileId: string): ModelProfilesError {
24
+ return new ModelProfilesError(
25
+ `Profile '${profileId}' not found. It may have been removed already.`,
26
+ PROFILE_NOT_FOUND_CODE,
27
+ );
28
+ }
29
+
30
+ function buildUpdatePlan(
31
+ data: ProfilesFile,
32
+ profileId: string,
33
+ agentOptions: AgentSelectionOptions,
34
+ ): ProfileUpdatePlan {
35
+ const profileIndex = data.profiles.findIndex((profile) => profile.id === profileId);
36
+ const profile = data.profiles[profileIndex];
37
+
38
+ if (profileIndex === -1 || !profile) {
39
+ multiProfilesDebugLogger.log("profile-update", {
40
+ event: "update_failed",
41
+ profileId,
42
+ reason: "profile_not_found",
43
+ profileCount: data.profiles.length,
44
+ });
45
+ throw createProfileNotFoundError(profileId);
46
+ }
47
+
48
+ const snapshot = captureAgentSnapshots(agentOptions);
49
+ const updatedProfile: SavedProfile = {
50
+ id: profile.id,
51
+ name: profile.name,
52
+ agents: snapshot.agents,
53
+ createdAt: profile.createdAt,
54
+ updatedAt: new Date().toISOString(),
55
+ };
56
+ const updatedProfiles = [
57
+ ...data.profiles.slice(0, profileIndex),
58
+ updatedProfile,
59
+ ...data.profiles.slice(profileIndex + 1),
60
+ ];
61
+
62
+ return {
63
+ updatedData: {
64
+ version: data.version,
65
+ importedAt: data.importedAt,
66
+ profiles: updatedProfiles,
67
+ },
68
+ updatedProfile,
69
+ previousProfile: profile,
70
+ result: {
71
+ updatedProfileId: profile.id,
72
+ updatedProfileName: profile.name,
73
+ updatedAgents: snapshot.agents.length,
74
+ warnings: snapshot.warnings,
75
+ },
76
+ };
77
+ }
78
+
79
+ function logProfileUpdated(plan: ProfileUpdatePlan): void {
80
+ multiProfilesDebugLogger.log("profile-update", {
81
+ event: "profile_updated",
82
+ profileId: plan.updatedProfile.id,
83
+ profileName: plan.updatedProfile.name,
84
+ beforeAgentCount: plan.previousProfile.agents.length,
85
+ afterAgentCount: plan.updatedProfile.agents.length,
86
+ warnings: plan.result.warnings,
87
+ });
88
+ }
89
+
90
+ /**
91
+ * Update a profile with the current agent state.
92
+ *
93
+ * Captures the current agent snapshots and replaces the profile's agents array.
94
+ * Preserves profile.id, profile.name, and profile.createdAt.
95
+ * Updates profile.updatedAt timestamp to current time.
96
+ * Logs update event with before/after agent counts via debug logger.
97
+ *
98
+ * @param data - The profiles file data
99
+ * @param profileId - The ID of the profile to update
100
+ * @param agentOptions - Options for capturing agent snapshots
101
+ * @returns ProfileUpdateResult with updated profile info and agent counts
102
+ * @throws ModelProfilesError with code PROFILE_NOT_FOUND if profile doesn't exist
103
+ */
104
+ export function updateProfile(
105
+ data: ProfilesFile,
106
+ profileId: string,
107
+ agentOptions: AgentSelectionOptions,
108
+ ): ProfileUpdateResult {
109
+ const plan = buildUpdatePlan(data, profileId, agentOptions);
110
+ logProfileUpdated(plan);
111
+ return plan.result;
112
+ }
113
+
114
+ /**
115
+ * Update a profile and return the updated profiles file with update metadata.
116
+ *
117
+ * @param data - The profiles file data
118
+ * @param profileId - The ID of the profile to update
119
+ * @param agentOptions - Options for capturing agent snapshots
120
+ * @returns New ProfilesFile with the profile updated and update metadata
121
+ * @throws ModelProfilesError with code PROFILE_NOT_FOUND if profile doesn't exist
122
+ */
123
+ export function updateProfileAndReturn(
124
+ data: ProfilesFile,
125
+ profileId: string,
126
+ agentOptions: AgentSelectionOptions,
127
+ ): ProfileUpdateDataResult {
128
+ const plan = buildUpdatePlan(data, profileId, agentOptions);
129
+ logProfileUpdated(plan);
130
+ return {
131
+ data: plan.updatedData,
132
+ result: plan.result,
133
+ };
134
+ }