@savestate/cli 0.6.0 → 0.8.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/dist/cli/__tests__/progress.test.d.ts +5 -0
- package/dist/cli/__tests__/progress.test.d.ts.map +1 -0
- package/dist/cli/__tests__/progress.test.js +212 -0
- package/dist/cli/__tests__/progress.test.js.map +1 -0
- package/dist/cli/__tests__/signal-handler.test.d.ts +5 -0
- package/dist/cli/__tests__/signal-handler.test.d.ts.map +1 -0
- package/dist/cli/__tests__/signal-handler.test.js +99 -0
- package/dist/cli/__tests__/signal-handler.test.js.map +1 -0
- package/dist/cli/__tests__/summary.test.d.ts +5 -0
- package/dist/cli/__tests__/summary.test.d.ts.map +1 -0
- package/dist/cli/__tests__/summary.test.js +242 -0
- package/dist/cli/__tests__/summary.test.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/progress.d.ts +86 -0
- package/dist/cli/progress.d.ts.map +1 -0
- package/dist/cli/progress.js +205 -0
- package/dist/cli/progress.js.map +1 -0
- package/dist/cli/prompts.d.ts +49 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +266 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/signal-handler.d.ts +63 -0
- package/dist/cli/signal-handler.d.ts.map +1 -0
- package/dist/cli/signal-handler.js +165 -0
- package/dist/cli/signal-handler.js.map +1 -0
- package/dist/cli/summary.d.ts +33 -0
- package/dist/cli/summary.d.ts.map +1 -0
- package/dist/cli/summary.js +296 -0
- package/dist/cli/summary.js.map +1 -0
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/migrate.d.ts +18 -4
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +324 -163
- package/dist/commands/migrate.js.map +1 -1
- package/dist/migrate/__tests__/capabilities.test.d.ts +7 -0
- package/dist/migrate/__tests__/capabilities.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/capabilities.test.js +90 -0
- package/dist/migrate/__tests__/capabilities.test.js.map +1 -0
- package/dist/migrate/__tests__/chatgpt-loader.test.d.ts +7 -0
- package/dist/migrate/__tests__/chatgpt-loader.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/chatgpt-loader.test.js +889 -0
- package/dist/migrate/__tests__/chatgpt-loader.test.js.map +1 -0
- package/dist/migrate/__tests__/claude-loader.test.d.ts +7 -0
- package/dist/migrate/__tests__/claude-loader.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/claude-loader.test.js +544 -0
- package/dist/migrate/__tests__/claude-loader.test.js.map +1 -0
- package/dist/migrate/__tests__/edge-cases.test.d.ts +7 -0
- package/dist/migrate/__tests__/edge-cases.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/edge-cases.test.js +787 -0
- package/dist/migrate/__tests__/edge-cases.test.js.map +1 -0
- package/dist/migrate/__tests__/error-recovery.test.d.ts +7 -0
- package/dist/migrate/__tests__/error-recovery.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/error-recovery.test.js +461 -0
- package/dist/migrate/__tests__/error-recovery.test.js.map +1 -0
- package/dist/migrate/__tests__/integration.test.d.ts +7 -0
- package/dist/migrate/__tests__/integration.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/integration.test.js +536 -0
- package/dist/migrate/__tests__/integration.test.js.map +1 -0
- package/dist/migrate/__tests__/orchestrator.test.d.ts +8 -0
- package/dist/migrate/__tests__/orchestrator.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/orchestrator.test.js +355 -0
- package/dist/migrate/__tests__/orchestrator.test.js.map +1 -0
- package/dist/migrate/__tests__/performance.test.d.ts +7 -0
- package/dist/migrate/__tests__/performance.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/performance.test.js +478 -0
- package/dist/migrate/__tests__/performance.test.js.map +1 -0
- package/dist/migrate/__tests__/registry.test.d.ts +7 -0
- package/dist/migrate/__tests__/registry.test.d.ts.map +1 -0
- package/dist/migrate/__tests__/registry.test.js +167 -0
- package/dist/migrate/__tests__/registry.test.js.map +1 -0
- package/dist/migrate/compatibility.d.ts +47 -0
- package/dist/migrate/compatibility.d.ts.map +1 -0
- package/dist/migrate/compatibility.js +468 -0
- package/dist/migrate/compatibility.js.map +1 -0
- package/dist/migrate/extractors/__tests__/chatgpt.test.d.ts +12 -0
- package/dist/migrate/extractors/__tests__/chatgpt.test.d.ts.map +1 -0
- package/dist/migrate/extractors/__tests__/chatgpt.test.js +522 -0
- package/dist/migrate/extractors/__tests__/chatgpt.test.js.map +1 -0
- package/dist/migrate/extractors/__tests__/claude.test.d.ts +12 -0
- package/dist/migrate/extractors/__tests__/claude.test.d.ts.map +1 -0
- package/dist/migrate/extractors/__tests__/claude.test.js +789 -0
- package/dist/migrate/extractors/__tests__/claude.test.js.map +1 -0
- package/dist/migrate/extractors/chatgpt.d.ts +70 -0
- package/dist/migrate/extractors/chatgpt.d.ts.map +1 -0
- package/dist/migrate/extractors/chatgpt.js +791 -0
- package/dist/migrate/extractors/chatgpt.js.map +1 -0
- package/dist/migrate/extractors/claude.d.ts +69 -0
- package/dist/migrate/extractors/claude.d.ts.map +1 -0
- package/dist/migrate/extractors/claude.js +1136 -0
- package/dist/migrate/extractors/claude.js.map +1 -0
- package/dist/migrate/extractors/registry.js +6 -4
- package/dist/migrate/extractors/registry.js.map +1 -1
- package/dist/migrate/index.d.ts +6 -1
- package/dist/migrate/index.d.ts.map +1 -1
- package/dist/migrate/index.js +12 -1
- package/dist/migrate/index.js.map +1 -1
- package/dist/migrate/loaders/chatgpt.d.ts +72 -0
- package/dist/migrate/loaders/chatgpt.d.ts.map +1 -0
- package/dist/migrate/loaders/chatgpt.js +691 -0
- package/dist/migrate/loaders/chatgpt.js.map +1 -0
- package/dist/migrate/loaders/claude.d.ts +61 -0
- package/dist/migrate/loaders/claude.d.ts.map +1 -0
- package/dist/migrate/loaders/claude.js +433 -0
- package/dist/migrate/loaders/claude.js.map +1 -0
- package/dist/migrate/loaders/registry.js +6 -4
- package/dist/migrate/loaders/registry.js.map +1 -1
- package/dist/migrate/orchestrator.d.ts +75 -1
- package/dist/migrate/orchestrator.d.ts.map +1 -1
- package/dist/migrate/orchestrator.js +215 -19
- package/dist/migrate/orchestrator.js.map +1 -1
- package/dist/migrate/testing/index.d.ts +28 -0
- package/dist/migrate/testing/index.d.ts.map +1 -0
- package/dist/migrate/testing/index.js +55 -0
- package/dist/migrate/testing/index.js.map +1 -0
- package/dist/migrate/testing/mock-extractor.d.ts +30 -0
- package/dist/migrate/testing/mock-extractor.d.ts.map +1 -0
- package/dist/migrate/testing/mock-extractor.js +137 -0
- package/dist/migrate/testing/mock-extractor.js.map +1 -0
- package/dist/migrate/testing/mock-loader.d.ts +36 -0
- package/dist/migrate/testing/mock-loader.d.ts.map +1 -0
- package/dist/migrate/testing/mock-loader.js +81 -0
- package/dist/migrate/testing/mock-loader.js.map +1 -0
- package/dist/migrate/testing/mock-transformer.d.ts +26 -0
- package/dist/migrate/testing/mock-transformer.d.ts.map +1 -0
- package/dist/migrate/testing/mock-transformer.js +185 -0
- package/dist/migrate/testing/mock-transformer.js.map +1 -0
- package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.d.ts +5 -0
- package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.d.ts.map +1 -0
- package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.js +333 -0
- package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.js.map +1 -0
- package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.d.ts +5 -0
- package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.d.ts.map +1 -0
- package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.js +333 -0
- package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.js.map +1 -0
- package/dist/migrate/transformers/__tests__/rules.test.d.ts +5 -0
- package/dist/migrate/transformers/__tests__/rules.test.d.ts.map +1 -0
- package/dist/migrate/transformers/__tests__/rules.test.js +375 -0
- package/dist/migrate/transformers/__tests__/rules.test.js.map +1 -0
- package/dist/migrate/transformers/chatgpt-to-claude.d.ts +40 -0
- package/dist/migrate/transformers/chatgpt-to-claude.d.ts.map +1 -0
- package/dist/migrate/transformers/chatgpt-to-claude.js +443 -0
- package/dist/migrate/transformers/chatgpt-to-claude.js.map +1 -0
- package/dist/migrate/transformers/claude-to-chatgpt.d.ts +41 -0
- package/dist/migrate/transformers/claude-to-chatgpt.d.ts.map +1 -0
- package/dist/migrate/transformers/claude-to-chatgpt.js +532 -0
- package/dist/migrate/transformers/claude-to-chatgpt.js.map +1 -0
- package/dist/migrate/transformers/registry.js +6 -4
- package/dist/migrate/transformers/registry.js.map +1 -1
- package/dist/migrate/transformers/rules.d.ts +168 -0
- package/dist/migrate/transformers/rules.d.ts.map +1 -0
- package/dist/migrate/transformers/rules.js +487 -0
- package/dist/migrate/transformers/rules.js.map +1 -0
- package/dist/migrate/types.d.ts +2 -0
- package/dist/migrate/types.d.ts.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transformation Rule Schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure and utilities for platform-to-platform data transformation.
|
|
5
|
+
* Rules specify how to convert data types between different AI assistant platforms,
|
|
6
|
+
* handling format differences, character limits, and feature disparities.
|
|
7
|
+
*/
|
|
8
|
+
import type { Platform, MigrationBundle } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Content type categories that can be transformed.
|
|
11
|
+
*/
|
|
12
|
+
export type ContentType = 'instructions' | 'memories' | 'conversations' | 'files' | 'customBots';
|
|
13
|
+
/**
|
|
14
|
+
* Transformation strategy when content exceeds target limits.
|
|
15
|
+
*/
|
|
16
|
+
export type OverflowStrategy = 'truncate' | 'summarize' | 'split' | 'error';
|
|
17
|
+
/**
|
|
18
|
+
* How content is adapted between platforms.
|
|
19
|
+
*/
|
|
20
|
+
export type AdaptationMethod = 'direct' | 'expand' | 'truncate' | 'summarize' | 'split' | 'convert' | 'merge' | 'skip';
|
|
21
|
+
/**
|
|
22
|
+
* A single transformation rule.
|
|
23
|
+
*/
|
|
24
|
+
export interface TransformationRule {
|
|
25
|
+
/** Source content type */
|
|
26
|
+
sourceType: ContentType;
|
|
27
|
+
/** Target content type (may differ from source) */
|
|
28
|
+
targetType: ContentType | ContentType[];
|
|
29
|
+
/** How the content is adapted */
|
|
30
|
+
method: AdaptationMethod;
|
|
31
|
+
/** Optional transformation function name */
|
|
32
|
+
transformer?: string;
|
|
33
|
+
/** Priority for this rule (higher = applied first) */
|
|
34
|
+
priority: number;
|
|
35
|
+
/** Description of what this rule does */
|
|
36
|
+
description: string;
|
|
37
|
+
/** Conditions for applying this rule */
|
|
38
|
+
conditions?: RuleCondition[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Condition for when a rule applies.
|
|
42
|
+
*/
|
|
43
|
+
export interface RuleCondition {
|
|
44
|
+
/** Type of condition */
|
|
45
|
+
type: 'length' | 'exists' | 'count' | 'capability' | 'custom';
|
|
46
|
+
/** What to check */
|
|
47
|
+
field?: string;
|
|
48
|
+
/** Comparison operator */
|
|
49
|
+
operator?: 'gt' | 'lt' | 'eq' | 'gte' | 'lte' | 'exists' | 'notExists';
|
|
50
|
+
/** Value to compare against */
|
|
51
|
+
value?: number | string | boolean;
|
|
52
|
+
/** Platform capability to check */
|
|
53
|
+
capability?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Result of applying a transformation rule.
|
|
57
|
+
*/
|
|
58
|
+
export interface TransformationResult {
|
|
59
|
+
/** Whether transformation succeeded */
|
|
60
|
+
success: boolean;
|
|
61
|
+
/** Transformed content (if applicable) */
|
|
62
|
+
content?: string;
|
|
63
|
+
/** Additional data (for split results, etc.) */
|
|
64
|
+
data?: unknown;
|
|
65
|
+
/** Warning message (if partially successful) */
|
|
66
|
+
warning?: string;
|
|
67
|
+
/** Error message (if failed) */
|
|
68
|
+
error?: string;
|
|
69
|
+
/** Whether user review is recommended */
|
|
70
|
+
needsReview?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Character limit specification for a content type.
|
|
74
|
+
*/
|
|
75
|
+
export interface CharacterLimit {
|
|
76
|
+
/** Hard limit (content will be cut/rejected if exceeded) */
|
|
77
|
+
hard: number;
|
|
78
|
+
/** Soft limit (warning issued if exceeded) */
|
|
79
|
+
soft?: number;
|
|
80
|
+
/** What to do when hard limit is exceeded */
|
|
81
|
+
overflowStrategy: OverflowStrategy;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Platform transformation mapping.
|
|
85
|
+
*/
|
|
86
|
+
export interface PlatformMapping {
|
|
87
|
+
source: Platform;
|
|
88
|
+
target: Platform;
|
|
89
|
+
rules: TransformationRule[];
|
|
90
|
+
limits: Record<ContentType, CharacterLimit | null>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get character limits for a target platform.
|
|
94
|
+
*/
|
|
95
|
+
export declare function getTargetLimits(target: Platform): Record<ContentType, CharacterLimit | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Intelligently truncate content while preserving meaning.
|
|
98
|
+
* Tries to remove less important parts first.
|
|
99
|
+
*/
|
|
100
|
+
export declare function intelligentTruncate(content: string, limit: number): TransformationResult;
|
|
101
|
+
/**
|
|
102
|
+
* Split content into multiple chunks that fit within a limit.
|
|
103
|
+
*/
|
|
104
|
+
export declare function splitContent(content: string, limit: number): string[];
|
|
105
|
+
/**
|
|
106
|
+
* Convert ChatGPT-style custom instructions to Claude system prompt format.
|
|
107
|
+
* ChatGPT splits into "About Me" and "How to Respond" sections.
|
|
108
|
+
*/
|
|
109
|
+
export declare function convertChatGPTInstructionsToClaude(aboutUser: string, aboutModel: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* Convert Claude system prompt to ChatGPT custom instructions.
|
|
112
|
+
* Must fit within 1500 character limit.
|
|
113
|
+
*/
|
|
114
|
+
export declare function convertClaudeInstructionsToChatGPT(systemPrompt: string, limit?: number): {
|
|
115
|
+
aboutUser: string;
|
|
116
|
+
aboutModel: string;
|
|
117
|
+
overflow?: string;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Convert memory entries to a structured document.
|
|
121
|
+
*/
|
|
122
|
+
export declare function convertMemoriesToDocument(memories: Array<{
|
|
123
|
+
id: string;
|
|
124
|
+
content: string;
|
|
125
|
+
createdAt: string;
|
|
126
|
+
category?: string;
|
|
127
|
+
}>): string;
|
|
128
|
+
/**
|
|
129
|
+
* Split a document back into discrete memory entries.
|
|
130
|
+
*/
|
|
131
|
+
export declare function convertDocumentToMemories(document: string): Array<{
|
|
132
|
+
content: string;
|
|
133
|
+
category: string;
|
|
134
|
+
}>;
|
|
135
|
+
/**
|
|
136
|
+
* Extract key decisions and preferences from conversation summaries.
|
|
137
|
+
*/
|
|
138
|
+
export declare function extractContextFromConversations(summaries: Array<{
|
|
139
|
+
title: string;
|
|
140
|
+
keyPoints?: string[];
|
|
141
|
+
}>): string;
|
|
142
|
+
/**
|
|
143
|
+
* Map a GPT configuration to Claude project settings.
|
|
144
|
+
*/
|
|
145
|
+
export declare function mapGPTToProject(gpt: {
|
|
146
|
+
name: string;
|
|
147
|
+
description?: string;
|
|
148
|
+
instructions: string;
|
|
149
|
+
knowledgeFiles?: string[];
|
|
150
|
+
capabilities?: string[];
|
|
151
|
+
}): {
|
|
152
|
+
projectName: string;
|
|
153
|
+
description: string;
|
|
154
|
+
systemPrompt: string;
|
|
155
|
+
knowledgeDocs: Array<{
|
|
156
|
+
name: string;
|
|
157
|
+
content: string;
|
|
158
|
+
}>;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Validate that a bundle can be transformed to the target platform.
|
|
162
|
+
*/
|
|
163
|
+
export declare function validateBundleForTarget(bundle: MigrationBundle, target: Platform): {
|
|
164
|
+
valid: boolean;
|
|
165
|
+
errors: string[];
|
|
166
|
+
warnings: string[];
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/migrate/transformers/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transformation Rule Schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure and utilities for platform-to-platform data transformation.
|
|
5
|
+
* Rules specify how to convert data types between different AI assistant platforms,
|
|
6
|
+
* handling format differences, character limits, and feature disparities.
|
|
7
|
+
*/
|
|
8
|
+
import { getPlatformCapabilities } from '../capabilities.js';
|
|
9
|
+
// ─── Character Limits by Platform ────────────────────────────
|
|
10
|
+
/**
|
|
11
|
+
* Get character limits for a target platform.
|
|
12
|
+
*/
|
|
13
|
+
export function getTargetLimits(target) {
|
|
14
|
+
const caps = getPlatformCapabilities(target);
|
|
15
|
+
switch (target) {
|
|
16
|
+
case 'claude':
|
|
17
|
+
return {
|
|
18
|
+
instructions: {
|
|
19
|
+
hard: caps.instructionLimit,
|
|
20
|
+
soft: caps.instructionLimit * 0.9,
|
|
21
|
+
overflowStrategy: 'summarize',
|
|
22
|
+
},
|
|
23
|
+
memories: null, // Claude doesn't have explicit memories - converted to docs
|
|
24
|
+
conversations: null, // Stored as context summary
|
|
25
|
+
files: {
|
|
26
|
+
hard: caps.fileSizeLimit ?? 32 * 1024 * 1024,
|
|
27
|
+
overflowStrategy: 'error',
|
|
28
|
+
},
|
|
29
|
+
customBots: null, // Mapped to projects
|
|
30
|
+
};
|
|
31
|
+
case 'chatgpt':
|
|
32
|
+
return {
|
|
33
|
+
instructions: {
|
|
34
|
+
hard: caps.instructionLimit,
|
|
35
|
+
soft: 1200, // Leave buffer for safety
|
|
36
|
+
overflowStrategy: 'truncate',
|
|
37
|
+
},
|
|
38
|
+
memories: {
|
|
39
|
+
hard: 500, // Per memory entry
|
|
40
|
+
soft: 400,
|
|
41
|
+
overflowStrategy: 'split',
|
|
42
|
+
},
|
|
43
|
+
conversations: null, // Not writeable via API
|
|
44
|
+
files: {
|
|
45
|
+
hard: caps.fileSizeLimit ?? 512 * 1024 * 1024,
|
|
46
|
+
overflowStrategy: 'error',
|
|
47
|
+
},
|
|
48
|
+
customBots: null, // GPTs require manual creation
|
|
49
|
+
};
|
|
50
|
+
case 'gemini':
|
|
51
|
+
return {
|
|
52
|
+
instructions: {
|
|
53
|
+
hard: caps.instructionLimit,
|
|
54
|
+
soft: 3500,
|
|
55
|
+
overflowStrategy: 'truncate',
|
|
56
|
+
},
|
|
57
|
+
memories: {
|
|
58
|
+
hard: 300,
|
|
59
|
+
soft: 250,
|
|
60
|
+
overflowStrategy: 'split',
|
|
61
|
+
},
|
|
62
|
+
conversations: null,
|
|
63
|
+
files: {
|
|
64
|
+
hard: caps.fileSizeLimit ?? 20 * 1024 * 1024,
|
|
65
|
+
overflowStrategy: 'error',
|
|
66
|
+
},
|
|
67
|
+
customBots: null,
|
|
68
|
+
};
|
|
69
|
+
case 'copilot':
|
|
70
|
+
return {
|
|
71
|
+
instructions: {
|
|
72
|
+
hard: caps.instructionLimit,
|
|
73
|
+
soft: 1800,
|
|
74
|
+
overflowStrategy: 'truncate',
|
|
75
|
+
},
|
|
76
|
+
memories: {
|
|
77
|
+
hard: 300,
|
|
78
|
+
soft: 250,
|
|
79
|
+
overflowStrategy: 'split',
|
|
80
|
+
},
|
|
81
|
+
conversations: null,
|
|
82
|
+
files: {
|
|
83
|
+
hard: caps.fileSizeLimit ?? 10 * 1024 * 1024,
|
|
84
|
+
overflowStrategy: 'error',
|
|
85
|
+
},
|
|
86
|
+
customBots: null,
|
|
87
|
+
};
|
|
88
|
+
default:
|
|
89
|
+
throw new Error(`Unknown platform: ${target}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// ─── Content Truncation & Summarization ──────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Intelligently truncate content while preserving meaning.
|
|
95
|
+
* Tries to remove less important parts first.
|
|
96
|
+
*/
|
|
97
|
+
export function intelligentTruncate(content, limit) {
|
|
98
|
+
if (content.length <= limit) {
|
|
99
|
+
return { success: true, content };
|
|
100
|
+
}
|
|
101
|
+
// Strategy 1: Remove examples (often verbose)
|
|
102
|
+
const withoutExamples = removeExamples(content);
|
|
103
|
+
if (withoutExamples.length <= limit) {
|
|
104
|
+
return {
|
|
105
|
+
success: true,
|
|
106
|
+
content: withoutExamples,
|
|
107
|
+
warning: 'Examples removed to fit character limit',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Strategy 2: Remove verbose sections (like "Note:" blocks)
|
|
111
|
+
const withoutNotes = removeVerboseSections(withoutExamples);
|
|
112
|
+
if (withoutNotes.length <= limit) {
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
content: withoutNotes,
|
|
116
|
+
warning: 'Verbose sections removed to fit character limit',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Strategy 3: Condense numbered/bulleted lists
|
|
120
|
+
const condensedLists = condenseLists(withoutNotes);
|
|
121
|
+
if (condensedLists.length <= limit) {
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
content: condensedLists,
|
|
125
|
+
warning: 'Lists condensed to fit character limit',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Strategy 4: Hard truncate at sentence boundary
|
|
129
|
+
const truncated = truncateAtSentence(condensedLists, limit - 3);
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
content: truncated + '...',
|
|
133
|
+
warning: `Content truncated from ${content.length} to ${limit} characters`,
|
|
134
|
+
needsReview: true,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Remove example blocks from content.
|
|
139
|
+
*/
|
|
140
|
+
function removeExamples(content) {
|
|
141
|
+
// Remove code block examples
|
|
142
|
+
let result = content.replace(/```[\s\S]*?```/g, '');
|
|
143
|
+
// Remove "Example:" or "For example:" sections
|
|
144
|
+
result = result.replace(/(?:Example|For example|e\.g\.|i\.e\.)[:\s]*[^\n]+(?:\n(?![A-Z#\-\d]).*?)*/gi, '');
|
|
145
|
+
// Clean up extra whitespace
|
|
146
|
+
return result.replace(/\n{3,}/g, '\n\n').trim();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Remove verbose sections like notes and warnings.
|
|
150
|
+
*/
|
|
151
|
+
function removeVerboseSections(content) {
|
|
152
|
+
// Remove "Note:" blocks
|
|
153
|
+
let result = content.replace(/(?:Note|Warning|Tip|Important)[:\s]*[^\n]+(?:\n(?![A-Z#\-\d]).*?)*/gi, '');
|
|
154
|
+
// Remove parenthetical asides
|
|
155
|
+
result = result.replace(/\s*\([^)]{50,}\)/g, '');
|
|
156
|
+
return result.replace(/\n{3,}/g, '\n\n').trim();
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Condense bulleted/numbered lists.
|
|
160
|
+
*/
|
|
161
|
+
function condenseLists(content) {
|
|
162
|
+
const lines = content.split('\n');
|
|
163
|
+
const result = [];
|
|
164
|
+
let consecutiveListItems = 0;
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
const isListItem = /^[\s]*[-*•\d.]+[\s]/.test(line);
|
|
167
|
+
if (isListItem) {
|
|
168
|
+
consecutiveListItems++;
|
|
169
|
+
// Keep first 5 items of any list
|
|
170
|
+
if (consecutiveListItems <= 5) {
|
|
171
|
+
result.push(line);
|
|
172
|
+
}
|
|
173
|
+
else if (consecutiveListItems === 6) {
|
|
174
|
+
result.push(' - (and more...)');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
consecutiveListItems = 0;
|
|
179
|
+
result.push(line);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return result.join('\n').trim();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Truncate at a sentence boundary.
|
|
186
|
+
*/
|
|
187
|
+
function truncateAtSentence(content, limit) {
|
|
188
|
+
if (content.length <= limit)
|
|
189
|
+
return content;
|
|
190
|
+
// Find the last sentence boundary before the limit
|
|
191
|
+
const truncated = content.substring(0, limit);
|
|
192
|
+
const lastSentence = truncated.search(/[.!?]\s[A-Z][^.!?]*$/);
|
|
193
|
+
if (lastSentence > limit * 0.7) {
|
|
194
|
+
return truncated.substring(0, lastSentence + 1).trim();
|
|
195
|
+
}
|
|
196
|
+
// Fall back to last complete word
|
|
197
|
+
const lastSpace = truncated.lastIndexOf(' ');
|
|
198
|
+
if (lastSpace > limit * 0.8) {
|
|
199
|
+
return truncated.substring(0, lastSpace).trim();
|
|
200
|
+
}
|
|
201
|
+
return truncated.trim();
|
|
202
|
+
}
|
|
203
|
+
// ─── Content Splitting ───────────────────────────────────────
|
|
204
|
+
/**
|
|
205
|
+
* Split content into multiple chunks that fit within a limit.
|
|
206
|
+
*/
|
|
207
|
+
export function splitContent(content, limit) {
|
|
208
|
+
if (content.length <= limit) {
|
|
209
|
+
return [content];
|
|
210
|
+
}
|
|
211
|
+
const chunks = [];
|
|
212
|
+
const paragraphs = content.split(/\n\n+/);
|
|
213
|
+
let currentChunk = '';
|
|
214
|
+
for (const para of paragraphs) {
|
|
215
|
+
// If adding this paragraph exceeds limit
|
|
216
|
+
if ((currentChunk + '\n\n' + para).length > limit) {
|
|
217
|
+
// Save current chunk if non-empty
|
|
218
|
+
if (currentChunk) {
|
|
219
|
+
chunks.push(currentChunk.trim());
|
|
220
|
+
}
|
|
221
|
+
// If single paragraph exceeds limit, split it
|
|
222
|
+
if (para.length > limit) {
|
|
223
|
+
const sentences = para.match(/[^.!?]+[.!?]+/g) || [];
|
|
224
|
+
// If no sentences found (no punctuation), split by characters
|
|
225
|
+
if (sentences.length === 0) {
|
|
226
|
+
// Split long content without natural breaks into fixed-size chunks
|
|
227
|
+
let remaining = para;
|
|
228
|
+
while (remaining.length > limit) {
|
|
229
|
+
chunks.push(remaining.substring(0, limit));
|
|
230
|
+
remaining = remaining.substring(limit);
|
|
231
|
+
}
|
|
232
|
+
currentChunk = remaining;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
currentChunk = '';
|
|
236
|
+
for (const sentence of sentences) {
|
|
237
|
+
if ((currentChunk + ' ' + sentence).length > limit) {
|
|
238
|
+
if (currentChunk)
|
|
239
|
+
chunks.push(currentChunk.trim());
|
|
240
|
+
// If single sentence exceeds limit, split it by characters
|
|
241
|
+
if (sentence.length > limit) {
|
|
242
|
+
let remaining = sentence;
|
|
243
|
+
while (remaining.length > limit) {
|
|
244
|
+
chunks.push(remaining.substring(0, limit));
|
|
245
|
+
remaining = remaining.substring(limit);
|
|
246
|
+
}
|
|
247
|
+
currentChunk = remaining;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
currentChunk = sentence;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
currentChunk += (currentChunk ? ' ' : '') + sentence;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
currentChunk = para;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
currentChunk += (currentChunk ? '\n\n' : '') + para;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (currentChunk) {
|
|
268
|
+
chunks.push(currentChunk.trim());
|
|
269
|
+
}
|
|
270
|
+
return chunks;
|
|
271
|
+
}
|
|
272
|
+
// ─── Format Conversion ───────────────────────────────────────
|
|
273
|
+
/**
|
|
274
|
+
* Convert ChatGPT-style custom instructions to Claude system prompt format.
|
|
275
|
+
* ChatGPT splits into "About Me" and "How to Respond" sections.
|
|
276
|
+
*/
|
|
277
|
+
export function convertChatGPTInstructionsToClaude(aboutUser, aboutModel) {
|
|
278
|
+
const sections = [];
|
|
279
|
+
if (aboutUser) {
|
|
280
|
+
sections.push(`# User Context\n\n${aboutUser}`);
|
|
281
|
+
}
|
|
282
|
+
if (aboutModel) {
|
|
283
|
+
sections.push(`# Response Guidelines\n\n${aboutModel}`);
|
|
284
|
+
}
|
|
285
|
+
return sections.join('\n\n');
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Convert Claude system prompt to ChatGPT custom instructions.
|
|
289
|
+
* Must fit within 1500 character limit.
|
|
290
|
+
*/
|
|
291
|
+
export function convertClaudeInstructionsToChatGPT(systemPrompt, limit = 1500) {
|
|
292
|
+
// Try to detect sections
|
|
293
|
+
const userContextMatch = systemPrompt.match(/(?:^|\n)#*\s*(?:User Context|About (?:the )?User|Background)[:\s]*\n*([\s\S]*?)(?=\n#|\n*$)/i);
|
|
294
|
+
const responseMatch = systemPrompt.match(/(?:^|\n)#*\s*(?:Response Guidelines?|How to Respond|Instructions?|Guidelines?)[:\s]*\n*([\s\S]*?)(?=\n#|\n*$)/i);
|
|
295
|
+
let aboutUser = userContextMatch?.[1]?.trim() || '';
|
|
296
|
+
let aboutModel = responseMatch?.[1]?.trim() || systemPrompt.trim();
|
|
297
|
+
// If no clear sections, put everything in aboutModel
|
|
298
|
+
if (!userContextMatch && !responseMatch) {
|
|
299
|
+
aboutModel = systemPrompt.trim();
|
|
300
|
+
aboutUser = '';
|
|
301
|
+
}
|
|
302
|
+
// Handle overflow
|
|
303
|
+
const halfLimit = Math.floor(limit / 2);
|
|
304
|
+
let overflow;
|
|
305
|
+
if (aboutUser.length > halfLimit) {
|
|
306
|
+
const result = intelligentTruncate(aboutUser, halfLimit);
|
|
307
|
+
overflow = aboutUser.substring(halfLimit);
|
|
308
|
+
aboutUser = result.content || aboutUser.substring(0, halfLimit);
|
|
309
|
+
}
|
|
310
|
+
if (aboutModel.length > halfLimit) {
|
|
311
|
+
const result = intelligentTruncate(aboutModel, halfLimit);
|
|
312
|
+
overflow = (overflow ? overflow + '\n\n' : '') + aboutModel.substring(halfLimit);
|
|
313
|
+
aboutModel = result.content || aboutModel.substring(0, halfLimit);
|
|
314
|
+
}
|
|
315
|
+
// Rebalance if one section has room
|
|
316
|
+
const totalUsed = aboutUser.length + aboutModel.length;
|
|
317
|
+
if (totalUsed < limit && overflow) {
|
|
318
|
+
const available = limit - totalUsed - 10;
|
|
319
|
+
if (available > 0) {
|
|
320
|
+
aboutModel += '\n\n' + overflow.substring(0, available);
|
|
321
|
+
overflow = overflow.length > available ? overflow.substring(available) : undefined;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return { aboutUser, aboutModel, overflow };
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Convert memory entries to a structured document.
|
|
328
|
+
*/
|
|
329
|
+
export function convertMemoriesToDocument(memories) {
|
|
330
|
+
const lines = [
|
|
331
|
+
'# User Memories',
|
|
332
|
+
'',
|
|
333
|
+
'> This document contains memories extracted from your previous AI assistant.',
|
|
334
|
+
'> Use this context to personalize responses and maintain continuity.',
|
|
335
|
+
'',
|
|
336
|
+
];
|
|
337
|
+
// Group by category
|
|
338
|
+
const byCategory = new Map();
|
|
339
|
+
for (const memory of memories) {
|
|
340
|
+
const category = memory.category || 'General';
|
|
341
|
+
if (!byCategory.has(category)) {
|
|
342
|
+
byCategory.set(category, []);
|
|
343
|
+
}
|
|
344
|
+
byCategory.get(category).push(memory);
|
|
345
|
+
}
|
|
346
|
+
// Sort categories by count (most entries first)
|
|
347
|
+
const sortedCategories = [...byCategory.entries()].sort((a, b) => b[1].length - a[1].length);
|
|
348
|
+
for (const [category, items] of sortedCategories) {
|
|
349
|
+
lines.push(`## ${category}`, '');
|
|
350
|
+
for (const item of items) {
|
|
351
|
+
lines.push(`- ${item.content}`);
|
|
352
|
+
}
|
|
353
|
+
lines.push('');
|
|
354
|
+
}
|
|
355
|
+
return lines.join('\n');
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Split a document back into discrete memory entries.
|
|
359
|
+
*/
|
|
360
|
+
export function convertDocumentToMemories(document) {
|
|
361
|
+
const memories = [];
|
|
362
|
+
const lines = document.split('\n');
|
|
363
|
+
let currentCategory = 'General';
|
|
364
|
+
for (const line of lines) {
|
|
365
|
+
// Check for category header
|
|
366
|
+
const headerMatch = line.match(/^##\s+(.+)$/);
|
|
367
|
+
if (headerMatch) {
|
|
368
|
+
currentCategory = headerMatch[1].trim();
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
// Check for bullet point
|
|
372
|
+
const bulletMatch = line.match(/^[\s]*[-*•]\s+(.+)$/);
|
|
373
|
+
if (bulletMatch) {
|
|
374
|
+
memories.push({
|
|
375
|
+
content: bulletMatch[1].trim(),
|
|
376
|
+
category: currentCategory,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return memories;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Extract key decisions and preferences from conversation summaries.
|
|
384
|
+
*/
|
|
385
|
+
export function extractContextFromConversations(summaries) {
|
|
386
|
+
const lines = [
|
|
387
|
+
'# Conversation Insights',
|
|
388
|
+
'',
|
|
389
|
+
'> Key decisions and preferences extracted from conversation history.',
|
|
390
|
+
'',
|
|
391
|
+
];
|
|
392
|
+
const allKeyPoints = [];
|
|
393
|
+
for (const summary of summaries) {
|
|
394
|
+
if (summary.keyPoints && summary.keyPoints.length > 0) {
|
|
395
|
+
for (const point of summary.keyPoints) {
|
|
396
|
+
if (!allKeyPoints.includes(point)) {
|
|
397
|
+
allKeyPoints.push(point);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (allKeyPoints.length > 0) {
|
|
403
|
+
lines.push('## Key Decisions & Preferences', '');
|
|
404
|
+
for (const point of allKeyPoints.slice(0, 20)) {
|
|
405
|
+
// Limit to 20 key points
|
|
406
|
+
lines.push(`- ${point}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
lines.push('*No key decisions or preferences were extracted from conversations.*', '', `Reviewed ${summaries.length} conversation${summaries.length === 1 ? '' : 's'}.`);
|
|
411
|
+
}
|
|
412
|
+
return lines.join('\n');
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Map a GPT configuration to Claude project settings.
|
|
416
|
+
*/
|
|
417
|
+
export function mapGPTToProject(gpt) {
|
|
418
|
+
const systemPrompt = [
|
|
419
|
+
gpt.instructions,
|
|
420
|
+
gpt.capabilities?.length
|
|
421
|
+
? `\n\n## Capabilities\nThis assistant can: ${gpt.capabilities.join(', ')}`
|
|
422
|
+
: '',
|
|
423
|
+
].join('');
|
|
424
|
+
return {
|
|
425
|
+
projectName: gpt.name,
|
|
426
|
+
description: gpt.description || `Migrated from GPT: ${gpt.name}`,
|
|
427
|
+
systemPrompt,
|
|
428
|
+
knowledgeDocs: [], // Files will be handled separately
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
// ─── Validation ──────────────────────────────────────────────
|
|
432
|
+
/**
|
|
433
|
+
* Validate that a bundle can be transformed to the target platform.
|
|
434
|
+
*/
|
|
435
|
+
export function validateBundleForTarget(bundle, target) {
|
|
436
|
+
const errors = [];
|
|
437
|
+
const warnings = [];
|
|
438
|
+
const limits = getTargetLimits(target);
|
|
439
|
+
const targetCaps = getPlatformCapabilities(target);
|
|
440
|
+
// Check instructions
|
|
441
|
+
if (bundle.contents.instructions) {
|
|
442
|
+
const len = bundle.contents.instructions.length;
|
|
443
|
+
const limit = limits.instructions;
|
|
444
|
+
if (limit) {
|
|
445
|
+
if (len > limit.hard) {
|
|
446
|
+
warnings.push(`Instructions (${len} chars) exceed ${target} limit (${limit.hard}). Will be ${limit.overflowStrategy === 'summarize' ? 'summarized' : 'truncated'}.`);
|
|
447
|
+
}
|
|
448
|
+
else if (limit.soft && len > limit.soft) {
|
|
449
|
+
warnings.push(`Instructions (${len} chars) exceed recommended length for ${target} (${limit.soft})`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Check memories
|
|
454
|
+
if (bundle.contents.memories && bundle.contents.memories.count > 0) {
|
|
455
|
+
if (!targetCaps.hasMemory) {
|
|
456
|
+
warnings.push(`${target} doesn't support explicit memories. Will be converted to knowledge document.`);
|
|
457
|
+
}
|
|
458
|
+
else if (targetCaps.memoryLimit && bundle.contents.memories.count > targetCaps.memoryLimit) {
|
|
459
|
+
warnings.push(`Memory count (${bundle.contents.memories.count}) exceeds ${target} limit (${targetCaps.memoryLimit})`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Check files
|
|
463
|
+
if (bundle.contents.files && bundle.contents.files.count > 0) {
|
|
464
|
+
if (!targetCaps.hasFiles) {
|
|
465
|
+
errors.push(`${target} doesn't support file uploads. ${bundle.contents.files.count} files cannot be migrated.`);
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
for (const file of bundle.contents.files.files) {
|
|
469
|
+
if (targetCaps.fileSizeLimit && file.size > targetCaps.fileSizeLimit) {
|
|
470
|
+
warnings.push(`File "${file.filename}" (${Math.round(file.size / 1024 / 1024)}MB) exceeds ${target} limit`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Check custom bots
|
|
476
|
+
if (bundle.contents.customBots && bundle.contents.customBots.count > 0) {
|
|
477
|
+
if (!targetCaps.hasCustomBots && !targetCaps.hasProjects) {
|
|
478
|
+
warnings.push(`${target} doesn't support custom bots. ${bundle.contents.customBots.count} GPTs will need manual recreation.`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
valid: errors.length === 0,
|
|
483
|
+
errors,
|
|
484
|
+
warnings,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
//# sourceMappingURL=rules.js.map
|