@greppleai/grip 0.1.3 → 0.1.5
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/CHANGELOG.md +52 -0
- package/README.md +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/types.d.ts +5 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/grip-agent.d.ts.map +1 -1
- package/dist/core/grip-agent.js +4 -2
- package/dist/core/grip-agent.js.map +1 -1
- package/dist/core/sandbox/lima.d.ts.map +1 -1
- package/dist/core/sandbox/lima.js +6 -6
- package/dist/core/sandbox/lima.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +2 -3
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +2 -3
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +2 -3
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +3 -3
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +1 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +5 -0
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -3
- package/dist/core/tools/write.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +18 -7
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/hook-execution.d.ts +3 -0
- package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-execution.js +17 -0
- package/dist/modes/interactive/components/hook-execution.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +26 -18
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +220 -192
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +118 -8
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/grip-user-agent.d.ts.map +1 -1
- package/dist/utils/grip-user-agent.js +1 -1
- package/dist/utils/grip-user-agent.js.map +1 -1
- package/docs/extensions.md +3 -0
- package/docs/keybindings.md +3 -1
- package/docs/providers.md +3 -1
- package/docs/sandbox.md +1 -1
- package/docs/usage.md +37 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -271,6 +271,7 @@ export class InteractiveMode {
|
|
|
271
271
|
hookExecutionSession;
|
|
272
272
|
hookExecutionNotices = [];
|
|
273
273
|
hookExecutionComponents = [];
|
|
274
|
+
pendingStopHookNotifications = [];
|
|
274
275
|
activeToolHookExecutionGroups = new Map();
|
|
275
276
|
hookExecutionTurnActive = false;
|
|
276
277
|
signalCleanupHandlers = [];
|
|
@@ -427,16 +428,78 @@ export class InteractiveMode {
|
|
|
427
428
|
}));
|
|
428
429
|
}
|
|
429
430
|
createBaseAutocompleteProvider() {
|
|
430
|
-
//
|
|
431
|
+
// Commands without arguments remain selectable after a trailing space (e.g. /new ).
|
|
432
|
+
const noArgumentCommands = new Set([
|
|
433
|
+
"settings",
|
|
434
|
+
"scoped-models",
|
|
435
|
+
"share",
|
|
436
|
+
"copy",
|
|
437
|
+
"session",
|
|
438
|
+
"changelog",
|
|
439
|
+
"hotkeys",
|
|
440
|
+
"fork",
|
|
441
|
+
"clone",
|
|
442
|
+
"tree",
|
|
443
|
+
"login",
|
|
444
|
+
"logout",
|
|
445
|
+
"new",
|
|
446
|
+
"reload",
|
|
447
|
+
"resume",
|
|
448
|
+
"quit",
|
|
449
|
+
]);
|
|
431
450
|
const slashCommands = BUILTIN_SLASH_COMMANDS.map((command) => ({
|
|
432
451
|
name: command.name,
|
|
433
452
|
description: command.description,
|
|
453
|
+
showWithoutArguments: noArgumentCommands.has(command.name),
|
|
434
454
|
}));
|
|
435
455
|
const cdCommand = slashCommands.find((command) => command.name === "cd");
|
|
436
456
|
if (cdCommand) {
|
|
437
457
|
cdCommand.argumentHint = "<directory>";
|
|
438
458
|
cdCommand.getArgumentCompletions = (prefix) => this.session.supportsDirectoryChange() ? getDirectoryCompletions(prefix, this.activeSession.getCwd()) : [];
|
|
439
459
|
}
|
|
460
|
+
const choiceCompletions = (choices) => (prefix) => {
|
|
461
|
+
if (prefix.includes(" "))
|
|
462
|
+
return null;
|
|
463
|
+
return fuzzyFilter([...choices], prefix, (choice) => choice).map((choice) => ({
|
|
464
|
+
value: choice,
|
|
465
|
+
label: choice,
|
|
466
|
+
}));
|
|
467
|
+
};
|
|
468
|
+
const commandsByName = new Map();
|
|
469
|
+
for (const command of slashCommands) {
|
|
470
|
+
if (!commandsByName.has(command.name))
|
|
471
|
+
commandsByName.set(command.name, command);
|
|
472
|
+
}
|
|
473
|
+
for (const [name, hint, choices] of [
|
|
474
|
+
["hooks", "<enable|disable>", ["enable", "disable"]],
|
|
475
|
+
["context-compression", "[on|off]", ["on", "off"]],
|
|
476
|
+
["compress-detection", "[on|off]", ["on", "off"]],
|
|
477
|
+
]) {
|
|
478
|
+
const command = commandsByName.get(name);
|
|
479
|
+
if (command) {
|
|
480
|
+
command.argumentHint = hint;
|
|
481
|
+
command.getArgumentCompletions = choiceCompletions(choices);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const sandboxCommand = slashCommands.find((command) => command.name === "sandbox");
|
|
485
|
+
if (sandboxCommand) {
|
|
486
|
+
sandboxCommand.argumentHint = "<status|clear|--attach|start|list|stop>";
|
|
487
|
+
sandboxCommand.getArgumentCompletions = (prefix) => {
|
|
488
|
+
if (!prefix.includes(" ")) {
|
|
489
|
+
return fuzzyFilter(["status", "clear", "--attach", "start", "list", "stop"], prefix, (item) => item).map((item) => ({
|
|
490
|
+
value: item === "start" || item === "stop" || item === "--attach" ? `${item} ` : item,
|
|
491
|
+
label: item,
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
const startMatch = prefix.match(/^start\s+(--[^\s]*)$/);
|
|
495
|
+
if (!startMatch)
|
|
496
|
+
return null;
|
|
497
|
+
return fuzzyFilter(["--name", "--template", "--update"], startMatch[1], (item) => item).map((item) => ({
|
|
498
|
+
value: `start ${item}${item === "--update" ? "" : " "}`,
|
|
499
|
+
label: item,
|
|
500
|
+
}));
|
|
501
|
+
};
|
|
502
|
+
}
|
|
440
503
|
const modelCommand = slashCommands.find((command) => command.name === "model");
|
|
441
504
|
if (modelCommand) {
|
|
442
505
|
modelCommand.getArgumentCompletions = (prefix) => {
|
|
@@ -520,7 +583,41 @@ export class InteractiveMode {
|
|
|
520
583
|
});
|
|
521
584
|
}
|
|
522
585
|
}
|
|
523
|
-
|
|
586
|
+
const base = new CombinedAutocompleteProvider([...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList, ...ruleCommandList], this.activeSession.getCwd(), this.fdPath);
|
|
587
|
+
const provider = {
|
|
588
|
+
getSuggestions: async (lines, cursorLine, cursorCol, options) => {
|
|
589
|
+
const beforeCursor = (lines[cursorLine] ?? "").slice(0, cursorCol);
|
|
590
|
+
const nameMatch = beforeCursor.match(/^\/sandbox[ \t]+(start[ \t]+--name(?:[ \t]+([^\s]*))?)$/);
|
|
591
|
+
if (!nameMatch)
|
|
592
|
+
return base.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
593
|
+
if (options.signal.aborted)
|
|
594
|
+
return null;
|
|
595
|
+
try {
|
|
596
|
+
const instances = await this.createLimaSandboxService().list({
|
|
597
|
+
workspaceRoot: this.activeSession.getCwd(),
|
|
598
|
+
allWorkspaces: true,
|
|
599
|
+
});
|
|
600
|
+
if (options.signal.aborted)
|
|
601
|
+
return null;
|
|
602
|
+
const prefix = nameMatch[2] ?? "";
|
|
603
|
+
const items = instances
|
|
604
|
+
.filter((instance) => /^[a-z0-9][a-z0-9-]*$/.test(instance.name) && instance.name.startsWith(prefix))
|
|
605
|
+
.map((instance) => ({
|
|
606
|
+
value: `start --name ${instance.name}`,
|
|
607
|
+
label: instance.name,
|
|
608
|
+
description: instance.status,
|
|
609
|
+
}));
|
|
610
|
+
return items.length > 0 ? { items, prefix: nameMatch[1] } : null;
|
|
611
|
+
}
|
|
612
|
+
catch {
|
|
613
|
+
// A failed Lima lookup must not fall back to directory suggestions.
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
},
|
|
617
|
+
applyCompletion: (lines, cursorLine, cursorCol, item, prefix) => base.applyCompletion(lines, cursorLine, cursorCol, item, prefix),
|
|
618
|
+
shouldTriggerFileCompletion: (lines, cursorLine, cursorCol) => base.shouldTriggerFileCompletion(lines, cursorLine, cursorCol),
|
|
619
|
+
};
|
|
620
|
+
return provider;
|
|
524
621
|
}
|
|
525
622
|
setupAutocompleteProvider() {
|
|
526
623
|
let provider = this.createBaseAutocompleteProvider();
|
|
@@ -1919,7 +2016,7 @@ export class InteractiveMode {
|
|
|
1919
2016
|
select: (title, options, opts) => this.showExtensionSelector(title, options, opts),
|
|
1920
2017
|
confirm: (title, message, opts) => this.showExtensionConfirm(title, message, opts),
|
|
1921
2018
|
input: (title, placeholder, opts) => this.showExtensionInput(title, placeholder, opts),
|
|
1922
|
-
notify: (message, type) => this.showExtensionNotify(message, type),
|
|
2019
|
+
notify: (message, type, options) => this.showExtensionNotify(message, type, options),
|
|
1923
2020
|
onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
|
|
1924
2021
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1925
2022
|
setWorkingMessage: (message) => {
|
|
@@ -2149,7 +2246,11 @@ export class InteractiveMode {
|
|
|
2149
2246
|
/**
|
|
2150
2247
|
* Show a notification for extensions.
|
|
2151
2248
|
*/
|
|
2152
|
-
showExtensionNotify(message, type) {
|
|
2249
|
+
showExtensionNotify(message, type, options) {
|
|
2250
|
+
if (options?.hookEvent === "Stop") {
|
|
2251
|
+
this.pendingStopHookNotifications.push({ message, type });
|
|
2252
|
+
return;
|
|
2253
|
+
}
|
|
2153
2254
|
if (type === "error") {
|
|
2154
2255
|
this.showError(message);
|
|
2155
2256
|
}
|
|
@@ -2684,6 +2785,11 @@ export class InteractiveMode {
|
|
|
2684
2785
|
const group = [notice];
|
|
2685
2786
|
this.hookExecutionNotices.push(group);
|
|
2686
2787
|
const component = new HookExecutionComponent(notice, this.getMarkdownThemeWithSettings());
|
|
2788
|
+
if (notice.event === "Stop") {
|
|
2789
|
+
for (const notification of this.pendingStopHookNotifications)
|
|
2790
|
+
component.appendAnnotation(notification.message);
|
|
2791
|
+
this.pendingStopHookNotifications = [];
|
|
2792
|
+
}
|
|
2687
2793
|
component.setExpanded(this.toolOutputExpanded);
|
|
2688
2794
|
this.hookExecutionComponents.push(component);
|
|
2689
2795
|
this.chatContainer.addChild(component);
|
|
@@ -3069,6 +3175,10 @@ export class InteractiveMode {
|
|
|
3069
3175
|
this.handleAgentEnd();
|
|
3070
3176
|
break;
|
|
3071
3177
|
case "agent_settled":
|
|
3178
|
+
for (const notification of this.pendingStopHookNotifications) {
|
|
3179
|
+
this.showExtensionNotify(notification.message, notification.type);
|
|
3180
|
+
}
|
|
3181
|
+
this.pendingStopHookNotifications = [];
|
|
3072
3182
|
await this.checkShutdownRequested();
|
|
3073
3183
|
this.ui.requestRender();
|
|
3074
3184
|
break;
|
|
@@ -4551,12 +4661,12 @@ export class InteractiveMode {
|
|
|
4551
4661
|
return options.sort((a, b) => a.name.localeCompare(b.name));
|
|
4552
4662
|
}
|
|
4553
4663
|
showLoginAuthTypeSelector() {
|
|
4554
|
-
const
|
|
4664
|
+
const browserLabel = "Sign in (subscriptions or OpenRouter credits)";
|
|
4555
4665
|
const apiKeyLabel = "Use an API key";
|
|
4556
4666
|
this.showSelector((done) => {
|
|
4557
|
-
const selector = new ExtensionSelectorComponent("Select authentication method:", [
|
|
4667
|
+
const selector = new ExtensionSelectorComponent("Select authentication method:", [browserLabel, apiKeyLabel], (option) => {
|
|
4558
4668
|
done();
|
|
4559
|
-
const authType = option ===
|
|
4669
|
+
const authType = option === browserLabel ? "oauth" : "api_key";
|
|
4560
4670
|
this.showLoginProviderSelector(authType);
|
|
4561
4671
|
}, () => {
|
|
4562
4672
|
done();
|
|
@@ -4568,7 +4678,7 @@ export class InteractiveMode {
|
|
|
4568
4678
|
showLoginProviderSelector(authType) {
|
|
4569
4679
|
const providerOptions = this.getLoginProviderOptions(authType);
|
|
4570
4680
|
if (providerOptions.length === 0) {
|
|
4571
|
-
this.showStatus(authType === "oauth" ? "No
|
|
4681
|
+
this.showStatus(authType === "oauth" ? "No browser sign-in providers available." : "No API key providers available.");
|
|
4572
4682
|
return;
|
|
4573
4683
|
}
|
|
4574
4684
|
this.showSelector((done) => {
|