@chances-ai/cli 1.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/boot/create-app.d.ts +3 -1
  2. package/dist/boot/create-app.d.ts.map +1 -1
  3. package/dist/boot/create-app.js +5 -6
  4. package/dist/boot/create-app.js.map +1 -1
  5. package/dist/boot/load-runtime.d.ts +7 -1
  6. package/dist/boot/load-runtime.d.ts.map +1 -1
  7. package/dist/boot/load-runtime.js +24 -4
  8. package/dist/boot/load-runtime.js.map +1 -1
  9. package/dist/commands/chat.d.ts +9 -1
  10. package/dist/commands/chat.d.ts.map +1 -1
  11. package/dist/commands/chat.js +95 -39
  12. package/dist/commands/chat.js.map +1 -1
  13. package/dist/commands/discover.d.ts +39 -0
  14. package/dist/commands/discover.d.ts.map +1 -0
  15. package/dist/commands/discover.js +280 -0
  16. package/dist/commands/discover.js.map +1 -0
  17. package/dist/commands/doctor.d.ts.map +1 -1
  18. package/dist/commands/doctor.js +5 -2
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/prompt.d.ts.map +1 -1
  21. package/dist/commands/prompt.js +30 -5
  22. package/dist/commands/prompt.js.map +1 -1
  23. package/dist/commands/stats.d.ts +42 -0
  24. package/dist/commands/stats.d.ts.map +1 -0
  25. package/dist/commands/stats.js +172 -0
  26. package/dist/commands/stats.js.map +1 -0
  27. package/dist/entrypoints/cli.d.ts.map +1 -1
  28. package/dist/entrypoints/cli.js +4 -0
  29. package/dist/entrypoints/cli.js.map +1 -1
  30. package/dist/slash/clear.d.ts +13 -0
  31. package/dist/slash/clear.d.ts.map +1 -0
  32. package/dist/slash/clear.js +28 -0
  33. package/dist/slash/clear.js.map +1 -0
  34. package/dist/slash/compact.d.ts +4 -0
  35. package/dist/slash/compact.d.ts.map +1 -0
  36. package/dist/slash/compact.js +68 -0
  37. package/dist/slash/compact.js.map +1 -0
  38. package/dist/slash/help.d.ts +13 -0
  39. package/dist/slash/help.d.ts.map +1 -0
  40. package/dist/slash/help.js +34 -0
  41. package/dist/slash/help.js.map +1 -0
  42. package/dist/slash/index.d.ts +22 -0
  43. package/dist/slash/index.d.ts.map +1 -0
  44. package/dist/slash/index.js +20 -0
  45. package/dist/slash/index.js.map +1 -0
  46. package/dist/slash/logout.d.ts +15 -0
  47. package/dist/slash/logout.d.ts.map +1 -0
  48. package/dist/slash/logout.js +44 -0
  49. package/dist/slash/logout.js.map +1 -0
  50. package/dist/slash/model.d.ts +14 -0
  51. package/dist/slash/model.d.ts.map +1 -0
  52. package/dist/slash/model.js +87 -0
  53. package/dist/slash/model.js.map +1 -0
  54. package/dist/slash/persist.d.ts +16 -0
  55. package/dist/slash/persist.d.ts.map +1 -0
  56. package/dist/slash/persist.js +46 -0
  57. package/dist/slash/persist.js.map +1 -0
  58. package/dist/slash/provider.d.ts +17 -0
  59. package/dist/slash/provider.d.ts.map +1 -0
  60. package/dist/slash/provider.js +98 -0
  61. package/dist/slash/provider.js.map +1 -0
  62. package/dist/slash/resume.d.ts +15 -0
  63. package/dist/slash/resume.d.ts.map +1 -0
  64. package/dist/slash/resume.js +76 -0
  65. package/dist/slash/resume.js.map +1 -0
  66. package/package.json +15 -13
@@ -3,6 +3,8 @@ import { chatCommand } from "../commands/chat.js";
3
3
  import { doctorCommand } from "../commands/doctor.js";
4
4
  import { sessionCommand } from "../commands/session.js";
5
5
  import { configCommand } from "../commands/config.js";
6
+ import { statsCommand } from "../commands/stats.js";
7
+ import { discoverCommand } from "../commands/discover.js";
6
8
  import { helpCommand, printHelp, printVersion, versionCommand } from "../commands/version.js";
7
9
  import { CommandRegistry } from "../commands/registry.js";
8
10
  function parseArgs(argv) {
@@ -54,6 +56,8 @@ export function buildCommandRegistry() {
54
56
  registry.register(doctorCommand);
55
57
  registry.register(configCommand);
56
58
  registry.register(sessionCommand);
59
+ registry.register(statsCommand);
60
+ registry.register(discoverCommand);
57
61
  registry.register(helpCommand);
58
62
  registry.register(versionCommand);
59
63
  return registry;
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/entrypoints/cli.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/entrypoints/cli.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type Plugin } from "@chances-ai/plugin-api";
2
+ import type { BuiltinSlashDeps } from "./index.js";
3
+ /**
4
+ * `/clear` — empties the current session's turn list and the rendered
5
+ * scrollback. The session keeps its id/title (so `/resume` can come back to
6
+ * it later if desired). The model selection is untouched.
7
+ *
8
+ * Implemented in-place via SessionManager.clearTurns + ChatViewModel.clearLines
9
+ * rather than a respawn — there's no architecture-level reason to tear down
10
+ * the engine and rebuild, and pi/oh-my-pi take the same path.
11
+ */
12
+ export declare function makeClearPlugin(deps: BuiltinSlashDeps): Plugin;
13
+ //# sourceMappingURL=clear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear.d.ts","sourceRoot":"","sources":["../../src/slash/clear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAqB,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAgB9D"}
@@ -0,0 +1,28 @@
1
+ import { definePlugin } from "@chances-ai/plugin-api";
2
+ /**
3
+ * `/clear` — empties the current session's turn list and the rendered
4
+ * scrollback. The session keeps its id/title (so `/resume` can come back to
5
+ * it later if desired). The model selection is untouched.
6
+ *
7
+ * Implemented in-place via SessionManager.clearTurns + ChatViewModel.clearLines
8
+ * rather than a respawn — there's no architecture-level reason to tear down
9
+ * the engine and rebuild, and pi/oh-my-pi take the same path.
10
+ */
11
+ export function makeClearPlugin(deps) {
12
+ const command = {
13
+ name: "clear",
14
+ description: "Clear the current conversation (keeps the session file).",
15
+ run: () => {
16
+ deps.session.clearTurns();
17
+ deps.vm.clearLines();
18
+ return "conversation cleared";
19
+ },
20
+ };
21
+ return definePlugin({
22
+ name: "builtin/clear",
23
+ onLoad(ctx) {
24
+ ctx.registerSlashCommand(command);
25
+ },
26
+ });
27
+ }
28
+ //# sourceMappingURL=clear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear.js","sourceRoot":"","sources":["../../src/slash/clear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,wBAAwB,CAAC;AAGtF;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsB;IACpD,MAAM,OAAO,GAAiB;QAC5B,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,0DAA0D;QACvE,GAAG,EAAE,GAAG,EAAE;YACR,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,sBAAsB,CAAC;QAChC,CAAC;KACF,CAAC;IACF,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,eAAe;QACrB,MAAM,CAAC,GAAG;YACR,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type Plugin } from "@chances-ai/plugin-api";
2
+ import type { BuiltinSlashDeps } from "./index.js";
3
+ export declare function makeCompactPlugin(deps: BuiltinSlashDeps): Plugin;
4
+ //# sourceMappingURL=compact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact.d.ts","sourceRoot":"","sources":["../../src/slash/compact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAqB,MAAM,wBAAwB,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAcnD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CA0DhE"}
@@ -0,0 +1,68 @@
1
+ import { definePlugin } from "@chances-ai/plugin-api";
2
+ import { AppError, ErrorCode } from "@chances-ai/runtime";
3
+ import { summarizeConversation } from "@chances-ai/ai";
4
+ /**
5
+ * `/compact` — summarizes the current conversation with the current model
6
+ * (the design call: "use current model, not a separate cheap one"). The
7
+ * summarized text replaces all but the last 5 turns.
8
+ *
9
+ * Failure modes — all surface as user-readable strings, never throws:
10
+ * - 0 turns to compact → no-op message
11
+ * - router refuses → "no model available"
12
+ * - summarizer returns empty / errors → conversation untouched
13
+ */
14
+ const KEEP_LAST_N = 5;
15
+ export function makeCompactPlugin(deps) {
16
+ const command = {
17
+ name: "compact",
18
+ description: "Summarize and shrink the current conversation.",
19
+ run: async () => {
20
+ const totalTurns = deps.session.snapshot().turns.length;
21
+ if (totalTurns === 0)
22
+ return "nothing to compact — the conversation is empty";
23
+ if (totalTurns <= KEEP_LAST_N) {
24
+ return `nothing to compact — conversation has ${totalTurns} turn(s), keeping last ${KEEP_LAST_N}`;
25
+ }
26
+ let route;
27
+ try {
28
+ const choice = deps.ctx.selection.get();
29
+ route = deps.ctx.router.pick({
30
+ preferredModel: choice.model,
31
+ preferredProvider: choice.provider,
32
+ needsTools: false,
33
+ });
34
+ }
35
+ catch (e) {
36
+ if (e instanceof AppError && e.code === ErrorCode.Provider) {
37
+ return `cannot compact: ${e.message}`;
38
+ }
39
+ throw e;
40
+ }
41
+ let summary;
42
+ try {
43
+ summary = await summarizeConversation(route.adapter, route.model.id, deps.session.messages(), new AbortController().signal);
44
+ }
45
+ catch (err) {
46
+ // try/catch (rather than a sentinel string) keeps the success path
47
+ // unambiguous — a real LLM summary that happens to start with the
48
+ // sentinel marker would have been mis-classified otherwise.
49
+ const msg = err instanceof Error ? err.message : String(err);
50
+ return `summarization failed — conversation untouched. ${msg}`;
51
+ }
52
+ if (!summary || summary.trim().length === 0) {
53
+ return "summarizer returned empty text — conversation untouched";
54
+ }
55
+ const beforeTurns = totalTurns;
56
+ deps.session.compactTurns(summary, KEEP_LAST_N);
57
+ const afterTurns = deps.session.snapshot().turns.length;
58
+ return `compacted ${beforeTurns} → ${afterTurns} turns using ${route.model.provider}/${route.model.id}`;
59
+ },
60
+ };
61
+ return definePlugin({
62
+ name: "builtin/compact",
63
+ onLoad(ctx) {
64
+ ctx.registerSlashCommand(command);
65
+ },
66
+ });
67
+ }
68
+ //# sourceMappingURL=compact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact.js","sourceRoot":"","sources":["../../src/slash/compact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGvD;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,MAAM,UAAU,iBAAiB,CAAC,IAAsB;IACtD,MAAM,OAAO,GAAiB;QAC5B,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,gDAAgD;QAC7D,GAAG,EAAE,KAAK,IAAI,EAAE;YACd,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;YACxD,IAAI,UAAU,KAAK,CAAC;gBAAE,OAAO,gDAAgD,CAAC;YAC9E,IAAI,UAAU,IAAI,WAAW,EAAE,CAAC;gBAC9B,OAAO,yCAAyC,UAAU,0BAA0B,WAAW,EAAE,CAAC;YACpG,CAAC;YAED,IAAI,KAAK,CAAC;YACV,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;gBACxC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;oBAC3B,cAAc,EAAE,MAAM,CAAC,KAAK;oBAC5B,iBAAiB,EAAE,MAAM,CAAC,QAAQ;oBAClC,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;oBAC3D,OAAO,mBAAmB,CAAC,CAAC,OAAO,EAAE,CAAC;gBACxC,CAAC;gBACD,MAAM,CAAC,CAAC;YACV,CAAC;YAED,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,qBAAqB,CACnC,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,KAAK,CAAC,EAAE,EACd,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EACvB,IAAI,eAAe,EAAE,CAAC,MAAM,CAC7B,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,mEAAmE;gBACnE,kEAAkE;gBAClE,4DAA4D;gBAC5D,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7D,OAAO,kDAAkD,GAAG,EAAE,CAAC;YACjE,CAAC;YAED,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,OAAO,yDAAyD,CAAC;YACnE,CAAC;YAED,MAAM,WAAW,GAAG,UAAU,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAChD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;YACxD,OAAO,aAAa,WAAW,MAAM,UAAU,gBAAgB,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAC1G,CAAC;KACF,CAAC;IACF,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,iBAAiB;QACvB,MAAM,CAAC,GAAG;YACR,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type Plugin, type PluginHost } from "@chances-ai/plugin-api";
2
+ /**
3
+ * Lists every registered slash command — built-ins and plugin-provided alike.
4
+ * Sorted alphabetically; the active command itself is included for symmetry.
5
+ * The output is a single multi-line string that the dispatcher renders as an
6
+ * info line.
7
+ *
8
+ * `host` is captured by closure so the listing reflects what's actually
9
+ * loaded — adding a new built-in or a plugin command at any time updates the
10
+ * `/help` output without changing this file.
11
+ */
12
+ export declare function makeHelpPlugin(host: PluginHost): Plugin;
13
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/slash/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,UAAU,EAAqB,MAAM,wBAAwB,CAAC;AAEvG;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAoBvD"}
@@ -0,0 +1,34 @@
1
+ import { definePlugin } from "@chances-ai/plugin-api";
2
+ /**
3
+ * Lists every registered slash command — built-ins and plugin-provided alike.
4
+ * Sorted alphabetically; the active command itself is included for symmetry.
5
+ * The output is a single multi-line string that the dispatcher renders as an
6
+ * info line.
7
+ *
8
+ * `host` is captured by closure so the listing reflects what's actually
9
+ * loaded — adding a new built-in or a plugin command at any time updates the
10
+ * `/help` output without changing this file.
11
+ */
12
+ export function makeHelpPlugin(host) {
13
+ const command = {
14
+ name: "help",
15
+ description: "List all slash commands.",
16
+ run: () => {
17
+ const commands = host.slashCommands();
18
+ if (commands.length === 0)
19
+ return "no slash commands registered";
20
+ const padTo = Math.max(...commands.map((c) => c.name.length));
21
+ const lines = [...commands]
22
+ .sort((a, b) => a.name.localeCompare(b.name))
23
+ .map((c) => ` /${c.name.padEnd(padTo)} ${c.description}`);
24
+ return ["Slash commands:", ...lines].join("\n");
25
+ },
26
+ };
27
+ return definePlugin({
28
+ name: "builtin/help",
29
+ onLoad(ctx) {
30
+ ctx.registerSlashCommand(command);
31
+ },
32
+ });
33
+ }
34
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/slash/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmD,MAAM,wBAAwB,CAAC;AAEvG;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB;IAC7C,MAAM,OAAO,GAAiB;QAC5B,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,0BAA0B;QACvC,GAAG,EAAE,GAAG,EAAE;YACR,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,8BAA8B,CAAC;YACjE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9D,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC;iBACxB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBAC5C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,iBAAiB,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC;KACF,CAAC;IACF,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,cAAc;QACpB,MAAM,CAAC,GAAG;YACR,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { PluginHost } from "@chances-ai/plugin-api";
2
+ import type { ChatViewModel } from "@chances-ai/tui";
3
+ import type { SessionManager, SessionStore } from "@chances-ai/session";
4
+ import type { AppContext } from "../boot/load-runtime.js";
5
+ /**
6
+ * Bundle of deps every built-in slash command may need. Kept as one object
7
+ * so adding a new built-in doesn't require threading another arg through
8
+ * every factory; commands ignore fields they don't use.
9
+ *
10
+ * `respawn` is the chat loop's "tear down + re-enter" hook. `/resume`
11
+ * triggers it with a target session id; `/clear` doesn't use it (it mutates
12
+ * the current session in place via SessionManager.clearTurns + vm.clearLines).
13
+ */
14
+ export interface BuiltinSlashDeps {
15
+ ctx: AppContext;
16
+ vm: ChatViewModel;
17
+ session: SessionManager;
18
+ store: SessionStore;
19
+ respawn: (resumeSessionId?: string) => void;
20
+ }
21
+ export declare function registerBuiltinSlashCommands(host: PluginHost, deps: BuiltinSlashDeps): Promise<void>;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/slash/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAS1D;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,UAAU,CAAC;IAChB,EAAE,EAAE,aAAa,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -0,0 +1,20 @@
1
+ import { makeHelpPlugin } from "./help.js";
2
+ import { makeModelPlugin } from "./model.js";
3
+ import { makeProviderPlugin } from "./provider.js";
4
+ import { makeClearPlugin } from "./clear.js";
5
+ import { makeResumePlugin } from "./resume.js";
6
+ import { makeCompactPlugin } from "./compact.js";
7
+ import { makeLogoutPlugin } from "./logout.js";
8
+ export async function registerBuiltinSlashCommands(host, deps) {
9
+ // Order doesn't matter; each plugin only mutates its own command slot.
10
+ // `await` so any onLoad error (e.g. duplicate registration in a buggy
11
+ // teardown) surfaces immediately rather than as an unhandled rejection.
12
+ await host.load(makeHelpPlugin(host));
13
+ await host.load(makeModelPlugin(deps));
14
+ await host.load(makeProviderPlugin(deps));
15
+ await host.load(makeClearPlugin(deps));
16
+ await host.load(makeResumePlugin(deps));
17
+ await host.load(makeCompactPlugin(deps));
18
+ await host.load(makeLogoutPlugin(deps));
19
+ }
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/slash/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAmB/C,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,IAAgB,EAChB,IAAsB;IAEtB,uEAAuE;IACvE,sEAAsE;IACtE,wEAAwE;IACxE,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type Plugin } from "@chances-ai/plugin-api";
2
+ import type { BuiltinSlashDeps } from "./index.js";
3
+ /**
4
+ * `/logout <provider>` — removes a provider's stored API key from the auth
5
+ * file. Does NOT touch env vars (we have no way to unset a parent shell's
6
+ * env). If the active selection points at the logged-out provider, clears
7
+ * the provider preference so the router falls back to the cheapest credentialed
8
+ * option on the next turn instead of failing.
9
+ *
10
+ * No interactive form yet — argument is required. A `/logout` with no arg
11
+ * could either log out everything (dangerous) or open a picker (more UI); we
12
+ * defer both until a real need.
13
+ */
14
+ export declare function makeLogoutPlugin(deps: BuiltinSlashDeps): Plugin;
15
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/slash/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAqB,MAAM,wBAAwB,CAAC;AAEtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CA8B/D"}
@@ -0,0 +1,44 @@
1
+ import { definePlugin } from "@chances-ai/plugin-api";
2
+ import { KNOWN_MODELS } from "@chances-ai/ai";
3
+ /**
4
+ * `/logout <provider>` — removes a provider's stored API key from the auth
5
+ * file. Does NOT touch env vars (we have no way to unset a parent shell's
6
+ * env). If the active selection points at the logged-out provider, clears
7
+ * the provider preference so the router falls back to the cheapest credentialed
8
+ * option on the next turn instead of failing.
9
+ *
10
+ * No interactive form yet — argument is required. A `/logout` with no arg
11
+ * could either log out everything (dangerous) or open a picker (more UI); we
12
+ * defer both until a real need.
13
+ */
14
+ export function makeLogoutPlugin(deps) {
15
+ const command = {
16
+ name: "logout",
17
+ description: "Remove a stored provider credential.",
18
+ run: (args) => {
19
+ const target = args[0];
20
+ if (!target)
21
+ return "usage: /logout <provider>";
22
+ const known = KNOWN_MODELS.find((e) => e.id === target);
23
+ if (!known)
24
+ return `unknown provider: ${target}. /provider list shows what's known.`;
25
+ // Idempotent on the auth file — deleteKey is a no-op when the key
26
+ // isn't there. We still adjust selection because the env var may have
27
+ // been the source, and the user's intent is "stop using this provider".
28
+ deps.ctx.auth.deleteKey(target);
29
+ const current = deps.ctx.selection.get();
30
+ if (current.provider === target) {
31
+ deps.ctx.selection.set({ provider: undefined, model: undefined });
32
+ return `${target} logged out — selection cleared so the router will pick the cheapest available next turn`;
33
+ }
34
+ return `${target} logged out (no env var unset — clear ${known.envKey} in your shell if it was set there)`;
35
+ },
36
+ };
37
+ return definePlugin({
38
+ name: "builtin/logout",
39
+ onLoad(ctx) {
40
+ ctx.registerSlashCommand(command);
41
+ },
42
+ });
43
+ }
44
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/slash/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAsB;IACrD,MAAM,OAAO,GAAiB;QAC5B,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,sCAAsC;QACnD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;YACZ,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,CAAC,MAAM;gBAAE,OAAO,2BAA2B,CAAC;YAEhD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;YACxD,IAAI,CAAC,KAAK;gBAAE,OAAO,qBAAqB,MAAM,sCAAsC,CAAC;YAErF,kEAAkE;YAClE,sEAAsE;YACtE,wEAAwE;YACxE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YACzC,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBAClE,OAAO,GAAG,MAAM,0FAA0F,CAAC;YAC7G,CAAC;YACD,OAAO,GAAG,MAAM,yCAAyC,KAAK,CAAC,MAAM,qCAAqC,CAAC;QAC7G,CAAC;KACF,CAAC;IACF,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,gBAAgB;QACtB,MAAM,CAAC,GAAG;YACR,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type Plugin } from "@chances-ai/plugin-api";
2
+ import type { BuiltinSlashDeps } from "./index.js";
3
+ /**
4
+ * `/model [id]`
5
+ * - With an id: switches the active model (matches by `id` alone or by
6
+ * `provider/id`). Writes the choice to `<workspaceRoot>/.chances/config.json`
7
+ * so the next invocation in this workspace defaults to it (per design call
8
+ * "default persisted").
9
+ * - Without args in TUI mode: opens the model picker (Step 6's ModelPicker).
10
+ * - Without args in text mode: prints the available models, marking the
11
+ * current one. Aligns with oh-my-pi's text-mode model list.
12
+ */
13
+ export declare function makeModelPlugin(deps: BuiltinSlashDeps): Plugin;
14
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/slash/model.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,MAAM,EAAqB,MAAM,wBAAwB,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAwC9D"}
@@ -0,0 +1,87 @@
1
+ import { createElement } from "react";
2
+ import { definePlugin } from "@chances-ai/plugin-api";
3
+ import { ModelPicker } from "@chances-ai/tui";
4
+ import { persistProjectModelChoice } from "./persist.js";
5
+ /**
6
+ * `/model [id]`
7
+ * - With an id: switches the active model (matches by `id` alone or by
8
+ * `provider/id`). Writes the choice to `<workspaceRoot>/.chances/config.json`
9
+ * so the next invocation in this workspace defaults to it (per design call
10
+ * "default persisted").
11
+ * - Without args in TUI mode: opens the model picker (Step 6's ModelPicker).
12
+ * - Without args in text mode: prints the available models, marking the
13
+ * current one. Aligns with oh-my-pi's text-mode model list.
14
+ */
15
+ export function makeModelPlugin(deps) {
16
+ const command = {
17
+ name: "model",
18
+ description: "Show or switch the active model.",
19
+ run: async (args, slashCtx) => {
20
+ const all = deps.ctx.registry.all();
21
+ const current = deps.ctx.selection.get();
22
+ if (args.length === 0) {
23
+ if (slashCtx.openModal) {
24
+ // TUI mode: open the picker. The picker is intentionally rendered
25
+ // inside the chat UI via the modal slot, not as a separate process.
26
+ const picked = await slashCtx.openModal((resolve) => {
27
+ const items = all.map((m) => ({
28
+ id: m.id,
29
+ provider: m.provider,
30
+ current: m.id === current.model && m.provider === current.provider,
31
+ }));
32
+ return renderModelPicker(items, resolve);
33
+ });
34
+ if (!picked)
35
+ return "model unchanged";
36
+ return applyChoice(deps, picked.provider, picked.id);
37
+ }
38
+ // Text mode: list the models the registry knows about.
39
+ return listText(all, current.model, current.provider);
40
+ }
41
+ // Args path. Accept either "id" or "provider/id" — pi's parseModelId pattern.
42
+ const want = args[0];
43
+ const match = resolveModel(all, want);
44
+ if (!match)
45
+ return `unknown model: ${want}. Run /model to see available ids.`;
46
+ return applyChoice(deps, match.provider, match.id);
47
+ },
48
+ };
49
+ return definePlugin({
50
+ name: "builtin/model",
51
+ onLoad(ctx) {
52
+ ctx.registerSlashCommand(command);
53
+ },
54
+ });
55
+ }
56
+ function applyChoice(deps, provider, model) {
57
+ deps.ctx.selection.set({ provider, model });
58
+ deps.session.setModel({ provider, model });
59
+ const persisted = persistProjectModelChoice(deps.ctx.workspaceRoot, { provider, model });
60
+ if (!persisted) {
61
+ return `model set to ${provider}/${model} (this session only — could not write .chances/config.json)`;
62
+ }
63
+ return `model set to ${provider}/${model} (saved to .chances/config.json)`;
64
+ }
65
+ function resolveModel(models, want) {
66
+ return models.find((m) => m.id === want || `${m.provider}/${m.id}` === want);
67
+ }
68
+ function listText(models, curModel, curProvider) {
69
+ if (models.length === 0)
70
+ return "no models registered — check your config and API keys";
71
+ const padTo = Math.max(...models.map((m) => `${m.provider}/${m.id}`.length));
72
+ const lines = models.map((m) => {
73
+ const active = m.id === curModel && m.provider === curProvider;
74
+ const marker = active ? "● " : " ";
75
+ return `${marker}${`${m.provider}/${m.id}`.padEnd(padTo)} ctx=${m.contextWindow}`;
76
+ });
77
+ return ["Available models (● = current):", ...lines].join("\n");
78
+ }
79
+ /** Builds the React element for the picker. The `openModal` host expects
80
+ * `unknown`, but we know the concrete shape — return `createElement(...)`
81
+ * which Ink will render. Even in text mode this code path isn't reached
82
+ * (the dispatcher leaves openModal undefined), so importing the React + Ink
83
+ * components at module top is free of runtime cost there. */
84
+ function renderModelPicker(items, resolve) {
85
+ return createElement(ModelPicker, { models: items, onChoose: resolve });
86
+ }
87
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/slash/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Writes the user's model/provider choice into `<workspaceRoot>/.chances/config.json`
3
+ * so the next `chances` invocation in this workspace defaults to it. Preserves
4
+ * any unrelated fields (permissions, plugins, …) — only the `provider` and
5
+ * `model` keys are touched.
6
+ *
7
+ * Returns true on success, false on filesystem failure (so the calling slash
8
+ * command can degrade to "in-session only" without throwing). Failures are
9
+ * intentionally not logged here — the slash command surfaces a user-visible
10
+ * notice with the right context.
11
+ */
12
+ export declare function persistProjectModelChoice(workspaceRoot: string, choice: {
13
+ provider?: string;
14
+ model?: string;
15
+ }): boolean;
16
+ //# sourceMappingURL=persist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/slash/persist.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,OAAO,CA2BT"}
@@ -0,0 +1,46 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Writes the user's model/provider choice into `<workspaceRoot>/.chances/config.json`
5
+ * so the next `chances` invocation in this workspace defaults to it. Preserves
6
+ * any unrelated fields (permissions, plugins, …) — only the `provider` and
7
+ * `model` keys are touched.
8
+ *
9
+ * Returns true on success, false on filesystem failure (so the calling slash
10
+ * command can degrade to "in-session only" without throwing). Failures are
11
+ * intentionally not logged here — the slash command surfaces a user-visible
12
+ * notice with the right context.
13
+ */
14
+ export function persistProjectModelChoice(workspaceRoot, choice) {
15
+ const dir = join(workspaceRoot, ".chances");
16
+ const path = join(dir, "config.json");
17
+ try {
18
+ mkdirSync(dir, { recursive: true });
19
+ let existing = {};
20
+ if (existsSync(path)) {
21
+ try {
22
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
23
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
24
+ existing = parsed;
25
+ }
26
+ }
27
+ catch {
28
+ // Malformed file — start fresh rather than refusing to write. The
29
+ // user's choice should win over a stale parse failure they may not
30
+ // even know about.
31
+ existing = {};
32
+ }
33
+ }
34
+ const next = { ...existing };
35
+ if (choice.provider !== undefined)
36
+ next.provider = choice.provider;
37
+ if (choice.model !== undefined)
38
+ next.model = choice.model;
39
+ writeFileSync(path, JSON.stringify(next, null, 2) + "\n");
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ //# sourceMappingURL=persist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/slash/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,aAAqB,EACrB,MAA6C;IAE7C,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,QAAQ,GAA4B,EAAE,CAAC;QAC3C,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC;gBACjE,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnE,QAAQ,GAAG,MAAiC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,kEAAkE;gBAClE,mEAAmE;gBACnE,mBAAmB;gBACnB,QAAQ,GAAG,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAA4B,EAAE,GAAG,QAAQ,EAAE,CAAC;QACtD,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACnE,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type Plugin } from "@chances-ai/plugin-api";
2
+ import type { BuiltinSlashDeps } from "./index.js";
3
+ /**
4
+ * `/provider [list|use|add]`
5
+ *
6
+ * - `/provider list` — text dump of which providers are configured.
7
+ * - `/provider use <id>` — sets selection's provider; lets the router pick
8
+ * the first model of that provider for next turn.
9
+ * - `/provider add <id>` — TUI: opens ApiKeyPrompt to enter the key, then
10
+ * persists via AuthStore.setKey. Text mode: refuses
11
+ * with an env-var hint (matching pi's pattern:
12
+ * `<ENVKEY>=… chances` works headlessly).
13
+ *
14
+ * Default (no subcommand) is `list`.
15
+ */
16
+ export declare function makeProviderPlugin(deps: BuiltinSlashDeps): Plugin;
17
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/slash/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,MAAM,EAAqB,MAAM,wBAAwB,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CA2BjE"}