impel-cli 0.16.4 → 0.17.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.
@@ -0,0 +1,114 @@
1
+ import { spawn } from "node:child_process";
2
+
3
+ import { parseFlags } from "../args.js";
4
+ import { collectSessionHook, flushCollectedSession, readHookInput, sessionOutboxStatus } from "../sessionCollector.js";
5
+ import { loadConfig, redactSecretText } from "../config.js";
6
+ import { impelCliInvocation } from "../selfInvocation.js";
7
+
8
+ const SPEC = {
9
+ provider: { type: "string" },
10
+ surface: { type: "string" },
11
+ tenant: { type: "string" },
12
+ session: { type: "string" },
13
+ "impel-managed-session-hook-v1": { type: "boolean" },
14
+ };
15
+
16
+ function startDetachedFlush({ provider, tenant, session }) {
17
+ const invocation = impelCliInvocation([
18
+ "sessions",
19
+ "flush",
20
+ "--provider",
21
+ provider,
22
+ "--tenant",
23
+ tenant,
24
+ "--session",
25
+ session,
26
+ "--impel-managed-session-hook-v1",
27
+ ]);
28
+ const child = spawn(invocation.command, invocation.args, {
29
+ detached: true,
30
+ stdio: "ignore",
31
+ env: { ...process.env, IMPEL_SESSIONS_FLUSH_CHILD: "1" },
32
+ windowsHide: true,
33
+ });
34
+ child.once("error", () => {});
35
+ child.unref();
36
+ }
37
+
38
+ export async function cmdSessions(argv) {
39
+ const [action, ...rest] = argv;
40
+ if (action === "hook") {
41
+ try {
42
+ const { flags, positionals } = parseFlags(rest, SPEC);
43
+ if (positionals.length > 0) throw new Error("unexpected positional arguments");
44
+ const input = await readHookInput();
45
+ let config = null;
46
+ try {
47
+ config = loadConfig();
48
+ } catch {
49
+ // Capture remains available even while the user's config needs repair.
50
+ }
51
+ await collectSessionHook({
52
+ provider: flags.provider,
53
+ surface: flags.surface,
54
+ tenantId: flags.tenant,
55
+ input,
56
+ config,
57
+ flush: false,
58
+ });
59
+ if (config && (config.tenantId === flags.tenant || process.env.IMPEL_SESSIONS_DEV_ORG_ID)) {
60
+ startDetachedFlush({
61
+ provider: flags.provider,
62
+ tenant: flags.tenant,
63
+ session: String(input.session_id || ""),
64
+ });
65
+ }
66
+ } catch (error) {
67
+ // Session persistence is observational. A collector outage must never
68
+ // block a model turn or change a provider hook's decision semantics.
69
+ if (process.env.IMPEL_SESSIONS_DEBUG === "1") {
70
+ console.error(`impel sessions hook: ${redactSecretText(error?.message || error)}`);
71
+ }
72
+ }
73
+ return;
74
+ }
75
+ const { flags, positionals } = parseFlags(rest, SPEC);
76
+ if (positionals.length > 0) {
77
+ console.error("impel sessions: unexpected positional arguments");
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ const config = loadConfig();
82
+ if (action === "flush") {
83
+ if (!flags.provider || !flags.session || !flags.tenant) return;
84
+ if (!["claude_code", "codex"].includes(flags.provider)) return;
85
+ if (!config || flags.tenant !== config.tenantId && !process.env.IMPEL_SESSIONS_DEV_ORG_ID) return;
86
+ const deadline = Date.now() + 90_000;
87
+ while (Date.now() < deadline) {
88
+ const result = await flushCollectedSession({
89
+ tenantId: flags.tenant,
90
+ provider: flags.provider,
91
+ sessionKey: flags.session,
92
+ config,
93
+ });
94
+ if (result.pending === 0) break;
95
+ await new Promise((resolve) => setTimeout(resolve, result.error || result.busy ? 1000 : 250));
96
+ }
97
+ return;
98
+ }
99
+ if (action === "status") {
100
+ if (!flags.provider || !flags.session || !flags.tenant) {
101
+ console.error("impel sessions status requires --provider, --session, and --tenant");
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+ console.log(JSON.stringify(sessionOutboxStatus({
106
+ tenantId: flags.tenant,
107
+ provider: flags.provider,
108
+ sessionKey: flags.session,
109
+ }), null, 2));
110
+ return;
111
+ }
112
+ console.error("impel sessions: use `hook` (managed internally) or `status`");
113
+ process.exitCode = 1;
114
+ }