ethagent 2.4.0 → 3.0.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/README.md +7 -4
- package/package.json +2 -1
- package/src/app/FirstRun.tsx +155 -15
- package/src/app/FirstRunTimeline.tsx +4 -0
- package/src/app/input/AppInputProvider.tsx +19 -0
- package/src/app/input/appInputParser.ts +19 -4
- package/src/chat/ChatBottomPane.tsx +3 -1
- package/src/chat/ChatScreen.tsx +7 -1
- package/src/chat/ConversationStack.tsx +25 -19
- package/src/chat/MessageList.tsx +194 -53
- package/src/chat/chatSessionState.ts +1 -1
- package/src/chat/chatTurnOrchestrator.ts +59 -0
- package/src/chat/input/ChatInput.tsx +3 -0
- package/src/chat/input/textCursor.ts +13 -3
- package/src/chat/transcript/TranscriptView.tsx +7 -5
- package/src/chat/transcript/transcriptViewport.ts +88 -17
- package/src/chat/views/PermissionPrompt.tsx +26 -26
- package/src/chat/views/PermissionsView.tsx +18 -12
- package/src/chat/views/RewindView.tsx +3 -1
- package/src/cli/ResetConfirmView.tsx +24 -9
- package/src/identity/continuity/editor.ts +27 -2
- package/src/identity/continuity/envelope.ts +125 -0
- package/src/identity/continuity/publicSkills.ts +37 -1
- package/src/identity/continuity/skills/frontmatter.ts +183 -0
- package/src/identity/continuity/skills/loadSkills.ts +609 -0
- package/src/identity/continuity/skills/publicSkillsSync.ts +32 -0
- package/src/identity/continuity/skills/scaffold.ts +52 -0
- package/src/identity/continuity/skills/types.ts +30 -0
- package/src/identity/continuity/storage/defaults.ts +28 -47
- package/src/identity/continuity/storage/files.ts +1 -0
- package/src/identity/continuity/storage/paths.ts +1 -0
- package/src/identity/continuity/storage/scaffold.ts +25 -23
- package/src/identity/continuity/storage/status.ts +34 -5
- package/src/identity/continuity/storage/types.ts +3 -2
- package/src/identity/continuity/storage.ts +3 -0
- package/src/identity/hub/OperationalRoutes.tsx +105 -3
- package/src/identity/hub/Routes.tsx +5 -3
- package/src/identity/hub/continuity/ContinuityDashboardScreen.tsx +5 -51
- package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +1 -1
- package/src/identity/hub/continuity/SavePromptScreen.tsx +1 -0
- package/src/identity/hub/continuity/effects.ts +36 -5
- package/src/identity/hub/continuity/skills/DeleteSkillConfirmScreen.tsx +112 -0
- package/src/identity/hub/continuity/skills/DeleteSkillScreen.tsx +123 -0
- package/src/identity/hub/continuity/skills/NewSkillScreen.tsx +57 -0
- package/src/identity/hub/continuity/skills/NewSkillVisibilityScreen.tsx +52 -0
- package/src/identity/hub/continuity/skills/SkillVisibilityScreen.tsx +171 -0
- package/src/identity/hub/continuity/skills/SkillsTreeScreen.tsx +213 -0
- package/src/identity/hub/continuity/snapshot.ts +3 -0
- package/src/identity/hub/continuity/state.ts +3 -2
- package/src/identity/hub/continuity/vault.ts +42 -10
- package/src/identity/hub/custody/CustodyEditFlow.tsx +3 -3
- package/src/identity/hub/identityHubReducer.ts +21 -0
- package/src/identity/hub/profile/effects.ts +16 -3
- package/src/identity/hub/restore/RestoreFlow.tsx +43 -6
- package/src/identity/hub/restore/apply.ts +12 -1
- package/src/identity/hub/restore/recovery.ts +11 -1
- package/src/identity/hub/restore/resolve.ts +1 -1
- package/src/identity/hub/restore/useRestoreEffects.ts +4 -6
- package/src/identity/hub/shared/components/DetailsScreen.tsx +4 -1
- package/src/identity/hub/shared/components/IdentitySummary.tsx +97 -53
- package/src/identity/hub/shared/components/MenuScreen.tsx +18 -15
- package/src/identity/hub/shared/components/UnlinkedIdentityScreen.tsx +1 -1
- package/src/identity/hub/shared/components/menuFlagsFromReconciliation.ts +8 -12
- package/src/identity/hub/shared/effects/sync.ts +16 -3
- package/src/identity/hub/shared/model/copy.ts +2 -4
- package/src/identity/hub/transfer/effects.ts +15 -2
- package/src/identity/hub/useIdentityHubContinuity.ts +145 -23
- package/src/identity/hub/useIdentityHubController.ts +5 -1
- package/src/identity/hub/useIdentityHubSideEffects.ts +2 -4
- package/src/mcp/manager.ts +1 -1
- package/src/models/ModelPicker.tsx +89 -84
- package/src/models/llamacpp.ts +160 -11
- package/src/models/llamacppPreflight.ts +1 -16
- package/src/models/modelPickerOptions.ts +43 -37
- package/src/providers/contracts.ts +1 -0
- package/src/providers/openai-chat.ts +50 -9
- package/src/providers/openai-responses.ts +19 -4
- package/src/runtime/toolExecution.ts +4 -3
- package/src/runtime/turn.ts +61 -30
- package/src/tools/changeDirectoryTool.ts +1 -1
- package/src/tools/contracts.ts +10 -0
- package/src/tools/deleteFileTool.ts +1 -1
- package/src/tools/editTool.ts +1 -1
- package/src/tools/listDirectoryTool.ts +1 -1
- package/src/tools/listSkillFilesTool.ts +77 -0
- package/src/tools/listSkillsTool.ts +68 -0
- package/src/tools/mcpResourceTools.ts +2 -2
- package/src/tools/privateContinuityReadTool.ts +1 -1
- package/src/tools/readSkillTool.ts +107 -0
- package/src/tools/readTool.ts +1 -1
- package/src/tools/registry.ts +6 -0
- package/src/tools/writeFileTool.ts +22 -2
- package/src/ui/Spinner.tsx +1 -1
- package/src/identity/continuity/localBackup.ts +0 -249
- package/src/identity/continuity/zipWriter.ts +0 -95
- package/src/identity/hub/continuity/index.ts +0 -7
- package/src/identity/hub/ens/index.ts +0 -11
- package/src/identity/hub/restore/index.ts +0 -22
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { SkillFrontmatter, SkillVisibility } from './types.js'
|
|
2
|
+
|
|
3
|
+
const SUPPORTED_KEYS = new Set([
|
|
4
|
+
'name',
|
|
5
|
+
'description',
|
|
6
|
+
'when_to_use',
|
|
7
|
+
'when-to-use',
|
|
8
|
+
'whenToUse',
|
|
9
|
+
'version',
|
|
10
|
+
'argument-hint',
|
|
11
|
+
'argument_hint',
|
|
12
|
+
'argumentHint',
|
|
13
|
+
'tags',
|
|
14
|
+
'visibility',
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
const VISIBILITY_VALUES: SkillVisibility[] = ['private', 'public', 'discoverable']
|
|
18
|
+
|
|
19
|
+
export type ParsedSkillFile = {
|
|
20
|
+
frontmatter: SkillFrontmatter
|
|
21
|
+
body: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function parseSkillFile(content: string): ParsedSkillFile {
|
|
25
|
+
const normalized = content.replace(/^/, '').replace(/\r\n?/g, '\n')
|
|
26
|
+
if (!normalized.startsWith('---\n') && normalized !== '---' && !normalized.startsWith('---\r')) {
|
|
27
|
+
return { frontmatter: {}, body: normalized.trim() }
|
|
28
|
+
}
|
|
29
|
+
const afterOpen = normalized.slice(4)
|
|
30
|
+
const closeIdx = afterOpen.search(/^---\s*$/m)
|
|
31
|
+
if (closeIdx < 0) {
|
|
32
|
+
return { frontmatter: {}, body: normalized.trim() }
|
|
33
|
+
}
|
|
34
|
+
const fmText = afterOpen.slice(0, closeIdx)
|
|
35
|
+
const bodyText = afterOpen.slice(closeIdx).replace(/^---\s*\n?/, '').replace(/^\n+/, '')
|
|
36
|
+
return {
|
|
37
|
+
frontmatter: parseFrontmatterBlock(fmText),
|
|
38
|
+
body: bodyText.trim(),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseFrontmatterBlock(text: string): SkillFrontmatter {
|
|
43
|
+
const out: SkillFrontmatter = {}
|
|
44
|
+
const lines = text.split('\n')
|
|
45
|
+
for (let i = 0; i < lines.length; i++) {
|
|
46
|
+
const line = lines[i]
|
|
47
|
+
if (line === undefined) continue
|
|
48
|
+
const trimmed = line.trim()
|
|
49
|
+
if (!trimmed || trimmed.startsWith('#')) continue
|
|
50
|
+
const match = /^([A-Za-z_][A-Za-z0-9_\-]*)\s*:\s*(.*)$/.exec(line)
|
|
51
|
+
if (!match) continue
|
|
52
|
+
const rawKey = match[1] ?? ''
|
|
53
|
+
if (!SUPPORTED_KEYS.has(rawKey)) continue
|
|
54
|
+
let rawValue = match[2] ?? ''
|
|
55
|
+
if (rawValue === '' || rawValue === '|' || rawValue === '>') {
|
|
56
|
+
const collected: string[] = []
|
|
57
|
+
while (i + 1 < lines.length) {
|
|
58
|
+
const next = lines[i + 1]
|
|
59
|
+
if (next === undefined) break
|
|
60
|
+
if (next.startsWith(' ') || next.startsWith('\t')) {
|
|
61
|
+
collected.push(next.replace(/^\s+/, ''))
|
|
62
|
+
i++
|
|
63
|
+
} else if (next === '' || next.trim() === '') {
|
|
64
|
+
break
|
|
65
|
+
} else {
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
rawValue = collected.join(' ').trim()
|
|
70
|
+
}
|
|
71
|
+
const key = normalizeKey(rawKey)
|
|
72
|
+
if (!key) continue
|
|
73
|
+
assignKey(out, key, rawValue)
|
|
74
|
+
}
|
|
75
|
+
return out
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizeKey(key: string): keyof SkillFrontmatter | null {
|
|
79
|
+
switch (key) {
|
|
80
|
+
case 'name': return 'name'
|
|
81
|
+
case 'description': return 'description'
|
|
82
|
+
case 'when_to_use':
|
|
83
|
+
case 'when-to-use':
|
|
84
|
+
case 'whenToUse':
|
|
85
|
+
return 'whenToUse'
|
|
86
|
+
case 'version': return 'version'
|
|
87
|
+
case 'argument-hint':
|
|
88
|
+
case 'argument_hint':
|
|
89
|
+
case 'argumentHint':
|
|
90
|
+
return 'argumentHint'
|
|
91
|
+
case 'tags': return 'tags'
|
|
92
|
+
case 'visibility': return 'visibility'
|
|
93
|
+
default: return null
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function assignKey(out: SkillFrontmatter, key: keyof SkillFrontmatter, rawValue: string): void {
|
|
98
|
+
const stripped = stripInlineComment(rawValue).trim()
|
|
99
|
+
if (key === 'tags') {
|
|
100
|
+
out.tags = parseStringList(stripped)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
if (key === 'visibility') {
|
|
104
|
+
const literal = parseScalar(stripped).toLowerCase()
|
|
105
|
+
if ((VISIBILITY_VALUES as string[]).includes(literal)) {
|
|
106
|
+
out.visibility = literal as SkillVisibility
|
|
107
|
+
}
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
const value = parseScalar(stripped)
|
|
111
|
+
if (!value) return
|
|
112
|
+
out[key] = value
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parseScalar(value: string): string {
|
|
116
|
+
if (value === '') return ''
|
|
117
|
+
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
118
|
+
return unescapeDoubleQuoted(value.slice(1, -1))
|
|
119
|
+
}
|
|
120
|
+
if (value.startsWith("'") && value.endsWith("'") && value.length >= 2) {
|
|
121
|
+
return value.slice(1, -1).replace(/''/g, "'")
|
|
122
|
+
}
|
|
123
|
+
return value
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseStringList(value: string): string[] {
|
|
127
|
+
if (!value) return []
|
|
128
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
129
|
+
const inner = value.slice(1, -1)
|
|
130
|
+
return splitListItems(inner)
|
|
131
|
+
.map(parseScalar)
|
|
132
|
+
.filter(item => item.length > 0)
|
|
133
|
+
}
|
|
134
|
+
return splitListItems(value)
|
|
135
|
+
.map(parseScalar)
|
|
136
|
+
.filter(item => item.length > 0)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function splitListItems(value: string): string[] {
|
|
140
|
+
const items: string[] = []
|
|
141
|
+
let buffer = ''
|
|
142
|
+
let quote: string | null = null
|
|
143
|
+
for (let i = 0; i < value.length; i++) {
|
|
144
|
+
const ch = value[i]
|
|
145
|
+
if (quote) {
|
|
146
|
+
buffer += ch
|
|
147
|
+
if (ch === quote && value[i - 1] !== '\\') quote = null
|
|
148
|
+
continue
|
|
149
|
+
}
|
|
150
|
+
if (ch === '"' || ch === "'") {
|
|
151
|
+
quote = ch
|
|
152
|
+
buffer += ch
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
if (ch === ',') {
|
|
156
|
+
items.push(buffer.trim())
|
|
157
|
+
buffer = ''
|
|
158
|
+
continue
|
|
159
|
+
}
|
|
160
|
+
buffer += ch
|
|
161
|
+
}
|
|
162
|
+
if (buffer.trim()) items.push(buffer.trim())
|
|
163
|
+
return items
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function unescapeDoubleQuoted(value: string): string {
|
|
167
|
+
return value.replace(/\\(["\\/bfnrt])/g, (_, c) => {
|
|
168
|
+
switch (c) {
|
|
169
|
+
case 'n': return '\n'
|
|
170
|
+
case 'r': return '\r'
|
|
171
|
+
case 't': return '\t'
|
|
172
|
+
case 'b': return '\b'
|
|
173
|
+
case 'f': return '\f'
|
|
174
|
+
default: return c
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function stripInlineComment(value: string): string {
|
|
180
|
+
if (value.startsWith('"') || value.startsWith("'") || value.startsWith('[')) return value
|
|
181
|
+
const hash = value.indexOf(' #')
|
|
182
|
+
return hash === -1 ? value : value.slice(0, hash)
|
|
183
|
+
}
|