@geminixiang/mikan 1.0.0-beta.20 → 1.0.0-beta.21
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 +34 -0
- package/README.md +18 -11
- package/dist/adapters/buffered-responder.d.ts +60 -0
- package/dist/adapters/buffered-responder.d.ts.map +1 -0
- package/dist/adapters/buffered-responder.js +201 -0
- package/dist/adapters/buffered-responder.js.map +1 -0
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +42 -177
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +14 -76
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +52 -443
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +4 -0
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +5 -0
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/context.d.ts.map +1 -1
- package/dist/adapters/github/context.js +32 -104
- package/dist/adapters/github/context.js.map +1 -1
- package/dist/adapters/github/github-ops.d.ts +90 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +405 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +2 -0
- package/dist/adapters/github/repo.d.ts.map +1 -1
- package/dist/adapters/github/repo.js +5 -0
- package/dist/adapters/github/repo.js.map +1 -1
- package/dist/adapters/github/tools/checks.d.ts.map +1 -1
- package/dist/adapters/github/tools/checks.js +6 -17
- package/dist/adapters/github/tools/checks.js.map +1 -1
- package/dist/adapters/github/tools/issue.d.ts.map +1 -1
- package/dist/adapters/github/tools/issue.js +6 -17
- package/dist/adapters/github/tools/issue.js.map +1 -1
- package/dist/adapters/github/tools/pr.d.ts.map +1 -1
- package/dist/adapters/github/tools/pr.js +6 -17
- package/dist/adapters/github/tools/pr.js.map +1 -1
- package/dist/adapters/github/tools/read.d.ts.map +1 -1
- package/dist/adapters/github/tools/read.js +6 -17
- package/dist/adapters/github/tools/read.js.map +1 -1
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
- package/dist/adapters/github/tools/review-reply.js +6 -17
- package/dist/adapters/github/tools/review-reply.js.map +1 -1
- package/dist/adapters/github/tools/sync.d.ts.map +1 -1
- package/dist/adapters/github/tools/sync.js +6 -17
- package/dist/adapters/github/tools/sync.js.map +1 -1
- package/dist/adapters/slack/bot.js +1 -1
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +33 -151
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +28 -32
- package/dist/agent.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +25 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +59 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +16 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +119 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/ext.js +9 -11
- package/dist/cli/ext.js.map +1 -1
- package/dist/commands/extensions.js +2 -2
- package/dist/commands/extensions.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +5 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +8 -8
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +7 -5
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -41
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +35 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +225 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts +0 -10
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +9 -82
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +1 -0
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +33 -36
- package/dist/execution-resolver.js.map +1 -1
- package/dist/harness/event-format.d.ts +66 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +112 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +9 -6
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +35 -50
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +10 -14
- package/dist/harness/extensions/types.d.ts.map +1 -1
- package/dist/harness/extensions/types.js.map +1 -1
- package/dist/harness/index.d.ts +1 -0
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +1 -0
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +16 -0
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +27 -1
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +18 -1
- package/dist/harness/subagent-runner.d.ts.map +1 -1
- package/dist/harness/subagent-runner.js +62 -30
- package/dist/harness/subagent-runner.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.js +69 -121
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +6 -4
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +3 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +13 -3
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +4 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +1 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +4 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +1 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +4 -1
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +1 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +4 -1
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/gondolin-bootstrap.d.ts +26 -0
- package/dist/sandbox/gondolin-bootstrap.d.ts.map +1 -0
- package/dist/sandbox/gondolin-bootstrap.js +27 -0
- package/dist/sandbox/gondolin-bootstrap.js.map +1 -0
- package/dist/sandbox/gondolin-contract.d.ts +125 -0
- package/dist/sandbox/gondolin-contract.d.ts.map +1 -0
- package/dist/sandbox/gondolin-contract.js +155 -0
- package/dist/sandbox/gondolin-contract.js.map +1 -0
- package/dist/sandbox/gondolin-fleet.d.ts +1 -1
- package/dist/sandbox/gondolin-fleet.d.ts.map +1 -1
- package/dist/sandbox/gondolin-fleet.js +1 -1
- package/dist/sandbox/gondolin-fleet.js.map +1 -1
- package/dist/sandbox/gondolin-gateway.d.ts +1 -0
- package/dist/sandbox/gondolin-gateway.d.ts.map +1 -1
- package/dist/sandbox/gondolin-gateway.js +13 -6
- package/dist/sandbox/gondolin-gateway.js.map +1 -1
- package/dist/sandbox/gondolin-inventory.d.ts +2 -16
- package/dist/sandbox/gondolin-inventory.d.ts.map +1 -1
- package/dist/sandbox/gondolin-inventory.js +2 -12
- package/dist/sandbox/gondolin-inventory.js.map +1 -1
- package/dist/sandbox/gondolin-placement.d.ts +0 -2
- package/dist/sandbox/gondolin-placement.d.ts.map +1 -1
- package/dist/sandbox/gondolin-placement.js +0 -6
- package/dist/sandbox/gondolin-placement.js.map +1 -1
- package/dist/sandbox/gondolin-recovery.d.ts +33 -0
- package/dist/sandbox/gondolin-recovery.d.ts.map +1 -0
- package/dist/sandbox/gondolin-recovery.js +39 -0
- package/dist/sandbox/gondolin-recovery.js.map +1 -0
- package/dist/sandbox/gondolin-remote.d.ts +2 -5
- package/dist/sandbox/gondolin-remote.d.ts.map +1 -1
- package/dist/sandbox/gondolin-remote.js +12 -39
- package/dist/sandbox/gondolin-remote.js.map +1 -1
- package/dist/sandbox/gondolin-worker-client.d.ts +8 -12
- package/dist/sandbox/gondolin-worker-client.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker-client.js +13 -15
- package/dist/sandbox/gondolin-worker-client.js.map +1 -1
- package/dist/sandbox/gondolin-worker.d.ts +2 -40
- package/dist/sandbox/gondolin-worker.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker.js.map +1 -1
- package/dist/sandbox/gondolin.d.ts +1 -0
- package/dist/sandbox/gondolin.d.ts.map +1 -1
- package/dist/sandbox/gondolin.js +8 -4
- package/dist/sandbox/gondolin.js.map +1 -1
- package/dist/sandbox/host.d.ts +1 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +3 -0
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/index.d.ts +9 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +14 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/types.d.ts +5 -0
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +1 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +5 -2
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +32 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +24 -83
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/conversation-log.d.ts +13 -0
- package/dist/sessions/conversation-log.d.ts.map +1 -0
- package/dist/sessions/conversation-log.js +47 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/rotation.d.ts +2 -0
- package/dist/sessions/rotation.d.ts.map +1 -0
- package/dist/sessions/rotation.js +39 -0
- package/dist/sessions/rotation.js.map +1 -0
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +4 -10
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +2 -2
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +23 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +42 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +27 -46
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/host-fn-tool.d.ts +21 -0
- package/dist/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/tools/host-fn-tool.js +32 -0
- package/dist/tools/host-fn-tool.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/react.d.ts.map +1 -1
- package/dist/tools/react.js +6 -17
- package/dist/tools/react.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +7 -26
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +5 -2
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/subagent-slots.d.ts +28 -0
- package/dist/tools/subagent-slots.d.ts.map +1 -0
- package/dist/tools/subagent-slots.js +57 -0
- package/dist/tools/subagent-slots.js.map +1 -0
- package/dist/tools/subagent.d.ts +7 -2
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +160 -111
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/types.d.ts +10 -9
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/types.d.ts +5 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/date.d.ts +1 -1
- package/dist/utils/date.js +1 -1
- package/dist/utils/date.js.map +1 -1
- package/dist/vault/disabled.d.ts.map +1 -1
- package/dist/vault/disabled.js +0 -1
- package/dist/vault/disabled.js.map +1 -1
- package/dist/vault/index.d.ts +0 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +0 -10
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/injection.d.ts +20 -0
- package/dist/vault/injection.d.ts.map +1 -0
- package/dist/vault/injection.js +27 -0
- package/dist/vault/injection.js.map +1 -0
- package/dist/vault/types.d.ts +0 -2
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts +3 -3
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +41 -39
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/types.d.ts +3 -0
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.js.map +1 -1
- package/dist/web/agent-events/portal.d.ts.map +1 -1
- package/dist/web/agent-events/portal.js +2 -1
- package/dist/web/agent-events/portal.js.map +1 -1
- package/package.json +1 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -4
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -6
- package/dist/vault/routing.js.map +0 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared pieces of the CLI flag grammar.
|
|
3
|
+
*
|
|
4
|
+
* `resolveBoot` (cli/boot.ts) is the daemon's only full argv parser. This
|
|
5
|
+
* module holds what other scanners must agree with it on: the value-flag
|
|
6
|
+
* spelling (`--flag value` / `--flag=value`) via `takeValueFlag`, the default
|
|
7
|
+
* state dir, and an early `--state-dir` probe for import-time consumers
|
|
8
|
+
* (Sentry instrumentation) that must not load the boot path.
|
|
9
|
+
*/
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join, resolve } from "path";
|
|
12
|
+
import { readEnv } from "../utils/env.js";
|
|
13
|
+
export function defaultStateDir() {
|
|
14
|
+
return join(homedir(), ".mikan");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Match `args[i]` against a value flag, accepting both `--name value` and
|
|
18
|
+
* `--name=value`. Returns the raw value and the index of the last argv slot
|
|
19
|
+
* consumed, or undefined when `args[i]` is not this flag.
|
|
20
|
+
*/
|
|
21
|
+
export function takeValueFlag(args, i, name) {
|
|
22
|
+
const arg = args[i];
|
|
23
|
+
if (arg === name)
|
|
24
|
+
return { value: args[i + 1] ?? "", lastIndex: i + 1 };
|
|
25
|
+
if (arg.startsWith(name + "="))
|
|
26
|
+
return { value: arg.slice(name.length + 1), lastIndex: i };
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Effective state dir — the ONE place its precedence is decided:
|
|
31
|
+
* `--state-dir` flag (last occurrence wins) > STATE_DIR / MIKAN_STATE_DIR
|
|
32
|
+
* env > `~/.mikan`. Boot writes the resolved value back into the env
|
|
33
|
+
* (setEnvAliases) purely as a compatibility channel for code that runs
|
|
34
|
+
* without access to the boot plan — see `effectiveStateDir`.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveStateDir(args = process.argv.slice(2), envValue = readEnv("STATE_DIR")) {
|
|
37
|
+
let flagValue;
|
|
38
|
+
for (let i = 0; i < args.length; i++) {
|
|
39
|
+
const taken = takeValueFlag(args, i, "--state-dir");
|
|
40
|
+
if (taken) {
|
|
41
|
+
flagValue = taken.value;
|
|
42
|
+
i = taken.lastIndex;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (flagValue !== undefined)
|
|
46
|
+
return resolve(flagValue);
|
|
47
|
+
if (envValue)
|
|
48
|
+
return resolve(envValue);
|
|
49
|
+
return defaultStateDir();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* State dir for post-boot readers: the env channel (which boot populated
|
|
53
|
+
* from the resolved plan) with the shared default. Never re-reads argv —
|
|
54
|
+
* by the time this runs, any `--state-dir` flag is already folded in.
|
|
55
|
+
*/
|
|
56
|
+
export function effectiveStateDir() {
|
|
57
|
+
return resolveStateDir([]);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=arg-grammar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arg-grammar.js","sourceRoot":"","sources":["../../src/cli/arg-grammar.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAc,EACd,CAAS,EACT,IAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IACxE,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAC3F,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAI,GAAa,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EACtC,QAAQ,GAAuB,OAAO,CAAC,WAAW,CAAC;IAEnD,IAAI,SAA6B,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;QACpD,IAAI,KAAK,EAAE,CAAC;YACV,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;YACxB,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;QACtB,CAAC;IACH,CAAC;IACD,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IACvD,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,eAAe,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["/**\n * Shared pieces of the CLI flag grammar.\n *\n * `resolveBoot` (cli/boot.ts) is the daemon's only full argv parser. This\n * module holds what other scanners must agree with it on: the value-flag\n * spelling (`--flag value` / `--flag=value`) via `takeValueFlag`, the default\n * state dir, and an early `--state-dir` probe for import-time consumers\n * (Sentry instrumentation) that must not load the boot path.\n */\nimport { homedir } from \"os\";\nimport { join, resolve } from \"path\";\nimport { readEnv } from \"../utils/env.js\";\n\nexport function defaultStateDir(): string {\n return join(homedir(), \".mikan\");\n}\n\n/**\n * Match `args[i]` against a value flag, accepting both `--name value` and\n * `--name=value`. Returns the raw value and the index of the last argv slot\n * consumed, or undefined when `args[i]` is not this flag.\n */\nexport function takeValueFlag(\n args: string[],\n i: number,\n name: string,\n): { value: string; lastIndex: number } | undefined {\n const arg = args[i];\n if (arg === name) return { value: args[i + 1] ?? \"\", lastIndex: i + 1 };\n if (arg.startsWith(name + \"=\")) return { value: arg.slice(name.length + 1), lastIndex: i };\n return undefined;\n}\n\n/**\n * Effective state dir — the ONE place its precedence is decided:\n * `--state-dir` flag (last occurrence wins) > STATE_DIR / MIKAN_STATE_DIR\n * env > `~/.mikan`. Boot writes the resolved value back into the env\n * (setEnvAliases) purely as a compatibility channel for code that runs\n * without access to the boot plan — see `effectiveStateDir`.\n */\nexport function resolveStateDir(\n args: string[] = process.argv.slice(2),\n envValue: string | undefined = readEnv(\"STATE_DIR\"),\n): string {\n let flagValue: string | undefined;\n for (let i = 0; i < args.length; i++) {\n const taken = takeValueFlag(args, i, \"--state-dir\");\n if (taken) {\n flagValue = taken.value;\n i = taken.lastIndex;\n }\n }\n if (flagValue !== undefined) return resolve(flagValue);\n if (envValue) return resolve(envValue);\n return defaultStateDir();\n}\n\n/**\n * State dir for post-boot readers: the env channel (which boot populated\n * from the resolved plan) with the shared default. Never re-reads argv —\n * by the time this runs, any `--state-dir` flag is already folded in.\n */\nexport function effectiveStateDir(): string {\n return resolveStateDir([]);\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SandboxConfig } from "../sandbox/index.js";
|
|
2
|
+
export interface BootPlan {
|
|
3
|
+
mode: "ext" | "env" | "help" | "version" | "worker-token" | "onboard" | "download" | "run";
|
|
4
|
+
/** argv after `ext`, handed to runExtCommand. Only set for mode "ext". */
|
|
5
|
+
extArgs?: string[];
|
|
6
|
+
stateDir: string;
|
|
7
|
+
/** Resolved working directory; defaults to `<stateDir>/workspace`. */
|
|
8
|
+
workingDir: string;
|
|
9
|
+
/** True when the working directory came from argv (then it is not auto-created). */
|
|
10
|
+
workingDirExplicit: boolean;
|
|
11
|
+
sandbox: SandboxConfig;
|
|
12
|
+
downloadChannel?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveBoot(args?: string[]): BootPlan;
|
|
15
|
+
export declare function helpText(): string;
|
|
16
|
+
//# sourceMappingURL=boot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"AAWA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG1E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IAC3F,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,kBAAkB,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,QAAQ,CAmE5E;AAED,wBAAgB,QAAQ,IAAI,MAAM,CA+BjC"}
|
package/dist/cli/boot.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot resolution for the `mikan` binary: argv → a BootPlan saying which mode
|
|
3
|
+
* to run and with what configuration. Pure — no side effects, no exits — so
|
|
4
|
+
* the grammar that actually drives the daemon is testable without spawning a
|
|
5
|
+
* process; main.ts just executes the plan.
|
|
6
|
+
*
|
|
7
|
+
* Modes, highest priority first: `ext` (own grammar, never flag-parsed here),
|
|
8
|
+
* `help`, `version`, `worker-token`, `onboard`, `download`, `run`.
|
|
9
|
+
*/
|
|
10
|
+
import { join, resolve } from "path";
|
|
11
|
+
import { envSummaryLines } from "../env-manifest.js";
|
|
12
|
+
import { parseSandboxArg } from "../sandbox/index.js";
|
|
13
|
+
import { defaultStateDir, resolveStateDir, takeValueFlag } from "./arg-grammar.js";
|
|
14
|
+
export function resolveBoot(args = process.argv.slice(2)) {
|
|
15
|
+
if (args[0] === "ext" || args[0] === "env") {
|
|
16
|
+
return {
|
|
17
|
+
mode: args[0],
|
|
18
|
+
...(args[0] === "ext" ? { extArgs: args.slice(1) } : {}),
|
|
19
|
+
stateDir: defaultStateDir(),
|
|
20
|
+
workingDir: join(defaultStateDir(), "workspace"),
|
|
21
|
+
workingDirExplicit: false,
|
|
22
|
+
sandbox: { type: "host" },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
let sandbox = { type: "host" };
|
|
26
|
+
let workingDirArg;
|
|
27
|
+
let downloadChannel;
|
|
28
|
+
let help = false;
|
|
29
|
+
let version = false;
|
|
30
|
+
let onboard = false;
|
|
31
|
+
let workerToken = false;
|
|
32
|
+
for (let i = 0; i < args.length; i++) {
|
|
33
|
+
const arg = args[i];
|
|
34
|
+
let taken;
|
|
35
|
+
if (arg === "--help" || arg === "-h") {
|
|
36
|
+
help = true;
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--version" || arg === "-v" || arg === "-V") {
|
|
39
|
+
version = true;
|
|
40
|
+
}
|
|
41
|
+
else if (arg === "--onboard") {
|
|
42
|
+
onboard = true;
|
|
43
|
+
}
|
|
44
|
+
else if (arg === "--worker-token") {
|
|
45
|
+
workerToken = true;
|
|
46
|
+
}
|
|
47
|
+
else if ((taken = takeValueFlag(args, i, "--sandbox"))) {
|
|
48
|
+
sandbox = parseSandboxArg(taken.value);
|
|
49
|
+
i = taken.lastIndex;
|
|
50
|
+
}
|
|
51
|
+
else if ((taken = takeValueFlag(args, i, "--state-dir"))) {
|
|
52
|
+
// Consumed here so its value never reads as the positional working
|
|
53
|
+
// dir; the value itself is resolved by resolveStateDir below.
|
|
54
|
+
i = taken.lastIndex;
|
|
55
|
+
}
|
|
56
|
+
else if ((taken = takeValueFlag(args, i, "--download"))) {
|
|
57
|
+
downloadChannel = taken.value;
|
|
58
|
+
i = taken.lastIndex;
|
|
59
|
+
}
|
|
60
|
+
else if (!arg.startsWith("-")) {
|
|
61
|
+
workingDirArg = arg;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new Error(`Unknown flag: ${arg}. Run \`mikan --help\` for usage.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const stateDir = resolveStateDir(args);
|
|
68
|
+
return {
|
|
69
|
+
mode: help
|
|
70
|
+
? "help"
|
|
71
|
+
: version
|
|
72
|
+
? "version"
|
|
73
|
+
: workerToken
|
|
74
|
+
? "worker-token"
|
|
75
|
+
: onboard
|
|
76
|
+
? "onboard"
|
|
77
|
+
: downloadChannel
|
|
78
|
+
? "download"
|
|
79
|
+
: "run",
|
|
80
|
+
stateDir,
|
|
81
|
+
workingDir: workingDirArg ? resolve(workingDirArg) : join(stateDir, "workspace"),
|
|
82
|
+
workingDirExplicit: workingDirArg !== undefined,
|
|
83
|
+
sandbox,
|
|
84
|
+
downloadChannel,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function helpText() {
|
|
88
|
+
return `mikan — multi-platform chat agent daemon
|
|
89
|
+
|
|
90
|
+
Usage:
|
|
91
|
+
mikan [options] [working-directory]
|
|
92
|
+
Start the daemon. The working directory defaults to <state-dir>/workspace.
|
|
93
|
+
mikan ext <install|validate|list|remove> …
|
|
94
|
+
Manage extensions (run \`mikan ext\` for details).
|
|
95
|
+
mikan env
|
|
96
|
+
Show the full environment-variable inventory and what is currently set.
|
|
97
|
+
|
|
98
|
+
Options:
|
|
99
|
+
--state-dir <dir> State directory (settings.json, vaults, extensions).
|
|
100
|
+
Default: ~/.mikan
|
|
101
|
+
--sandbox <spec> Execution sandbox. One of:
|
|
102
|
+
host
|
|
103
|
+
container:<existing-container-name>
|
|
104
|
+
image:<image[:tag]>
|
|
105
|
+
gondolin:default | gondolin:remote
|
|
106
|
+
firecracker:<vm-id>:<host-path>[:<ssh-user>[:<ssh-port>]]
|
|
107
|
+
cloudflare:<sandbox-id>
|
|
108
|
+
Default: host
|
|
109
|
+
--onboard Create <state-dir>/settings.json from a template, then exit.
|
|
110
|
+
--worker-token Mint a one-time gondolin worker join token, then exit.
|
|
111
|
+
--download <channel> Dump a Slack channel's history (Slack only), then exit.
|
|
112
|
+
--version, -v Print the version.
|
|
113
|
+
--help, -h Show this help.
|
|
114
|
+
|
|
115
|
+
Environment (platform tokens select which chat adapters start):
|
|
116
|
+
${envSummaryLines().join("\n")}
|
|
117
|
+
Run \`mikan env\` for the full inventory.`;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=boot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Boot resolution for the `mikan` binary: argv → a BootPlan saying which mode\n * to run and with what configuration. Pure — no side effects, no exits — so\n * the grammar that actually drives the daemon is testable without spawning a\n * process; main.ts just executes the plan.\n *\n * Modes, highest priority first: `ext` (own grammar, never flag-parsed here),\n * `help`, `version`, `worker-token`, `onboard`, `download`, `run`.\n */\nimport { join, resolve } from \"path\";\nimport { envSummaryLines } from \"../env-manifest.js\";\nimport { parseSandboxArg, type SandboxConfig } from \"../sandbox/index.js\";\nimport { defaultStateDir, resolveStateDir, takeValueFlag } from \"./arg-grammar.js\";\n\nexport interface BootPlan {\n mode: \"ext\" | \"env\" | \"help\" | \"version\" | \"worker-token\" | \"onboard\" | \"download\" | \"run\";\n /** argv after `ext`, handed to runExtCommand. Only set for mode \"ext\". */\n extArgs?: string[];\n stateDir: string;\n /** Resolved working directory; defaults to `<stateDir>/workspace`. */\n workingDir: string;\n /** True when the working directory came from argv (then it is not auto-created). */\n workingDirExplicit: boolean;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n}\n\nexport function resolveBoot(args: string[] = process.argv.slice(2)): BootPlan {\n if (args[0] === \"ext\" || args[0] === \"env\") {\n return {\n mode: args[0],\n ...(args[0] === \"ext\" ? { extArgs: args.slice(1) } : {}),\n stateDir: defaultStateDir(),\n workingDir: join(defaultStateDir(), \"workspace\"),\n workingDirExplicit: false,\n sandbox: { type: \"host\" },\n };\n }\n\n let sandbox: SandboxConfig = { type: \"host\" };\n let workingDirArg: string | undefined;\n let downloadChannel: string | undefined;\n let help = false;\n let version = false;\n let onboard = false;\n let workerToken = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n let taken;\n if (arg === \"--help\" || arg === \"-h\") {\n help = true;\n } else if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n version = true;\n } else if (arg === \"--onboard\") {\n onboard = true;\n } else if (arg === \"--worker-token\") {\n workerToken = true;\n } else if ((taken = takeValueFlag(args, i, \"--sandbox\"))) {\n sandbox = parseSandboxArg(taken.value);\n i = taken.lastIndex;\n } else if ((taken = takeValueFlag(args, i, \"--state-dir\"))) {\n // Consumed here so its value never reads as the positional working\n // dir; the value itself is resolved by resolveStateDir below.\n i = taken.lastIndex;\n } else if ((taken = takeValueFlag(args, i, \"--download\"))) {\n downloadChannel = taken.value;\n i = taken.lastIndex;\n } else if (!arg.startsWith(\"-\")) {\n workingDirArg = arg;\n } else {\n throw new Error(`Unknown flag: ${arg}. Run \\`mikan --help\\` for usage.`);\n }\n }\n\n const stateDir = resolveStateDir(args);\n return {\n mode: help\n ? \"help\"\n : version\n ? \"version\"\n : workerToken\n ? \"worker-token\"\n : onboard\n ? \"onboard\"\n : downloadChannel\n ? \"download\"\n : \"run\",\n stateDir,\n workingDir: workingDirArg ? resolve(workingDirArg) : join(stateDir, \"workspace\"),\n workingDirExplicit: workingDirArg !== undefined,\n sandbox,\n downloadChannel,\n };\n}\n\nexport function helpText(): string {\n return `mikan — multi-platform chat agent daemon\n\nUsage:\n mikan [options] [working-directory]\n Start the daemon. The working directory defaults to <state-dir>/workspace.\n mikan ext <install|validate|list|remove> …\n Manage extensions (run \\`mikan ext\\` for details).\n mikan env\n Show the full environment-variable inventory and what is currently set.\n\nOptions:\n --state-dir <dir> State directory (settings.json, vaults, extensions).\n Default: ~/.mikan\n --sandbox <spec> Execution sandbox. One of:\n host\n container:<existing-container-name>\n image:<image[:tag]>\n gondolin:default | gondolin:remote\n firecracker:<vm-id>:<host-path>[:<ssh-user>[:<ssh-port>]]\n cloudflare:<sandbox-id>\n Default: host\n --onboard Create <state-dir>/settings.json from a template, then exit.\n --worker-token Mint a one-time gondolin worker join token, then exit.\n --download <channel> Dump a Slack channel's history (Slack only), then exit.\n --version, -v Print the version.\n --help, -h Show this help.\n\nEnvironment (platform tokens select which chat adapters start):\n${envSummaryLines().join(\"\\n\")}\nRun \\`mikan env\\` for the full inventory.`;\n}\n"]}
|
package/dist/cli/ext.js
CHANGED
|
@@ -12,31 +12,29 @@
|
|
|
12
12
|
* host-only state dir (never the workspace); see src/harness/extensions/LAYOUT.md.
|
|
13
13
|
*/
|
|
14
14
|
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
15
|
import { basename, join, resolve } from "node:path";
|
|
17
16
|
import { defaultExtensionDirs, listInstalledExtensions, validateExtension, } from "../harness/index.js";
|
|
17
|
+
import { resolveStateDir, takeValueFlag } from "./arg-grammar.js";
|
|
18
18
|
import { parseGitSource, resolveGitSource } from "./ext-git.js";
|
|
19
19
|
function parseExtArgs(argv) {
|
|
20
|
-
|
|
20
|
+
// Shares the daemon's state-dir precedence: --state-dir > env > ~/.mikan.
|
|
21
|
+
const stateDir = resolveStateDir(argv);
|
|
21
22
|
let scope;
|
|
22
23
|
let conversationId;
|
|
23
24
|
const positional = [];
|
|
24
25
|
for (let i = 0; i < argv.length; i++) {
|
|
25
26
|
const arg = argv[i];
|
|
27
|
+
let taken;
|
|
26
28
|
if (arg === "--global")
|
|
27
29
|
scope = "global";
|
|
28
|
-
else if (
|
|
30
|
+
else if ((taken = takeValueFlag(argv, i, "--conversation"))) {
|
|
29
31
|
scope = "conversation";
|
|
30
|
-
conversationId =
|
|
32
|
+
conversationId = taken.value || undefined;
|
|
33
|
+
i = taken.lastIndex;
|
|
31
34
|
}
|
|
32
|
-
else if (
|
|
33
|
-
|
|
34
|
-
conversationId = arg.slice("--conversation=".length);
|
|
35
|
+
else if ((taken = takeValueFlag(argv, i, "--state-dir"))) {
|
|
36
|
+
i = taken.lastIndex; // value already folded in by resolveStateDir
|
|
35
37
|
}
|
|
36
|
-
else if (arg === "--state-dir")
|
|
37
|
-
stateDir = resolve(argv[++i] ?? "");
|
|
38
|
-
else if (arg.startsWith("--state-dir="))
|
|
39
|
-
stateDir = resolve(arg.slice("--state-dir=".length));
|
|
40
38
|
else
|
|
41
39
|
positional.push(arg);
|
|
42
40
|
}
|
package/dist/cli/ext.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ext.js","sourceRoot":"","sources":["../../src/cli/ext.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mikan ext` — manage extensions from the CLI.\n *\n * mikan ext install <source> [--global | --conversation <id>] [--state-dir <dir>]\n * mikan ext validate <path>\n * mikan ext list [--conversation <id>] [--state-dir <dir>]\n * mikan ext remove <slug> (--global | --conversation <id>) [--state-dir <dir>]\n *\n * `<source>` is a local path or a git URL (https://…, git@…, or github:owner/repo)\n * with an optional `#subpath` for extensions inside a repo. Reinstalling over an\n * existing extension updates it (data is preserved). Extensions install into the\n * host-only state dir (never the workspace); see src/harness/extensions/LAYOUT.md.\n */\nimport { cpSync, existsSync, mkdirSync, rmSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport {\n defaultExtensionDirs,\n listInstalledExtensions,\n validateExtension,\n} from \"../harness/index.js\";\nimport { parseGitSource, resolveGitSource } from \"./ext-git.js\";\n\ninterface ExtArgs {\n action?: string;\n target?: string;\n stateDir: string;\n scope: \"global\" | \"conversation\" | undefined;\n conversationId?: string;\n}\n\nfunction parseExtArgs(argv: string[]): ExtArgs {\n let stateDir = join(homedir(), \".mikan\");\n let scope: ExtArgs[\"scope\"];\n let conversationId: string | undefined;\n const positional: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--global\") scope = \"global\";\n else if (arg === \"--conversation\") {\n scope = \"conversation\";\n conversationId = argv[++i];\n } else if (arg.startsWith(\"--conversation=\")) {\n scope = \"conversation\";\n conversationId = arg.slice(\"--conversation=\".length);\n } else if (arg === \"--state-dir\") stateDir = resolve(argv[++i] ?? \"\");\n else if (arg.startsWith(\"--state-dir=\")) stateDir = resolve(arg.slice(\"--state-dir=\".length));\n else positional.push(arg);\n }\n\n return { action: positional[0], target: positional[1], stateDir, scope, conversationId };\n}\n\n/** Directory that extension CODE for the chosen scope lives in. */\nfunction scopeExtensionsDir(args: ExtArgs): string {\n if (args.scope === \"global\") return join(args.stateDir, \"global\", \"extensions\");\n if (args.scope === \"conversation\" && args.conversationId) {\n // defaultExtensionDirs returns [global, conversation]; take the conversation one.\n return defaultExtensionDirs(args.conversationId, args.stateDir)[1];\n }\n throw new Error(\"Specify a scope: --global or --conversation <id>\");\n}\n\nconst USAGE = `Usage:\n mikan ext install <source> (--global | --conversation <id>) [--state-dir <dir>]\n <source>: a local path, or a git URL / github:owner/repo with optional #subpath\n e.g. github:geminixiang/mikan#examples/extensions/agent-pm\n Reinstalling over an existing extension updates it (data preserved).\n mikan ext validate <path>\n mikan ext list [--conversation <id>] [--state-dir <dir>]\n mikan ext remove <slug> (--global | --conversation <id>) [--state-dir <dir>]`;\n\nfunction noop(): void {}\n\nexport async function runExtCommand(argv: string[]): Promise<number> {\n const args = parseExtArgs(argv);\n\n switch (args.action) {\n case \"validate\":\n return validateAction(args);\n case \"install\":\n return installAction(args);\n case \"list\":\n return listAction(args);\n case \"remove\":\n return removeAction(args);\n default:\n console.error(USAGE);\n return 1;\n }\n}\n\nasync function validateAction(args: ExtArgs): Promise<number> {\n if (!args.target) {\n console.error(\"ext validate: missing <path>\");\n return 1;\n }\n const result = await validateExtension(resolve(args.target));\n printValidation(result);\n return result.ok ? 0 : 1;\n}\n\nasync function installAction(args: ExtArgs): Promise<number> {\n if (!args.target) {\n console.error(\"ext install: missing <path>\");\n return 1;\n }\n let destDir: string;\n try {\n destDir = scopeExtensionsDir(args);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n return 1;\n }\n\n // Resolve the source: a git URL (optionally with #subpath) is cloned to a\n // temp dir; a local path is used directly.\n const gitSpec = parseGitSource(args.target);\n let source: string;\n let cleanup = noop;\n if (gitSpec) {\n try {\n const resolved = resolveGitSource(gitSpec);\n source = resolved.dir;\n cleanup = resolved.cleanup;\n } catch (err) {\n console.error(`Failed to fetch ${gitSpec.url}: ${err instanceof Error ? err.message : err}`);\n return 1;\n }\n } else {\n source = resolve(args.target);\n }\n\n try {\n return await installResolved(args, source, destDir);\n } finally {\n cleanup();\n }\n}\n\nasync function installResolved(args: ExtArgs, source: string, destDir: string): Promise<number> {\n const result = await validateExtension(source);\n printValidation(result);\n if (!result.ok) {\n console.error(\"Refusing to install: fix the errors above.\");\n return 1;\n }\n\n // Install into a named subdirectory so the slug never degenerates to the\n // scope name. A bare file installs as <name>.<ext>; a directory as <name>/.\n const destName = basename(source);\n const dest = join(destDir, destName);\n mkdirSync(destDir, { recursive: true });\n // Reinstalling over an existing install is how updates work: replace it.\n const replaced = existsSync(dest);\n if (replaced) rmSync(dest, { recursive: true, force: true });\n cpSync(source, dest, { recursive: true });\n\n const scopeLabel =\n args.scope === \"global\" ? \"all conversations\" : `conversation ${args.conversationId}`;\n const dataDir =\n args.scope === \"global\"\n ? join(args.stateDir, \"global\", \"extension-data\", result.slug)\n : join(args.stateDir, \"conversations\", args.conversationId!, \"extension-data\", result.slug);\n const verb = replaced ? \"Reinstalled\" : \"Installed\";\n console.log(`\\n${verb} ${result.name} (slug: ${result.slug}) for ${scopeLabel}.`);\n console.log(` code: ${dest}`);\n console.log(` data: ${dataDir} (created on first use, preserved on reinstall)`);\n console.log(\"Run /pi-new in the conversation to activate.\");\n return 0;\n}\n\nfunction listAction(args: ExtArgs): number {\n // List the requested scope, or both when no conversation is given.\n const dirs = args.conversationId\n ? defaultExtensionDirs(args.conversationId, args.stateDir)\n : [join(args.stateDir, \"global\", \"extensions\")];\n const installed = listInstalledExtensions(dirs);\n if (installed.length === 0) {\n console.log(\"No extensions installed.\");\n return 0;\n }\n for (const info of installed) {\n const scope = basename(resolve(info.dir, \"..\")) === \"global\" ? \"global\" : \"conversation\";\n const version = info.version ? `@${info.version}` : \"\";\n console.log(`${info.name}${version} [${scope}] slug=${info.slug}`);\n if (info.description) console.log(` ${info.description}`);\n if (info.skillNames.length > 0) console.log(` skills: ${info.skillNames.join(\", \")}`);\n }\n return 0;\n}\n\nfunction removeAction(args: ExtArgs): number {\n if (!args.target) {\n console.error(\"ext remove: missing <slug>\");\n return 1;\n }\n let destDir: string;\n try {\n destDir = scopeExtensionsDir(args);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n return 1;\n }\n // Match by installed slug so the caller doesn't need the exact dir name.\n const match = listInstalledExtensions([destDir]).find((info) => info.slug === args.target);\n if (!match) {\n console.error(`No extension with slug '${args.target}' in ${destDir}`);\n return 1;\n }\n // match.path is the entrypoint. Dir-form: its parent is the extension dir to\n // remove. Bare-file: the parent is the scan dir, so remove the file itself.\n const parent = resolve(match.path, \"..\");\n const removeTarget = parent === resolve(destDir) ? match.path : parent;\n rmSync(removeTarget, { recursive: true, force: true });\n console.log(`Removed ${match.name} (slug: ${match.slug}). Data left in place.`);\n console.log(\"Run /pi-new in the conversation to apply.\");\n return 0;\n}\n\nfunction printValidation(result: {\n ok: boolean;\n name: string;\n slug: string;\n version?: string;\n entrypoint?: string;\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}): void {\n console.log(`${result.name}${result.version ? `@${result.version}` : \"\"} (slug: ${result.slug})`);\n if (result.entrypoint) console.log(` entrypoint: ${result.entrypoint}`);\n if (result.skillNames.length > 0) console.log(` skills: ${result.skillNames.join(\", \")}`);\n for (const warning of result.warnings) console.log(` warning: ${warning}`);\n for (const error of result.errors) console.error(` error: ${error}`);\n console.log(result.ok ? \" ✓ valid\" : \" ✗ invalid\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ext.js","sourceRoot":"","sources":["../../src/cli/ext.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mikan ext` — manage extensions from the CLI.\n *\n * mikan ext install <source> [--global | --conversation <id>] [--state-dir <dir>]\n * mikan ext validate <path>\n * mikan ext list [--conversation <id>] [--state-dir <dir>]\n * mikan ext remove <slug> (--global | --conversation <id>) [--state-dir <dir>]\n *\n * `<source>` is a local path or a git URL (https://…, git@…, or github:owner/repo)\n * with an optional `#subpath` for extensions inside a repo. Reinstalling over an\n * existing extension updates it (data is preserved). Extensions install into the\n * host-only state dir (never the workspace); see src/harness/extensions/LAYOUT.md.\n */\nimport { cpSync, existsSync, mkdirSync, rmSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport {\n defaultExtensionDirs,\n listInstalledExtensions,\n validateExtension,\n} from \"../harness/index.js\";\nimport { resolveStateDir, takeValueFlag } from \"./arg-grammar.js\";\nimport { parseGitSource, resolveGitSource } from \"./ext-git.js\";\n\ninterface ExtArgs {\n action?: string;\n target?: string;\n stateDir: string;\n scope: \"global\" | \"conversation\" | undefined;\n conversationId?: string;\n}\n\nfunction parseExtArgs(argv: string[]): ExtArgs {\n // Shares the daemon's state-dir precedence: --state-dir > env > ~/.mikan.\n const stateDir = resolveStateDir(argv);\n let scope: ExtArgs[\"scope\"];\n let conversationId: string | undefined;\n const positional: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n let taken;\n if (arg === \"--global\") scope = \"global\";\n else if ((taken = takeValueFlag(argv, i, \"--conversation\"))) {\n scope = \"conversation\";\n conversationId = taken.value || undefined;\n i = taken.lastIndex;\n } else if ((taken = takeValueFlag(argv, i, \"--state-dir\"))) {\n i = taken.lastIndex; // value already folded in by resolveStateDir\n } else positional.push(arg);\n }\n\n return { action: positional[0], target: positional[1], stateDir, scope, conversationId };\n}\n\n/** Directory that extension CODE for the chosen scope lives in. */\nfunction scopeExtensionsDir(args: ExtArgs): string {\n if (args.scope === \"global\") return join(args.stateDir, \"global\", \"extensions\");\n if (args.scope === \"conversation\" && args.conversationId) {\n // defaultExtensionDirs returns [global, conversation]; take the conversation one.\n return defaultExtensionDirs(args.conversationId, args.stateDir)[1];\n }\n throw new Error(\"Specify a scope: --global or --conversation <id>\");\n}\n\nconst USAGE = `Usage:\n mikan ext install <source> (--global | --conversation <id>) [--state-dir <dir>]\n <source>: a local path, or a git URL / github:owner/repo with optional #subpath\n e.g. github:geminixiang/mikan#examples/extensions/agent-pm\n Reinstalling over an existing extension updates it (data preserved).\n mikan ext validate <path>\n mikan ext list [--conversation <id>] [--state-dir <dir>]\n mikan ext remove <slug> (--global | --conversation <id>) [--state-dir <dir>]`;\n\nfunction noop(): void {}\n\nexport async function runExtCommand(argv: string[]): Promise<number> {\n const args = parseExtArgs(argv);\n\n switch (args.action) {\n case \"validate\":\n return validateAction(args);\n case \"install\":\n return installAction(args);\n case \"list\":\n return listAction(args);\n case \"remove\":\n return removeAction(args);\n default:\n console.error(USAGE);\n return 1;\n }\n}\n\nasync function validateAction(args: ExtArgs): Promise<number> {\n if (!args.target) {\n console.error(\"ext validate: missing <path>\");\n return 1;\n }\n const result = await validateExtension(resolve(args.target));\n printValidation(result);\n return result.ok ? 0 : 1;\n}\n\nasync function installAction(args: ExtArgs): Promise<number> {\n if (!args.target) {\n console.error(\"ext install: missing <path>\");\n return 1;\n }\n let destDir: string;\n try {\n destDir = scopeExtensionsDir(args);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n return 1;\n }\n\n // Resolve the source: a git URL (optionally with #subpath) is cloned to a\n // temp dir; a local path is used directly.\n const gitSpec = parseGitSource(args.target);\n let source: string;\n let cleanup = noop;\n if (gitSpec) {\n try {\n const resolved = resolveGitSource(gitSpec);\n source = resolved.dir;\n cleanup = resolved.cleanup;\n } catch (err) {\n console.error(`Failed to fetch ${gitSpec.url}: ${err instanceof Error ? err.message : err}`);\n return 1;\n }\n } else {\n source = resolve(args.target);\n }\n\n try {\n return await installResolved(args, source, destDir);\n } finally {\n cleanup();\n }\n}\n\nasync function installResolved(args: ExtArgs, source: string, destDir: string): Promise<number> {\n const result = await validateExtension(source);\n printValidation(result);\n if (!result.ok) {\n console.error(\"Refusing to install: fix the errors above.\");\n return 1;\n }\n\n // Install into a named subdirectory so the slug never degenerates to the\n // scope name. A bare file installs as <name>.<ext>; a directory as <name>/.\n const destName = basename(source);\n const dest = join(destDir, destName);\n mkdirSync(destDir, { recursive: true });\n // Reinstalling over an existing install is how updates work: replace it.\n const replaced = existsSync(dest);\n if (replaced) rmSync(dest, { recursive: true, force: true });\n cpSync(source, dest, { recursive: true });\n\n const scopeLabel =\n args.scope === \"global\" ? \"all conversations\" : `conversation ${args.conversationId}`;\n const dataDir =\n args.scope === \"global\"\n ? join(args.stateDir, \"global\", \"extension-data\", result.slug)\n : join(args.stateDir, \"conversations\", args.conversationId!, \"extension-data\", result.slug);\n const verb = replaced ? \"Reinstalled\" : \"Installed\";\n console.log(`\\n${verb} ${result.name} (slug: ${result.slug}) for ${scopeLabel}.`);\n console.log(` code: ${dest}`);\n console.log(` data: ${dataDir} (created on first use, preserved on reinstall)`);\n console.log(\"Run /pi-new in the conversation to activate.\");\n return 0;\n}\n\nfunction listAction(args: ExtArgs): number {\n // List the requested scope, or both when no conversation is given.\n const dirs = args.conversationId\n ? defaultExtensionDirs(args.conversationId, args.stateDir)\n : [join(args.stateDir, \"global\", \"extensions\")];\n const installed = listInstalledExtensions(dirs);\n if (installed.length === 0) {\n console.log(\"No extensions installed.\");\n return 0;\n }\n for (const info of installed) {\n const scope = basename(resolve(info.dir, \"..\")) === \"global\" ? \"global\" : \"conversation\";\n const version = info.version ? `@${info.version}` : \"\";\n console.log(`${info.name}${version} [${scope}] slug=${info.slug}`);\n if (info.description) console.log(` ${info.description}`);\n if (info.skillNames.length > 0) console.log(` skills: ${info.skillNames.join(\", \")}`);\n }\n return 0;\n}\n\nfunction removeAction(args: ExtArgs): number {\n if (!args.target) {\n console.error(\"ext remove: missing <slug>\");\n return 1;\n }\n let destDir: string;\n try {\n destDir = scopeExtensionsDir(args);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n return 1;\n }\n // Match by installed slug so the caller doesn't need the exact dir name.\n const match = listInstalledExtensions([destDir]).find((info) => info.slug === args.target);\n if (!match) {\n console.error(`No extension with slug '${args.target}' in ${destDir}`);\n return 1;\n }\n // match.path is the entrypoint. Dir-form: its parent is the extension dir to\n // remove. Bare-file: the parent is the scan dir, so remove the file itself.\n const parent = resolve(match.path, \"..\");\n const removeTarget = parent === resolve(destDir) ? match.path : parent;\n rmSync(removeTarget, { recursive: true, force: true });\n console.log(`Removed ${match.name} (slug: ${match.slug}). Data left in place.`);\n console.log(\"Run /pi-new in the conversation to apply.\");\n return 0;\n}\n\nfunction printValidation(result: {\n ok: boolean;\n name: string;\n slug: string;\n version?: string;\n entrypoint?: string;\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}): void {\n console.log(`${result.name}${result.version ? `@${result.version}` : \"\"} (slug: ${result.slug})`);\n if (result.entrypoint) console.log(` entrypoint: ${result.entrypoint}`);\n if (result.skillNames.length > 0) console.log(` skills: ${result.skillNames.join(\", \")}`);\n for (const warning of result.warnings) console.log(` warning: ${warning}`);\n for (const error of result.errors) console.error(` error: ${error}`);\n console.log(result.ok ? \" ✓ valid\" : \" ✗ invalid\");\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { defaultExtensionDirs, listInstalledExtensions } from "../harness/index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { effectiveStateDir } from "../cli/arg-grammar.js";
|
|
5
5
|
import { slashForms } from "./manifest.js";
|
|
6
6
|
import { matchCommand } from "./parse.js";
|
|
7
7
|
import { replyDiagnosticWithContext } from "./utils.js";
|
|
@@ -20,7 +20,7 @@ export class ExtensionsCommandHandler {
|
|
|
20
20
|
const matched = matchCommand(context.commandText, EXTENSIONS_COMMANDS, { stripMention: true });
|
|
21
21
|
if (!matched)
|
|
22
22
|
return false;
|
|
23
|
-
const dirs = defaultExtensionDirs(context.conversationId,
|
|
23
|
+
const dirs = defaultExtensionDirs(context.conversationId, effectiveStateDir());
|
|
24
24
|
const installed = listInstalledExtensions(dirs);
|
|
25
25
|
// A root-level index file means an extension's contents were copied into
|
|
26
26
|
// the scope directory itself; the loader skips it (the slug would
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/commands/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/commands/extensions.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { defaultExtensionDirs, listInstalledExtensions } from \"../harness/index.js\";\nimport { effectiveStateDir } from \"../cli/arg-grammar.js\";\nimport { slashForms } from \"./manifest.js\";\nimport { matchCommand } from \"./parse.js\";\nimport type { CommandContext, CommandHandler } from \"./types.js\";\nimport { replyDiagnosticWithContext } from \"./utils.js\";\n\nconst EXTENSIONS_COMMANDS = slashForms(\"extensions\");\n\n/**\n * `/pi-extensions` — inventory of extensions installed for this conversation.\n *\n * Discovery-only (nothing is imported or activated): it reports what is on\n * disk under the host-only state dir, for both the `global` scope and this\n * conversation's scope. Doubles as the user-facing answer to \"why can the\n * bot suddenly do X\" and the operator-facing answer to \"what is installed\n * where\".\n */\nexport class ExtensionsCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n const matched = matchCommand(context.commandText, EXTENSIONS_COMMANDS, { stripMention: true });\n if (!matched) return false;\n\n const dirs = defaultExtensionDirs(context.conversationId, effectiveStateDir());\n const installed = listInstalledExtensions(dirs);\n\n // A root-level index file means an extension's contents were copied into\n // the scope directory itself; the loader skips it (the slug would\n // degenerate to the scope name). Surface that here, not just in logs.\n const misinstalled = dirs.filter((dir) =>\n [\"index.mjs\", \"index.js\"].some((file) => existsSync(join(dir, file))),\n );\n const misinstallLines = misinstalled.map(\n (dir) =>\n `⚠️ \\`${dir}/index.mjs\\` 位於範圍根目錄,已被忽略 — 請移入具名子目錄(如 \\`${dir}/my-ext/\\`)。`,\n );\n\n if (installed.length === 0 && misinstallLines.length === 0) {\n await replyDiagnosticWithContext(\n context.responder,\n [\n \"_Extensions_\",\n \"沒有安裝任何 extension。\",\n `安裝位置:\\`${dirs[0]}\\`(所有會話)或 \\`${dirs[1]}\\`(僅此會話)。`,\n ].join(\"\\n\"),\n { style: \"muted\" },\n );\n return true;\n }\n\n const lines = [\"_Extensions_\", ...misinstallLines];\n for (const info of installed) {\n // info.dir ends in `<scope>/extensions`; the scope is its parent segment\n // (`global` or a conversation id).\n const scope = basename(dirname(info.dir)) === \"global\" ? \"global\" : \"this conversation\";\n const version = info.version ? `@${info.version}` : \"\";\n const slug = info.slug !== info.name ? ` (slug: ${info.slug})` : \"\";\n lines.push(`• *${info.name}*${version} — ${scope}${slug}`);\n if (info.description) lines.push(` ${info.description}`);\n if (info.skillNames.length > 0) lines.push(` skills: ${info.skillNames.join(\", \")}`);\n }\n lines.push(\"_(安裝/移除後,對話輸入 `/pi-new` 生效)_\");\n\n await replyDiagnosticWithContext(context.responder, lines.join(\"\\n\"), { style: \"muted\" });\n return true;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAKrF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA0BzE;
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAKrF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA0BzE;AAoCD,qBAAa,mBAAoB,YAAW,cAAc;IAClD,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAoGzD;CACF"}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as log from "../log.js";
|
|
2
|
-
import {
|
|
2
|
+
import { actorKey } from "../sandbox/identity.js";
|
|
3
3
|
import { sharedVaultKey } from "../vault/index.js";
|
|
4
4
|
import { slashForms } from "./manifest.js";
|
|
5
5
|
import { matchCommand } from "./parse.js";
|
|
@@ -34,7 +34,10 @@ export function parseLoginCommand(text) {
|
|
|
34
34
|
}
|
|
35
35
|
function ensureLoginVault(context) {
|
|
36
36
|
const { services, platformUserId, conversationId, vaultConversationId } = context;
|
|
37
|
-
return
|
|
37
|
+
return actorKey(services.sandbox, {
|
|
38
|
+
userId: platformUserId,
|
|
39
|
+
conversationId: vaultConversationId ?? conversationId,
|
|
40
|
+
});
|
|
38
41
|
}
|
|
39
42
|
async function replyVault(context, lines) {
|
|
40
43
|
await replyDiagnosticWithContext(context.responder, formatCommandSummary("Vault", lines), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import * as log from \"../log.js\";\nimport { resolveActorVaultKey } from \"../vault/routing.js\";\nimport { sharedVaultKey } from \"../vault/index.js\";\nimport { slashForms } from \"./manifest.js\";\nimport { matchCommand } from \"./parse.js\";\nimport type { CommandContext, CommandHandler, ParsedLoginCommand } from \"./types.js\";\nimport { formatCommandSummary, replyDiagnosticWithContext } from \"./utils.js\";\n\nconst LOGIN_COMMANDS = slashForms(\"login\");\n\nexport function parseLoginCommand(text: string): ParsedLoginCommand | null {\n const matched = matchCommand(text, LOGIN_COMMANDS);\n if (!matched) return null;\n\n const [subcommand, operation, name, ...extra] = matched.args;\n if (!subcommand) return { action: \"setup\" };\n\n if (subcommand.toLowerCase() === \"shared\") {\n const op = operation?.toLowerCase();\n if (op === \"list\" && !name && extra.length === 0) return { action: \"shared_list\" };\n if ((op === \"create\" || op === \"update\" || op === \"delete\") && name && extra.length === 0) {\n return {\n action: `shared_${op}` as \"shared_create\" | \"shared_update\" | \"shared_delete\",\n name,\n };\n }\n return null;\n }\n\n if (subcommand.toLowerCase() === \"copy\" && operation && !name && extra.length === 0) {\n return { action: \"copy_shared\", name: operation };\n }\n\n // Backward-compatible provider arguments open the generic login page.\n if (!operation && extra.length === 0) return { action: \"setup\" };\n return null;\n}\n\nfunction ensureLoginVault(context: CommandContext): string {\n const { services, platformUserId, conversationId, vaultConversationId } = context;\n return resolveActorVaultKey(\n services.sandbox,\n platformUserId,\n vaultConversationId ?? conversationId,\n );\n}\n\nasync function replyVault(context: CommandContext, lines: string[]): Promise<void> {\n await replyDiagnosticWithContext(context.responder, formatCommandSummary(\"Vault\", lines), {\n style: \"muted\",\n });\n}\n\nasync function refreshCopiedVaultRuntime(\n context: CommandContext,\n vaultId: string,\n): Promise<string | undefined> {\n if (context.services.sandbox.type !== \"image\") return undefined;\n\n const targetConversationId = context.vaultConversationId ?? context.conversationId;\n const cleared = context.services.runtime?.refreshConversationEnvironment(targetConversationId);\n if (cleared === false) {\n return \"A session is currently running, so the sandbox was not restarted. The copied credentials will be applied after the run finishes and the sandbox is recreated.\";\n }\n\n if (!context.services.provisioner) {\n return \"The cached session was refreshed. The sandbox will pick up copied credentials on the next provision.\";\n }\n\n await context.services.provisioner.remove(vaultId);\n return \"The sandbox container was removed and will be recreated with the copied env and file mounts on the next message.\";\n}\n\nexport class LoginCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n const parsed = parseLoginCommand(context.commandText);\n if (!parsed) return false;\n\n if (!context.privateConversation) {\n await replyVault(context, [\n \"為了保護你的憑證,`/login` 只能在與機器人的私訊中使用。\",\n \"請先私訊機器人,再重新執行 `/login`。\",\n ]);\n return true;\n }\n\n if (parsed.action === \"shared_list\") {\n const profiles = context.services.vaultManager.listSharedVaults();\n await replyVault(\n context,\n profiles.length > 0\n ? [\"Shared login profiles:\", ...profiles.map((name) => `- ${name}`)]\n : [\"No shared login profiles found.\"],\n );\n return true;\n }\n\n if (parsed.action === \"shared_delete\") {\n try {\n const deleted = context.services.vaultManager.deleteSharedVault(parsed.name);\n await replyVault(context, [\n deleted\n ? `Deleted shared login profile \\`${parsed.name}\\`.`\n : `Shared login profile \\`${parsed.name}\\` does not exist.`,\n ]);\n } catch (error) {\n await replyVault(context, [error instanceof Error ? error.message : String(error)]);\n }\n return true;\n }\n\n if (parsed.action === \"copy_shared\") {\n try {\n const vaultId = ensureLoginVault(context);\n const result = context.services.vaultManager.copySharedVaultTo(parsed.name, vaultId);\n const refreshNote = await refreshCopiedVaultRuntime(context, vaultId);\n await replyVault(context, [\n `Copied shared login profile \\`${parsed.name}\\` into this conversation.`,\n \"Shared values overwrite matching conversation values; conversation-only values are kept.\",\n `Copied: ${result.envKeysCopied} env key(s), ${result.filesCopied} file(s).`,\n ...(refreshNote ? [refreshNote] : []),\n ]);\n } catch (error) {\n await replyVault(context, [error instanceof Error ? error.message : String(error)]);\n }\n return true;\n }\n\n if (!context.services.portalBaseUrl) {\n await replyVault(context, [\n \"Login is not configured.\",\n \"Set `MIKAN_LINK_URL` or `MIKAN_LINK_PORT` on the server.\",\n ]);\n return true;\n }\n\n const isSharedSetup = parsed.action === \"shared_create\" || parsed.action === \"shared_update\";\n let vaultId: string;\n try {\n vaultId = isSharedSetup ? (sharedVaultKey(parsed.name) ?? \"\") : ensureLoginVault(context);\n if (!vaultId) {\n throw new Error(\n isSharedSetup ? `Invalid shared login profile name: ${parsed.name}` : \"Invalid vault id\",\n );\n }\n } catch (error) {\n log.logWarning(\n `[${context.conversationId}] Failed to prepare login vault for ${context.platform}/${context.platformUserId}`,\n error instanceof Error ? error.message : String(error),\n );\n await replyVault(context, [\n \"Login setup failed on the server.\",\n \"請稍後重試,或聯絡管理員檢查 vault 儲存權限。\",\n ]);\n return true;\n }\n\n const token = context.services.linkTokenStore.create(\n context.platform,\n context.platformUserId,\n context.conversationId,\n vaultId,\n \"\",\n );\n const vaultLabel = isSharedSetup\n ? `shared login profile (${parsed.name})`\n : context.services.sandbox.type === \"container\"\n ? `container vault (${vaultId})`\n : \"your vault\";\n await replyVault(context, [\n `${context.services.portalBaseUrl}/link?token=${token.token}`,\n `Target: ${vaultLabel} · Expires: 15 minutes`,\n ]);\n return true;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAE5C,IAAI,UAAU,CAAC,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,SAAS,EAAE,WAAW,EAAE,CAAC;QACpC,IAAI,EAAE,KAAK,MAAM,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACnF,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1F,OAAO;gBACL,MAAM,EAAE,UAAU,EAAE,EAAyD;gBAC7E,IAAI;aACL,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAU,CAAC,WAAW,EAAE,KAAK,MAAM,IAAI,SAAS,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;IAED,sEAAsE;IACtE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACjE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAuB;IAC/C,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAClF,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE;QAChC,MAAM,EAAE,cAAc;QACtB,cAAc,EAAE,mBAAmB,IAAI,cAAc;KACtD,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAuB,EAAE,KAAe;IAChE,MAAM,0BAA0B,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;QACxF,KAAK,EAAE,OAAO;KACf,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,OAAuB,EACvB,OAAe;IAEf,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAEhE,MAAM,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,IAAI,OAAO,CAAC,cAAc,CAAC;IACnF,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,8BAA8B,CAAC,oBAAoB,CAAC,CAAC;IAC/F,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,+JAA+J,CAAC;IACzK,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAClC,OAAO,sGAAsG,CAAC;IAChH,CAAC;IAED,MAAM,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,kHAAkH,CAAC;AAC5H,CAAC;AAED,MAAM,OAAO,mBAAmB;IAC9B,KAAK,CAAC,SAAS,CAAC,OAAuB;QACrC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAE1B,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;YACjC,MAAM,UAAU,CAAC,OAAO,EAAE;gBACxB,kCAAkC;gBAClC,yBAAyB;aAC1B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;YAClE,MAAM,UAAU,CACd,OAAO,EACP,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACjB,CAAC,CAAC,CAAC,wBAAwB,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACpE,CAAC,CAAC,CAAC,iCAAiC,CAAC,CACxC,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC7E,MAAM,UAAU,CAAC,OAAO,EAAE;oBACxB,OAAO;wBACL,CAAC,CAAC,kCAAkC,MAAM,CAAC,IAAI,KAAK;wBACpD,CAAC,CAAC,0BAA0B,MAAM,CAAC,IAAI,oBAAoB;iBAC9D,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtF,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACrF,MAAM,WAAW,GAAG,MAAM,yBAAyB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACtE,MAAM,UAAU,CAAC,OAAO,EAAE;oBACxB,iCAAiC,MAAM,CAAC,IAAI,4BAA4B;oBACxE,0FAA0F;oBAC1F,WAAW,MAAM,CAAC,aAAa,gBAAgB,MAAM,CAAC,WAAW,WAAW;oBAC5E,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtF,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,UAAU,CAAC,OAAO,EAAE;gBACxB,0BAA0B;gBAC1B,0DAA0D;aAC3D,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,KAAK,eAAe,IAAI,MAAM,CAAC,MAAM,KAAK,eAAe,CAAC;QAC7F,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC1F,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CACb,aAAa,CAAC,CAAC,CAAC,sCAAsC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,kBAAkB,CACzF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,UAAU,CACZ,IAAI,OAAO,CAAC,cAAc,uCAAuC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,EAAE,EAC7G,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;YACF,MAAM,UAAU,CAAC,OAAO,EAAE;gBACxB,mCAAmC;gBACnC,4BAA4B;aAC7B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAClD,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,cAAc,EACtB,OAAO,CAAC,cAAc,EACtB,OAAO,EACP,EAAE,CACH,CAAC;QACF,MAAM,UAAU,GAAG,aAAa;YAC9B,CAAC,CAAC,yBAAyB,MAAM,CAAC,IAAI,GAAG;YACzC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;gBAC7C,CAAC,CAAC,oBAAoB,OAAO,GAAG;gBAChC,CAAC,CAAC,YAAY,CAAC;QACnB,MAAM,UAAU,CAAC,OAAO,EAAE;YACxB,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,eAAe,KAAK,CAAC,KAAK,EAAE;YAC7D,WAAW,UAAU,wBAAwB;SAC9C,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import * as log from \"../log.js\";\nimport { actorKey } from \"../sandbox/identity.js\";\nimport { sharedVaultKey } from \"../vault/index.js\";\nimport { slashForms } from \"./manifest.js\";\nimport { matchCommand } from \"./parse.js\";\nimport type { CommandContext, CommandHandler, ParsedLoginCommand } from \"./types.js\";\nimport { formatCommandSummary, replyDiagnosticWithContext } from \"./utils.js\";\n\nconst LOGIN_COMMANDS = slashForms(\"login\");\n\nexport function parseLoginCommand(text: string): ParsedLoginCommand | null {\n const matched = matchCommand(text, LOGIN_COMMANDS);\n if (!matched) return null;\n\n const [subcommand, operation, name, ...extra] = matched.args;\n if (!subcommand) return { action: \"setup\" };\n\n if (subcommand.toLowerCase() === \"shared\") {\n const op = operation?.toLowerCase();\n if (op === \"list\" && !name && extra.length === 0) return { action: \"shared_list\" };\n if ((op === \"create\" || op === \"update\" || op === \"delete\") && name && extra.length === 0) {\n return {\n action: `shared_${op}` as \"shared_create\" | \"shared_update\" | \"shared_delete\",\n name,\n };\n }\n return null;\n }\n\n if (subcommand.toLowerCase() === \"copy\" && operation && !name && extra.length === 0) {\n return { action: \"copy_shared\", name: operation };\n }\n\n // Backward-compatible provider arguments open the generic login page.\n if (!operation && extra.length === 0) return { action: \"setup\" };\n return null;\n}\n\nfunction ensureLoginVault(context: CommandContext): string {\n const { services, platformUserId, conversationId, vaultConversationId } = context;\n return actorKey(services.sandbox, {\n userId: platformUserId,\n conversationId: vaultConversationId ?? conversationId,\n });\n}\n\nasync function replyVault(context: CommandContext, lines: string[]): Promise<void> {\n await replyDiagnosticWithContext(context.responder, formatCommandSummary(\"Vault\", lines), {\n style: \"muted\",\n });\n}\n\nasync function refreshCopiedVaultRuntime(\n context: CommandContext,\n vaultId: string,\n): Promise<string | undefined> {\n if (context.services.sandbox.type !== \"image\") return undefined;\n\n const targetConversationId = context.vaultConversationId ?? context.conversationId;\n const cleared = context.services.runtime?.refreshConversationEnvironment(targetConversationId);\n if (cleared === false) {\n return \"A session is currently running, so the sandbox was not restarted. The copied credentials will be applied after the run finishes and the sandbox is recreated.\";\n }\n\n if (!context.services.provisioner) {\n return \"The cached session was refreshed. The sandbox will pick up copied credentials on the next provision.\";\n }\n\n await context.services.provisioner.remove(vaultId);\n return \"The sandbox container was removed and will be recreated with the copied env and file mounts on the next message.\";\n}\n\nexport class LoginCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n const parsed = parseLoginCommand(context.commandText);\n if (!parsed) return false;\n\n if (!context.privateConversation) {\n await replyVault(context, [\n \"為了保護你的憑證,`/login` 只能在與機器人的私訊中使用。\",\n \"請先私訊機器人,再重新執行 `/login`。\",\n ]);\n return true;\n }\n\n if (parsed.action === \"shared_list\") {\n const profiles = context.services.vaultManager.listSharedVaults();\n await replyVault(\n context,\n profiles.length > 0\n ? [\"Shared login profiles:\", ...profiles.map((name) => `- ${name}`)]\n : [\"No shared login profiles found.\"],\n );\n return true;\n }\n\n if (parsed.action === \"shared_delete\") {\n try {\n const deleted = context.services.vaultManager.deleteSharedVault(parsed.name);\n await replyVault(context, [\n deleted\n ? `Deleted shared login profile \\`${parsed.name}\\`.`\n : `Shared login profile \\`${parsed.name}\\` does not exist.`,\n ]);\n } catch (error) {\n await replyVault(context, [error instanceof Error ? error.message : String(error)]);\n }\n return true;\n }\n\n if (parsed.action === \"copy_shared\") {\n try {\n const vaultId = ensureLoginVault(context);\n const result = context.services.vaultManager.copySharedVaultTo(parsed.name, vaultId);\n const refreshNote = await refreshCopiedVaultRuntime(context, vaultId);\n await replyVault(context, [\n `Copied shared login profile \\`${parsed.name}\\` into this conversation.`,\n \"Shared values overwrite matching conversation values; conversation-only values are kept.\",\n `Copied: ${result.envKeysCopied} env key(s), ${result.filesCopied} file(s).`,\n ...(refreshNote ? [refreshNote] : []),\n ]);\n } catch (error) {\n await replyVault(context, [error instanceof Error ? error.message : String(error)]);\n }\n return true;\n }\n\n if (!context.services.portalBaseUrl) {\n await replyVault(context, [\n \"Login is not configured.\",\n \"Set `MIKAN_LINK_URL` or `MIKAN_LINK_PORT` on the server.\",\n ]);\n return true;\n }\n\n const isSharedSetup = parsed.action === \"shared_create\" || parsed.action === \"shared_update\";\n let vaultId: string;\n try {\n vaultId = isSharedSetup ? (sharedVaultKey(parsed.name) ?? \"\") : ensureLoginVault(context);\n if (!vaultId) {\n throw new Error(\n isSharedSetup ? `Invalid shared login profile name: ${parsed.name}` : \"Invalid vault id\",\n );\n }\n } catch (error) {\n log.logWarning(\n `[${context.conversationId}] Failed to prepare login vault for ${context.platform}/${context.platformUserId}`,\n error instanceof Error ? error.message : String(error),\n );\n await replyVault(context, [\n \"Login setup failed on the server.\",\n \"請稍後重試,或聯絡管理員檢查 vault 儲存權限。\",\n ]);\n return true;\n }\n\n const token = context.services.linkTokenStore.create(\n context.platform,\n context.platformUserId,\n context.conversationId,\n vaultId,\n \"\",\n );\n const vaultLabel = isSharedSetup\n ? `shared login profile (${parsed.name})`\n : context.services.sandbox.type === \"container\"\n ? `container vault (${vaultId})`\n : \"your vault\";\n await replyVault(context, [\n `${context.services.portalBaseUrl}/link?token=${token.token}`,\n `Target: ${vaultLabel} · Expires: 15 minutes`,\n ]);\n return true;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/commands/model.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/commands/model.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAarF,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIrD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAsBzE;AA0BD,qBAAa,mBAAoB,YAAW,cAAc;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAA1C,YAA6B,aAAa,EAAE,WAAW,EAAI;IACrD,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAyEzD;CACF"}
|
package/dist/commands/model.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { join } from "path";
|
|
2
|
-
import { resolveConversationSettings
|
|
2
|
+
import { resolveConversationSettings } from "../config.js";
|
|
3
|
+
import { applyConversationSettings } from "../settings-mutation.js";
|
|
3
4
|
import { slashForms } from "./manifest.js";
|
|
4
5
|
import { matchCommand } from "./parse.js";
|
|
5
6
|
import { formatCommandSummary, replyDiagnosticWithContext } from "./utils.js";
|
|
@@ -82,18 +83,17 @@ export class ModelCommandHandler {
|
|
|
82
83
|
]), { style: "muted" });
|
|
83
84
|
return true;
|
|
84
85
|
}
|
|
85
|
-
const
|
|
86
|
-
|
|
86
|
+
const result = applyConversationSettings(context.services.runtime, context.services.workingDir, context.conversationId, {
|
|
87
|
+
provider: parsed.provider,
|
|
88
|
+
model: parsed.model,
|
|
89
|
+
...(parsed.thinkingLevel ? { thinkingLevel: parsed.thinkingLevel } : {}),
|
|
90
|
+
});
|
|
91
|
+
if (!result.ok) {
|
|
87
92
|
await replyDiagnosticWithContext(context.responder, formatCommandSummary("Model", [
|
|
88
93
|
"目前這個 conversation 有執行中的工作,請等它完成或先 `/stop` 後再切換模型。",
|
|
89
94
|
]), { style: "muted" });
|
|
90
95
|
return true;
|
|
91
96
|
}
|
|
92
|
-
updateConversationSettings(conversationDir, {
|
|
93
|
-
provider: parsed.provider,
|
|
94
|
-
model: parsed.model,
|
|
95
|
-
...(parsed.thinkingLevel ? { thinkingLevel: parsed.thinkingLevel } : {}),
|
|
96
|
-
});
|
|
97
97
|
await replyDiagnosticWithContext(context.responder, formatCommandSummary("Model", [
|
|
98
98
|
`Switched: \`${formatModelSpec(parsed.provider, parsed.model, parsed.thinkingLevel)}\``,
|
|
99
99
|
"下一則訊息會使用新模型。",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/commands/model.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAE,
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/commands/model.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { ThinkingLevel as PiAiThinkingLevel } from \"@earendil-works/pi-ai\";\nimport type { MikanModels } from \"../harness/index.js\";\nimport { join } from \"path\";\nimport { resolveConversationSettings } from \"../config.js\";\nimport { applyConversationSettings } from \"../settings-mutation.js\";\nimport { slashForms } from \"./manifest.js\";\nimport { matchCommand } from \"./parse.js\";\nimport type { CommandContext, CommandHandler, ParsedModelCommand } from \"./types.js\";\nimport { formatCommandSummary, replyDiagnosticWithContext } from \"./utils.js\";\n\nconst PI_AI_THINKING_LEVELS = [\n \"minimal\",\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n] satisfies PiAiThinkingLevel[];\nconst THINKING_LEVELS = new Set<ThinkingLevel>([\"off\", ...PI_AI_THINKING_LEVELS]);\n\nexport type { ParsedModelCommand } from \"./types.js\";\n\nconst MODEL_COMMANDS = slashForms(\"model\");\n\nexport function parseModelCommand(text: string): ParsedModelCommand | null {\n const matched = matchCommand(text, MODEL_COMMANDS);\n if (!matched) return null;\n\n if (matched.args.length === 0) {\n return {};\n }\n\n const spec = matched.args[0];\n const slash = spec.indexOf(\"/\");\n if (slash <= 0 || slash === spec.length - 1) {\n return {};\n }\n\n const modelSpec = spec.slice(slash + 1);\n const parsedModel = parseModelThinkingLevel(modelSpec);\n\n return {\n provider: spec.slice(0, slash),\n model: parsedModel.model,\n thinkingLevel: parsedModel.thinkingLevel,\n };\n}\n\nfunction parseModelThinkingLevel(modelSpec: string): {\n model: string;\n thinkingLevel?: ThinkingLevel;\n} {\n const colon = modelSpec.lastIndexOf(\":\");\n if (colon <= 0 || colon === modelSpec.length - 1) {\n return { model: modelSpec };\n }\n\n const suffix = modelSpec.slice(colon + 1);\n if (!THINKING_LEVELS.has(suffix as ThinkingLevel)) {\n return { model: modelSpec };\n }\n\n return {\n model: modelSpec.slice(0, colon),\n thinkingLevel: suffix as ThinkingLevel,\n };\n}\n\nfunction formatModelSpec(provider: string, model: string, thinkingLevel?: ThinkingLevel): string {\n return `${provider}/${model}${thinkingLevel ? `:${thinkingLevel}` : \"\"}`;\n}\n\nexport class ModelCommandHandler implements CommandHandler {\n constructor(private readonly modelRegistry: MikanModels) {}\n async tryHandle(context: CommandContext): Promise<boolean> {\n const parsed = parseModelCommand(context.commandText);\n if (!parsed) return false;\n\n const conversationDir = join(context.services.workingDir, context.conversationId);\n if (!parsed.provider || !parsed.model) {\n const current = resolveConversationSettings(conversationDir);\n await replyDiagnosticWithContext(\n context.responder,\n formatCommandSummary(\"Model\", [\n `Current: \\`${formatModelSpec(current.provider, current.model, current.thinkingLevel)}\\``,\n \"\",\n \"Usage: `/pi-model provider/model[:thinking]`\",\n \"Example: `/pi-model anthropic/claude-sonnet-4-6:off`\",\n ]),\n { style: \"muted\" },\n );\n return true;\n }\n\n if (!this.modelRegistry.find(parsed.provider, parsed.model)) {\n await replyDiagnosticWithContext(\n context.responder,\n formatCommandSummary(\"Model\", [\n `找不到模型:\\`${formatModelSpec(parsed.provider, parsed.model, parsed.thinkingLevel)}\\``,\n \"請確認 provider/model 名稱,或先在 pi models.json 註冊自訂模型。\",\n ]),\n { style: \"muted\" },\n );\n return true;\n }\n\n if (!context.services.runtime) {\n await replyDiagnosticWithContext(\n context.responder,\n formatCommandSummary(\"Model\", [\n \"Model command is not configured correctly on the server. Please try again later.\",\n ]),\n { style: \"muted\" },\n );\n return true;\n }\n\n const result = applyConversationSettings(\n context.services.runtime,\n context.services.workingDir,\n context.conversationId,\n {\n provider: parsed.provider,\n model: parsed.model,\n ...(parsed.thinkingLevel ? { thinkingLevel: parsed.thinkingLevel } : {}),\n },\n );\n if (!result.ok) {\n await replyDiagnosticWithContext(\n context.responder,\n formatCommandSummary(\"Model\", [\n \"目前這個 conversation 有執行中的工作,請等它完成或先 `/stop` 後再切換模型。\",\n ]),\n { style: \"muted\" },\n );\n return true;\n }\n\n await replyDiagnosticWithContext(\n context.responder,\n formatCommandSummary(\"Model\", [\n `Switched: \\`${formatModelSpec(parsed.provider, parsed.model, parsed.thinkingLevel)}\\``,\n \"下一則訊息會使用新模型。\",\n ]),\n { style: \"muted\" },\n );\n return true;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/commands/sandbox.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/commands/sandbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvF,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIvD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAS7E;AAED,qBAAa,qBAAsB,YAAW,cAAc;IACpD,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAkGzD;CACF"}
|