@draig/lexis-two 1.0.8 → 1.1.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.
@@ -0,0 +1,223 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+ const {
5
+ DEFAULT_MODE,
6
+ getDefaultMode,
7
+ normalizeMode,
8
+ normalizeConfigMode,
9
+ normalizePersistedMode,
10
+ writeDefaultMode,
11
+ } = require("../hooks/lexis-two-config.js");
12
+ const { getLexisInstructions, filterSkillBodyForMode } = require("../hooks/lexis-two-instructions.js");
13
+
14
+ export { filterSkillBodyForMode };
15
+ export const readDefaultMode = getDefaultMode;
16
+
17
+ export function resolveSessionMode(entries, fallbackMode = DEFAULT_MODE) {
18
+ const fallback = normalizePersistedMode(fallbackMode) || DEFAULT_MODE;
19
+ if (!Array.isArray(entries)) return fallback;
20
+
21
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
22
+ const entry = entries[i];
23
+ if (entry?.type !== "custom" || entry?.customType !== "lexis-two-mode") continue;
24
+
25
+ const mode = normalizePersistedMode(entry?.data?.mode);
26
+ if (mode) return mode;
27
+ }
28
+
29
+ return fallback;
30
+ }
31
+
32
+ export function parseLexisCommand(text, defaultMode = DEFAULT_MODE) {
33
+ const fallback = normalizePersistedMode(defaultMode) || DEFAULT_MODE;
34
+ const normalizedText = String(text || "").trim().toLowerCase();
35
+
36
+ if (!normalizedText) {
37
+ return { type: "set-mode", mode: fallback === "off" ? "full" : fallback };
38
+ }
39
+
40
+ const [primary, secondary] = normalizedText.split(/\s+/);
41
+
42
+ if (primary === "status") return { type: "status" };
43
+
44
+ if (primary === "default") {
45
+ const mode = normalizeConfigMode(secondary);
46
+ return mode ? { type: "set-default", mode } : { type: "invalid", reason: "invalid-default-mode" };
47
+ }
48
+
49
+ const mode = normalizeMode(primary);
50
+ return mode ? { type: "set-mode", mode } : { type: "invalid", reason: "invalid-mode", mode: primary };
51
+ }
52
+
53
+ export { writeDefaultMode };
54
+
55
+ export default function lexisExtension(pi) {
56
+ let currentMode = DEFAULT_MODE;
57
+ let configuredDefaultMode = getDefaultMode();
58
+
59
+ const setMode = (mode, ctx) => {
60
+ const normalized = normalizePersistedMode(mode);
61
+ if (!normalized) return;
62
+
63
+ currentMode = normalized;
64
+ pi.appendEntry("lexis-two-mode", { mode: normalized });
65
+ ctx?.ui?.notify?.(`Lexis-Two mode set to ${normalized}.`, "info");
66
+ };
67
+
68
+ const sendAlias = (skillName, args, ctx) => {
69
+ const normalized = String(args || "").trim();
70
+ const message = normalized ? `${skillName} ${normalized}` : skillName;
71
+
72
+ if (ctx?.isIdle?.() === false) {
73
+ pi.sendUserMessage(message, { deliverAs: "followUp" });
74
+ ctx?.ui?.notify?.(`${skillName} queued as follow-up.`, "info");
75
+ return;
76
+ }
77
+
78
+ pi.sendUserMessage(message);
79
+ };
80
+
81
+ pi.registerCommand("lexis", {
82
+ description: "Manage Lexis senior dev mode, intensity levels, and quality/security tools",
83
+ handler: async (args, ctx) => {
84
+ const parsedArgs = String(args || "").trim();
85
+ if (!parsedArgs) {
86
+ ctx?.ui?.notify?.(`Lexis: current ${currentMode} • default ${configuredDefaultMode}`, "info");
87
+ sendAlias("/skill:lexis-two-help", "", ctx);
88
+ return;
89
+ }
90
+
91
+ const [subcommand, ...rest] = parsedArgs.toLowerCase().split(/\s+/);
92
+ const restArgs = rest.join(" ");
93
+
94
+ if (subcommand === "status") {
95
+ ctx?.ui?.notify?.(`Lexis: current ${currentMode} • default ${configuredDefaultMode}`, "info");
96
+ return;
97
+ }
98
+ if (subcommand === "plan" || subcommand === "p") {
99
+ sendAlias("/skill:lexis-two-plan", restArgs, ctx);
100
+ return;
101
+ }
102
+ if (subcommand === "review" || subcommand === "r") {
103
+ sendAlias("/skill:lexis-two-review", restArgs, ctx);
104
+ return;
105
+ }
106
+ if (subcommand === "audit" || subcommand === "a") {
107
+ sendAlias("/skill:lexis-two-audit", restArgs, ctx);
108
+ return;
109
+ }
110
+ if (subcommand === "debt" || subcommand === "d") {
111
+ sendAlias("/skill:lexis-two-debt", restArgs, ctx);
112
+ return;
113
+ }
114
+ if (subcommand === "security" || subcommand === "s") {
115
+ sendAlias("/skill:lexis-two-security", restArgs, ctx);
116
+ return;
117
+ }
118
+ if (subcommand === "help" || subcommand === "h") {
119
+ sendAlias("/skill:lexis-two-help", restArgs, ctx);
120
+ return;
121
+ }
122
+
123
+ const parsed = parseLexisCommand(parsedArgs, configuredDefaultMode);
124
+
125
+ if (parsed.type === "set-default") {
126
+ const written = writeDefaultMode(parsed.mode);
127
+ if (written) {
128
+ configuredDefaultMode = getDefaultMode();
129
+ const message = configuredDefaultMode === written
130
+ ? `Default Lexis mode set to ${written}.`
131
+ : `Saved default ${written}, but env override keeps default at ${configuredDefaultMode}.`;
132
+ ctx?.ui?.notify?.(message, "info");
133
+ }
134
+ return;
135
+ }
136
+
137
+ if (parsed.type === "set-mode") {
138
+ setMode(parsed.mode, ctx);
139
+ return;
140
+ }
141
+
142
+ ctx?.ui?.notify?.(`Unknown /lexis subcommand or mode: ${subcommand}. Type '/lexis help' for options.`, "warning");
143
+ },
144
+ });
145
+
146
+ pi.registerCommand("lexis-two", {
147
+ description: "Set or report Lexis-Two mode (alias for /lexis)",
148
+ handler: async (args, ctx) => {
149
+ const parsedArgs = String(args || "").trim();
150
+ const [subcommand] = parsedArgs.toLowerCase().split(/\s+/);
151
+ const validSubcommands = ["status", "plan", "p", "review", "r", "audit", "a", "debt", "d", "security", "s", "help", "h"];
152
+
153
+ if (validSubcommands.includes(subcommand)) {
154
+ ctx?.ui?.notify?.(`[Deprecated] Use '/lexis ${parsedArgs}' instead.`, "warning");
155
+ }
156
+
157
+ // Delegate to handleLexis logic via registering command
158
+ return pi.commands["lexis"].handler(args, ctx);
159
+ },
160
+ });
161
+
162
+ pi.registerCommand("specxis", {
163
+ description: "Manage the Specxis Spec-Driven Development lifecycle (new, plan, implement, review, close, debt, status)",
164
+ handler: (args, ctx) => sendAlias("/skill:specxis", args, ctx),
165
+ });
166
+
167
+ const makeDeprecatedHandler = (subcommand) => {
168
+ return (args, ctx) => {
169
+ ctx?.ui?.notify?.(`[Deprecated] Use '/lexis ${subcommand}' instead.`, "warning");
170
+ sendAlias(`/skill:lexis-two-${subcommand}`, args, ctx);
171
+ };
172
+ };
173
+
174
+ pi.registerCommand("lexis-two-review", {
175
+ description: "[Deprecated] Use /lexis review instead",
176
+ handler: makeDeprecatedHandler("review"),
177
+ });
178
+
179
+ pi.registerCommand("lexis-two-audit", {
180
+ description: "[Deprecated] Use /lexis audit instead",
181
+ handler: makeDeprecatedHandler("audit"),
182
+ });
183
+
184
+ pi.registerCommand("lexis-two-debt", {
185
+ description: "[Deprecated] Use /lexis debt instead",
186
+ handler: makeDeprecatedHandler("debt"),
187
+ });
188
+
189
+ pi.registerCommand("lexis-two-plan", {
190
+ description: "[Deprecated] Use /lexis plan instead",
191
+ handler: makeDeprecatedHandler("plan"),
192
+ });
193
+
194
+ pi.registerCommand("lexis-two-security", {
195
+ description: "[Deprecated] Use /lexis security instead",
196
+ handler: makeDeprecatedHandler("security"),
197
+ });
198
+
199
+ pi.registerCommand("lexis-two-help", {
200
+ description: "[Deprecated] Use /lexis help instead",
201
+ handler: makeDeprecatedHandler("help"),
202
+ });
203
+
204
+ pi.on("input", async (event) => {
205
+ if (event?.source === "extension") return;
206
+
207
+ const text = String(event?.text || "");
208
+ if (currentMode !== "off" && /\b(stop lexis|normal mode)\b/i.test(text)) {
209
+ setMode("off");
210
+ }
211
+ });
212
+
213
+ pi.on("session_start", async (_event, ctx) => {
214
+ const entries = ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
215
+ configuredDefaultMode = getDefaultMode();
216
+ currentMode = resolveSessionMode(entries, configuredDefaultMode);
217
+ });
218
+
219
+ pi.on("before_agent_start", async (event) => {
220
+ if (!currentMode || currentMode === "off") return;
221
+ return { systemPrompt: `${event.systemPrompt}\n\n${getLexisInstructions(currentMode)}` };
222
+ });
223
+ }