pi-model-profiles 0.3.1 → 0.3.3
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/CHANGELOG.md +59 -48
- package/package.json +66 -66
- package/src/command-handler.ts +137 -0
- package/src/errors.ts +2 -0
- package/src/import-service.ts +60 -60
- package/src/index.ts +36 -158
- package/src/profile-removal-service.ts +106 -106
- package/src/profile-sort-service.ts +105 -105
- package/src/profile-update-service.ts +134 -134
package/CHANGELOG.md
CHANGED
|
@@ -1,48 +1,59 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [Unreleased]
|
|
9
|
-
|
|
10
|
-
## [0.3.
|
|
11
|
-
|
|
12
|
-
### Changed
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.3] - 2026-06-01
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Lazy-loaded the model profiles command handler by extracting it into `src/command-handler.ts`, reducing startup work.
|
|
14
|
+
- Widened Pi peer dependency compatibility to include Pi 0.77.x and 0.78.x.
|
|
15
|
+
|
|
16
|
+
## [0.3.2] - 2026-05-26
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Widened peer dependency ranges to `^0.74.0 || ^0.75.0`.
|
|
20
|
+
|
|
21
|
+
## [0.3.1] - 2026-05-22
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Reworked debug logging to redact sensitive values and use asynchronous buffered file writes with safe shutdown.
|
|
25
|
+
- Updated Pi peer dependencies and runtime imports to the `@earendil-works` scope.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Improved debug log writer lifecycle handling so buffered events flush reliably without opening logs when debug is disabled.
|
|
29
|
+
|
|
30
|
+
## [0.3.0] - 2026-04-30
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- Refined the model profiles modal layout with wider sizing, a single bordered grid, and clearer model table columns.
|
|
34
|
+
- Updated the public README screenshot and usage details.
|
|
35
|
+
- Bumped Pi peer dependency ranges to `^0.70.6`.
|
|
36
|
+
|
|
37
|
+
## [0.2.0] - 2026-04-26
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- Phase 6: Git & publishing preparation.
|
|
41
|
+
- NPM package metadata, README, CHANGELOG, LICENSE, and package ignore rules.
|
|
42
|
+
- Profile update, removal, persisted sorting, configuration, and file-gated debug logging.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- Confirmation prompts now accept typed input before update or removal actions run.
|
|
46
|
+
- Sort menu keyboard handling now works consistently and closes without exiting the modal.
|
|
47
|
+
- Profile update and removal command handlers now avoid duplicate scans and duplicate removal events.
|
|
48
|
+
|
|
49
|
+
## [0.1.0] - 2026-04-25
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
- Initial extension structure
|
|
53
|
+
- Core profile management functionality
|
|
54
|
+
- Frontmatter parser implementation
|
|
55
|
+
- Profile store with atomic writes
|
|
56
|
+
- Import service for external profiles
|
|
57
|
+
- Agent writer for profile application
|
|
58
|
+
- Type definitions and error handling
|
|
59
|
+
- Test suite for core functionality
|
package/package.json
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-model-profiles",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Pi extension for saving, importing, and applying agent model frontmatter profiles.",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./index.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./index.ts"
|
|
10
|
-
},
|
|
11
|
-
"files": [
|
|
12
|
-
"index.ts",
|
|
13
|
-
"src",
|
|
14
|
-
"README.md",
|
|
15
|
-
"CHANGELOG.md",
|
|
16
|
-
"config/config.example.json",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "npx --yes -p typescript@5.9.2 tsc -p tsconfig.json",
|
|
21
|
-
"lint": "npm run build",
|
|
22
|
-
"test:clean": "node -e \"require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
|
|
23
|
-
"prepublishOnly": "npm run test",
|
|
24
|
-
"pretest": "npm run test:clean",
|
|
25
|
-
"test": "npx --yes -p typescript@5.9.2 tsc --strict --skipLibCheck --module nodenext --moduleResolution nodenext --target ES2022 --outDir .test-dist src/types-shims.d.ts src/errors.ts src/types.ts src/constants.ts src/atomic-write.ts src/profile-fields.ts src/frontmatter-parser.ts src/profile-store.ts src/agent-writer.ts src/import-service.ts src/config.ts src/debug-logger.ts test/frontmatter-parser.test.ts test/import-service.test.ts test/agent-writer.test.ts test/profile-store.test.ts test/debug-logger.test.ts && node --test .test-dist/test/frontmatter-parser.test.js .test-dist/test/import-service.test.js .test-dist/test/agent-writer.test.js .test-dist/test/profile-store.test.js .test-dist/test/debug-logger.test.js",
|
|
26
|
-
"posttest": "npm run test:clean",
|
|
27
|
-
"check": "npm run build && npm run test",
|
|
28
|
-
"package:dry-run": "npm pack --dry-run"
|
|
29
|
-
},
|
|
30
|
-
"keywords": [
|
|
31
|
-
"pi-package",
|
|
32
|
-
"pi",
|
|
33
|
-
"pi-extension",
|
|
34
|
-
"pi-coding-agent",
|
|
35
|
-
"coding-agent",
|
|
36
|
-
"model-profiles",
|
|
37
|
-
"frontmatter",
|
|
38
|
-
"agent-configuration",
|
|
39
|
-
"profiles"
|
|
40
|
-
],
|
|
41
|
-
"author": "MasuRii",
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"homepage": "https://github.com/MasuRii/pi-model-profiles#readme",
|
|
44
|
-
"repository": {
|
|
45
|
-
"type": "git",
|
|
46
|
-
"url": "git+https://github.com/MasuRii/pi-model-profiles.git"
|
|
47
|
-
},
|
|
48
|
-
"bugs": {
|
|
49
|
-
"url": "https://github.com/MasuRii/pi-model-profiles/issues"
|
|
50
|
-
},
|
|
51
|
-
"engines": {
|
|
52
|
-
"node": ">=20"
|
|
53
|
-
},
|
|
54
|
-
"pi": {
|
|
55
|
-
"extensions": [
|
|
56
|
-
"./index.ts"
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
"peerDependencies": {
|
|
60
|
-
"@earendil-works/pi-coding-agent": "^0.75.
|
|
61
|
-
"@earendil-works/pi-tui": "^0.75.
|
|
62
|
-
},
|
|
63
|
-
"publishConfig": {
|
|
64
|
-
"access": "public"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-model-profiles",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Pi extension for saving, importing, and applying agent model frontmatter profiles.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.ts"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"index.ts",
|
|
13
|
+
"src",
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"config/config.example.json",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "npx --yes -p typescript@5.9.2 tsc -p tsconfig.json",
|
|
21
|
+
"lint": "npm run build",
|
|
22
|
+
"test:clean": "node -e \"require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
|
|
23
|
+
"prepublishOnly": "npm run test",
|
|
24
|
+
"pretest": "npm run test:clean",
|
|
25
|
+
"test": "npx --yes -p typescript@5.9.2 tsc --strict --skipLibCheck --module nodenext --moduleResolution nodenext --target ES2022 --outDir .test-dist src/types-shims.d.ts src/errors.ts src/types.ts src/constants.ts src/atomic-write.ts src/profile-fields.ts src/frontmatter-parser.ts src/profile-store.ts src/agent-writer.ts src/import-service.ts src/config.ts src/debug-logger.ts test/frontmatter-parser.test.ts test/import-service.test.ts test/agent-writer.test.ts test/profile-store.test.ts test/debug-logger.test.ts && node --test .test-dist/test/frontmatter-parser.test.js .test-dist/test/import-service.test.js .test-dist/test/agent-writer.test.js .test-dist/test/profile-store.test.js .test-dist/test/debug-logger.test.js",
|
|
26
|
+
"posttest": "npm run test:clean",
|
|
27
|
+
"check": "npm run build && npm run test",
|
|
28
|
+
"package:dry-run": "npm pack --dry-run"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"pi-package",
|
|
32
|
+
"pi",
|
|
33
|
+
"pi-extension",
|
|
34
|
+
"pi-coding-agent",
|
|
35
|
+
"coding-agent",
|
|
36
|
+
"model-profiles",
|
|
37
|
+
"frontmatter",
|
|
38
|
+
"agent-configuration",
|
|
39
|
+
"profiles"
|
|
40
|
+
],
|
|
41
|
+
"author": "MasuRii",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"homepage": "https://github.com/MasuRii/pi-model-profiles#readme",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/MasuRii/pi-model-profiles.git"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/MasuRii/pi-model-profiles/issues"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20"
|
|
53
|
+
},
|
|
54
|
+
"pi": {
|
|
55
|
+
"extensions": [
|
|
56
|
+
"./index.ts"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0",
|
|
61
|
+
"@earendil-works/pi-tui": "^0.74.0 || ^0.75.0 || ^0.77.0 || ^0.78.0"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
INITIAL_PROFILE_NAME,
|
|
5
|
+
PROFILE_NAME_SUFFIX,
|
|
6
|
+
PROFILE_STORE_PATH,
|
|
7
|
+
} from "./constants.js";
|
|
8
|
+
import { applySavedProfile, captureAgentSnapshots, detectActiveAgentName } from "./agent-writer.js";
|
|
9
|
+
import { toErrorMessage } from "./errors.js";
|
|
10
|
+
import { loadAndPrepareProfiles } from "./import-service.js";
|
|
11
|
+
import { updateProfileAndReturn } from "./profile-update-service.js";
|
|
12
|
+
import {
|
|
13
|
+
appendProfile,
|
|
14
|
+
createProfile,
|
|
15
|
+
findProfileById,
|
|
16
|
+
renameStoredProfile,
|
|
17
|
+
resolveUniqueProfileName,
|
|
18
|
+
saveProfilesFile,
|
|
19
|
+
} from "./profile-store.js";
|
|
20
|
+
import { removeProfileAndUpdate } from "./profile-removal-service.js";
|
|
21
|
+
import { openProfilesModal, type ProfileModalResult } from "./profile-modal.js";
|
|
22
|
+
import type { AppliedProfileOutcome, ProfilesFile } from "./types.js";
|
|
23
|
+
|
|
24
|
+
function buildCurrentProfileName(activeAgentName: string | null, data: ProfilesFile): string {
|
|
25
|
+
const baseName = activeAgentName ? `${activeAgentName} ${PROFILE_NAME_SUFFIX}` : INITIAL_PROFILE_NAME;
|
|
26
|
+
return resolveUniqueProfileName(baseName, data.profiles);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function notifyWarnings(ctx: ExtensionCommandContext, warnings: readonly string[]): void {
|
|
30
|
+
if (warnings.length === 0) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
ctx.ui.notify(warnings.join(" "), "warning");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function summarizeApplyOutcome(outcome: AppliedProfileOutcome): string {
|
|
37
|
+
const appliedCount = outcome.appliedAgents.length;
|
|
38
|
+
const missingCount = outcome.missingAgents.length;
|
|
39
|
+
const appliedLabel = `${appliedCount} agent file${appliedCount === 1 ? "" : "s"}`;
|
|
40
|
+
if (missingCount === 0) {
|
|
41
|
+
return appliedLabel;
|
|
42
|
+
}
|
|
43
|
+
return `${appliedLabel}; ${missingCount} missing`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function reloadAfterApply(ctx: ExtensionCommandContext, outcome: AppliedProfileOutcome): Promise<void> {
|
|
47
|
+
const summary = summarizeApplyOutcome(outcome);
|
|
48
|
+
ctx.ui.notify(`Profile '${outcome.profileName}' applied across ${summary}. Reloading…`, "info");
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await ctx.reload();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
ctx.ui.notify(
|
|
54
|
+
`Profile '${outcome.profileName}' applied across ${summary}, but automatic reload failed: ${toErrorMessage(error)}. Run /reload.`,
|
|
55
|
+
"error",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function handleModelProfilesCommand(ctx: ExtensionCommandContext): Promise<void> {
|
|
61
|
+
const agentOptions = { cwd: ctx.cwd, scope: "both" as const };
|
|
62
|
+
const prepared = loadAndPrepareProfiles(PROFILE_STORE_PATH, agentOptions);
|
|
63
|
+
notifyWarnings(ctx, prepared.warnings);
|
|
64
|
+
|
|
65
|
+
let data = prepared.data;
|
|
66
|
+
const activeAgentName = detectActiveAgentName(ctx.sessionManager, ctx.getSystemPrompt());
|
|
67
|
+
|
|
68
|
+
const result: ProfileModalResult = await openProfilesModal(ctx, data, activeAgentName, {
|
|
69
|
+
renameProfile: async (profileId, nextName) => {
|
|
70
|
+
data = renameStoredProfile(data, profileId, nextName);
|
|
71
|
+
saveProfilesFile(data, PROFILE_STORE_PATH);
|
|
72
|
+
return {
|
|
73
|
+
data,
|
|
74
|
+
message: `Renamed saved snapshot to '${nextName.trim()}'.`,
|
|
75
|
+
selectedProfileId: profileId,
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
addCurrentProfile: async () => {
|
|
79
|
+
const snapshot = captureAgentSnapshots(agentOptions);
|
|
80
|
+
notifyWarnings(ctx, snapshot.warnings);
|
|
81
|
+
const profile = createProfile(buildCurrentProfileName(activeAgentName, data), snapshot.agents);
|
|
82
|
+
data = appendProfile(data, profile);
|
|
83
|
+
saveProfilesFile(data, PROFILE_STORE_PATH);
|
|
84
|
+
return {
|
|
85
|
+
data,
|
|
86
|
+
message: `Saved current agents snapshot (${snapshot.agents.length} agents).`,
|
|
87
|
+
selectedProfileId: profile.id,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
applyProfile: async (profileId) => {
|
|
91
|
+
const profile = findProfileById(data, profileId);
|
|
92
|
+
if (!profile) {
|
|
93
|
+
throw new Error(`Saved profile '${profileId}' was not found.`);
|
|
94
|
+
}
|
|
95
|
+
const applied = applySavedProfile(profile, agentOptions);
|
|
96
|
+
notifyWarnings(ctx, applied.warnings);
|
|
97
|
+
return {
|
|
98
|
+
...applied,
|
|
99
|
+
profileName: profile.name,
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
removeProfile: async (profileId) => {
|
|
103
|
+
const profile = findProfileById(data, profileId);
|
|
104
|
+
if (!profile) {
|
|
105
|
+
throw new Error(`Saved profile '${profileId}' was not found.`);
|
|
106
|
+
}
|
|
107
|
+
const removal = removeProfileAndUpdate(data, profileId);
|
|
108
|
+
data = removal.data;
|
|
109
|
+
saveProfilesFile(data, PROFILE_STORE_PATH);
|
|
110
|
+
return {
|
|
111
|
+
data,
|
|
112
|
+
message: `Removed saved snapshot '${removal.result.removedProfileName}' (${removal.result.remainingCount} snapshots remaining).`,
|
|
113
|
+
selectedProfileId: data.profiles[0]?.id,
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
updateProfile: async (profileId) => {
|
|
117
|
+
const profile = findProfileById(data, profileId);
|
|
118
|
+
if (!profile) {
|
|
119
|
+
throw new Error(`Saved profile '${profileId}' was not found.`);
|
|
120
|
+
}
|
|
121
|
+
const update = updateProfileAndReturn(data, profileId, agentOptions);
|
|
122
|
+
notifyWarnings(ctx, update.result.warnings);
|
|
123
|
+
data = update.data;
|
|
124
|
+
saveProfilesFile(data, PROFILE_STORE_PATH);
|
|
125
|
+
return {
|
|
126
|
+
data,
|
|
127
|
+
message: `Updated '${profile.name}' with current agent state (${update.result.updatedAgents} agents).`,
|
|
128
|
+
selectedProfileId: profileId,
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (result.type === "applied") {
|
|
134
|
+
await reloadAfterApply(ctx, result.outcome);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/errors.ts
CHANGED
package/src/import-service.ts
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { AGENTS_DIR, INITIAL_PROFILE_NAME, PROFILE_STORE_PATH } from "./constants.js";
|
|
2
|
-
import { captureAgentSnapshots, type AgentSelectionOptions } from "./agent-writer.js";
|
|
3
|
-
import { appendProfile, createProfile, loadProfilesFile, resolveUniqueProfileName, saveProfilesFile } from "./profile-store.js";
|
|
4
|
-
import { loadMultiProfilesConfig } from "./config.js";
|
|
5
|
-
import { multiProfilesDebugLogger } from "./debug-logger.js";
|
|
6
|
-
import type { ImportProfilesResult, ProfilesFile } from "./types.js";
|
|
7
|
-
|
|
8
|
-
export function ensureProfilesImported(
|
|
9
|
-
data: ProfilesFile,
|
|
10
|
-
agentOptions: string | AgentSelectionOptions = AGENTS_DIR,
|
|
11
|
-
): ImportProfilesResult {
|
|
12
|
-
if (data.importedAt) {
|
|
13
|
-
return {
|
|
14
|
-
data,
|
|
15
|
-
imported: false,
|
|
16
|
-
importedCount: 0,
|
|
17
|
-
warnings: [],
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const snapshot = captureAgentSnapshots(agentOptions);
|
|
22
|
-
const timestamp = new Date().toISOString();
|
|
23
|
-
const profile = createProfile(resolveUniqueProfileName(INITIAL_PROFILE_NAME, data.profiles), snapshot.agents, { timestamp });
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
data: {
|
|
27
|
-
...appendProfile(data, profile),
|
|
28
|
-
importedAt: timestamp,
|
|
29
|
-
},
|
|
30
|
-
imported: true,
|
|
31
|
-
importedCount: 1,
|
|
32
|
-
warnings: snapshot.warnings,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function loadAndPrepareProfiles(
|
|
37
|
-
storePath = PROFILE_STORE_PATH,
|
|
38
|
-
agentOptions: string | AgentSelectionOptions = AGENTS_DIR,
|
|
39
|
-
): ImportProfilesResult {
|
|
40
|
-
const configLoad = loadMultiProfilesConfig();
|
|
41
|
-
|
|
42
|
-
multiProfilesDebugLogger.log("extension.initialized", {
|
|
43
|
-
configCreated: configLoad.created,
|
|
44
|
-
timestamp: new Date().toISOString(),
|
|
45
|
-
profilesVersion: 2,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const loaded = loadProfilesFile(storePath, agentOptions);
|
|
49
|
-
const prepared = ensureProfilesImported(loaded.data, agentOptions);
|
|
50
|
-
|
|
51
|
-
if (loaded.needsSave || prepared.imported) {
|
|
52
|
-
saveProfilesFile(prepared.data, storePath);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const warnings = [configLoad.warning, loaded.warning, ...prepared.warnings].filter((message): message is string => Boolean(message));
|
|
56
|
-
return {
|
|
57
|
-
...prepared,
|
|
58
|
-
warnings,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
1
|
+
import { AGENTS_DIR, INITIAL_PROFILE_NAME, PROFILE_STORE_PATH } from "./constants.js";
|
|
2
|
+
import { captureAgentSnapshots, type AgentSelectionOptions } from "./agent-writer.js";
|
|
3
|
+
import { appendProfile, createProfile, loadProfilesFile, resolveUniqueProfileName, saveProfilesFile } from "./profile-store.js";
|
|
4
|
+
import { loadMultiProfilesConfig } from "./config.js";
|
|
5
|
+
import { multiProfilesDebugLogger } from "./debug-logger.js";
|
|
6
|
+
import type { ImportProfilesResult, ProfilesFile } from "./types.js";
|
|
7
|
+
|
|
8
|
+
export function ensureProfilesImported(
|
|
9
|
+
data: ProfilesFile,
|
|
10
|
+
agentOptions: string | AgentSelectionOptions = AGENTS_DIR,
|
|
11
|
+
): ImportProfilesResult {
|
|
12
|
+
if (data.importedAt) {
|
|
13
|
+
return {
|
|
14
|
+
data,
|
|
15
|
+
imported: false,
|
|
16
|
+
importedCount: 0,
|
|
17
|
+
warnings: [],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const snapshot = captureAgentSnapshots(agentOptions);
|
|
22
|
+
const timestamp = new Date().toISOString();
|
|
23
|
+
const profile = createProfile(resolveUniqueProfileName(INITIAL_PROFILE_NAME, data.profiles), snapshot.agents, { timestamp });
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
data: {
|
|
27
|
+
...appendProfile(data, profile),
|
|
28
|
+
importedAt: timestamp,
|
|
29
|
+
},
|
|
30
|
+
imported: true,
|
|
31
|
+
importedCount: 1,
|
|
32
|
+
warnings: snapshot.warnings,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function loadAndPrepareProfiles(
|
|
37
|
+
storePath = PROFILE_STORE_PATH,
|
|
38
|
+
agentOptions: string | AgentSelectionOptions = AGENTS_DIR,
|
|
39
|
+
): ImportProfilesResult {
|
|
40
|
+
const configLoad = loadMultiProfilesConfig();
|
|
41
|
+
|
|
42
|
+
multiProfilesDebugLogger.log("extension.initialized", {
|
|
43
|
+
configCreated: configLoad.created,
|
|
44
|
+
timestamp: new Date().toISOString(),
|
|
45
|
+
profilesVersion: 2,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const loaded = loadProfilesFile(storePath, agentOptions);
|
|
49
|
+
const prepared = ensureProfilesImported(loaded.data, agentOptions);
|
|
50
|
+
|
|
51
|
+
if (loaded.needsSave || prepared.imported) {
|
|
52
|
+
saveProfilesFile(prepared.data, storePath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const warnings = [configLoad.warning, loaded.warning, ...prepared.warnings].filter((message): message is string => Boolean(message));
|
|
56
|
+
return {
|
|
57
|
+
...prepared,
|
|
58
|
+
warnings,
|
|
59
|
+
};
|
|
60
|
+
}
|