@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.
Files changed (159) hide show
  1. package/dist/cli/__tests__/progress.test.d.ts +5 -0
  2. package/dist/cli/__tests__/progress.test.d.ts.map +1 -0
  3. package/dist/cli/__tests__/progress.test.js +212 -0
  4. package/dist/cli/__tests__/progress.test.js.map +1 -0
  5. package/dist/cli/__tests__/signal-handler.test.d.ts +5 -0
  6. package/dist/cli/__tests__/signal-handler.test.d.ts.map +1 -0
  7. package/dist/cli/__tests__/signal-handler.test.js +99 -0
  8. package/dist/cli/__tests__/signal-handler.test.js.map +1 -0
  9. package/dist/cli/__tests__/summary.test.d.ts +5 -0
  10. package/dist/cli/__tests__/summary.test.d.ts.map +1 -0
  11. package/dist/cli/__tests__/summary.test.js +242 -0
  12. package/dist/cli/__tests__/summary.test.js.map +1 -0
  13. package/dist/cli/index.d.ts +10 -0
  14. package/dist/cli/index.d.ts.map +1 -0
  15. package/dist/cli/index.js +10 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/cli/progress.d.ts +86 -0
  18. package/dist/cli/progress.d.ts.map +1 -0
  19. package/dist/cli/progress.js +205 -0
  20. package/dist/cli/progress.js.map +1 -0
  21. package/dist/cli/prompts.d.ts +49 -0
  22. package/dist/cli/prompts.d.ts.map +1 -0
  23. package/dist/cli/prompts.js +266 -0
  24. package/dist/cli/prompts.js.map +1 -0
  25. package/dist/cli/signal-handler.d.ts +63 -0
  26. package/dist/cli/signal-handler.d.ts.map +1 -0
  27. package/dist/cli/signal-handler.js +165 -0
  28. package/dist/cli/signal-handler.js.map +1 -0
  29. package/dist/cli/summary.d.ts +33 -0
  30. package/dist/cli/summary.d.ts.map +1 -0
  31. package/dist/cli/summary.js +296 -0
  32. package/dist/cli/summary.js.map +1 -0
  33. package/dist/cli.js +7 -1
  34. package/dist/cli.js.map +1 -1
  35. package/dist/commands/migrate.d.ts +18 -4
  36. package/dist/commands/migrate.d.ts.map +1 -1
  37. package/dist/commands/migrate.js +324 -163
  38. package/dist/commands/migrate.js.map +1 -1
  39. package/dist/migrate/__tests__/capabilities.test.d.ts +7 -0
  40. package/dist/migrate/__tests__/capabilities.test.d.ts.map +1 -0
  41. package/dist/migrate/__tests__/capabilities.test.js +90 -0
  42. package/dist/migrate/__tests__/capabilities.test.js.map +1 -0
  43. package/dist/migrate/__tests__/chatgpt-loader.test.d.ts +7 -0
  44. package/dist/migrate/__tests__/chatgpt-loader.test.d.ts.map +1 -0
  45. package/dist/migrate/__tests__/chatgpt-loader.test.js +889 -0
  46. package/dist/migrate/__tests__/chatgpt-loader.test.js.map +1 -0
  47. package/dist/migrate/__tests__/claude-loader.test.d.ts +7 -0
  48. package/dist/migrate/__tests__/claude-loader.test.d.ts.map +1 -0
  49. package/dist/migrate/__tests__/claude-loader.test.js +544 -0
  50. package/dist/migrate/__tests__/claude-loader.test.js.map +1 -0
  51. package/dist/migrate/__tests__/edge-cases.test.d.ts +7 -0
  52. package/dist/migrate/__tests__/edge-cases.test.d.ts.map +1 -0
  53. package/dist/migrate/__tests__/edge-cases.test.js +787 -0
  54. package/dist/migrate/__tests__/edge-cases.test.js.map +1 -0
  55. package/dist/migrate/__tests__/error-recovery.test.d.ts +7 -0
  56. package/dist/migrate/__tests__/error-recovery.test.d.ts.map +1 -0
  57. package/dist/migrate/__tests__/error-recovery.test.js +461 -0
  58. package/dist/migrate/__tests__/error-recovery.test.js.map +1 -0
  59. package/dist/migrate/__tests__/integration.test.d.ts +7 -0
  60. package/dist/migrate/__tests__/integration.test.d.ts.map +1 -0
  61. package/dist/migrate/__tests__/integration.test.js +536 -0
  62. package/dist/migrate/__tests__/integration.test.js.map +1 -0
  63. package/dist/migrate/__tests__/orchestrator.test.d.ts +8 -0
  64. package/dist/migrate/__tests__/orchestrator.test.d.ts.map +1 -0
  65. package/dist/migrate/__tests__/orchestrator.test.js +355 -0
  66. package/dist/migrate/__tests__/orchestrator.test.js.map +1 -0
  67. package/dist/migrate/__tests__/performance.test.d.ts +7 -0
  68. package/dist/migrate/__tests__/performance.test.d.ts.map +1 -0
  69. package/dist/migrate/__tests__/performance.test.js +478 -0
  70. package/dist/migrate/__tests__/performance.test.js.map +1 -0
  71. package/dist/migrate/__tests__/registry.test.d.ts +7 -0
  72. package/dist/migrate/__tests__/registry.test.d.ts.map +1 -0
  73. package/dist/migrate/__tests__/registry.test.js +167 -0
  74. package/dist/migrate/__tests__/registry.test.js.map +1 -0
  75. package/dist/migrate/compatibility.d.ts +47 -0
  76. package/dist/migrate/compatibility.d.ts.map +1 -0
  77. package/dist/migrate/compatibility.js +468 -0
  78. package/dist/migrate/compatibility.js.map +1 -0
  79. package/dist/migrate/extractors/__tests__/chatgpt.test.d.ts +12 -0
  80. package/dist/migrate/extractors/__tests__/chatgpt.test.d.ts.map +1 -0
  81. package/dist/migrate/extractors/__tests__/chatgpt.test.js +522 -0
  82. package/dist/migrate/extractors/__tests__/chatgpt.test.js.map +1 -0
  83. package/dist/migrate/extractors/__tests__/claude.test.d.ts +12 -0
  84. package/dist/migrate/extractors/__tests__/claude.test.d.ts.map +1 -0
  85. package/dist/migrate/extractors/__tests__/claude.test.js +789 -0
  86. package/dist/migrate/extractors/__tests__/claude.test.js.map +1 -0
  87. package/dist/migrate/extractors/chatgpt.d.ts +70 -0
  88. package/dist/migrate/extractors/chatgpt.d.ts.map +1 -0
  89. package/dist/migrate/extractors/chatgpt.js +791 -0
  90. package/dist/migrate/extractors/chatgpt.js.map +1 -0
  91. package/dist/migrate/extractors/claude.d.ts +69 -0
  92. package/dist/migrate/extractors/claude.d.ts.map +1 -0
  93. package/dist/migrate/extractors/claude.js +1136 -0
  94. package/dist/migrate/extractors/claude.js.map +1 -0
  95. package/dist/migrate/extractors/registry.js +6 -4
  96. package/dist/migrate/extractors/registry.js.map +1 -1
  97. package/dist/migrate/index.d.ts +6 -1
  98. package/dist/migrate/index.d.ts.map +1 -1
  99. package/dist/migrate/index.js +12 -1
  100. package/dist/migrate/index.js.map +1 -1
  101. package/dist/migrate/loaders/chatgpt.d.ts +72 -0
  102. package/dist/migrate/loaders/chatgpt.d.ts.map +1 -0
  103. package/dist/migrate/loaders/chatgpt.js +691 -0
  104. package/dist/migrate/loaders/chatgpt.js.map +1 -0
  105. package/dist/migrate/loaders/claude.d.ts +61 -0
  106. package/dist/migrate/loaders/claude.d.ts.map +1 -0
  107. package/dist/migrate/loaders/claude.js +433 -0
  108. package/dist/migrate/loaders/claude.js.map +1 -0
  109. package/dist/migrate/loaders/registry.js +6 -4
  110. package/dist/migrate/loaders/registry.js.map +1 -1
  111. package/dist/migrate/orchestrator.d.ts +75 -1
  112. package/dist/migrate/orchestrator.d.ts.map +1 -1
  113. package/dist/migrate/orchestrator.js +215 -19
  114. package/dist/migrate/orchestrator.js.map +1 -1
  115. package/dist/migrate/testing/index.d.ts +28 -0
  116. package/dist/migrate/testing/index.d.ts.map +1 -0
  117. package/dist/migrate/testing/index.js +55 -0
  118. package/dist/migrate/testing/index.js.map +1 -0
  119. package/dist/migrate/testing/mock-extractor.d.ts +30 -0
  120. package/dist/migrate/testing/mock-extractor.d.ts.map +1 -0
  121. package/dist/migrate/testing/mock-extractor.js +137 -0
  122. package/dist/migrate/testing/mock-extractor.js.map +1 -0
  123. package/dist/migrate/testing/mock-loader.d.ts +36 -0
  124. package/dist/migrate/testing/mock-loader.d.ts.map +1 -0
  125. package/dist/migrate/testing/mock-loader.js +81 -0
  126. package/dist/migrate/testing/mock-loader.js.map +1 -0
  127. package/dist/migrate/testing/mock-transformer.d.ts +26 -0
  128. package/dist/migrate/testing/mock-transformer.d.ts.map +1 -0
  129. package/dist/migrate/testing/mock-transformer.js +185 -0
  130. package/dist/migrate/testing/mock-transformer.js.map +1 -0
  131. package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.d.ts +5 -0
  132. package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.d.ts.map +1 -0
  133. package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.js +333 -0
  134. package/dist/migrate/transformers/__tests__/chatgpt-to-claude.test.js.map +1 -0
  135. package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.d.ts +5 -0
  136. package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.d.ts.map +1 -0
  137. package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.js +333 -0
  138. package/dist/migrate/transformers/__tests__/claude-to-chatgpt.test.js.map +1 -0
  139. package/dist/migrate/transformers/__tests__/rules.test.d.ts +5 -0
  140. package/dist/migrate/transformers/__tests__/rules.test.d.ts.map +1 -0
  141. package/dist/migrate/transformers/__tests__/rules.test.js +375 -0
  142. package/dist/migrate/transformers/__tests__/rules.test.js.map +1 -0
  143. package/dist/migrate/transformers/chatgpt-to-claude.d.ts +40 -0
  144. package/dist/migrate/transformers/chatgpt-to-claude.d.ts.map +1 -0
  145. package/dist/migrate/transformers/chatgpt-to-claude.js +443 -0
  146. package/dist/migrate/transformers/chatgpt-to-claude.js.map +1 -0
  147. package/dist/migrate/transformers/claude-to-chatgpt.d.ts +41 -0
  148. package/dist/migrate/transformers/claude-to-chatgpt.d.ts.map +1 -0
  149. package/dist/migrate/transformers/claude-to-chatgpt.js +532 -0
  150. package/dist/migrate/transformers/claude-to-chatgpt.js.map +1 -0
  151. package/dist/migrate/transformers/registry.js +6 -4
  152. package/dist/migrate/transformers/registry.js.map +1 -1
  153. package/dist/migrate/transformers/rules.d.ts +168 -0
  154. package/dist/migrate/transformers/rules.d.ts.map +1 -0
  155. package/dist/migrate/transformers/rules.js +487 -0
  156. package/dist/migrate/transformers/rules.js.map +1 -0
  157. package/dist/migrate/types.d.ts +2 -0
  158. package/dist/migrate/types.d.ts.map +1 -1
  159. 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