@marcopeg/hal 1.0.18 → 1.0.20
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 +31 -6
- package/dist/bot/commands/git/callback.d.ts +8 -0
- package/dist/bot/commands/git/callback.d.ts.map +1 -0
- package/dist/bot/commands/git/callback.js +72 -0
- package/dist/bot/commands/git/callback.js.map +1 -0
- package/dist/bot/commands/git/clean.d.ts +4 -0
- package/dist/bot/commands/git/clean.d.ts.map +1 -0
- package/dist/bot/commands/git/clean.js +50 -0
- package/dist/bot/commands/git/clean.js.map +1 -0
- package/dist/bot/commands/git/commit.d.ts +4 -0
- package/dist/bot/commands/git/commit.d.ts.map +1 -0
- package/dist/bot/commands/git/commit.js +72 -0
- package/dist/bot/commands/git/commit.js.map +1 -0
- package/dist/bot/commands/git/exec.d.ts +6 -0
- package/dist/bot/commands/git/exec.d.ts.map +1 -0
- package/dist/bot/commands/git/exec.js +16 -0
- package/dist/bot/commands/git/exec.js.map +1 -0
- package/dist/bot/commands/git/index.d.ts +6 -0
- package/dist/bot/commands/git/index.d.ts.map +1 -0
- package/dist/bot/commands/git/index.js +6 -0
- package/dist/bot/commands/git/index.js.map +1 -0
- package/dist/bot/commands/git/init.d.ts +4 -0
- package/dist/bot/commands/git/init.d.ts.map +1 -0
- package/dist/bot/commands/git/init.js +22 -0
- package/dist/bot/commands/git/init.js.map +1 -0
- package/dist/bot/commands/git/status.d.ts +4 -0
- package/dist/bot/commands/git/status.d.ts.map +1 -0
- package/dist/bot/commands/git/status.js +18 -0
- package/dist/bot/commands/git/status.js.map +1 -0
- package/dist/bot/commands/help.js +1 -1
- package/dist/bot/commands/help.js.map +1 -1
- package/dist/bot/commands/loader.d.ts +12 -5
- package/dist/bot/commands/loader.d.ts.map +1 -1
- package/dist/bot/commands/loader.js +73 -15
- package/dist/bot/commands/loader.js.map +1 -1
- package/dist/bot/commands/message.d.ts.map +1 -1
- package/dist/bot/commands/message.js +49 -24
- package/dist/bot/commands/message.js.map +1 -1
- package/dist/bot/commands/reset.js +1 -1
- package/dist/bot/commands/reset.js.map +1 -1
- package/dist/bot/commands/session.d.ts +2 -2
- package/dist/bot/commands/session.d.ts.map +1 -1
- package/dist/bot/commands/session.js +7 -4
- package/dist/bot/commands/session.js.map +1 -1
- package/dist/bot/commands/start.js +2 -2
- package/dist/bot/commands/start.js.map +1 -1
- package/dist/bot/commands/watcher.d.ts +2 -1
- package/dist/bot/commands/watcher.d.ts.map +1 -1
- package/dist/bot/commands/watcher.js +2 -2
- package/dist/bot/commands/watcher.js.map +1 -1
- package/dist/bot/handlers/text.d.ts.map +1 -1
- package/dist/bot/handlers/text.js +7 -0
- package/dist/bot/handlers/text.js.map +1 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +30 -9
- package/dist/bot.js.map +1 -1
- package/dist/cli.js +49 -19
- package/dist/cli.js.map +1 -1
- package/dist/config-watcher.d.ts +10 -0
- package/dist/config-watcher.d.ts.map +1 -0
- package/dist/config-watcher.js +49 -0
- package/dist/config-watcher.js.map +1 -0
- package/dist/config.d.ts +118 -41
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +124 -58
- package/dist/config.js.map +1 -1
- package/dist/context/resolver.d.ts +4 -0
- package/dist/context/resolver.d.ts.map +1 -1
- package/dist/context/resolver.js +8 -2
- package/dist/context/resolver.js.map +1 -1
- package/dist/default-models.d.ts +3 -0
- package/dist/default-models.d.ts.map +1 -0
- package/dist/default-models.js +16 -0
- package/dist/default-models.js.map +1 -0
- package/dist/engine/adapters/codex.d.ts.map +1 -1
- package/dist/engine/adapters/codex.js +25 -5
- package/dist/engine/adapters/codex.js.map +1 -1
- package/dist/engine/adapters/cursor.d.ts +3 -0
- package/dist/engine/adapters/cursor.d.ts.map +1 -0
- package/dist/engine/adapters/cursor.js +103 -0
- package/dist/engine/adapters/cursor.js.map +1 -0
- package/dist/engine/adapters/opencode.d.ts +2 -2
- package/dist/engine/adapters/opencode.d.ts.map +1 -1
- package/dist/engine/adapters/opencode.js +27 -11
- package/dist/engine/adapters/opencode.js.map +1 -1
- package/dist/engine/prompt.d.ts.map +1 -1
- package/dist/engine/prompt.js +8 -0
- package/dist/engine/prompt.js.map +1 -1
- package/dist/engine/registry.d.ts.map +1 -1
- package/dist/engine/registry.js +2 -0
- package/dist/engine/registry.js.map +1 -1
- package/dist/engine/types.d.ts +1 -1
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/engine/types.js +1 -0
- package/dist/engine/types.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -182,6 +182,10 @@ These keys are injected for every message, even without any `context` configurat
|
|
|
182
182
|
| `sys.time` | Current time, `HH:MM:SS` |
|
|
183
183
|
| `sys.ts` | Current Unix timestamp (seconds) |
|
|
184
184
|
| `sys.tz` | Timezone name (e.g. `Europe/Berlin`) |
|
|
185
|
+
| `engine.name` | Engine identifier (e.g. `claude`, `copilot`) |
|
|
186
|
+
| `engine.command` | CLI command used to invoke the engine |
|
|
187
|
+
| `engine.model` | AI model from config (only present when explicitly set) |
|
|
188
|
+
| `engine.defaultModel` | HAL default model applied (only present when `engine.model` is omitted; see [Model defaults](#model-defaults)) |
|
|
185
189
|
|
|
186
190
|
#### Custom context via config
|
|
187
191
|
|
|
@@ -267,9 +271,10 @@ Default settings applied to all projects. Any setting defined in a project overr
|
|
|
267
271
|
|-----|-------------|---------|
|
|
268
272
|
| `globals.engine.name` | Engine: `claude`, `copilot`, `codex`, `opencode` | `"claude"` |
|
|
269
273
|
| `globals.engine.command` | Override the CLI command path | _(engine name)_ |
|
|
270
|
-
| `globals.engine.model` | Override the AI model | _(engine
|
|
274
|
+
| `globals.engine.model` | Override the AI model (see [Model defaults](#model-defaults)) | _(per engine)_ |
|
|
271
275
|
| `globals.engine.session` | Use persistent sessions (`--resume` / `--continue`) | `true` |
|
|
272
276
|
| `globals.engine.sessionMsg` | Message sent when renewing session (e.g. `/clean`) | `"hi!"` |
|
|
277
|
+
| `globals.engine.codex.*` | Codex permission flags (see [Engine Configuration](#engine-configuration)) | all `false` |
|
|
273
278
|
| `globals.logging.level` | Log level: `debug`, `info`, `warn`, `error` | `"info"` |
|
|
274
279
|
| `globals.logging.flow` | Write logs to terminal | `true` |
|
|
275
280
|
| `globals.logging.persist` | Write logs to file | `false` |
|
|
@@ -294,9 +299,10 @@ Each project entry creates one Telegram bot connected to one directory.
|
|
|
294
299
|
| `access.allowedUserIds` | No | Override the global user whitelist for this bot |
|
|
295
300
|
| `engine.name` | No | Override the engine for this project |
|
|
296
301
|
| `engine.command` | No | Override the CLI command path |
|
|
297
|
-
| `engine.model` | No | Override the AI model |
|
|
302
|
+
| `engine.model` | No | Override the AI model (see [Model defaults](#model-defaults)) |
|
|
298
303
|
| `engine.session` | No | Use persistent sessions for this project |
|
|
299
304
|
| `engine.sessionMsg` | No | Message used when renewing session |
|
|
305
|
+
| `engine.codex.*` | No | Codex permission flags (see [Engine Configuration](#engine-configuration)) |
|
|
300
306
|
| `transcription.showTranscription` | No | Override transcription display |
|
|
301
307
|
| `dataDir` | No | Override user data directory (see below) |
|
|
302
308
|
| `context` | No | Per-project context overrides (see [Context Injection](#context-injection)) |
|
|
@@ -447,16 +453,24 @@ In this example:
|
|
|
447
453
|
- **frontend** uses GitHub Copilot with the `gpt-5-mini` model
|
|
448
454
|
- **legacy** is inactive and will be skipped at boot
|
|
449
455
|
|
|
450
|
-
The `engine` object supports five fields
|
|
456
|
+
The `engine` object supports five fields. Engine-specific sub-objects (e.g. `codex`) can be used to control permissions and behavior per engine.
|
|
451
457
|
|
|
452
458
|
| Field | Description | Default |
|
|
453
459
|
|-------|-------------|---------|
|
|
454
460
|
| `name` | Engine identifier: `claude`, `copilot`, `codex`, `opencode` | `"claude"` |
|
|
455
461
|
| `command` | Custom path to the CLI binary | _(engine name)_ |
|
|
456
|
-
| `model` | AI model override (omit
|
|
462
|
+
| `model` | AI model override (omit for engine or HAL default; see [Model defaults](#model-defaults)) | _(per engine)_ |
|
|
457
463
|
| `session` | Use persistent sessions (`--resume` / `--continue`) | `true` |
|
|
458
464
|
| `sessionMsg` | Message sent when renewing session (e.g. `/clean`) | `"hi!"` |
|
|
459
465
|
|
|
466
|
+
When using the Codex engine, the `engine` object also accepts a `codex` block:
|
|
467
|
+
|
|
468
|
+
| Field | Description | Default |
|
|
469
|
+
|-------|-------------|---------|
|
|
470
|
+
| `codex.networkAccess` | Allow outbound network in shell commands | `false` |
|
|
471
|
+
| `codex.fullDiskAccess` | Unrestricted filesystem access (implies network) | `false` |
|
|
472
|
+
| `codex.dangerouslyEnableYolo` | Disable all sandboxing and approvals | `false` |
|
|
473
|
+
|
|
460
474
|
#### Claude Code
|
|
461
475
|
|
|
462
476
|
- **CLI:** `claude` — install and authenticate via [Claude Code CLI](https://github.com/anthropics/claude-code) (see [Prerequisites](#prerequisites)).
|
|
@@ -475,8 +489,9 @@ The `engine` object supports five fields:
|
|
|
475
489
|
|
|
476
490
|
- **CLI:** `codex` — install and authenticate via [Codex CLI](https://github.com/openai/codex-cli) (see [Prerequisites](#prerequisites)).
|
|
477
491
|
- **Project file:** `AGENTS.md`.
|
|
478
|
-
- **Config:** `engine.name: "codex"`. Optional: `engine.command`, `engine.model` (e.g. `gpt-5.1-codex-mini`), `engine.session`, `engine.sessionMsg
|
|
492
|
+
- **Config:** `engine.name: "codex"`. Optional: `engine.command`, `engine.model` (e.g. `gpt-5.1-codex-mini`), `engine.session`, `engine.sessionMsg`, and the permission flags under `engine.codex` (see table above).
|
|
479
493
|
- **Sessions:** When `engine.session` is `true`, the CLI is invoked with `codex exec resume --last` to continue the most recent session; otherwise `codex exec` starts a fresh run. `/clean` sends `engine.sessionMsg` without resuming, so the engine starts a new session; the engine's reply is sent to the user (same behaviour as Copilot).
|
|
494
|
+
- **Permission flags:** HAL always passes `--skip-git-repo-check` so Codex runs without the trusted-directory check. You can escalate via `engine.codex`: `networkAccess` (allow outbound HTTP etc.), `fullDiskAccess` (unrestricted filesystem; implies network), or `dangerouslyEnableYolo` (disable all sandboxing and approvals). Higher tiers supersede lower ones. **Warning:** Use `dangerouslyEnableYolo` only in hardened environments (e.g. Docker, VMs). The example config in `examples/hal.config.json` enables all three codex flags for the Obsidian project so you can try full permissions locally.
|
|
480
495
|
|
|
481
496
|
#### GitHub Copilot Models
|
|
482
497
|
|
|
@@ -502,7 +517,16 @@ When using the `copilot` engine, the following models are available via `engine.
|
|
|
502
517
|
| `gpt-5-mini` | OpenAI GPT-5 Mini |
|
|
503
518
|
| `gpt-4.1` | OpenAI GPT-4.1 |
|
|
504
519
|
|
|
505
|
-
|
|
520
|
+
#### Model defaults
|
|
521
|
+
|
|
522
|
+
When `engine.model` is omitted (neither in globals nor project config), behavior depends on the engine:
|
|
523
|
+
|
|
524
|
+
- **Engine default** — Codex, Copilot, and Cursor: HAL does not pass a model flag, so the CLI picks its own default (Cursor passes `--model auto`).
|
|
525
|
+
- **HAL default** — Claude Code and OpenCode: HAL passes a built-in default so the engine always receives a model. Defaults are defined in `src/default-models.ts`:
|
|
526
|
+
- Claude Code: `default` (account-recommended model)
|
|
527
|
+
- OpenCode: `opencode/gpt-5-nano` (free Zen model)
|
|
528
|
+
|
|
529
|
+
To change HAL defaults, edit `src/default-models.ts`.
|
|
506
530
|
|
|
507
531
|
## Directory Structure
|
|
508
532
|
|
|
@@ -618,6 +642,7 @@ The fully-resolved context that would be sent to the AI for this message — ide
|
|
|
618
642
|
| `bot.*` | `bot.userId`, `bot.username`, `bot.firstName`, `bot.chatId`, `bot.messageId`, `bot.timestamp`, `bot.datetime`, `bot.messageType` |
|
|
619
643
|
| `sys.*` | `sys.date`, `sys.time`, `sys.datetime`, `sys.ts`, `sys.tz` |
|
|
620
644
|
| `project.*` | `project.name`, `project.cwd`, `project.slug` |
|
|
645
|
+
| `engine.*` | `engine.name`, `engine.command`, `engine.model` (if set), `engine.defaultModel` (if HAL default applied) |
|
|
621
646
|
| custom | Any keys defined in `context` config blocks, after `${}` / `#{}` / `@{}` substitution and context hook transforms |
|
|
622
647
|
|
|
623
648
|
Use `/context` (the built-in global command) to inspect the exact keys available at runtime.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context, NextFunction } from "grammy";
|
|
2
|
+
import type { ProjectContext } from "../../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Callback query handler for `/git_clean` inline keyboard interactions.
|
|
5
|
+
* Recognizes data prefixed with `gc:` and ignores all other callbacks.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createGitCallbackHandler(ctx: ProjectContext): (gramCtx: Context, next: NextFunction) => Promise<void>;
|
|
8
|
+
//# sourceMappingURL=callback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/callback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,cAAc,IAC5C,SAAS,OAAO,EAAE,MAAM,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CA8EnE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { InlineKeyboard } from "grammy";
|
|
2
|
+
import { gitExec } from "./exec.js";
|
|
3
|
+
/**
|
|
4
|
+
* Callback query handler for `/git_clean` inline keyboard interactions.
|
|
5
|
+
* Recognizes data prefixed with `gc:` and ignores all other callbacks.
|
|
6
|
+
*/
|
|
7
|
+
export function createGitCallbackHandler(ctx) {
|
|
8
|
+
return async (gramCtx, next) => {
|
|
9
|
+
const data = gramCtx.callbackQuery?.data;
|
|
10
|
+
if (!data?.startsWith("gc:")) {
|
|
11
|
+
return next();
|
|
12
|
+
}
|
|
13
|
+
const { config, logger } = ctx;
|
|
14
|
+
const cwd = config.cwd;
|
|
15
|
+
try {
|
|
16
|
+
if (data.startsWith("gc:select:")) {
|
|
17
|
+
const file = data.slice("gc:select:".length);
|
|
18
|
+
const keyboard = new InlineKeyboard()
|
|
19
|
+
.text("Confirm", `gc:confirm:${file}`)
|
|
20
|
+
.text("Cancel", "gc:cancel");
|
|
21
|
+
await gramCtx.editMessageText(`Revert \`${file}\` and lose the changes?`, { parse_mode: "Markdown", reply_markup: keyboard });
|
|
22
|
+
await gramCtx.answerCallbackQuery();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (data === "gc:all") {
|
|
26
|
+
const keyboard = new InlineKeyboard()
|
|
27
|
+
.text("Confirm", "gc:confirm:__all__")
|
|
28
|
+
.text("Cancel", "gc:cancel");
|
|
29
|
+
await gramCtx.editMessageText("Revert *all* uncommitted changes and lose them?", { parse_mode: "Markdown", reply_markup: keyboard });
|
|
30
|
+
await gramCtx.answerCallbackQuery();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (data.startsWith("gc:confirm:")) {
|
|
34
|
+
const target = data.slice("gc:confirm:".length);
|
|
35
|
+
if (target === "__all__") {
|
|
36
|
+
await gitExec(cwd, ["restore", "."]);
|
|
37
|
+
// Also clean untracked files
|
|
38
|
+
await gitExec(cwd, ["clean", "-fd"]).catch(() => { });
|
|
39
|
+
await gramCtx.editMessageText("All uncommitted changes reverted.", {
|
|
40
|
+
reply_markup: undefined,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
await gitExec(cwd, ["restore", target]);
|
|
45
|
+
await gramCtx.editMessageText(`Restored \`${target}\`.`, {
|
|
46
|
+
parse_mode: "Markdown",
|
|
47
|
+
reply_markup: undefined,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
await gramCtx.answerCallbackQuery();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (data === "gc:cancel") {
|
|
54
|
+
await gramCtx.editMessageText("Cancelled.", {
|
|
55
|
+
reply_markup: undefined,
|
|
56
|
+
});
|
|
57
|
+
await gramCtx.answerCallbackQuery();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
logger.error({ data, error: err instanceof Error ? err.message : String(err) }, "git_clean callback failed");
|
|
63
|
+
try {
|
|
64
|
+
await gramCtx.answerCallbackQuery({ text: "Operation failed." });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// ignore
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=callback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/callback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/clean.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAYxD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,IACzC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAkD/C"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { InlineKeyboard } from "grammy";
|
|
2
|
+
import { gitExec } from "./exec.js";
|
|
3
|
+
/** Parse `git status --short` into a list of file paths. */
|
|
4
|
+
function parseChangedFiles(statusOutput) {
|
|
5
|
+
return statusOutput
|
|
6
|
+
.split("\n")
|
|
7
|
+
.map((line) => line.trim())
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map((line) => line.slice(3)); // strip status flags + space (e.g. " M src/file.ts")
|
|
10
|
+
}
|
|
11
|
+
export function createGitCleanHandler(ctx) {
|
|
12
|
+
return async (gramCtx) => {
|
|
13
|
+
const { config, logger } = ctx;
|
|
14
|
+
const cwd = config.cwd;
|
|
15
|
+
const messageText = gramCtx.message?.text ?? "";
|
|
16
|
+
const fileArg = messageText.replace(/^\/git_clean\s*/, "").trim();
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await gitExec(cwd, ["status", "--short"]);
|
|
19
|
+
const files = parseChangedFiles(stdout);
|
|
20
|
+
if (files.length === 0) {
|
|
21
|
+
await gramCtx.reply("Working tree is clean.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (fileArg) {
|
|
25
|
+
if (!files.includes(fileArg)) {
|
|
26
|
+
await gramCtx.reply(`File \`${fileArg}\` has no uncommitted changes.`, { parse_mode: "Markdown" });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
await gitExec(cwd, ["restore", fileArg]);
|
|
30
|
+
await gramCtx.reply(`Restored \`${fileArg}\`.`, {
|
|
31
|
+
parse_mode: "Markdown",
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const keyboard = new InlineKeyboard();
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
keyboard.text(file, `gc:select:${file}`).row();
|
|
38
|
+
}
|
|
39
|
+
keyboard.text("Reset all", "gc:all").row();
|
|
40
|
+
await gramCtx.reply("Select file(s) to revert:", {
|
|
41
|
+
reply_markup: keyboard,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
logger.error({ error: err instanceof Error ? err.message : String(err) }, "/git_clean failed");
|
|
46
|
+
await gramCtx.reply(`Failed to check changes: ${err instanceof Error ? err.message : String(err)}`);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=clean.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/clean.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,4DAA4D;AAC5D,SAAS,iBAAiB,CAAC,YAAoB;IAC7C,OAAO,YAAY;SAChB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qDAAqD;AACxF,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAmB;IACvD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACvB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAElE,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;YAC7D,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC7B,MAAM,OAAO,CAAC,KAAK,CACjB,UAAU,OAAO,gCAAgC,EACjD,EAAE,UAAU,EAAE,UAAU,EAAE,CAC3B,CAAC;oBACF,OAAO;gBACT,CAAC;gBAED,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;gBACzC,MAAM,OAAO,CAAC,KAAK,CAAC,cAAc,OAAO,KAAK,EAAE;oBAC9C,UAAU,EAAE,UAAU;iBACvB,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;YACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;YACjD,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;YAE3C,MAAM,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE;gBAC/C,YAAY,EAAE,QAAQ;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CACV,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,mBAAmB,CACpB,CAAC;YACF,MAAM,OAAO,CAAC,KAAK,CACjB,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/commit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOxD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,cAAc,IAC1C,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAyF/C"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createAgent } from "../../../agent/index.js";
|
|
2
|
+
import { gitExec } from "./exec.js";
|
|
3
|
+
const COMMIT_MSG_PROMPT = `Generate a concise git commit message (one line, max 72 chars) for the following changes. Return ONLY the commit message, no quotes or explanation.
|
|
4
|
+
|
|
5
|
+
`;
|
|
6
|
+
export function createGitCommitHandler(ctx) {
|
|
7
|
+
return async (gramCtx) => {
|
|
8
|
+
const { config, logger } = ctx;
|
|
9
|
+
const cwd = config.cwd;
|
|
10
|
+
const messageText = gramCtx.message?.text ?? "";
|
|
11
|
+
const userMessage = messageText.replace(/^\/git_commit\s*/, "").trim();
|
|
12
|
+
try {
|
|
13
|
+
await gitExec(cwd, ["add", "."]);
|
|
14
|
+
const { stdout: statusOut } = await gitExec(cwd, [
|
|
15
|
+
"status",
|
|
16
|
+
"--porcelain",
|
|
17
|
+
]);
|
|
18
|
+
if (!statusOut.trim()) {
|
|
19
|
+
await gramCtx.reply("Nothing to commit — working tree is clean.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let commitMessage;
|
|
23
|
+
if (userMessage) {
|
|
24
|
+
commitMessage = userMessage;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const statusMsg = await gramCtx.reply("_Generating commit message..._", { parse_mode: "Markdown" });
|
|
28
|
+
try {
|
|
29
|
+
const { stdout: diffOut } = await gitExec(cwd, [
|
|
30
|
+
"diff",
|
|
31
|
+
"--cached",
|
|
32
|
+
"--stat",
|
|
33
|
+
]);
|
|
34
|
+
const agent = createAgent(ctx);
|
|
35
|
+
const generated = await agent.call(`${COMMIT_MSG_PROMPT}${diffOut || statusOut}`);
|
|
36
|
+
commitMessage = generated.trim().replace(/^["']|["']$/g, "");
|
|
37
|
+
try {
|
|
38
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// ignore delete errors
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
try {
|
|
46
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// ignore delete errors
|
|
50
|
+
}
|
|
51
|
+
logger.error({ error: err instanceof Error ? err.message : String(err) }, "AI commit message generation failed");
|
|
52
|
+
await gramCtx.reply("Failed to generate commit message. Please provide one:\n`/git_commit your message here`", { parse_mode: "Markdown" });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const { stdout: commitOut } = await gitExec(cwd, [
|
|
57
|
+
"commit",
|
|
58
|
+
"-m",
|
|
59
|
+
commitMessage,
|
|
60
|
+
]);
|
|
61
|
+
const summary = commitOut.trim().split("\n")[0] ?? "Committed.";
|
|
62
|
+
await gramCtx.reply(`\`\`\`\n${summary}\n\`\`\``, {
|
|
63
|
+
parse_mode: "Markdown",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
logger.error({ error: err instanceof Error ? err.message : String(err) }, "/git_commit failed");
|
|
68
|
+
await gramCtx.reply(`Commit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/commit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/exec.ts"],"names":[],"mappings":"AAKA,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAE7C;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
export async function gitExec(cwd, args) {
|
|
5
|
+
return execFileAsync("git", args, { cwd, timeout: 30_000 });
|
|
6
|
+
}
|
|
7
|
+
export async function isGitRepo(cwd) {
|
|
8
|
+
try {
|
|
9
|
+
await gitExec(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,IAAc;IAEd,OAAO,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createGitCallbackHandler } from "./callback.js";
|
|
2
|
+
export { createGitCleanHandler } from "./clean.js";
|
|
3
|
+
export { createGitCommitHandler } from "./commit.js";
|
|
4
|
+
export { createGitInitHandler } from "./init.js";
|
|
5
|
+
export { createGitStatusHandler } from "./status.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createGitCallbackHandler } from "./callback.js";
|
|
2
|
+
export { createGitCleanHandler } from "./clean.js";
|
|
3
|
+
export { createGitCommitHandler } from "./commit.js";
|
|
4
|
+
export { createGitInitHandler } from "./init.js";
|
|
5
|
+
export { createGitStatusHandler } from "./status.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,cAAc,IACxC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAyB/C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { gitExec, isGitRepo } from "./exec.js";
|
|
2
|
+
export function createGitInitHandler(ctx) {
|
|
3
|
+
return async (gramCtx) => {
|
|
4
|
+
const { config, logger } = ctx;
|
|
5
|
+
const cwd = config.cwd;
|
|
6
|
+
try {
|
|
7
|
+
if (await isGitRepo(cwd)) {
|
|
8
|
+
await gramCtx.reply("Already a git repository.");
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
await gitExec(cwd, ["init"]);
|
|
12
|
+
await gitExec(cwd, ["add", "."]);
|
|
13
|
+
await gitExec(cwd, ["commit", "-m", "Initial commit"]);
|
|
14
|
+
await gramCtx.reply("Git repository initialized with initial commit.");
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
logger.error({ error: err instanceof Error ? err.message : String(err) }, "/git_init failed");
|
|
18
|
+
await gramCtx.reply(`Failed to initialize git repository: ${err instanceof Error ? err.message : String(err)}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/init.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,UAAU,oBAAoB,CAAC,GAAmB;IACtD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QAEvB,IAAI,CAAC;YACH,IAAI,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBACjD,OAAO;YACT,CAAC;YAED,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7B,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;YACjC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAEvD,MAAM,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CACV,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,kBAAkB,CACnB,CAAC;YACF,MAAM,OAAO,CAAC,KAAK,CACjB,wCAAwC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC3F,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/bot/commands/git/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,cAAc,IAC1C,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAmB/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { gitExec } from "./exec.js";
|
|
2
|
+
export function createGitStatusHandler(ctx) {
|
|
3
|
+
return async (gramCtx) => {
|
|
4
|
+
const { config, logger } = ctx;
|
|
5
|
+
try {
|
|
6
|
+
const { stdout } = await gitExec(config.cwd, ["status"]);
|
|
7
|
+
const output = stdout.trim() || "Nothing to report.";
|
|
8
|
+
await gramCtx.reply(`\`\`\`\n${output}\n\`\`\``, {
|
|
9
|
+
parse_mode: "Markdown",
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
logger.error({ error: err instanceof Error ? err.message : String(err) }, "/git_status failed");
|
|
14
|
+
await gramCtx.reply(`Failed to get git status: ${err instanceof Error ? err.message : String(err)}`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/bot/commands/git/status.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,UAAU,sBAAsB,CAAC,GAAmB;IACxD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;QAE/B,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,oBAAoB,CAAC;YACrD,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,MAAM,UAAU,EAAE;gBAC/C,UAAU,EAAE,UAAU;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CACV,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,oBAAoB,CACrB,CAAC;YACF,MAAM,OAAO,CAAC,KAAK,CACjB,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAChF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -4,7 +4,7 @@ const DEFAULT_TEMPLATE = "${HAL_COMMANDS}";
|
|
|
4
4
|
export function createHelpHandler(ctx) {
|
|
5
5
|
return async (gramCtx) => {
|
|
6
6
|
const helpCfg = ctx.config.commands.help;
|
|
7
|
-
const template = helpCfg
|
|
7
|
+
const template = helpCfg.message ?? DEFAULT_TEMPLATE;
|
|
8
8
|
const message = await resolveCommandMessage(template, ctx, gramCtx);
|
|
9
9
|
await gramCtx.reply(message, { parse_mode: "Markdown" });
|
|
10
10
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/bot/commands/help.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,gGAAgG;AAChG,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAEzC,MAAM,QAAQ,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/bot/commands/help.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,gGAAgG;AAChG,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAEzC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;QACrD,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QACpE,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import type pino from "pino";
|
|
2
|
+
export type CommandSource = "builtin" | "git" | "project" | "system" | "skill";
|
|
2
3
|
export interface CommandEntry {
|
|
3
4
|
command: string;
|
|
4
5
|
description: string;
|
|
5
6
|
filePath: string;
|
|
6
7
|
skillPrompt?: string;
|
|
7
8
|
public?: boolean;
|
|
9
|
+
source: CommandSource;
|
|
10
|
+
}
|
|
11
|
+
export interface CommandEnabledFlags {
|
|
12
|
+
start: boolean;
|
|
13
|
+
help: boolean;
|
|
14
|
+
reset: boolean;
|
|
15
|
+
clean: boolean;
|
|
16
|
+
git: boolean;
|
|
8
17
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Commands that are always registered with Telegram, regardless of
|
|
11
|
-
* whether custom .mjs files or skills exist.
|
|
12
|
-
*/
|
|
13
18
|
export declare const BUILTIN_COMMANDS: CommandEntry[];
|
|
19
|
+
export declare const GIT_COMMANDS: CommandEntry[];
|
|
14
20
|
/**
|
|
15
21
|
* Scan command directories and optionally the skills dir, then return the merged list.
|
|
22
|
+
* When `enabled` flags are provided, disabled built-in/git commands are excluded.
|
|
16
23
|
*
|
|
17
24
|
* Precedence (lowest → highest):
|
|
18
25
|
* engine skills < global .hal/commands < project .hal/commands
|
|
19
26
|
*/
|
|
20
|
-
export declare function loadCommands(projectCwd: string, configDir: string, logger: pino.Logger, skillsDir?: string): Promise<CommandEntry[]>;
|
|
27
|
+
export declare function loadCommands(projectCwd: string, configDir: string, logger: pino.Logger, skillsDir?: string, enabled?: CommandEnabledFlags): Promise<CommandEntry[]>;
|
|
21
28
|
/**
|
|
22
29
|
* Resolve a skill entry by command name from the engine's skills directory.
|
|
23
30
|
* Returns null if the skill doesn't exist or its SKILL.md can't be parsed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd;AAuOD,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAyB1C,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,YAAY,EAyBtC,CAAC;AAWF;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,EAAE,CAAC,CAuCzB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,GAClB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA6B9B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAcf"}
|