@ridit/lens 0.4.6 → 0.4.8
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/dist/index.mjs +43 -13
- package/package.json +1 -1
- package/src/index.tsx +66 -15
package/dist/index.mjs
CHANGED
|
@@ -78205,16 +78205,46 @@ function getLastDeniedAction(messages) {
|
|
|
78205
78205
|
async function runHeadless(opts) {
|
|
78206
78206
|
const repoPath = opts.path;
|
|
78207
78207
|
let session = opts.sessionId ? loadSession(opts.sessionId) ?? createSessionWithId(opts.sessionId, repoPath) : opts.single ? getLatestSession(repoPath) ?? createSession(repoPath) : createSession(repoPath);
|
|
78208
|
-
|
|
78209
|
-
|
|
78210
|
-
const pending = getLastDeniedAction(
|
|
78208
|
+
if (opts.resume) {
|
|
78209
|
+
const msgs = getMessages(session);
|
|
78210
|
+
const pending = getLastDeniedAction(msgs);
|
|
78211
|
+
let trimAt = -1;
|
|
78212
|
+
for (let i = msgs.length - 1;i >= 0; i--) {
|
|
78213
|
+
const msg = msgs[i];
|
|
78214
|
+
if (!msg || msg.role !== "tool")
|
|
78215
|
+
continue;
|
|
78216
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
78217
|
+
const isDenied = content.some((p) => typeof p === "object" && p !== null && ("type" in p) && p.type === "tool-result" && ("result" in p) && typeof p.result === "string" && p.result.includes("Permission denied"));
|
|
78218
|
+
if (isDenied) {
|
|
78219
|
+
for (let j = i - 1;j >= 0; j--) {
|
|
78220
|
+
if (msgs[j]?.role === "assistant") {
|
|
78221
|
+
trimAt = j;
|
|
78222
|
+
break;
|
|
78223
|
+
}
|
|
78224
|
+
}
|
|
78225
|
+
break;
|
|
78226
|
+
}
|
|
78227
|
+
}
|
|
78228
|
+
if (trimAt >= 0) {
|
|
78229
|
+
session = { ...session, messages: msgs.slice(0, trimAt) };
|
|
78230
|
+
}
|
|
78211
78231
|
if (pending) {
|
|
78212
|
-
|
|
78232
|
+
session = addMessage(session, "user", `Proceed with the previously denied operation: use the ${pending.tool} tool on "${pending.description}". Permission has been granted.`);
|
|
78233
|
+
}
|
|
78234
|
+
if (!opts.single || opts.sessionId)
|
|
78235
|
+
saveSession(session);
|
|
78236
|
+
} else {
|
|
78237
|
+
let prompt = opts.prompt;
|
|
78238
|
+
if (opts.forceAll && APPROVAL_WORDS.has(prompt.trim().toLowerCase())) {
|
|
78239
|
+
const pending = getLastDeniedAction(getMessages(session));
|
|
78240
|
+
if (pending) {
|
|
78241
|
+
prompt = `Proceed with the previously denied operation: use the ${pending.tool} tool on "${pending.description}".`;
|
|
78242
|
+
}
|
|
78213
78243
|
}
|
|
78244
|
+
session = addMessage(session, "user", prompt);
|
|
78245
|
+
if (!opts.single || opts.sessionId)
|
|
78246
|
+
saveSession(session);
|
|
78214
78247
|
}
|
|
78215
|
-
session = addMessage(session, "user", prompt);
|
|
78216
|
-
if (!opts.single || opts.sessionId)
|
|
78217
|
-
saveSession(session);
|
|
78218
78248
|
const toolLog = [];
|
|
78219
78249
|
const denied = [];
|
|
78220
78250
|
const runtimeToolNames = new Set;
|
|
@@ -78264,10 +78294,10 @@ async function runHeadless(opts) {
|
|
|
78264
78294
|
});
|
|
78265
78295
|
}
|
|
78266
78296
|
var program = new Command().enablePositionalOptions();
|
|
78267
|
-
program.command("chat").description("Chat with your codebase — ask questions or make changes").option("-p, --path <path>", "Path to the repo", ".").option("-d, --dev", "Output structured JSON (no UI)").option("--single", "Single-shot: run one message then exit").option("--session <id>", "Resume session by ID, or create one with that ID").option("--id <id>", "Alias for --session").option("--force-all", "Auto-approve all tools").option("--prompt <text>", "Run a prompt non-interactively").option("--runtime-tools <path>", "path to runtime tools JSON file").action((opts) => {
|
|
78297
|
+
program.command("chat").description("Chat with your codebase — ask questions or make changes").option("-p, --path <path>", "Path to the repo", ".").option("-d, --dev", "Output structured JSON (no UI)").option("--single", "Single-shot: run one message then exit").option("--session <id>", "Resume session by ID, or create one with that ID").option("--id <id>", "Alias for --session").option("--force-all", "Auto-approve all tools").option("--prompt <text>", "Run a prompt non-interactively").option("--resume", "Resume from last permission-denied tool call (no new prompt needed)").option("--runtime-tools <path>", "path to runtime tools JSON file").action((opts) => {
|
|
78268
78298
|
const sessionId = opts.session ?? opts.id;
|
|
78269
|
-
if (opts.prompt && (opts.dev || opts.single)) {
|
|
78270
|
-
runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll, runtimeTools: opts.runtimeTools });
|
|
78299
|
+
if ((opts.prompt || opts.resume) && (opts.dev || opts.single)) {
|
|
78300
|
+
runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll ?? opts.resume, runtimeTools: opts.runtimeTools, resume: opts.resume });
|
|
78271
78301
|
return;
|
|
78272
78302
|
}
|
|
78273
78303
|
render(/* @__PURE__ */ jsxDEV21(ChatCommand, {
|
|
@@ -78365,13 +78395,13 @@ program.command("run <cmd>").description("Run your dev server. Lens watches and
|
|
|
78365
78395
|
});
|
|
78366
78396
|
var firstArg = process.argv[2];
|
|
78367
78397
|
if (!firstArg || firstArg.startsWith("-")) {
|
|
78368
|
-
const defaultFlags = new Command().option("-p, --path <path>", "Path to the repo", ".").option("--session <id>", "Resume session by ID").option("--single", "Single-shot mode").option("--prompt <text>", "Run a prompt").option("-d, --dev", "Output JSON (no UI)").option("--force-all", "Auto-approve all tools").allowUnknownOption().exitOverride();
|
|
78398
|
+
const defaultFlags = new Command().option("-p, --path <path>", "Path to the repo", ".").option("--session <id>", "Resume session by ID").option("--single", "Single-shot mode").option("--prompt <text>", "Run a prompt").option("-d, --dev", "Output JSON (no UI)").option("--force-all", "Auto-approve all tools").option("--resume", "Resume from last permission-denied tool call").allowUnknownOption().exitOverride();
|
|
78369
78399
|
try {
|
|
78370
78400
|
defaultFlags.parse(process.argv);
|
|
78371
78401
|
} catch {}
|
|
78372
78402
|
const opts = defaultFlags.opts();
|
|
78373
|
-
if (opts.prompt && (opts.dev || opts.single)) {
|
|
78374
|
-
runHeadless({ path: opts.path ?? ".", prompt: opts.prompt, sessionId: opts.session, single: opts.single, forceAll: opts.forceAll });
|
|
78403
|
+
if ((opts.prompt || opts.resume) && (opts.dev || opts.single)) {
|
|
78404
|
+
runHeadless({ path: opts.path ?? ".", prompt: opts.prompt, sessionId: opts.session, single: opts.single, forceAll: opts.forceAll ?? opts.resume, resume: opts.resume });
|
|
78375
78405
|
} else {
|
|
78376
78406
|
render(/* @__PURE__ */ jsxDEV21(ChatCommand, {
|
|
78377
78407
|
path: opts.path ?? ".",
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -72,11 +72,12 @@ function getLastDeniedAction(messages: ReturnType<typeof getMessages>): { tool:
|
|
|
72
72
|
|
|
73
73
|
async function runHeadless(opts: {
|
|
74
74
|
path: string;
|
|
75
|
-
prompt
|
|
75
|
+
prompt?: string;
|
|
76
76
|
sessionId?: string;
|
|
77
77
|
single?: boolean;
|
|
78
78
|
forceAll?: boolean;
|
|
79
79
|
runtimeTools?: string;
|
|
80
|
+
resume?: boolean;
|
|
80
81
|
}) {
|
|
81
82
|
const repoPath = opts.path;
|
|
82
83
|
|
|
@@ -86,18 +87,64 @@ async function runHeadless(opts: {
|
|
|
86
87
|
? (getLatestSession(repoPath) ?? createSession(repoPath))
|
|
87
88
|
: createSession(repoPath);
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
if (opts.resume) {
|
|
91
|
+
// Rewind the session: strip the last denied tool-call (assistant message),
|
|
92
|
+
// its "Permission denied" tool result, and the assistant's text response after it.
|
|
93
|
+
// This leaves the session ending at the last successful state so the agent
|
|
94
|
+
// can re-attempt the denied tool with forceAll: true.
|
|
95
|
+
const msgs = getMessages(session);
|
|
96
|
+
// Capture the pending denied action before trimming so we can add an explicit proceed instruction
|
|
97
|
+
const pending = getLastDeniedAction(msgs);
|
|
98
|
+
let trimAt = -1;
|
|
99
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
100
|
+
const msg = msgs[i];
|
|
101
|
+
if (!msg || msg.role !== "tool") continue;
|
|
102
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
103
|
+
const isDenied = content.some(
|
|
104
|
+
(p: unknown) =>
|
|
105
|
+
typeof p === "object" && p !== null &&
|
|
106
|
+
"type" in p && (p as { type: string }).type === "tool-result" &&
|
|
107
|
+
"result" in p && typeof (p as { result: unknown }).result === "string" &&
|
|
108
|
+
((p as { result: string }).result).includes("Permission denied"),
|
|
109
|
+
);
|
|
110
|
+
if (isDenied) {
|
|
111
|
+
// Find the assistant message immediately before this tool result (the tool-call message)
|
|
112
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
113
|
+
if (msgs[j]?.role === "assistant") {
|
|
114
|
+
trimAt = j;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (trimAt >= 0) {
|
|
122
|
+
session = { ...session, messages: msgs.slice(0, trimAt) };
|
|
123
|
+
}
|
|
124
|
+
// Add an explicit instruction to proceed with the denied tool so the model doesn't ask again
|
|
93
125
|
if (pending) {
|
|
94
|
-
|
|
126
|
+
session = addMessage(
|
|
127
|
+
session,
|
|
128
|
+
"user",
|
|
129
|
+
`Proceed with the previously denied operation: use the ${pending.tool} tool on "${pending.description}". Permission has been granted.`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
// Save trimmed session so context is clean for this run
|
|
133
|
+
if (!opts.single || opts.sessionId) saveSession(session);
|
|
134
|
+
} else {
|
|
135
|
+
// if user is approving a prior denial, make the intent unambiguous
|
|
136
|
+
let prompt = opts.prompt!;
|
|
137
|
+
if (opts.forceAll && APPROVAL_WORDS.has(prompt.trim().toLowerCase())) {
|
|
138
|
+
const pending = getLastDeniedAction(getMessages(session));
|
|
139
|
+
if (pending) {
|
|
140
|
+
prompt = `Proceed with the previously denied operation: use the ${pending.tool} tool on "${pending.description}".`;
|
|
141
|
+
}
|
|
95
142
|
}
|
|
96
|
-
}
|
|
97
143
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
144
|
+
session = addMessage(session, "user", prompt);
|
|
145
|
+
// save now so context is available on follow-up messages even if we exit early
|
|
146
|
+
if (!opts.single || opts.sessionId) saveSession(session);
|
|
147
|
+
}
|
|
101
148
|
|
|
102
149
|
const toolLog: { tool: string; args: unknown; result: unknown }[] = [];
|
|
103
150
|
const denied: { tool: string; description: string }[] = [];
|
|
@@ -170,6 +217,7 @@ program
|
|
|
170
217
|
.option("--id <id>", "Alias for --session")
|
|
171
218
|
.option("--force-all", "Auto-approve all tools")
|
|
172
219
|
.option("--prompt <text>", "Run a prompt non-interactively")
|
|
220
|
+
.option("--resume", "Resume from last permission-denied tool call (no new prompt needed)")
|
|
173
221
|
.option("--runtime-tools <path>", "path to runtime tools JSON file")
|
|
174
222
|
.action(
|
|
175
223
|
(opts: {
|
|
@@ -180,12 +228,13 @@ program
|
|
|
180
228
|
id?: string;
|
|
181
229
|
forceAll?: boolean;
|
|
182
230
|
prompt?: string;
|
|
231
|
+
resume?: boolean;
|
|
183
232
|
runtimeTools?: string;
|
|
184
233
|
}) => {
|
|
185
234
|
const sessionId = opts.session ?? opts.id;
|
|
186
|
-
// headless: dev+prompt
|
|
187
|
-
if (opts.prompt && (opts.dev || opts.single)) {
|
|
188
|
-
runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll, runtimeTools: opts.runtimeTools });
|
|
235
|
+
// headless: dev+prompt, single+prompt, or --resume → no UI, output JSON and exit
|
|
236
|
+
if ((opts.prompt || opts.resume) && (opts.dev || opts.single)) {
|
|
237
|
+
runHeadless({ path: opts.path, prompt: opts.prompt, sessionId, single: opts.single, forceAll: opts.forceAll ?? opts.resume, runtimeTools: opts.runtimeTools, resume: opts.resume });
|
|
189
238
|
return;
|
|
190
239
|
}
|
|
191
240
|
render(
|
|
@@ -367,6 +416,7 @@ if (!firstArg || firstArg.startsWith("-")) {
|
|
|
367
416
|
.option("--prompt <text>", "Run a prompt")
|
|
368
417
|
.option("-d, --dev", "Output JSON (no UI)")
|
|
369
418
|
.option("--force-all", "Auto-approve all tools")
|
|
419
|
+
.option("--resume", "Resume from last permission-denied tool call")
|
|
370
420
|
.allowUnknownOption()
|
|
371
421
|
.exitOverride();
|
|
372
422
|
|
|
@@ -379,10 +429,11 @@ if (!firstArg || firstArg.startsWith("-")) {
|
|
|
379
429
|
prompt?: string;
|
|
380
430
|
dev?: boolean;
|
|
381
431
|
forceAll?: boolean;
|
|
432
|
+
resume?: boolean;
|
|
382
433
|
}>();
|
|
383
434
|
|
|
384
|
-
if (opts.prompt && (opts.dev || opts.single)) {
|
|
385
|
-
runHeadless({ path: opts.path ?? ".", prompt: opts.prompt, sessionId: opts.session, single: opts.single, forceAll: opts.forceAll });
|
|
435
|
+
if ((opts.prompt || opts.resume) && (opts.dev || opts.single)) {
|
|
436
|
+
runHeadless({ path: opts.path ?? ".", prompt: opts.prompt, sessionId: opts.session, single: opts.single, forceAll: opts.forceAll ?? opts.resume, resume: opts.resume });
|
|
386
437
|
} else {
|
|
387
438
|
render(
|
|
388
439
|
<ChatCommand
|