codexmate 0.1.24 → 0.1.25
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/cli.js +4 -1
- package/package.json +1 -1
- package/plugins/prompt-templates/computed.mjs +1 -1
- package/plugins/prompt-templates/index.mjs +3 -3
- package/plugins/prompt-templates/manifest.mjs +5 -3
- package/plugins/prompt-templates/methods.mjs +9 -2
- package/plugins/registry.mjs +5 -2
- package/plugins/text-tools/computed.mjs +23 -0
- package/plugins/text-tools/index.mjs +14 -0
- package/plugins/text-tools/manifest.mjs +20 -0
- package/plugins/text-tools/methods.mjs +24 -0
- package/plugins/text-tools/overview.mjs +12 -0
- package/plugins/text-tools/ownership.mjs +7 -0
- package/web-ui/app.js +2 -2
- package/web-ui/index.html +0 -1
- package/web-ui/logic.markdown-editor.mjs +5 -57
- package/web-ui/modules/app.methods.navigation.mjs +79 -3
- package/web-ui/modules/app.methods.prompts-editor.mjs +6 -64
- package/web-ui/modules/app.methods.web-ui-preferences.mjs +7 -1
- package/web-ui/modules/i18n/locales/en.mjs +11 -0
- package/web-ui/modules/i18n/locales/ja.mjs +11 -0
- package/web-ui/modules/i18n/locales/vi.mjs +11 -0
- package/web-ui/modules/i18n/locales/zh-tw.mjs +11 -0
- package/web-ui/modules/i18n/locales/zh.mjs +11 -0
- package/web-ui/modules/plugins.computed.mjs +8 -2
- package/web-ui/modules/plugins.methods.mjs +8 -2
- package/web-ui/partials/index/layout-header.html +19 -4
- package/web-ui/partials/index/panel-plugins.html +45 -5
- package/web-ui/partials/index/panel-prompts.html +2 -17
- package/web-ui/res/web-ui-render.precompiled.js +104 -72
- package/web-ui/session-helpers.mjs +0 -1
- package/web-ui/source-bundle.cjs +1 -0
- package/web-ui/styles/prompts-editor.css +3 -66
package/cli.js
CHANGED
|
@@ -1098,7 +1098,10 @@ function normalizeWebUiPreferences(value = {}) {
|
|
|
1098
1098
|
skillsTargetApp: navigation.skillsTargetApp === 'claude' || navigation.skillsTargetApp === 'pi'
|
|
1099
1099
|
? navigation.skillsTargetApp
|
|
1100
1100
|
: 'codex',
|
|
1101
|
-
promptTemplatesMode: navigation.promptTemplatesMode === 'manage' ? 'manage' : 'compose'
|
|
1101
|
+
promptTemplatesMode: navigation.promptTemplatesMode === 'manage' ? 'manage' : 'compose',
|
|
1102
|
+
pluginsActiveId: typeof navigation.pluginsActiveId === 'string' && navigation.pluginsActiveId.trim()
|
|
1103
|
+
? navigation.pluginsActiveId.trim()
|
|
1104
|
+
: 'prompt-templates'
|
|
1102
1105
|
}
|
|
1103
1106
|
};
|
|
1104
1107
|
}
|
package/package.json
CHANGED
|
@@ -158,7 +158,7 @@ function localizeBuiltinPromptTemplate(item, t) {
|
|
|
158
158
|
|
|
159
159
|
import { pluginsRegistry } from '../registry.mjs';
|
|
160
160
|
|
|
161
|
-
export function
|
|
161
|
+
export function createPromptTemplatesComputed() {
|
|
162
162
|
return {
|
|
163
163
|
pluginsCatalog() {
|
|
164
164
|
return pluginsRegistry
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createPluginsMethods } from './methods.mjs';
|
|
2
|
-
export { createPluginsComputed } from './computed.mjs';
|
|
3
|
-
export { pluginMeta } from './manifest.mjs';
|
|
1
|
+
export { createPromptTemplatesMethods as createPluginsMethods } from './methods.mjs';
|
|
2
|
+
export { createPromptTemplatesComputed as createPluginsComputed } from './computed.mjs';
|
|
3
|
+
export { promptTemplatesPluginMeta as pluginMeta } from './manifest.mjs';
|
|
4
4
|
export {
|
|
5
5
|
readPromptTemplatesFromStorage,
|
|
6
6
|
persistPromptTemplatesToStorage,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pluginOwnership } from './ownership.mjs';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const promptTemplatesBaseMeta = {
|
|
4
4
|
id: 'prompt-templates',
|
|
5
5
|
title: 'Prompt Templates',
|
|
6
6
|
titleKey: 'plugins.catalog.promptTemplates.title',
|
|
@@ -11,8 +11,10 @@ const baseMeta = {
|
|
|
11
11
|
tone: 'configured'
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const
|
|
15
|
-
...
|
|
14
|
+
export const promptTemplatesPluginMeta = {
|
|
15
|
+
...promptTemplatesBaseMeta,
|
|
16
16
|
createdBy: pluginOwnership && typeof pluginOwnership.createdBy === 'string' ? pluginOwnership.createdBy : '',
|
|
17
17
|
maintainers: pluginOwnership && Array.isArray(pluginOwnership.maintainers) ? pluginOwnership.maintainers : []
|
|
18
18
|
};
|
|
19
|
+
|
|
20
|
+
export { promptTemplatesPluginMeta as pluginMeta };
|
|
@@ -79,7 +79,7 @@ function normalizePromptTemplateDraft(draft) {
|
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
export function
|
|
82
|
+
export function createPromptTemplatesMethods() {
|
|
83
83
|
return {
|
|
84
84
|
resetPromptComposerVarValues() {
|
|
85
85
|
this.promptComposerVarValuesRaw = {};
|
|
@@ -280,8 +280,15 @@ export function createPluginsMethods() {
|
|
|
280
280
|
selectPlugin(pluginId) {
|
|
281
281
|
const id = typeof pluginId === 'string' ? pluginId.trim() : '';
|
|
282
282
|
if (!id) return;
|
|
283
|
-
|
|
283
|
+
const entry = getPluginEntry(id);
|
|
284
|
+
if (!entry) return;
|
|
284
285
|
this.pluginsActiveId = id;
|
|
286
|
+
if (typeof this.saveNavState === 'function') {
|
|
287
|
+
this.saveNavState();
|
|
288
|
+
}
|
|
289
|
+
if (typeof entry.loadOverview === 'function' && typeof this.loadPluginsOverview === 'function') {
|
|
290
|
+
void Promise.resolve(this.loadPluginsOverview({ silent: true })).catch(() => {});
|
|
291
|
+
}
|
|
285
292
|
},
|
|
286
293
|
|
|
287
294
|
async loadPluginsOverview(options = {}) {
|
package/plugins/registry.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { promptTemplatesPluginMeta } from './prompt-templates/manifest.mjs';
|
|
2
2
|
import { loadPromptTemplatesOverview } from './prompt-templates/overview.mjs';
|
|
3
|
+
import { textToolsPluginMeta } from './text-tools/manifest.mjs';
|
|
4
|
+
import { loadTextToolsOverview } from './text-tools/overview.mjs';
|
|
3
5
|
|
|
4
6
|
export const pluginsRegistry = [
|
|
5
|
-
{ id:
|
|
7
|
+
{ id: promptTemplatesPluginMeta.id, meta: promptTemplatesPluginMeta, loadOverview: loadPromptTemplatesOverview },
|
|
8
|
+
{ id: textToolsPluginMeta.id, meta: textToolsPluginMeta, loadOverview: loadTextToolsOverview }
|
|
6
9
|
];
|
|
7
10
|
|
|
8
11
|
export function getFirstPluginId() {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { textTools, DEFAULT_TEXT_TOOL_ID } from './index.mjs';
|
|
2
|
+
|
|
3
|
+
export function createTextToolsComputed() {
|
|
4
|
+
return {
|
|
5
|
+
textToolsList() {
|
|
6
|
+
const t = typeof this.t === 'function' ? this.t : null;
|
|
7
|
+
return textTools.map((tool) => ({
|
|
8
|
+
id: tool.id,
|
|
9
|
+
labelKey: tool.labelKey,
|
|
10
|
+
label: t ? t(tool.labelKey) : tool.labelKey
|
|
11
|
+
}));
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
textToolsOutput() {
|
|
15
|
+
const activeId = typeof this.textToolsActiveToolId === 'string' ? this.textToolsActiveToolId.trim() : '';
|
|
16
|
+
const tool = textTools.find((item) => item && item.id === activeId)
|
|
17
|
+
|| textTools.find((item) => item && item.id === DEFAULT_TEXT_TOOL_ID)
|
|
18
|
+
|| null;
|
|
19
|
+
const input = typeof this.textToolsInput === 'string' ? this.textToolsInput : '';
|
|
20
|
+
return tool && typeof tool.run === 'function' ? tool.run(input) : '';
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DEFAULT_TEXT_TOOL_ID = 'compress';
|
|
2
|
+
|
|
3
|
+
export function compressTextToSingleLine(input) {
|
|
4
|
+
if (typeof input !== 'string') return '';
|
|
5
|
+
return input.replace(/\s+/g, ' ').trim();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const textTools = [
|
|
9
|
+
{
|
|
10
|
+
id: 'compress',
|
|
11
|
+
labelKey: 'plugins.textTools.tools.compress',
|
|
12
|
+
run: compressTextToSingleLine
|
|
13
|
+
}
|
|
14
|
+
];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { textToolsPluginOwnership } from './ownership.mjs';
|
|
2
|
+
|
|
3
|
+
const textToolsBaseMeta = {
|
|
4
|
+
id: 'text-tools',
|
|
5
|
+
title: 'Text Tools',
|
|
6
|
+
titleKey: 'plugins.catalog.textTools.title',
|
|
7
|
+
description: 'Lightweight in-browser text utilities; the first tool compresses text into a single line.',
|
|
8
|
+
descriptionKey: 'plugins.catalog.textTools.description',
|
|
9
|
+
statusLabel: 'standard',
|
|
10
|
+
statusLabelKey: 'plugins.status.standard',
|
|
11
|
+
tone: 'configured'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const textToolsPluginMeta = {
|
|
15
|
+
...textToolsBaseMeta,
|
|
16
|
+
createdBy: textToolsPluginOwnership && typeof textToolsPluginOwnership.createdBy === 'string' ? textToolsPluginOwnership.createdBy : '',
|
|
17
|
+
maintainers: textToolsPluginOwnership && Array.isArray(textToolsPluginOwnership.maintainers) ? textToolsPluginOwnership.maintainers : []
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { textToolsPluginMeta as pluginMeta };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function createTextToolsMethods() {
|
|
2
|
+
return {
|
|
3
|
+
async copyTextToolsOutput() {
|
|
4
|
+
const text = typeof this.textToolsOutput === 'string' ? this.textToolsOutput.trim() : '';
|
|
5
|
+
if (!text) {
|
|
6
|
+
this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.empty') : 'Nothing to copy', 'info');
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
11
|
+
await navigator.clipboard.writeText(text);
|
|
12
|
+
this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.ok') : 'Copied', 'success');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
} catch (_) {}
|
|
16
|
+
const ok = typeof this.fallbackCopyText === 'function' ? this.fallbackCopyText(text) : false;
|
|
17
|
+
if (ok) {
|
|
18
|
+
this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.ok') : 'Copied', 'success');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.fail') : 'Copy failed', 'error');
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { textTools, DEFAULT_TEXT_TOOL_ID } from './index.mjs';
|
|
2
|
+
|
|
3
|
+
export async function loadTextToolsOverview(ctx) {
|
|
4
|
+
const app = ctx && typeof ctx === 'object' ? ctx : {};
|
|
5
|
+
const activeId = typeof app.textToolsActiveToolId === 'string' ? app.textToolsActiveToolId.trim() : '';
|
|
6
|
+
const exists = textTools.some((tool) => tool && tool.id === activeId);
|
|
7
|
+
app.textToolsActiveToolId = exists ? activeId : DEFAULT_TEXT_TOOL_ID;
|
|
8
|
+
if (typeof app.textToolsInput !== 'string') {
|
|
9
|
+
app.textToolsInput = '';
|
|
10
|
+
}
|
|
11
|
+
return true;
|
|
12
|
+
}
|
package/web-ui/app.js
CHANGED
|
@@ -111,8 +111,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
111
111
|
promptsPathReferencePaths: {},
|
|
112
112
|
promptsPathReferenceLoading: false,
|
|
113
113
|
promptsPathReferenceCacheKey: '',
|
|
114
|
-
agentsHighlightHtml: '',
|
|
115
|
-
sysPromptHighlightHtml: '',
|
|
116
114
|
agentsPreviewHtml: '',
|
|
117
115
|
sysPromptPreviewHtml: '',
|
|
118
116
|
projectClaudeMdPath: '',
|
|
@@ -172,6 +170,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
172
170
|
pluginsActiveId: 'prompt-templates',
|
|
173
171
|
pluginsLoading: false,
|
|
174
172
|
pluginsError: '',
|
|
173
|
+
textToolsActiveToolId: '',
|
|
174
|
+
textToolsInput: '',
|
|
175
175
|
promptTemplatesListRaw: [],
|
|
176
176
|
promptTemplatesLoadedOnce: false,
|
|
177
177
|
promptTemplatesKeyword: '',
|
package/web-ui/index.html
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
<link rel="apple-touch-icon" href="/res/logo-pack.webp">
|
|
9
9
|
<script src="/res/vue.runtime.global.prod.js"></script>
|
|
10
10
|
<script src="/res/json5.min.js"></script>
|
|
11
|
-
<script src="/res/highlight.min.js"></script>
|
|
12
11
|
<script src="/res/marked.min.js"></script>
|
|
13
12
|
<script src="/res/purify.min.js"></script>
|
|
14
13
|
<link rel="stylesheet" href="/web-ui/styles.css">
|
|
@@ -2,67 +2,15 @@
|
|
|
2
2
|
* Pure logic for the prompts-panel Markdown editor.
|
|
3
3
|
* No DOM access in this module so every function stays unit-testable.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* transparent textarea. Preview rendering delegates to the vendored
|
|
9
|
-
* marked + DOMPurify pair; raw markdown may embed arbitrary HTML, so
|
|
10
|
-
* sanitize is mandatory before the result reaches v-html.
|
|
5
|
+
* Preview rendering delegates to the vendored marked + DOMPurify pair; raw
|
|
6
|
+
* markdown may embed arbitrary HTML, so sanitize is mandatory before the
|
|
7
|
+
* result reaches v-html.
|
|
11
8
|
*/
|
|
12
9
|
|
|
13
|
-
const HIGHLIGHT_MAX_CHARS = 200000;
|
|
14
|
-
const HTML_ESCAPE_MAP = {
|
|
15
|
-
'&': '&',
|
|
16
|
-
'<': '<',
|
|
17
|
-
'>': '>',
|
|
18
|
-
'"': '"',
|
|
19
|
-
"'": '''
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let hasWarnedHighlightFallback = false;
|
|
24
|
-
|
|
25
|
-
export function escapeHtmlText(text) {
|
|
26
|
-
return String(text === null || text === undefined ? '' : text)
|
|
27
|
-
.replace(/[&<>"']/g, (ch) => HTML_ESCAPE_MAP[ch]);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function plainHighlightFallback(text) {
|
|
31
|
-
if (!hasWarnedHighlightFallback) {
|
|
32
|
-
hasWarnedHighlightFallback = true;
|
|
33
|
-
// eslint-disable-next-line no-console
|
|
34
|
-
console.warn('prompts editor: highlight.js unavailable, editor falls back to plain text rendering');
|
|
35
|
-
}
|
|
36
|
-
return escapeHtmlText(text) + '\n';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Produce the highlighted HTML layer for a markdown source string.
|
|
41
|
-
* highlight.js escapes HTML entities itself; the trailing newline keeps
|
|
42
|
-
* the <pre> backdrop visually aligned with the textarea's final line.
|
|
43
|
-
* Returns escaped plain text when hljs is missing or the input exceeds
|
|
44
|
-
* the highlight budget (observable degradation, never a fake success).
|
|
45
|
-
*/
|
|
46
|
-
export function highlightMarkdownText(text, hljs) {
|
|
47
|
-
const source = typeof text === 'string' ? text : '';
|
|
48
|
-
if (!hljs || typeof hljs.highlight !== 'function' || typeof hljs.getLanguage !== 'function' || !hljs.getLanguage('markdown')) {
|
|
49
|
-
return plainHighlightFallback(source);
|
|
50
|
-
}
|
|
51
|
-
if (source.length > HIGHLIGHT_MAX_CHARS) {
|
|
52
|
-
return plainHighlightFallback(source);
|
|
53
|
-
}
|
|
54
|
-
try {
|
|
55
|
-
return hljs.highlight(source, { language: 'markdown', ignoreUnescapedHTML: true }).value + '\n';
|
|
56
|
-
} catch (e) {
|
|
57
|
-
return plainHighlightFallback(source);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
10
|
/**
|
|
63
11
|
* Render a markdown preview. Returns a state object instead of raw HTML so
|
|
64
|
-
* the UI can surface "libs missing" and "empty input" explicitly instead
|
|
65
|
-
*
|
|
12
|
+
* the UI can surface "libs missing" and "empty input" explicitly instead of
|
|
13
|
+
* faking a successful render.
|
|
66
14
|
*/
|
|
67
15
|
export function buildMarkdownPreviewHtml(text, marked, purify) {
|
|
68
16
|
const source = typeof text === 'string' ? text : '';
|
|
@@ -110,12 +110,17 @@
|
|
|
110
110
|
const settingsTab = typeof vm.settingsTab === 'string' ? vm.settingsTab.trim().toLowerCase() : 'general';
|
|
111
111
|
const skillsTargetApp = typeof vm.skillsTargetApp === 'string' && (vm.skillsTargetApp === 'codex' || vm.skillsTargetApp === 'claude' || vm.skillsTargetApp === 'pi') ? vm.skillsTargetApp : 'codex';
|
|
112
112
|
const promptTemplatesMode = typeof vm.promptTemplatesMode === 'string' && (vm.promptTemplatesMode === 'compose' || vm.promptTemplatesMode === 'manage') ? vm.promptTemplatesMode : 'compose';
|
|
113
|
+
const pluginsActiveIdSource = resolvedOverrides && typeof resolvedOverrides.pluginsActiveId === 'string'
|
|
114
|
+
? resolvedOverrides.pluginsActiveId
|
|
115
|
+
: vm.pluginsActiveId;
|
|
116
|
+
const pluginsActiveId = typeof pluginsActiveIdSource === 'string' ? pluginsActiveIdSource.trim() : '';
|
|
113
117
|
const snapshot = {
|
|
114
118
|
settingsTab: settingsTab === 'data' ? 'data' : 'general',
|
|
115
119
|
mainTab: resolveSelectableMainTab(mainTab),
|
|
116
120
|
configMode: configModeSet && configModeSet.has(configMode) ? configMode : 'codex',
|
|
117
121
|
skillsTargetApp,
|
|
118
|
-
promptTemplatesMode
|
|
122
|
+
promptTemplatesMode,
|
|
123
|
+
pluginsActiveId: pluginsActiveId || 'prompt-templates'
|
|
119
124
|
};
|
|
120
125
|
if (typeof vm.persistWebUiPreferences === 'function') {
|
|
121
126
|
vm.persistWebUiPreferences({ navigation: snapshot });
|
|
@@ -192,6 +197,7 @@
|
|
|
192
197
|
intent: '',
|
|
193
198
|
pendingTarget: '',
|
|
194
199
|
pendingConfigMode: '',
|
|
200
|
+
pendingPluginsId: '',
|
|
195
201
|
ticket: 0
|
|
196
202
|
};
|
|
197
203
|
return this.__mainTabSwitchState;
|
|
@@ -242,7 +248,7 @@
|
|
|
242
248
|
if (!normalizedKind || !normalizedValue) {
|
|
243
249
|
return;
|
|
244
250
|
}
|
|
245
|
-
const expectedIntent = normalizedKind === 'config'
|
|
251
|
+
const expectedIntent = normalizedKind === 'config' || normalizedKind === 'plugins' ? normalizedKind : normalizedValue;
|
|
246
252
|
this.cancelTouchNavIntentReset();
|
|
247
253
|
const token = (Number(this.__touchNavIntentResetToken) || 0) + 1;
|
|
248
254
|
this.__touchNavIntentResetToken = token;
|
|
@@ -259,21 +265,26 @@
|
|
|
259
265
|
this.clearMainTabSwitchIntent(expectedIntent);
|
|
260
266
|
}, 1000);
|
|
261
267
|
},
|
|
262
|
-
applyImmediateNavIntent(tab, configMode = '') {
|
|
268
|
+
applyImmediateNavIntent(tab, configMode = '', pluginsId = '') {
|
|
263
269
|
if (typeof document === 'undefined') return;
|
|
264
270
|
const normalizedTab = typeof tab === 'string' ? tab.trim().toLowerCase() : '';
|
|
265
271
|
if (!normalizedTab) return;
|
|
266
272
|
const normalizedMode = typeof configMode === 'string' ? configMode.trim().toLowerCase() : '';
|
|
273
|
+
const normalizedPluginId = typeof pluginsId === 'string' ? pluginsId.trim().toLowerCase() : '';
|
|
267
274
|
const domState = this.ensureImmediateNavDomState();
|
|
268
275
|
const nodes = Array.isArray(domState.navNodes) ? domState.navNodes : [];
|
|
269
276
|
for (const node of nodes) {
|
|
270
277
|
if (!node || !node.classList) continue;
|
|
271
278
|
const nodeTab = String(node.getAttribute('data-main-tab') || '').trim().toLowerCase();
|
|
272
279
|
const nodeMode = String(node.getAttribute('data-config-mode') || '').trim().toLowerCase();
|
|
280
|
+
const nodePluginId = String(node.getAttribute('data-plugins-id') || '').trim().toLowerCase();
|
|
273
281
|
let shouldActivate = nodeTab === normalizedTab;
|
|
274
282
|
if (shouldActivate && normalizedTab === 'config') {
|
|
275
283
|
shouldActivate = nodeMode ? nodeMode === normalizedMode : false;
|
|
276
284
|
}
|
|
285
|
+
if (shouldActivate && normalizedTab === 'plugins') {
|
|
286
|
+
shouldActivate = nodePluginId ? nodePluginId === normalizedPluginId : !normalizedPluginId;
|
|
287
|
+
}
|
|
277
288
|
node.classList.toggle('nav-intent-active', !!shouldActivate);
|
|
278
289
|
node.classList.toggle('nav-intent-inactive', !shouldActivate);
|
|
279
290
|
}
|
|
@@ -395,6 +406,67 @@
|
|
|
395
406
|
if (this.consumePointerNavCommit('config', normalizedMode)) return;
|
|
396
407
|
this.switchConfigMode(normalizedMode);
|
|
397
408
|
},
|
|
409
|
+
|
|
410
|
+
switchPluginsTab(pluginId) {
|
|
411
|
+
const normalizedId = typeof pluginId === 'string' ? pluginId.trim().toLowerCase() : '';
|
|
412
|
+
if (!normalizedId) return;
|
|
413
|
+
if (typeof this.selectPlugin === 'function') {
|
|
414
|
+
this.selectPlugin(normalizedId);
|
|
415
|
+
} else {
|
|
416
|
+
this.pluginsActiveId = normalizedId;
|
|
417
|
+
}
|
|
418
|
+
this.switchMainTab('plugins');
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
onPluginsTabPointerDown(pluginId) {
|
|
422
|
+
const event = arguments.length > 1 ? arguments[1] : null;
|
|
423
|
+
if (event && typeof event.button === 'number' && event.button !== 0) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const normalizedId = typeof pluginId === 'string' ? pluginId.trim().toLowerCase() : '';
|
|
427
|
+
if (!normalizedId) return;
|
|
428
|
+
persistNavState(this, { mainTab: 'plugins', pluginsActiveId: normalizedId });
|
|
429
|
+
this.setMainTabSwitchIntent('plugins');
|
|
430
|
+
if (typeof this.ensureMainTabSwitchState === 'function') {
|
|
431
|
+
this.ensureMainTabSwitchState().pendingPluginsId = normalizedId;
|
|
432
|
+
}
|
|
433
|
+
this.applyImmediateNavIntent('plugins', '', normalizedId);
|
|
434
|
+
const shouldHideSessionPanel = this.mainTab === 'sessions';
|
|
435
|
+
this.setSessionPanelFastHidden(shouldHideSessionPanel);
|
|
436
|
+
const pointerType = event && typeof event.pointerType === 'string'
|
|
437
|
+
? event.pointerType.trim().toLowerCase()
|
|
438
|
+
: '';
|
|
439
|
+
if (pointerType === 'touch') {
|
|
440
|
+
this.scheduleTouchNavIntentReset('plugins', normalizedId);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
this.recordPointerNavCommit('plugins', normalizedId);
|
|
444
|
+
this.switchPluginsTab(normalizedId);
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
onPluginsTabClick(pluginId) {
|
|
448
|
+
const normalizedId = typeof pluginId === 'string' ? pluginId.trim().toLowerCase() : '';
|
|
449
|
+
if (!normalizedId) return;
|
|
450
|
+
if (this.consumePointerNavCommit('plugins', normalizedId)) return;
|
|
451
|
+
this.switchPluginsTab(normalizedId);
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
isPluginsIdNavActive(pluginId) {
|
|
455
|
+
const normalizedId = typeof pluginId === 'string' ? pluginId.trim().toLowerCase() : '';
|
|
456
|
+
if (!normalizedId) return false;
|
|
457
|
+
if (!this.isMainTabNavActive('plugins')) return false;
|
|
458
|
+
const state = this.ensureMainTabSwitchState();
|
|
459
|
+
const pendingId = typeof state.pendingPluginsId === 'string'
|
|
460
|
+
? state.pendingPluginsId.trim().toLowerCase()
|
|
461
|
+
: '';
|
|
462
|
+
if (state.intent === 'plugins' && pendingId) {
|
|
463
|
+
return pendingId === normalizedId;
|
|
464
|
+
}
|
|
465
|
+
const currentId = typeof this.pluginsActiveId === 'string'
|
|
466
|
+
? this.pluginsActiveId.trim().toLowerCase()
|
|
467
|
+
: '';
|
|
468
|
+
return currentId === normalizedId;
|
|
469
|
+
},
|
|
398
470
|
clearMainTabSwitchIntent(expectedTab = '') {
|
|
399
471
|
const state = this.ensureMainTabSwitchState();
|
|
400
472
|
if (expectedTab && state.intent && state.intent !== expectedTab) {
|
|
@@ -404,6 +476,7 @@
|
|
|
404
476
|
state.intent = '';
|
|
405
477
|
state.pendingTarget = '';
|
|
406
478
|
state.pendingConfigMode = '';
|
|
479
|
+
state.pendingPluginsId = '';
|
|
407
480
|
this.clearImmediateNavIntent();
|
|
408
481
|
this.setSessionPanelFastHidden(false);
|
|
409
482
|
},
|
|
@@ -463,6 +536,9 @@
|
|
|
463
536
|
if (targetTab !== 'config') {
|
|
464
537
|
switchState.pendingConfigMode = '';
|
|
465
538
|
}
|
|
539
|
+
if (targetTab !== 'plugins') {
|
|
540
|
+
switchState.pendingPluginsId = '';
|
|
541
|
+
}
|
|
466
542
|
if (targetTab === previousTab) {
|
|
467
543
|
switchState.ticket += 1;
|
|
468
544
|
switchState.pendingTarget = '';
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Prompts-panel Markdown editor methods:
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* and the sysPromptContent editor.
|
|
2
|
+
* Prompts-panel Markdown editor methods: mobile view switching and the
|
|
3
|
+
* live split preview (marked + DOMPurify, debounced). One implementation
|
|
4
|
+
* is shared by the agentsContent editor and the sysPromptContent editor.
|
|
6
5
|
*
|
|
7
6
|
* State contract (declared in app.js data()):
|
|
8
7
|
* promptsPreviewEnabled, promptsPreviewCollapsed, promptsMobileView,
|
|
9
|
-
* promptsPreviewLibsMissing,
|
|
10
|
-
*
|
|
8
|
+
* promptsPreviewLibsMissing, agentsPreviewHtml, sysPromptPreviewHtml,
|
|
9
|
+
* agentsChangeAxis, sysChangeAxis,
|
|
11
10
|
* promptsPathReferencePaths, promptsPathReferenceLoading,
|
|
12
11
|
* promptsPathReferenceCacheKey (path-reference dropdown)
|
|
13
12
|
* Template contract:
|
|
14
13
|
* refs promptsAgentsTextarea / promptsSysTextarea on the two textareas,
|
|
15
|
-
* refs promptsAgentsHighlight / promptsSysHighlight on the backdrop <pre>,
|
|
16
14
|
* refs promptsAgentsDiffView / promptsSysDiffView on the two diff row containers.
|
|
17
15
|
*/
|
|
18
16
|
|
|
19
|
-
import {
|
|
20
|
-
buildMarkdownPreviewHtml,
|
|
21
|
-
highlightMarkdownText
|
|
22
|
-
} from '../logic.markdown-editor.mjs';
|
|
17
|
+
import { buildMarkdownPreviewHtml } from '../logic.markdown-editor.mjs';
|
|
23
18
|
import {
|
|
24
19
|
buildPromptPathReferenceOptions as buildPromptPathReferenceOptionList,
|
|
25
20
|
buildPromptPathReferenceSentence,
|
|
@@ -29,7 +24,6 @@ import {
|
|
|
29
24
|
buildPromptsDiffAxis
|
|
30
25
|
} from '../logic.prompts-change-axis.mjs';
|
|
31
26
|
|
|
32
|
-
const PROMPTS_HIGHLIGHT_DEBOUNCE_MS = 150;
|
|
33
27
|
const PROMPTS_PREVIEW_DEBOUNCE_MS = 300;
|
|
34
28
|
const PROMPTS_AXIS_DEBOUNCE_MS = 300;
|
|
35
29
|
|
|
@@ -37,7 +31,6 @@ const PROMPTS_EDITOR_META = {
|
|
|
37
31
|
agents: {
|
|
38
32
|
contentField: 'agentsContent',
|
|
39
33
|
originalField: 'agentsOriginalContent',
|
|
40
|
-
highlightField: 'agentsHighlightHtml',
|
|
41
34
|
previewField: 'agentsPreviewHtml',
|
|
42
35
|
axisField: 'agentsChangeAxis',
|
|
43
36
|
diffLinesField: 'agentsDiffLines',
|
|
@@ -48,13 +41,11 @@ const PROMPTS_EDITOR_META = {
|
|
|
48
41
|
diffLoadingField: 'agentsDiffLoading',
|
|
49
42
|
prepareDiffMethod: 'prepareAgentsDiff',
|
|
50
43
|
textareaRef: 'promptsAgentsTextarea',
|
|
51
|
-
highlightRef: 'promptsAgentsHighlight',
|
|
52
44
|
diffViewRef: 'promptsAgentsDiffView'
|
|
53
45
|
},
|
|
54
46
|
sys: {
|
|
55
47
|
contentField: 'sysPromptContent',
|
|
56
48
|
originalField: 'sysPromptOriginalContent',
|
|
57
|
-
highlightField: 'sysPromptHighlightHtml',
|
|
58
49
|
previewField: 'sysPromptPreviewHtml',
|
|
59
50
|
axisField: 'sysChangeAxis',
|
|
60
51
|
diffLinesField: 'sysPromptDiffLines',
|
|
@@ -65,7 +56,6 @@ const PROMPTS_EDITOR_META = {
|
|
|
65
56
|
diffLoadingField: 'sysPromptDiffLoading',
|
|
66
57
|
prepareDiffMethod: 'prepareSysPromptDiff',
|
|
67
58
|
textareaRef: 'promptsSysTextarea',
|
|
68
|
-
highlightRef: 'promptsSysHighlight',
|
|
69
59
|
diffViewRef: 'promptsSysDiffView'
|
|
70
60
|
}
|
|
71
61
|
};
|
|
@@ -74,13 +64,6 @@ function emptyPromptsChangeAxis() {
|
|
|
74
64
|
return { mode: 'edit', ticks: [], truncated: false, totalLines: 0, added: 0, removed: 0 };
|
|
75
65
|
}
|
|
76
66
|
|
|
77
|
-
function resolvePromptsHljs() {
|
|
78
|
-
if (typeof window !== 'undefined' && window.hljs) {
|
|
79
|
-
return window.hljs;
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
67
|
function resolvePromptsPreviewLibs() {
|
|
85
68
|
if (typeof window === 'undefined') {
|
|
86
69
|
return { marked: null, purify: null };
|
|
@@ -97,46 +80,6 @@ export function createPromptsEditorMethods(options = {}) {
|
|
|
97
80
|
},
|
|
98
81
|
|
|
99
82
|
|
|
100
|
-
refreshPromptsHighlight(key) {
|
|
101
|
-
const meta = this.promptsEditorMeta(key);
|
|
102
|
-
if (!meta) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
this[meta.highlightField] = highlightMarkdownText(this[meta.contentField], resolvePromptsHljs());
|
|
106
|
-
this.syncPromptsOverlayScroll(key);
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
schedulePromptsHighlight(key) {
|
|
110
|
-
const meta = this.promptsEditorMeta(key);
|
|
111
|
-
if (!meta) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (!this._promptsHighlightTimers) {
|
|
115
|
-
this._promptsHighlightTimers = {};
|
|
116
|
-
}
|
|
117
|
-
if (this._promptsHighlightTimers[key]) {
|
|
118
|
-
clearTimeout(this._promptsHighlightTimers[key]);
|
|
119
|
-
}
|
|
120
|
-
this._promptsHighlightTimers[key] = setTimeout(() => {
|
|
121
|
-
this._promptsHighlightTimers[key] = null;
|
|
122
|
-
this.refreshPromptsHighlight(key);
|
|
123
|
-
}, PROMPTS_HIGHLIGHT_DEBOUNCE_MS);
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
syncPromptsOverlayScroll(key) {
|
|
127
|
-
const meta = this.promptsEditorMeta(key);
|
|
128
|
-
if (!meta || typeof this.$refs !== 'object' || !this.$refs) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const textarea = this.$refs[meta.textareaRef];
|
|
132
|
-
const backdrop = this.$refs[meta.highlightRef];
|
|
133
|
-
if (!textarea || !backdrop) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
backdrop.scrollTop = textarea.scrollTop;
|
|
137
|
-
backdrop.scrollLeft = textarea.scrollLeft;
|
|
138
|
-
},
|
|
139
|
-
|
|
140
83
|
refreshPromptsPreview(key) {
|
|
141
84
|
const meta = this.promptsEditorMeta(key);
|
|
142
85
|
if (!meta) {
|
|
@@ -174,7 +117,6 @@ export function createPromptsEditorMethods(options = {}) {
|
|
|
174
117
|
},
|
|
175
118
|
|
|
176
119
|
schedulePromptsEditorRefresh(key) {
|
|
177
|
-
this.schedulePromptsHighlight(key);
|
|
178
120
|
this.schedulePromptsPreview(key);
|
|
179
121
|
this.schedulePromptsChangeAxis(key);
|
|
180
122
|
},
|
|
@@ -114,7 +114,10 @@ function normalizeNavigationSnapshot(vm, source = {}) {
|
|
|
114
114
|
: currentSkillsTargetApp,
|
|
115
115
|
promptTemplatesMode: source.promptTemplatesMode === 'manage' || source.promptTemplatesMode === 'compose'
|
|
116
116
|
? source.promptTemplatesMode
|
|
117
|
-
: currentPromptTemplatesMode
|
|
117
|
+
: currentPromptTemplatesMode,
|
|
118
|
+
pluginsActiveId: typeof source.pluginsActiveId === 'string'
|
|
119
|
+
? source.pluginsActiveId
|
|
120
|
+
: (typeof vm.pluginsActiveId === 'string' ? vm.pluginsActiveId : '')
|
|
118
121
|
};
|
|
119
122
|
}
|
|
120
123
|
|
|
@@ -475,6 +478,9 @@ export function createWebUiPreferencesMethods(options = {}) {
|
|
|
475
478
|
this.settingsTab = this.normalizeSettingsTab(nav.settingsTab);
|
|
476
479
|
}
|
|
477
480
|
if (typeof nav.configMode === 'string') this.configMode = nav.configMode;
|
|
481
|
+
if (typeof nav.pluginsActiveId === 'string' && nav.pluginsActiveId.trim()) {
|
|
482
|
+
this.pluginsActiveId = nav.pluginsActiveId.trim();
|
|
483
|
+
}
|
|
478
484
|
if (typeof nav.mainTab === 'string') {
|
|
479
485
|
if (typeof this.switchMainTab === 'function') {
|
|
480
486
|
this.switchMainTab(nav.mainTab);
|
|
@@ -384,6 +384,17 @@ const en = Object.freeze({
|
|
|
384
384
|
'plugins.catalog.promptTemplates.title': 'Prompt templates',
|
|
385
385
|
'plugins.catalog.promptTemplates.description': 'Standardized, template-driven prompt tools with variables, copy, and export helpers.',
|
|
386
386
|
'plugins.status.standard': 'standard',
|
|
387
|
+
'plugins.catalog.textTools.title': 'Text tools',
|
|
388
|
+
'plugins.catalog.textTools.description': 'A set of lightweight plain-text utilities; the first tool compresses multi-line text into a single line.',
|
|
389
|
+
'plugins.textTools.title': 'Text tools',
|
|
390
|
+
'plugins.textTools.tools.aria': 'Text tool selection',
|
|
391
|
+
'plugins.textTools.tools.compress': 'Compress text',
|
|
392
|
+
'plugins.textTools.compress.inputLabel': 'Input text',
|
|
393
|
+
'plugins.textTools.compress.inputPlaceholder': 'Paste or type the text to compress…',
|
|
394
|
+
'plugins.textTools.compress.inputAria': 'Text to compress',
|
|
395
|
+
'plugins.textTools.compress.outputTitle': 'Compressed result',
|
|
396
|
+
'plugins.textTools.compress.outputAria': 'Compressed text result',
|
|
397
|
+
'plugins.textTools.compress.copy': 'Copy',
|
|
387
398
|
'plugins.main.ariaWorkspace': 'Plugin workspace',
|
|
388
399
|
'plugins.refresh': 'Refresh',
|
|
389
400
|
'plugins.refreshing': 'Refreshing...',
|