codexmate 0.1.22 → 0.1.24
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 +0 -10
- package/README.vi.md +0 -2
- package/README.zh.md +0 -10
- package/cli.js +1 -0
- package/package.json +1 -1
- package/web-ui/app.js +24 -1
- package/web-ui/logic.prompts-change-axis.mjs +102 -0
- package/web-ui/logic.prompts-path-reference.mjs +118 -0
- package/web-ui/modules/app.methods.agents.mjs +1 -0
- package/web-ui/modules/app.methods.index.mjs +1 -1
- package/web-ui/modules/app.methods.prompts-editor.mjs +231 -5
- package/web-ui/modules/app.methods.web-ui-preferences.mjs +4 -0
- package/web-ui/modules/i18n/locales/en.mjs +13 -0
- package/web-ui/modules/i18n/locales/ja.mjs +13 -0
- package/web-ui/modules/i18n/locales/vi.mjs +13 -0
- package/web-ui/modules/i18n/locales/zh-tw.mjs +13 -0
- package/web-ui/modules/i18n/locales/zh.mjs +13 -0
- package/web-ui/partials/index/panel-prompts.html +42 -10
- package/web-ui/res/web-ui-render.precompiled.js +104 -20
- package/web-ui/styles/prompts-editor.css +94 -0
package/README.md
CHANGED
|
@@ -26,16 +26,6 @@
|
|
|
26
26
|
|
|
27
27
|
<br />
|
|
28
28
|
|
|
29
|
-
<p>
|
|
30
|
-
<img src="site/.vitepress/public/images/readme/config-codex.png" alt="Codex Mate Codex provider configuration" width="100%" />
|
|
31
|
-
</p>
|
|
32
|
-
<p>
|
|
33
|
-
<img src="site/.vitepress/public/images/readme/config-opencode.png" alt="Codex Mate OpenCode provider configuration" width="100%" />
|
|
34
|
-
</p>
|
|
35
|
-
<p>
|
|
36
|
-
<img src="site/.vitepress/public/images/readme/sessions.png" alt="Codex Mate unified session browser" width="100%" />
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
29
|
</div>
|
|
40
30
|
|
|
41
31
|
---
|
package/README.vi.md
CHANGED
package/README.zh.md
CHANGED
|
@@ -25,16 +25,6 @@
|
|
|
25
25
|
|
|
26
26
|
<br />
|
|
27
27
|
|
|
28
|
-
<p>
|
|
29
|
-
<img src="site/.vitepress/public/images/readme/config-codex.png" alt="Codex Mate Codex Provider 配置" width="100%" />
|
|
30
|
-
</p>
|
|
31
|
-
<p>
|
|
32
|
-
<img src="site/.vitepress/public/images/readme/config-opencode.png" alt="Codex Mate OpenCode Provider 配置" width="100%" />
|
|
33
|
-
</p>
|
|
34
|
-
<p>
|
|
35
|
-
<img src="site/.vitepress/public/images/readme/sessions.png" alt="Codex Mate 统一会话浏览器" width="100%" />
|
|
36
|
-
</p>
|
|
37
|
-
|
|
38
28
|
</div>
|
|
39
29
|
|
|
40
30
|
---
|
package/cli.js
CHANGED
|
@@ -1076,6 +1076,7 @@ function normalizeWebUiPreferences(value = {}) {
|
|
|
1076
1076
|
configTemplateDiffConfirmEnabled: normalizeBooleanPreference(source.configTemplateDiffConfirmEnabled, true),
|
|
1077
1077
|
sessionsUsageTimeRange: normalizeUsageTimeRangePreference(source.sessionsUsageTimeRange),
|
|
1078
1078
|
promptsSubTab: normalizePromptsSubTabPreference(source.promptsSubTab),
|
|
1079
|
+
promptsPreviewCollapsed: normalizeBooleanPreference(source.promptsPreviewCollapsed, true),
|
|
1079
1080
|
sysPromptScope: normalizeSysPromptScopePreference(source.sysPromptScope),
|
|
1080
1081
|
sysPromptMode: normalizeSysPromptModePreference(source.sysPromptMode),
|
|
1081
1082
|
projectClaudeMdPath: typeof source.projectClaudeMdPath === 'string' ? source.projectClaudeMdPath : '',
|
package/package.json
CHANGED
package/web-ui/app.js
CHANGED
|
@@ -103,9 +103,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
103
103
|
showAgentsModal: false,
|
|
104
104
|
promptsSubTab: 'codex',
|
|
105
105
|
promptsPreviewEnabled: true,
|
|
106
|
-
promptsPreviewCollapsed:
|
|
106
|
+
promptsPreviewCollapsed: true,
|
|
107
|
+
agentsChangeAxis: { mode: 'edit', ticks: [], truncated: false, totalLines: 0, added: 0, removed: 0 },
|
|
108
|
+
sysChangeAxis: { mode: 'edit', ticks: [], truncated: false, totalLines: 0, added: 0, removed: 0 },
|
|
107
109
|
promptsMobileView: 'edit',
|
|
108
110
|
promptsPreviewLibsMissing: false,
|
|
111
|
+
promptsPathReferencePaths: {},
|
|
112
|
+
promptsPathReferenceLoading: false,
|
|
113
|
+
promptsPathReferenceCacheKey: '',
|
|
109
114
|
agentsHighlightHtml: '',
|
|
110
115
|
sysPromptHighlightHtml: '',
|
|
111
116
|
agentsPreviewHtml: '',
|
|
@@ -826,6 +831,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
826
831
|
sysPromptContent() {
|
|
827
832
|
if (typeof this.schedulePromptsEditorRefresh === 'function') this.schedulePromptsEditorRefresh('sys');
|
|
828
833
|
},
|
|
834
|
+
agentsOriginalContent() {
|
|
835
|
+
if (typeof this.schedulePromptsChangeAxis === 'function') this.schedulePromptsChangeAxis('agents');
|
|
836
|
+
},
|
|
837
|
+
sysPromptOriginalContent() {
|
|
838
|
+
if (typeof this.schedulePromptsChangeAxis === 'function') this.schedulePromptsChangeAxis('sys');
|
|
839
|
+
},
|
|
840
|
+
agentsDiffVisible() {
|
|
841
|
+
if (typeof this.refreshPromptsChangeAxis === 'function') this.refreshPromptsChangeAxis('agents');
|
|
842
|
+
},
|
|
843
|
+
sysPromptDiffVisible() {
|
|
844
|
+
if (typeof this.refreshPromptsChangeAxis === 'function') this.refreshPromptsChangeAxis('sys');
|
|
845
|
+
},
|
|
846
|
+
agentsDiffLines() {
|
|
847
|
+
if (this.agentsDiffVisible && typeof this.refreshPromptsChangeAxis === 'function') this.refreshPromptsChangeAxis('agents');
|
|
848
|
+
},
|
|
849
|
+
sysPromptDiffLines() {
|
|
850
|
+
if (this.sysPromptDiffVisible && typeof this.refreshPromptsChangeAxis === 'function') this.refreshPromptsChangeAxis('sys');
|
|
851
|
+
},
|
|
829
852
|
projectClaudeMdPath(newPath) {
|
|
830
853
|
if (typeof this.persistWebUiPreferences === 'function') {
|
|
831
854
|
this.persistWebUiPreferences({ projectClaudeMdPath: newPath || '' });
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts-panel change axis: aggregates the rendered diff rows into
|
|
3
|
+
* clickable tick positions for the red/green diff preview view.
|
|
4
|
+
* Pure functions only.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const AXIS_MAX_TICKS = 200;
|
|
8
|
+
const AXIS_MIN_TICK_HEIGHT_PERCENT = 1.2;
|
|
9
|
+
|
|
10
|
+
function isChangedDiffType(type) {
|
|
11
|
+
return type === 'add' || type === 'del';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function clampAxisPercent(value) {
|
|
15
|
+
if (!Number.isFinite(value) || value < 0) return 0;
|
|
16
|
+
if (value > 100) return 100;
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function tickKindForRun(added, removed) {
|
|
21
|
+
if (added && removed) return 'mixed';
|
|
22
|
+
return added ? 'add' : 'del';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildTickFromRun(run, positioning) {
|
|
26
|
+
const height = clampAxisPercent(Math.max(
|
|
27
|
+
AXIS_MIN_TICK_HEIGHT_PERCENT,
|
|
28
|
+
(Math.max(run.added, run.removed) / Math.max(1, positioning.total)) * 100
|
|
29
|
+
));
|
|
30
|
+
const top = Math.min(clampAxisPercent((run.anchor / Math.max(1, positioning.total)) * 100), 100 - height);
|
|
31
|
+
return {
|
|
32
|
+
kind: tickKindForRun(run.added, run.removed),
|
|
33
|
+
startLine: run.startLine,
|
|
34
|
+
endLine: run.startLine + Math.max(run.added, run.removed) - 1,
|
|
35
|
+
added: run.added,
|
|
36
|
+
removed: run.removed,
|
|
37
|
+
top,
|
|
38
|
+
height,
|
|
39
|
+
rowIndex: typeof run.rowIndex === 'number' ? run.rowIndex : null
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function capAxisTicks(runs, positioning) {
|
|
44
|
+
const truncated = runs.length > AXIS_MAX_TICKS;
|
|
45
|
+
const visibleRuns = truncated ? runs.slice(0, AXIS_MAX_TICKS) : runs;
|
|
46
|
+
return {
|
|
47
|
+
ticks: visibleRuns.map((run) => buildTickFromRun(run, positioning)),
|
|
48
|
+
truncated
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build change-axis ticks for the diff preview view. Tick positions map to
|
|
54
|
+
* rendered row indexes so clicks scroll the diff list to the exact row.
|
|
55
|
+
*
|
|
56
|
+
* @param {Array<object>} diffLines rendered diff rows ({type, value, oldNumber, newNumber})
|
|
57
|
+
* @returns {{ ticks: Array<object>, rowCount: number, truncated: boolean }}
|
|
58
|
+
*/
|
|
59
|
+
export function buildPromptsDiffAxis(diffLines) {
|
|
60
|
+
const rows = Array.isArray(diffLines) ? diffLines.filter((line) => line && line.type) : [];
|
|
61
|
+
const rowCount = rows.length;
|
|
62
|
+
const runs = [];
|
|
63
|
+
let run = null;
|
|
64
|
+
const flushRun = () => {
|
|
65
|
+
if (run) {
|
|
66
|
+
runs.push(run);
|
|
67
|
+
run = null;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
rows.forEach((line, index) => {
|
|
72
|
+
if (!isChangedDiffType(line.type)) {
|
|
73
|
+
flushRun();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!run) {
|
|
77
|
+
run = {
|
|
78
|
+
anchor: index,
|
|
79
|
+
rowIndex: index,
|
|
80
|
+
startLine: line.type === 'add' && typeof line.newNumber === 'number'
|
|
81
|
+
? line.newNumber
|
|
82
|
+
: (typeof line.oldNumber === 'number' ? line.oldNumber : index + 1),
|
|
83
|
+
added: 0,
|
|
84
|
+
removed: 0
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (line.type === 'add') {
|
|
88
|
+
run.added += 1;
|
|
89
|
+
} else {
|
|
90
|
+
run.removed += 1;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
flushRun();
|
|
94
|
+
|
|
95
|
+
const { ticks, truncated } = capAxisTicks(runs, { total: Math.max(1, rowCount) });
|
|
96
|
+
return {
|
|
97
|
+
ticks,
|
|
98
|
+
rowCount,
|
|
99
|
+
truncated
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts-panel "path reference" logic: build the dropdown entries that
|
|
3
|
+
* point to the OTHER instruction-file tabs' real absolute paths, and
|
|
4
|
+
* splice the rendered reference sentence into editor content at the caret.
|
|
5
|
+
*
|
|
6
|
+
* The inserted sentence is instruction-file CONTENT (not UI text), so it
|
|
7
|
+
* is intentionally a fixed English template, independent of the UI locale.
|
|
8
|
+
*
|
|
9
|
+
* Pure functions only: no Vue, no DOM, no api access.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const PROMPT_PATH_REFERENCE_TEMPLATE = 'Always follow the rules defined in `{path}`.';
|
|
13
|
+
|
|
14
|
+
const PROMPT_PATH_REFERENCE_ENTRY_ORDER = ['codex', 'opencode', 'claudeGlobal', 'claudeProject', 'system'];
|
|
15
|
+
|
|
16
|
+
// promptsSubTab value -> entry id excluded from that tab's own dropdown.
|
|
17
|
+
const CURRENT_TAB_EXCLUDED_ENTRY = {
|
|
18
|
+
'codex': 'codex',
|
|
19
|
+
'opencode': 'opencode',
|
|
20
|
+
'claude-project': 'claudeProject',
|
|
21
|
+
'system': 'system'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function buildPromptPathReferenceSentence(path) {
|
|
25
|
+
const target = typeof path === 'string' ? path.trim() : '';
|
|
26
|
+
if (!target) {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
return PROMPT_PATH_REFERENCE_TEMPLATE.replace('{path}', target);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Splice `text` into `content` at the given selection, replacing the
|
|
34
|
+
* selected range (same contract as typing over a selection). Out-of-range
|
|
35
|
+
* indices are clamped; invalid indices fall back to "insert at end".
|
|
36
|
+
*/
|
|
37
|
+
export function insertPromptPathReferenceText(content, selectionStart, selectionEnd, text) {
|
|
38
|
+
const source = typeof content === 'string' ? content : '';
|
|
39
|
+
const inserted = typeof text === 'string' ? text : '';
|
|
40
|
+
const fallback = source.length;
|
|
41
|
+
const rawStart = Number.isFinite(selectionStart) ? Number(selectionStart) : fallback;
|
|
42
|
+
const rawEnd = Number.isFinite(selectionEnd) ? Number(selectionEnd) : fallback;
|
|
43
|
+
const start = Math.min(Math.max(rawStart, 0), source.length);
|
|
44
|
+
const end = Math.min(Math.max(rawEnd, start), source.length);
|
|
45
|
+
return {
|
|
46
|
+
content: source.slice(0, start) + inserted + source.slice(end),
|
|
47
|
+
caret: start + inserted.length
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Build the dropdown option list for the prompts editors.
|
|
53
|
+
*
|
|
54
|
+
* config:
|
|
55
|
+
* - currentTab: promptsSubTab value ('codex' | 'opencode' | 'claude-project' | 'system')
|
|
56
|
+
* - paths: map entry id -> { path, exists, error } (server-resolved absolute paths)
|
|
57
|
+
* - t: i18n translator, signature t(key, params)
|
|
58
|
+
* - systemFile: file name shown for the Pi system-prompt entry (SYSTEM.md / APPEND_SYSTEM.md)
|
|
59
|
+
*
|
|
60
|
+
* Each option: { id, label, path, exists, disabled, disabledReason }.
|
|
61
|
+
* Missing/error entries stay in the list but render disabled, so a failed
|
|
62
|
+
* fetch is visible instead of silently hiding a tab.
|
|
63
|
+
*/
|
|
64
|
+
export function buildPromptPathReferenceOptions(config) {
|
|
65
|
+
const cfg = config || {};
|
|
66
|
+
const currentTab = CURRENT_TAB_EXCLUDED_ENTRY[cfg.currentTab] ? cfg.currentTab : 'codex';
|
|
67
|
+
const excludedEntry = CURRENT_TAB_EXCLUDED_ENTRY[currentTab];
|
|
68
|
+
const paths = cfg.paths || {};
|
|
69
|
+
const t = typeof cfg.t === 'function' ? cfg.t : ((key) => key);
|
|
70
|
+
const systemFile = typeof cfg.systemFile === 'string' && cfg.systemFile.trim()
|
|
71
|
+
? cfg.systemFile.trim()
|
|
72
|
+
: 'SYSTEM.md';
|
|
73
|
+
|
|
74
|
+
const labelKeys = {
|
|
75
|
+
codex: 'prompts.pathReference.codex',
|
|
76
|
+
opencode: 'prompts.pathReference.opencode',
|
|
77
|
+
claudeGlobal: 'prompts.pathReference.claudeGlobal',
|
|
78
|
+
claudeProject: 'prompts.pathReference.claudeProject',
|
|
79
|
+
system: 'prompts.pathReference.system'
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const options = [];
|
|
83
|
+
for (const id of PROMPT_PATH_REFERENCE_ENTRY_ORDER) {
|
|
84
|
+
if (id === excludedEntry) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const entry = paths[id] || null;
|
|
88
|
+
let label = id === 'system'
|
|
89
|
+
? t(labelKeys[id], { file: systemFile })
|
|
90
|
+
: t(labelKeys[id]);
|
|
91
|
+
let disabled = false;
|
|
92
|
+
let disabledReason = '';
|
|
93
|
+
if (id === 'claudeProject' && !(entry && entry.path)) {
|
|
94
|
+
disabled = true;
|
|
95
|
+
disabledReason = t('prompts.pathReference.projectMissing');
|
|
96
|
+
}
|
|
97
|
+
if (!entry) {
|
|
98
|
+
disabled = true;
|
|
99
|
+
if (!disabledReason) {
|
|
100
|
+
disabledReason = t('prompts.pathReference.notLoaded');
|
|
101
|
+
}
|
|
102
|
+
} else if (entry.error) {
|
|
103
|
+
disabled = true;
|
|
104
|
+
disabledReason = entry.error;
|
|
105
|
+
} else if (entry.path && entry.exists === false) {
|
|
106
|
+
label += ' · ' + t('common.notExistsWillCreateOnSave');
|
|
107
|
+
}
|
|
108
|
+
options.push({
|
|
109
|
+
id,
|
|
110
|
+
label,
|
|
111
|
+
path: entry && entry.path ? entry.path : '',
|
|
112
|
+
exists: entry ? !!entry.exists : false,
|
|
113
|
+
disabled,
|
|
114
|
+
disabledReason
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return options;
|
|
118
|
+
}
|
|
@@ -1020,6 +1020,7 @@ export function createAgentsMethods(options = {}) {
|
|
|
1020
1020
|
},
|
|
1021
1021
|
|
|
1022
1022
|
loadPromptsTabContent() {
|
|
1023
|
+
if (typeof this.loadPromptsPathReferences === "function") this.loadPromptsPathReferences();
|
|
1023
1024
|
if (this.promptsSubTab === 'system') {
|
|
1024
1025
|
if (typeof this.loadSystemPrompt === 'function') this.loadSystemPrompt();
|
|
1025
1026
|
} else {
|
|
@@ -7,37 +7,73 @@
|
|
|
7
7
|
* State contract (declared in app.js data()):
|
|
8
8
|
* promptsPreviewEnabled, promptsPreviewCollapsed, promptsMobileView,
|
|
9
9
|
* promptsPreviewLibsMissing, agentsHighlightHtml, sysPromptHighlightHtml,
|
|
10
|
-
* agentsPreviewHtml, sysPromptPreviewHtml
|
|
10
|
+
* agentsPreviewHtml, sysPromptPreviewHtml, agentsChangeAxis, sysChangeAxis,
|
|
11
|
+
* promptsPathReferencePaths, promptsPathReferenceLoading,
|
|
12
|
+
* promptsPathReferenceCacheKey (path-reference dropdown)
|
|
11
13
|
* Template contract:
|
|
12
14
|
* refs promptsAgentsTextarea / promptsSysTextarea on the two textareas,
|
|
13
|
-
* refs promptsAgentsHighlight / promptsSysHighlight on the backdrop <pre
|
|
15
|
+
* refs promptsAgentsHighlight / promptsSysHighlight on the backdrop <pre>,
|
|
16
|
+
* refs promptsAgentsDiffView / promptsSysDiffView on the two diff row containers.
|
|
14
17
|
*/
|
|
15
18
|
|
|
16
19
|
import {
|
|
17
20
|
buildMarkdownPreviewHtml,
|
|
18
21
|
highlightMarkdownText
|
|
19
22
|
} from '../logic.markdown-editor.mjs';
|
|
23
|
+
import {
|
|
24
|
+
buildPromptPathReferenceOptions as buildPromptPathReferenceOptionList,
|
|
25
|
+
buildPromptPathReferenceSentence,
|
|
26
|
+
insertPromptPathReferenceText
|
|
27
|
+
} from '../logic.prompts-path-reference.mjs';
|
|
28
|
+
import {
|
|
29
|
+
buildPromptsDiffAxis
|
|
30
|
+
} from '../logic.prompts-change-axis.mjs';
|
|
20
31
|
|
|
21
32
|
const PROMPTS_HIGHLIGHT_DEBOUNCE_MS = 150;
|
|
22
33
|
const PROMPTS_PREVIEW_DEBOUNCE_MS = 300;
|
|
34
|
+
const PROMPTS_AXIS_DEBOUNCE_MS = 300;
|
|
23
35
|
|
|
24
36
|
const PROMPTS_EDITOR_META = {
|
|
25
37
|
agents: {
|
|
26
38
|
contentField: 'agentsContent',
|
|
39
|
+
originalField: 'agentsOriginalContent',
|
|
27
40
|
highlightField: 'agentsHighlightHtml',
|
|
28
41
|
previewField: 'agentsPreviewHtml',
|
|
42
|
+
axisField: 'agentsChangeAxis',
|
|
43
|
+
diffLinesField: 'agentsDiffLines',
|
|
44
|
+
diffStatsField: 'agentsDiffStats',
|
|
45
|
+
diffVisibleField: 'agentsDiffVisible',
|
|
46
|
+
loadingField: 'agentsLoading',
|
|
47
|
+
savingField: 'agentsSaving',
|
|
48
|
+
diffLoadingField: 'agentsDiffLoading',
|
|
49
|
+
prepareDiffMethod: 'prepareAgentsDiff',
|
|
29
50
|
textareaRef: 'promptsAgentsTextarea',
|
|
30
|
-
highlightRef: 'promptsAgentsHighlight'
|
|
51
|
+
highlightRef: 'promptsAgentsHighlight',
|
|
52
|
+
diffViewRef: 'promptsAgentsDiffView'
|
|
31
53
|
},
|
|
32
54
|
sys: {
|
|
33
55
|
contentField: 'sysPromptContent',
|
|
56
|
+
originalField: 'sysPromptOriginalContent',
|
|
34
57
|
highlightField: 'sysPromptHighlightHtml',
|
|
35
58
|
previewField: 'sysPromptPreviewHtml',
|
|
59
|
+
axisField: 'sysChangeAxis',
|
|
60
|
+
diffLinesField: 'sysPromptDiffLines',
|
|
61
|
+
diffStatsField: 'sysPromptDiffStats',
|
|
62
|
+
diffVisibleField: 'sysPromptDiffVisible',
|
|
63
|
+
loadingField: 'sysPromptLoading',
|
|
64
|
+
savingField: 'sysPromptSaving',
|
|
65
|
+
diffLoadingField: 'sysPromptDiffLoading',
|
|
66
|
+
prepareDiffMethod: 'prepareSysPromptDiff',
|
|
36
67
|
textareaRef: 'promptsSysTextarea',
|
|
37
|
-
highlightRef: 'promptsSysHighlight'
|
|
68
|
+
highlightRef: 'promptsSysHighlight',
|
|
69
|
+
diffViewRef: 'promptsSysDiffView'
|
|
38
70
|
}
|
|
39
71
|
};
|
|
40
72
|
|
|
73
|
+
function emptyPromptsChangeAxis() {
|
|
74
|
+
return { mode: 'edit', ticks: [], truncated: false, totalLines: 0, added: 0, removed: 0 };
|
|
75
|
+
}
|
|
76
|
+
|
|
41
77
|
function resolvePromptsHljs() {
|
|
42
78
|
if (typeof window !== 'undefined' && window.hljs) {
|
|
43
79
|
return window.hljs;
|
|
@@ -52,7 +88,9 @@ function resolvePromptsPreviewLibs() {
|
|
|
52
88
|
return { marked: window.marked || null, purify: window.DOMPurify || null };
|
|
53
89
|
}
|
|
54
90
|
|
|
55
|
-
export function createPromptsEditorMethods() {
|
|
91
|
+
export function createPromptsEditorMethods(options = {}) {
|
|
92
|
+
const { api } = options;
|
|
93
|
+
|
|
56
94
|
return {
|
|
57
95
|
promptsEditorMeta(key) {
|
|
58
96
|
return PROMPTS_EDITOR_META[key] || null;
|
|
@@ -138,6 +176,65 @@ export function createPromptsEditorMethods() {
|
|
|
138
176
|
schedulePromptsEditorRefresh(key) {
|
|
139
177
|
this.schedulePromptsHighlight(key);
|
|
140
178
|
this.schedulePromptsPreview(key);
|
|
179
|
+
this.schedulePromptsChangeAxis(key);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
refreshPromptsChangeAxis(key) {
|
|
183
|
+
const meta = this.promptsEditorMeta(key);
|
|
184
|
+
if (!meta) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (this[meta.diffVisibleField]) {
|
|
188
|
+
const axis = buildPromptsDiffAxis(this[meta.diffLinesField]);
|
|
189
|
+
const stats = this[meta.diffStatsField];
|
|
190
|
+
this[meta.axisField] = {
|
|
191
|
+
mode: 'diff',
|
|
192
|
+
ticks: axis.truncated ? [] : axis.ticks,
|
|
193
|
+
truncated: axis.truncated,
|
|
194
|
+
totalLines: axis.rowCount,
|
|
195
|
+
added: Number(stats && stats.added) || 0,
|
|
196
|
+
removed: Number(stats && stats.removed) || 0
|
|
197
|
+
};
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// Edit mode renders no axis (the axis is a diff-preview-only
|
|
201
|
+
// affordance): keep it empty so the full line-diff cost is only
|
|
202
|
+
// paid while the red/green preview is open.
|
|
203
|
+
this[meta.axisField] = emptyPromptsChangeAxis();
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
schedulePromptsChangeAxis(key) {
|
|
207
|
+
const meta = this.promptsEditorMeta(key);
|
|
208
|
+
if (!meta) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!this._promptsAxisTimers) {
|
|
212
|
+
this._promptsAxisTimers = {};
|
|
213
|
+
}
|
|
214
|
+
if (this._promptsAxisTimers[key]) {
|
|
215
|
+
clearTimeout(this._promptsAxisTimers[key]);
|
|
216
|
+
}
|
|
217
|
+
this._promptsAxisTimers[key] = setTimeout(() => {
|
|
218
|
+
this._promptsAxisTimers[key] = null;
|
|
219
|
+
this.refreshPromptsChangeAxis(key);
|
|
220
|
+
}, PROMPTS_AXIS_DEBOUNCE_MS);
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
jumpToPromptsChangeTick(key, tick) {
|
|
224
|
+
const meta = this.promptsEditorMeta(key);
|
|
225
|
+
const axis = meta ? this[meta.axisField] : null;
|
|
226
|
+
if (!meta || !axis || !tick) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (axis.mode === 'diff') {
|
|
230
|
+
const view = this.$refs && this.$refs[meta.diffViewRef];
|
|
231
|
+
const rows = view && view.children ? Array.prototype.slice.call(view.children) : [];
|
|
232
|
+
const target = rows[tick.rowIndex];
|
|
233
|
+
if (target && typeof target.scrollIntoView === 'function') {
|
|
234
|
+
target.scrollIntoView({ block: 'center' });
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
141
238
|
},
|
|
142
239
|
|
|
143
240
|
setPromptsMobileView(view) {
|
|
@@ -148,6 +245,135 @@ export function createPromptsEditorMethods() {
|
|
|
148
245
|
|
|
149
246
|
togglePromptsPreviewCollapsed() {
|
|
150
247
|
this.promptsPreviewCollapsed = !this.promptsPreviewCollapsed;
|
|
248
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
249
|
+
this.persistWebUiPreferences({ promptsPreviewCollapsed: this.promptsPreviewCollapsed });
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
buildPromptsPathReferenceCacheKey() {
|
|
254
|
+
return [
|
|
255
|
+
(this.projectClaudeMdPath || '').trim(),
|
|
256
|
+
this.sysPromptScope || 'global',
|
|
257
|
+
this.sysPromptMode || 'system'
|
|
258
|
+
].join('|');
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// Lazy loader for the path-reference dropdown. Fetches the OTHER tabs'
|
|
262
|
+
// real absolute paths via the existing metaOnly RPC contracts
|
|
263
|
+
// (get-agents-file / get-opencode-agents-file / get-claude-md-file
|
|
264
|
+
// return path + exists without content; get-system-prompt returns
|
|
265
|
+
// path + a small SYSTEM.md/APPEND_SYSTEM.md read). Cache key covers the
|
|
266
|
+
// only inputs that change a resolved path: project baseDir, sysPrompt
|
|
267
|
+
// scope and mode. Idempotent per key; concurrent callers share the
|
|
268
|
+
// in-flight promise.
|
|
269
|
+
loadPromptsPathReferences() {
|
|
270
|
+
const cacheKey = this.buildPromptsPathReferenceCacheKey();
|
|
271
|
+
if (this.promptsPathReferenceCacheKey === cacheKey && !this.promptsPathReferenceLoading) {
|
|
272
|
+
return Promise.resolve();
|
|
273
|
+
}
|
|
274
|
+
if (this.promptsPathReferenceLoading && this._promptsPathReferencePromise) {
|
|
275
|
+
return this._promptsPathReferencePromise;
|
|
276
|
+
}
|
|
277
|
+
if (typeof api !== 'function') {
|
|
278
|
+
return Promise.resolve();
|
|
279
|
+
}
|
|
280
|
+
const projectPath = (this.projectClaudeMdPath || '').trim();
|
|
281
|
+
const scope = this.sysPromptScope || 'global';
|
|
282
|
+
const mode = this.sysPromptMode || 'system';
|
|
283
|
+
const fetchEntry = async (action, params) => {
|
|
284
|
+
try {
|
|
285
|
+
const res = await api(action, params);
|
|
286
|
+
if (res && res.error) {
|
|
287
|
+
return { path: '', exists: false, error: String(res.error) };
|
|
288
|
+
}
|
|
289
|
+
return { path: (res && res.path) || '', exists: !!(res && res.exists) };
|
|
290
|
+
} catch (e) {
|
|
291
|
+
return {
|
|
292
|
+
path: '',
|
|
293
|
+
exists: false,
|
|
294
|
+
error: typeof this.t === 'function' ? this.t('prompts.pathReference.loadFailed') : 'load failed'
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
this.promptsPathReferenceLoading = true;
|
|
299
|
+
const promise = Promise.all([
|
|
300
|
+
fetchEntry('get-agents-file', { metaOnly: true }),
|
|
301
|
+
fetchEntry('get-opencode-agents-file', { metaOnly: true }),
|
|
302
|
+
fetchEntry('get-claude-md-file', { metaOnly: true }),
|
|
303
|
+
projectPath
|
|
304
|
+
? fetchEntry('get-claude-md-file', { baseDir: projectPath, metaOnly: true })
|
|
305
|
+
: Promise.resolve(null),
|
|
306
|
+
fetchEntry('get-system-prompt', { scope, mode })
|
|
307
|
+
]).then((results) => {
|
|
308
|
+
this.promptsPathReferencePaths = {
|
|
309
|
+
codex: results[0],
|
|
310
|
+
opencode: results[1],
|
|
311
|
+
claudeGlobal: results[2],
|
|
312
|
+
claudeProject: results[3] || { path: '', exists: false, error: '' },
|
|
313
|
+
system: results[4]
|
|
314
|
+
};
|
|
315
|
+
this.promptsPathReferenceCacheKey = cacheKey;
|
|
316
|
+
}).finally(() => {
|
|
317
|
+
this.promptsPathReferenceLoading = false;
|
|
318
|
+
this._promptsPathReferencePromise = null;
|
|
319
|
+
});
|
|
320
|
+
this._promptsPathReferencePromise = promise;
|
|
321
|
+
return promise;
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
promptsPathReferenceOptionList() {
|
|
325
|
+
return buildPromptPathReferenceOptionList({
|
|
326
|
+
currentTab: this.promptsSubTab,
|
|
327
|
+
paths: this.promptsPathReferencePaths || {},
|
|
328
|
+
t: (key, params) => (typeof this.t === 'function' ? this.t(key, params) : key),
|
|
329
|
+
systemFile: (this.sysPromptMode || 'system') === 'append' ? 'APPEND_SYSTEM.md' : 'SYSTEM.md'
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
insertPromptPathReference(entryId, key, event) {
|
|
334
|
+
const select = event && event.target;
|
|
335
|
+
if (select && typeof select.value === 'string') {
|
|
336
|
+
select.value = '';
|
|
337
|
+
}
|
|
338
|
+
const meta = this.promptsEditorMeta(key);
|
|
339
|
+
const entry = (this.promptsPathReferencePaths || {})[entryId];
|
|
340
|
+
if (!meta || !entry || !entry.path || entry.error) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (this[meta.loadingField] || this[meta.savingField] || this[meta.diffVisibleField]) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const sentence = buildPromptPathReferenceSentence(entry.path);
|
|
347
|
+
if (!sentence) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const textarea = typeof this.$refs === 'object' && this.$refs
|
|
351
|
+
? this.$refs[meta.textareaRef]
|
|
352
|
+
: null;
|
|
353
|
+
const content = typeof this[meta.contentField] === 'string' ? this[meta.contentField] : '';
|
|
354
|
+
let start = content.length;
|
|
355
|
+
let end = content.length;
|
|
356
|
+
if (textarea && typeof textarea.selectionStart === 'number') {
|
|
357
|
+
start = textarea.selectionStart;
|
|
358
|
+
end = textarea.selectionEnd;
|
|
359
|
+
}
|
|
360
|
+
const result = insertPromptPathReferenceText(content, start, end, sentence);
|
|
361
|
+
this[meta.contentField] = result.content;
|
|
362
|
+
this.schedulePromptsEditorRefresh(key);
|
|
363
|
+
const restoreCaret = () => {
|
|
364
|
+
if (textarea && typeof textarea.setSelectionRange === 'function') {
|
|
365
|
+
textarea.setSelectionRange(result.caret, result.caret);
|
|
366
|
+
textarea.focus();
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
if (typeof this.$nextTick === 'function') {
|
|
370
|
+
this.$nextTick(restoreCaret);
|
|
371
|
+
} else {
|
|
372
|
+
restoreCaret();
|
|
373
|
+
}
|
|
374
|
+
if (typeof this.showMessage === 'function') {
|
|
375
|
+
this.showMessage(this.t('prompts.pathReference.toast.inserted'), 'success');
|
|
376
|
+
}
|
|
151
377
|
}
|
|
152
378
|
};
|
|
153
379
|
}
|
|
@@ -341,6 +341,7 @@ export function createWebUiPreferencesMethods(options = {}) {
|
|
|
341
341
|
: this.configTemplateDiffConfirmEnabled !== false,
|
|
342
342
|
sessionsUsageTimeRange: normalizeUsageTimeRange(hasOwn(source, 'sessionsUsageTimeRange') ? source.sessionsUsageTimeRange : this.sessionsUsageTimeRange),
|
|
343
343
|
promptsSubTab: normalizePromptsSubTab(hasOwn(source, 'promptsSubTab') ? source.promptsSubTab : this.promptsSubTab),
|
|
344
|
+
promptsPreviewCollapsed: normalizeBoolean(hasOwn(source, 'promptsPreviewCollapsed') ? source.promptsPreviewCollapsed : this.promptsPreviewCollapsed, true),
|
|
344
345
|
sysPromptScope: normalizeSysPromptScope(hasOwn(source, 'sysPromptScope') ? source.sysPromptScope : this.sysPromptScope),
|
|
345
346
|
sysPromptMode: normalizeSysPromptMode(hasOwn(source, 'sysPromptMode') ? source.sysPromptMode : this.sysPromptMode),
|
|
346
347
|
promptPresets: normalizePromptPresets(hasOwn(source, 'promptPresets') ? source.promptPresets : this.promptPresets),
|
|
@@ -398,6 +399,9 @@ export function createWebUiPreferencesMethods(options = {}) {
|
|
|
398
399
|
if (typeof source.promptsSubTab === 'string') {
|
|
399
400
|
this.promptsSubTab = normalizePromptsSubTab(source.promptsSubTab);
|
|
400
401
|
}
|
|
402
|
+
if (hasOwn(source, 'promptsPreviewCollapsed')) {
|
|
403
|
+
this.promptsPreviewCollapsed = normalizeBoolean(source.promptsPreviewCollapsed, true);
|
|
404
|
+
}
|
|
401
405
|
if (typeof source.sysPromptScope === 'string') {
|
|
402
406
|
this.sysPromptScope = normalizeSysPromptScope(source.sysPromptScope);
|
|
403
407
|
}
|
|
@@ -232,6 +232,17 @@ const en = Object.freeze({
|
|
|
232
232
|
'prompts.subTab.opencode': 'AGENTS.md (OpenCode)',
|
|
233
233
|
'prompts.subTab.project': 'CLAUDE.md',
|
|
234
234
|
'prompts.subTab.system': 'System Prompt (Pi)',
|
|
235
|
+
'prompts.pathReference.title': 'Insert rule reference',
|
|
236
|
+
'prompts.pathReference.placeholder': 'Insert rule reference…',
|
|
237
|
+
'prompts.pathReference.codex': 'AGENTS.md (Codex)',
|
|
238
|
+
'prompts.pathReference.opencode': 'AGENTS.md (OpenCode)',
|
|
239
|
+
'prompts.pathReference.claudeGlobal': 'CLAUDE.md (Global)',
|
|
240
|
+
'prompts.pathReference.claudeProject': 'CLAUDE.md (Project)',
|
|
241
|
+
'prompts.pathReference.system': '{file} (Pi System Prompt)',
|
|
242
|
+
'prompts.pathReference.projectMissing': 'No project path selected',
|
|
243
|
+
'prompts.pathReference.notLoaded': 'Loading path…',
|
|
244
|
+
'prompts.pathReference.loadFailed': 'Failed to load path',
|
|
245
|
+
'prompts.pathReference.toast.inserted': 'Rule reference inserted',
|
|
235
246
|
'prompts.subTab.presets': 'Preset pool',
|
|
236
247
|
'prompts.editor.toolbar': 'Markdown toolbar',
|
|
237
248
|
'prompts.editor.collapsePreview': 'Collapse preview',
|
|
@@ -241,6 +252,8 @@ const en = Object.freeze({
|
|
|
241
252
|
'prompts.editor.preview': 'Preview',
|
|
242
253
|
'prompts.editor.previewUnavailable': 'Preview components missing (marked / DOMPurify), please refresh the page',
|
|
243
254
|
'prompts.editor.previewEmpty': 'Nothing to preview yet',
|
|
255
|
+
'prompts.editor.changeAxis': 'Change navigation axis',
|
|
256
|
+
'prompts.editor.changeAxisTick': 'Line {line} (+{added} / -{removed})',
|
|
244
257
|
'prompts.presets.title': 'Presets',
|
|
245
258
|
'prompts.presets.hint': 'Manage presets.',
|
|
246
259
|
'prompts.presets.namePlaceholder': 'Preset name',
|
|
@@ -233,6 +233,17 @@ const ja = Object.freeze({
|
|
|
233
233
|
'prompts.subTab.opencode': 'AGENTS.md (OpenCode)',
|
|
234
234
|
'prompts.subTab.project': 'CLAUDE.md',
|
|
235
235
|
'prompts.subTab.system': 'System Prompt (Pi)',
|
|
236
|
+
'prompts.pathReference.title': 'ルール参照を挿入',
|
|
237
|
+
'prompts.pathReference.placeholder': 'ルール参照を挿入…',
|
|
238
|
+
'prompts.pathReference.codex': 'AGENTS.md (Codex)',
|
|
239
|
+
'prompts.pathReference.opencode': 'AGENTS.md (OpenCode)',
|
|
240
|
+
'prompts.pathReference.claudeGlobal': 'CLAUDE.md(グローバル)',
|
|
241
|
+
'prompts.pathReference.claudeProject': 'CLAUDE.md(現在のプロジェクト)',
|
|
242
|
+
'prompts.pathReference.system': '{file}(Pi System Prompt)',
|
|
243
|
+
'prompts.pathReference.projectMissing': 'プロジェクトパス未選択',
|
|
244
|
+
'prompts.pathReference.notLoaded': 'パス読み込み中…',
|
|
245
|
+
'prompts.pathReference.loadFailed': 'パスの読み込みに失敗しました',
|
|
246
|
+
'prompts.pathReference.toast.inserted': 'ルール参照を挿入しました',
|
|
236
247
|
'prompts.subTab.presets': 'プリセット',
|
|
237
248
|
'prompts.editor.toolbar': 'Markdown ツールバー',
|
|
238
249
|
'prompts.editor.collapsePreview': 'プレビューを折りたたむ',
|
|
@@ -242,6 +253,8 @@ const ja = Object.freeze({
|
|
|
242
253
|
'prompts.editor.preview': 'プレビュー',
|
|
243
254
|
'prompts.editor.previewUnavailable': 'プレビュー用コンポーネント(marked / DOMPurify)が読み込まれていません。ページを再読み込みしてください',
|
|
244
255
|
'prompts.editor.previewEmpty': 'プレビューする内容がありません',
|
|
256
|
+
'prompts.editor.changeAxis': '変更ナビゲーション軸',
|
|
257
|
+
'prompts.editor.changeAxisTick': '{line} 行目(+{added} / -{removed})',
|
|
245
258
|
'prompts.presets.title': 'プリセット',
|
|
246
259
|
'prompts.presets.hint': 'プリセットを管理します。',
|
|
247
260
|
'prompts.presets.namePlaceholder': 'プリセット名',
|
|
@@ -250,6 +250,17 @@ const vi = Object.freeze({
|
|
|
250
250
|
'prompts.subTab.opencode': 'AGENTS.md (OpenCode)',
|
|
251
251
|
'prompts.subTab.project': 'CLAUDE.md',
|
|
252
252
|
'prompts.subTab.system': 'System Prompt (Pi)',
|
|
253
|
+
'prompts.pathReference.title': 'Chèn tham chiếu quy tắc',
|
|
254
|
+
'prompts.pathReference.placeholder': 'Chèn tham chiếu quy tắc…',
|
|
255
|
+
'prompts.pathReference.codex': 'AGENTS.md (Codex)',
|
|
256
|
+
'prompts.pathReference.opencode': 'AGENTS.md (OpenCode)',
|
|
257
|
+
'prompts.pathReference.claudeGlobal': 'CLAUDE.md (Toàn cục)',
|
|
258
|
+
'prompts.pathReference.claudeProject': 'CLAUDE.md (Dự án hiện tại)',
|
|
259
|
+
'prompts.pathReference.system': '{file} (System Prompt Pi)',
|
|
260
|
+
'prompts.pathReference.projectMissing': 'Chưa chọn đường dẫn dự án',
|
|
261
|
+
'prompts.pathReference.notLoaded': 'Đang tải đường dẫn…',
|
|
262
|
+
'prompts.pathReference.loadFailed': 'Tải đường dẫn thất bại',
|
|
263
|
+
'prompts.pathReference.toast.inserted': 'Đã chèn tham chiếu quy tắc',
|
|
253
264
|
'prompts.subTab.presets': 'Kho preset',
|
|
254
265
|
'prompts.editor.toolbar': 'Thanh công cụ Markdown',
|
|
255
266
|
'prompts.editor.collapsePreview': 'Thu gọn bản xem trước',
|
|
@@ -259,6 +270,8 @@ const vi = Object.freeze({
|
|
|
259
270
|
'prompts.editor.preview': 'Xem trước',
|
|
260
271
|
'prompts.editor.previewUnavailable': 'Thư viện xem trước (marked / DOMPurify) chưa được tải, hãy tải lại trang',
|
|
261
272
|
'prompts.editor.previewEmpty': 'Chưa có nội dung để xem trước',
|
|
273
|
+
'prompts.editor.changeAxis': 'Trục điều hướng thay đổi',
|
|
274
|
+
'prompts.editor.changeAxisTick': 'Dòng {line} (+{added} / -{removed})',
|
|
262
275
|
'prompts.presets.title': 'Preset',
|
|
263
276
|
'prompts.presets.hint': 'Quản lý preset.',
|
|
264
277
|
'prompts.presets.namePlaceholder': 'Tên preset',
|
|
@@ -232,6 +232,17 @@ const zhTw = Object.freeze({
|
|
|
232
232
|
'prompts.subTab.opencode': 'AGENTS.md (OpenCode)',
|
|
233
233
|
'prompts.subTab.project': 'CLAUDE.md',
|
|
234
234
|
'prompts.subTab.system': 'System Prompt (Pi)',
|
|
235
|
+
'prompts.pathReference.title': '插入規則引用',
|
|
236
|
+
'prompts.pathReference.placeholder': '插入規則引用…',
|
|
237
|
+
'prompts.pathReference.codex': 'AGENTS.md (Codex)',
|
|
238
|
+
'prompts.pathReference.opencode': 'AGENTS.md (OpenCode)',
|
|
239
|
+
'prompts.pathReference.claudeGlobal': 'CLAUDE.md(全域)',
|
|
240
|
+
'prompts.pathReference.claudeProject': 'CLAUDE.md(目前專案)',
|
|
241
|
+
'prompts.pathReference.system': '{file}(Pi System Prompt)',
|
|
242
|
+
'prompts.pathReference.projectMissing': '未選擇專案路徑',
|
|
243
|
+
'prompts.pathReference.notLoaded': '路徑載入中…',
|
|
244
|
+
'prompts.pathReference.loadFailed': '路徑載入失敗',
|
|
245
|
+
'prompts.pathReference.toast.inserted': '已插入規則引用',
|
|
235
246
|
'prompts.subTab.presets': '預設池',
|
|
236
247
|
'prompts.editor.toolbar': 'Markdown 工具列',
|
|
237
248
|
'prompts.editor.collapsePreview': '收起預覽',
|
|
@@ -241,6 +252,8 @@ const zhTw = Object.freeze({
|
|
|
241
252
|
'prompts.editor.preview': '預覽',
|
|
242
253
|
'prompts.editor.previewUnavailable': '預覽元件未載入(marked / DOMPurify 缺失),請重新整理頁面',
|
|
243
254
|
'prompts.editor.previewEmpty': '尚無內容可預覽',
|
|
255
|
+
'prompts.editor.changeAxis': '改動導覽軸',
|
|
256
|
+
'prompts.editor.changeAxisTick': '第 {line} 行(+{added} / -{removed})',
|
|
244
257
|
'prompts.presets.title': '預設池',
|
|
245
258
|
'prompts.presets.hint': '管理預設。',
|
|
246
259
|
'prompts.presets.namePlaceholder': '預設名稱',
|
|
@@ -232,6 +232,17 @@ const zh = Object.freeze({
|
|
|
232
232
|
'prompts.subTab.opencode': 'AGENTS.md (OpenCode)',
|
|
233
233
|
'prompts.subTab.project': 'CLAUDE.md',
|
|
234
234
|
'prompts.subTab.system': 'System Prompt (Pi)',
|
|
235
|
+
'prompts.pathReference.title': '插入规则引用',
|
|
236
|
+
'prompts.pathReference.placeholder': '插入规则引用…',
|
|
237
|
+
'prompts.pathReference.codex': 'AGENTS.md (Codex)',
|
|
238
|
+
'prompts.pathReference.opencode': 'AGENTS.md (OpenCode)',
|
|
239
|
+
'prompts.pathReference.claudeGlobal': 'CLAUDE.md(全局)',
|
|
240
|
+
'prompts.pathReference.claudeProject': 'CLAUDE.md(当前项目)',
|
|
241
|
+
'prompts.pathReference.system': '{file}(Pi System Prompt)',
|
|
242
|
+
'prompts.pathReference.projectMissing': '未选择项目路径',
|
|
243
|
+
'prompts.pathReference.notLoaded': '路径加载中…',
|
|
244
|
+
'prompts.pathReference.loadFailed': '路径加载失败',
|
|
245
|
+
'prompts.pathReference.toast.inserted': '已插入规则引用',
|
|
235
246
|
'prompts.subTab.presets': '预设池',
|
|
236
247
|
'prompts.editor.toolbar': 'Markdown 工具栏',
|
|
237
248
|
'prompts.editor.collapsePreview': '收起预览',
|
|
@@ -241,6 +252,8 @@ const zh = Object.freeze({
|
|
|
241
252
|
'prompts.editor.preview': '预览',
|
|
242
253
|
'prompts.editor.previewUnavailable': '预览组件未加载(marked / DOMPurify 缺失),请刷新页面',
|
|
243
254
|
'prompts.editor.previewEmpty': '暂无内容可预览',
|
|
255
|
+
'prompts.editor.changeAxis': '改动导航轴',
|
|
256
|
+
'prompts.editor.changeAxisTick': '第 {line} 行(+{added} / -{removed})',
|
|
244
257
|
'prompts.presets.title': '预设池',
|
|
245
258
|
'prompts.presets.hint': '管理预设。',
|
|
246
259
|
'prompts.presets.namePlaceholder': '预设名称',
|
|
@@ -44,6 +44,17 @@
|
|
|
44
44
|
</span>
|
|
45
45
|
</div>
|
|
46
46
|
<div class="prompts-editor-actions">
|
|
47
|
+
<div class="prompts-editor-group prompts-editor-group--pathref">
|
|
48
|
+
<select
|
|
49
|
+
class="form-input prompts-path-reference-select"
|
|
50
|
+
:disabled="agentsLoading || agentsSaving || agentsDiffVisible || promptsPathReferenceLoading"
|
|
51
|
+
:title="t('prompts.pathReference.title')"
|
|
52
|
+
@focus="loadPromptsPathReferences()"
|
|
53
|
+
@change="insertPromptPathReference($event.target.value, 'agents', $event)">
|
|
54
|
+
<option value="">{{ t('prompts.pathReference.placeholder') }}</option>
|
|
55
|
+
<option v-for="opt in promptsPathReferenceOptionList()" :key="opt.id" :value="opt.id" :disabled="opt.disabled">{{ opt.label }}</option>
|
|
56
|
+
</select>
|
|
57
|
+
</div>
|
|
47
58
|
<div class="prompts-editor-group prompts-editor-group--secondary">
|
|
48
59
|
<button
|
|
49
60
|
class="btn-mini"
|
|
@@ -189,15 +200,20 @@
|
|
|
189
200
|
<div v-else-if="agentsDiffError" class="state-message error">{{ agentsDiffError }}</div>
|
|
190
201
|
<div v-else-if="agentsDiffTruncated" class="agents-diff-empty">{{ t('diff.tooLargeSkip') }}</div>
|
|
191
202
|
<div v-else-if="!agentsDiffHasChanges" class="agents-diff-empty">{{ t('diff.noChanges') }}</div>
|
|
192
|
-
<div v-else class="
|
|
193
|
-
<div
|
|
194
|
-
v-for="(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
<div v-else class="prompts-diff-frame">
|
|
204
|
+
<div v-if="agentsChangeAxis.ticks.length" class="prompts-change-axis prompts-change-axis--diff" role="navigation" :aria-label="t('prompts.editor.changeAxis')">
|
|
205
|
+
<button v-for="(tick, index) in agentsChangeAxis.ticks" :key="'agents-diff-axis-' + index" type="button" class="prompts-change-tick" :class="'prompts-change-tick--' + tick.kind" :style="{ top: tick.top + '%', height: tick.height + '%' }" :title="t('prompts.editor.changeAxisTick', { line: tick.startLine, added: tick.added, removed: tick.removed })" @click="jumpToPromptsChangeTick('agents', tick)"></button>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="agents-diff-view agents-diff-editor" ref="promptsAgentsDiffView">
|
|
208
|
+
<div
|
|
209
|
+
v-for="(line, index) in agentsDiffLines"
|
|
210
|
+
:key="line.key || (line.type + '-' + index)"
|
|
211
|
+
:class="['agents-diff-line', line.type]">
|
|
212
|
+
<span class="agents-diff-line-sign">
|
|
213
|
+
{{ line.type === 'add' ? '+' : (line.type === 'del' ? '-' : ' ') }}
|
|
214
|
+
</span>
|
|
215
|
+
<span class="agents-diff-line-text">{{ line.value }}</span>
|
|
216
|
+
</div>
|
|
201
217
|
</div>
|
|
202
218
|
</div>
|
|
203
219
|
</div>
|
|
@@ -270,6 +286,17 @@
|
|
|
270
286
|
</span>
|
|
271
287
|
</div>
|
|
272
288
|
<div class="prompts-editor-actions">
|
|
289
|
+
<div class="prompts-editor-group prompts-editor-group--pathref">
|
|
290
|
+
<select
|
|
291
|
+
class="form-input prompts-path-reference-select"
|
|
292
|
+
:disabled="sysPromptLoading || sysPromptSaving || sysPromptDiffVisible || promptsPathReferenceLoading"
|
|
293
|
+
:title="t('prompts.pathReference.title')"
|
|
294
|
+
@focus="loadPromptsPathReferences()"
|
|
295
|
+
@change="insertPromptPathReference($event.target.value, 'sys', $event)">
|
|
296
|
+
<option value="">{{ t('prompts.pathReference.placeholder') }}</option>
|
|
297
|
+
<option v-for="opt in promptsPathReferenceOptionList()" :key="opt.id" :value="opt.id" :disabled="opt.disabled">{{ opt.label }}</option>
|
|
298
|
+
</select>
|
|
299
|
+
</div>
|
|
273
300
|
<div class="prompts-editor-group prompts-editor-group--secondary">
|
|
274
301
|
<button class="btn-mini" @click="exportSysPromptContent" :disabled="sysPromptLoading || sysPromptSaving || !sysPromptContent" :title="t('modal.agents.export')">
|
|
275
302
|
<svg class="btn-icon-sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v12M8 11l4 4 4-4M4 17v2h16v-2"/></svg>
|
|
@@ -331,7 +358,11 @@
|
|
|
331
358
|
<div v-else-if="sysPromptDiffError" class="state-message error">{{ sysPromptDiffError }}</div>
|
|
332
359
|
<div v-else-if="sysPromptDiffTruncated" class="agents-diff-empty">{{ t('diff.tooLargeSkip') }}</div>
|
|
333
360
|
<div v-else-if="!sysPromptDiffHasChangesValue" class="agents-diff-empty">{{ t('diff.noChanges') }}</div>
|
|
334
|
-
|
|
361
|
+
<div v-else class="prompts-diff-frame">
|
|
362
|
+
<div v-if="sysChangeAxis.ticks.length" class="prompts-change-axis prompts-change-axis--diff" role="navigation" :aria-label="t('prompts.editor.changeAxis')">
|
|
363
|
+
<button v-for="(tick, index) in sysChangeAxis.ticks" :key="'sys-diff-axis-' + index" type="button" class="prompts-change-tick" :class="'prompts-change-tick--' + tick.kind" :style="{ top: tick.top + '%', height: tick.height + '%' }" :title="t('prompts.editor.changeAxisTick', { line: tick.startLine, added: tick.added, removed: tick.removed })" @click="jumpToPromptsChangeTick('sys', tick)"></button>
|
|
364
|
+
</div>
|
|
365
|
+
<div class="agents-diff-view agents-diff-editor" ref="promptsSysDiffView">
|
|
335
366
|
<div
|
|
336
367
|
v-for="(line, index) in sysPromptDiffLines"
|
|
337
368
|
:key="'sys-prompt-diff-' + index"
|
|
@@ -343,6 +374,7 @@
|
|
|
343
374
|
</div>
|
|
344
375
|
</div>
|
|
345
376
|
</div>
|
|
377
|
+
</div>
|
|
346
378
|
<div class="prompts-md-toolbar" role="toolbar" :aria-label="t('prompts.editor.toolbar')">
|
|
347
379
|
<div class="prompts-md-toolbar-group prompts-md-toolbar-group--view">
|
|
348
380
|
<div v-if="promptsPreviewEnabled" class="prompts-mobile-view-switch" role="tablist" :aria-label="t('prompts.editor.previewToggle')">
|
|
@@ -6953,6 +6953,24 @@ return function render(_ctx, _cache) {
|
|
|
6953
6953
|
: _createCommentVNode("v-if", true)
|
|
6954
6954
|
]),
|
|
6955
6955
|
_createElementVNode("div", { class: "prompts-editor-actions" }, [
|
|
6956
|
+
_createElementVNode("div", { class: "prompts-editor-group prompts-editor-group--pathref" }, [
|
|
6957
|
+
_createElementVNode("select", {
|
|
6958
|
+
class: "form-input prompts-path-reference-select",
|
|
6959
|
+
disabled: _ctx.agentsLoading || _ctx.agentsSaving || _ctx.agentsDiffVisible || _ctx.promptsPathReferenceLoading,
|
|
6960
|
+
title: _ctx.t('prompts.pathReference.title'),
|
|
6961
|
+
onFocus: $event => (_ctx.loadPromptsPathReferences()),
|
|
6962
|
+
onChange: $event => (_ctx.insertPromptPathReference($event.target.value, 'agents', $event))
|
|
6963
|
+
}, [
|
|
6964
|
+
_createElementVNode("option", { value: "" }, _toDisplayString(_ctx.t('prompts.pathReference.placeholder')), 1 /* TEXT */),
|
|
6965
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.promptsPathReferenceOptionList(), (opt) => {
|
|
6966
|
+
return (_openBlock(), _createElementBlock("option", {
|
|
6967
|
+
key: opt.id,
|
|
6968
|
+
value: opt.id,
|
|
6969
|
+
disabled: opt.disabled
|
|
6970
|
+
}, _toDisplayString(opt.label), 9 /* TEXT, PROPS */, ["value", "disabled"]))
|
|
6971
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
6972
|
+
], 40 /* PROPS, NEED_HYDRATION */, ["disabled", "title", "onFocus", "onChange"])
|
|
6973
|
+
]),
|
|
6956
6974
|
_createElementVNode("div", { class: "prompts-editor-group prompts-editor-group--secondary" }, [
|
|
6957
6975
|
_createElementVNode("button", {
|
|
6958
6976
|
class: "btn-mini",
|
|
@@ -7300,17 +7318,41 @@ return function render(_ctx, _cache) {
|
|
|
7300
7318
|
}, _toDisplayString(_ctx.t('diff.noChanges')), 1 /* TEXT */))
|
|
7301
7319
|
: (_openBlock(), _createElementBlock("div", {
|
|
7302
7320
|
key: 5,
|
|
7303
|
-
class: "
|
|
7321
|
+
class: "prompts-diff-frame"
|
|
7304
7322
|
}, [
|
|
7305
|
-
(
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7323
|
+
(_ctx.agentsChangeAxis.ticks.length)
|
|
7324
|
+
? (_openBlock(), _createElementBlock("div", {
|
|
7325
|
+
key: 0,
|
|
7326
|
+
class: "prompts-change-axis prompts-change-axis--diff",
|
|
7327
|
+
role: "navigation",
|
|
7328
|
+
"aria-label": _ctx.t('prompts.editor.changeAxis')
|
|
7329
|
+
}, [
|
|
7330
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.agentsChangeAxis.ticks, (tick, index) => {
|
|
7331
|
+
return (_openBlock(), _createElementBlock("button", {
|
|
7332
|
+
key: 'agents-diff-axis-' + index,
|
|
7333
|
+
type: "button",
|
|
7334
|
+
class: _normalizeClass(["prompts-change-tick", 'prompts-change-tick--' + tick.kind]),
|
|
7335
|
+
style: _normalizeStyle({ top: tick.top + '%', height: tick.height + '%' }),
|
|
7336
|
+
title: _ctx.t('prompts.editor.changeAxisTick', { line: tick.startLine, added: tick.added, removed: tick.removed }),
|
|
7337
|
+
onClick: $event => (_ctx.jumpToPromptsChangeTick('agents', tick))
|
|
7338
|
+
}, null, 14 /* CLASS, STYLE, PROPS */, ["title", "onClick"]))
|
|
7339
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
7340
|
+
], 8 /* PROPS */, ["aria-label"]))
|
|
7341
|
+
: _createCommentVNode("v-if", true),
|
|
7342
|
+
_createElementVNode("div", {
|
|
7343
|
+
class: "agents-diff-view agents-diff-editor",
|
|
7344
|
+
ref: "promptsAgentsDiffView"
|
|
7345
|
+
}, [
|
|
7346
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.agentsDiffLines, (line, index) => {
|
|
7347
|
+
return (_openBlock(), _createElementBlock("div", {
|
|
7348
|
+
key: line.key || (line.type + '-' + index),
|
|
7349
|
+
class: _normalizeClass(['agents-diff-line', line.type])
|
|
7350
|
+
}, [
|
|
7351
|
+
_createElementVNode("span", { class: "agents-diff-line-sign" }, _toDisplayString(line.type === 'add' ? '+' : (line.type === 'del' ? '-' : ' ')), 1 /* TEXT */),
|
|
7352
|
+
_createElementVNode("span", { class: "agents-diff-line-text" }, _toDisplayString(line.value), 1 /* TEXT */)
|
|
7353
|
+
], 2 /* CLASS */))
|
|
7354
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
7355
|
+
], 512 /* NEED_PATCH */)
|
|
7314
7356
|
]))
|
|
7315
7357
|
]))
|
|
7316
7358
|
: _createCommentVNode("v-if", true),
|
|
@@ -7472,6 +7514,24 @@ return function render(_ctx, _cache) {
|
|
|
7472
7514
|
: _createCommentVNode("v-if", true)
|
|
7473
7515
|
]),
|
|
7474
7516
|
_createElementVNode("div", { class: "prompts-editor-actions" }, [
|
|
7517
|
+
_createElementVNode("div", { class: "prompts-editor-group prompts-editor-group--pathref" }, [
|
|
7518
|
+
_createElementVNode("select", {
|
|
7519
|
+
class: "form-input prompts-path-reference-select",
|
|
7520
|
+
disabled: _ctx.sysPromptLoading || _ctx.sysPromptSaving || _ctx.sysPromptDiffVisible || _ctx.promptsPathReferenceLoading,
|
|
7521
|
+
title: _ctx.t('prompts.pathReference.title'),
|
|
7522
|
+
onFocus: $event => (_ctx.loadPromptsPathReferences()),
|
|
7523
|
+
onChange: $event => (_ctx.insertPromptPathReference($event.target.value, 'sys', $event))
|
|
7524
|
+
}, [
|
|
7525
|
+
_createElementVNode("option", { value: "" }, _toDisplayString(_ctx.t('prompts.pathReference.placeholder')), 1 /* TEXT */),
|
|
7526
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.promptsPathReferenceOptionList(), (opt) => {
|
|
7527
|
+
return (_openBlock(), _createElementBlock("option", {
|
|
7528
|
+
key: opt.id,
|
|
7529
|
+
value: opt.id,
|
|
7530
|
+
disabled: opt.disabled
|
|
7531
|
+
}, _toDisplayString(opt.label), 9 /* TEXT, PROPS */, ["value", "disabled"]))
|
|
7532
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
7533
|
+
], 40 /* PROPS, NEED_HYDRATION */, ["disabled", "title", "onFocus", "onChange"])
|
|
7534
|
+
]),
|
|
7475
7535
|
_createElementVNode("div", { class: "prompts-editor-group prompts-editor-group--secondary" }, [
|
|
7476
7536
|
_createElementVNode("button", {
|
|
7477
7537
|
class: "btn-mini",
|
|
@@ -7725,17 +7785,41 @@ return function render(_ctx, _cache) {
|
|
|
7725
7785
|
}, _toDisplayString(_ctx.t('diff.noChanges')), 1 /* TEXT */))
|
|
7726
7786
|
: (_openBlock(), _createElementBlock("div", {
|
|
7727
7787
|
key: 5,
|
|
7728
|
-
class: "
|
|
7788
|
+
class: "prompts-diff-frame"
|
|
7729
7789
|
}, [
|
|
7730
|
-
(
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7790
|
+
(_ctx.sysChangeAxis.ticks.length)
|
|
7791
|
+
? (_openBlock(), _createElementBlock("div", {
|
|
7792
|
+
key: 0,
|
|
7793
|
+
class: "prompts-change-axis prompts-change-axis--diff",
|
|
7794
|
+
role: "navigation",
|
|
7795
|
+
"aria-label": _ctx.t('prompts.editor.changeAxis')
|
|
7796
|
+
}, [
|
|
7797
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.sysChangeAxis.ticks, (tick, index) => {
|
|
7798
|
+
return (_openBlock(), _createElementBlock("button", {
|
|
7799
|
+
key: 'sys-diff-axis-' + index,
|
|
7800
|
+
type: "button",
|
|
7801
|
+
class: _normalizeClass(["prompts-change-tick", 'prompts-change-tick--' + tick.kind]),
|
|
7802
|
+
style: _normalizeStyle({ top: tick.top + '%', height: tick.height + '%' }),
|
|
7803
|
+
title: _ctx.t('prompts.editor.changeAxisTick', { line: tick.startLine, added: tick.added, removed: tick.removed }),
|
|
7804
|
+
onClick: $event => (_ctx.jumpToPromptsChangeTick('sys', tick))
|
|
7805
|
+
}, null, 14 /* CLASS, STYLE, PROPS */, ["title", "onClick"]))
|
|
7806
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
7807
|
+
], 8 /* PROPS */, ["aria-label"]))
|
|
7808
|
+
: _createCommentVNode("v-if", true),
|
|
7809
|
+
_createElementVNode("div", {
|
|
7810
|
+
class: "agents-diff-view agents-diff-editor",
|
|
7811
|
+
ref: "promptsSysDiffView"
|
|
7812
|
+
}, [
|
|
7813
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.sysPromptDiffLines, (line, index) => {
|
|
7814
|
+
return (_openBlock(), _createElementBlock("div", {
|
|
7815
|
+
key: 'sys-prompt-diff-' + index,
|
|
7816
|
+
class: _normalizeClass(['agents-diff-line', line.type])
|
|
7817
|
+
}, [
|
|
7818
|
+
_createElementVNode("span", { class: "agents-diff-line-sign" }, _toDisplayString(line.type === 'add' ? '+' : (line.type === 'del' ? '-' : ' ')), 1 /* TEXT */),
|
|
7819
|
+
_createElementVNode("span", { class: "agents-diff-line-text" }, _toDisplayString(line.value), 1 /* TEXT */)
|
|
7820
|
+
], 2 /* CLASS */))
|
|
7821
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
7822
|
+
], 512 /* NEED_PATCH */)
|
|
7739
7823
|
]))
|
|
7740
7824
|
]))
|
|
7741
7825
|
: _createCommentVNode("v-if", true),
|
|
@@ -291,6 +291,79 @@
|
|
|
291
291
|
max-width: 100%;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
|
|
295
|
+
/*
|
|
296
|
+
* Change axis: clickable per-hunk navigation strip rendered on the
|
|
297
|
+
* right edge of the edit pane (edit mode) and of the diff frame
|
|
298
|
+
* (diff preview mode). Ticks are positioned by percentage of the
|
|
299
|
+
* content line space (edit) or of the rendered rows (diff).
|
|
300
|
+
*/
|
|
301
|
+
.prompts-change-axis {
|
|
302
|
+
position: absolute;
|
|
303
|
+
top: 6px;
|
|
304
|
+
bottom: 6px;
|
|
305
|
+
right: 2px;
|
|
306
|
+
width: 10px;
|
|
307
|
+
z-index: 3;
|
|
308
|
+
pointer-events: none;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.prompts-change-tick {
|
|
312
|
+
position: absolute;
|
|
313
|
+
left: 0;
|
|
314
|
+
right: 0;
|
|
315
|
+
min-height: 8px;
|
|
316
|
+
padding: 0;
|
|
317
|
+
border: none;
|
|
318
|
+
border-radius: 3px;
|
|
319
|
+
cursor: pointer;
|
|
320
|
+
pointer-events: auto;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.prompts-change-tick:focus-visible {
|
|
324
|
+
outline: 2px solid var(--color-brand);
|
|
325
|
+
outline-offset: 1px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.prompts-change-tick--add {
|
|
329
|
+
background: rgba(57, 181, 97, 0.5);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.prompts-change-tick--add:hover,
|
|
333
|
+
.prompts-change-tick--add:focus-visible {
|
|
334
|
+
background: rgba(57, 181, 97, 0.85);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.prompts-change-tick--del {
|
|
338
|
+
background: rgba(220, 95, 108, 0.5);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.prompts-change-tick--del:hover,
|
|
342
|
+
.prompts-change-tick--del:focus-visible {
|
|
343
|
+
background: rgba(220, 95, 108, 0.85);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.prompts-change-tick--mixed {
|
|
347
|
+
background: linear-gradient(180deg,
|
|
348
|
+
rgba(220, 95, 108, 0.5) 0%,
|
|
349
|
+
rgba(220, 95, 108, 0.5) 50%,
|
|
350
|
+
rgba(57, 181, 97, 0.5) 50%,
|
|
351
|
+
rgba(57, 181, 97, 0.5) 100%);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.prompts-change-tick--mixed:hover,
|
|
355
|
+
.prompts-change-tick--mixed:focus-visible {
|
|
356
|
+
background: linear-gradient(180deg,
|
|
357
|
+
rgba(220, 95, 108, 0.85) 0%,
|
|
358
|
+
rgba(220, 95, 108, 0.85) 50%,
|
|
359
|
+
rgba(57, 181, 97, 0.85) 50%,
|
|
360
|
+
rgba(57, 181, 97, 0.85) 100%);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.prompts-diff-frame {
|
|
364
|
+
position: relative;
|
|
365
|
+
}
|
|
366
|
+
|
|
294
367
|
/* Mobile: force single column and edit/preview tab switching */
|
|
295
368
|
@media (max-width: 767.98px) {
|
|
296
369
|
.prompts-mobile-view-switch {
|
|
@@ -317,4 +390,25 @@
|
|
|
317
390
|
.prompts-split-collapse-btn {
|
|
318
391
|
display: none;
|
|
319
392
|
}
|
|
393
|
+
|
|
394
|
+
.prompts-change-tick {
|
|
395
|
+
min-height: 12px;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
.prompts-editor-group--pathref .prompts-path-reference-select {
|
|
401
|
+
width: auto;
|
|
402
|
+
max-width: 190px;
|
|
403
|
+
min-width: 120px;
|
|
404
|
+
padding: 5px 8px;
|
|
405
|
+
font-size: var(--font-size-caption);
|
|
406
|
+
color: var(--color-text-secondary);
|
|
407
|
+
cursor: pointer;
|
|
408
|
+
flex-shrink: 1;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.prompts-editor-group--pathref .prompts-path-reference-select:disabled {
|
|
412
|
+
opacity: 0.6;
|
|
413
|
+
cursor: not-allowed;
|
|
320
414
|
}
|