@slock-ai/daemon 0.52.2 → 0.53.0-play.20260524064439

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/dist/cli/index.js CHANGED
@@ -14161,6 +14161,7 @@ var SERVER_CAPABILITY_MATRIX = {
14161
14161
  var RUNTIMES = [
14162
14162
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
14163
14163
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
14164
+ { id: "pi", displayName: "Pi", binary: "pi", supported: true },
14164
14165
  { id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
14165
14166
  { id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
14166
14167
  { id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
@@ -14281,6 +14282,7 @@ var ApiClient = class {
14281
14282
  if (suffix.startsWith("/search")) return `/internal/agent-api/search${suffix.slice("/search".length)}`;
14282
14283
  if (suffix.startsWith("/channel-members")) return `/internal/agent-api/channel-members${suffix.slice("/channel-members".length)}`;
14283
14284
  if (suffix === "/profile" || suffix.startsWith("/profile/")) return `/internal/agent-api${suffix}`;
14285
+ if (suffix === "/integrations" || suffix.startsWith("/integrations/")) return `/internal/agent-api${suffix}`;
14284
14286
  if (suffix === "/upload") return "/internal/agent-api/upload";
14285
14287
  if (suffix === "/resolve-channel") return "/internal/agent-api/resolve-channel";
14286
14288
  if (suffix === "/threads/unfollow") return "/internal/agent-api/threads/unfollow";
@@ -14432,6 +14434,7 @@ var ApiClient = class {
14432
14434
  };
14433
14435
 
14434
14436
  // src/commands/action/prepare.ts
14437
+ var ACTION_HEREDOC_DELIMITER = "SLOCKACTION";
14435
14438
  var PrepareActionInputError = class extends Error {
14436
14439
  constructor(code, message) {
14437
14440
  super(message);
@@ -14451,9 +14454,9 @@ function missingActionMessage() {
14451
14454
  return [
14452
14455
  "No action JSON received on stdin.",
14453
14456
  "Pipe a JSON ActionCardAction object (channel:create / agent:create / channel:add_member) into slock action prepare:",
14454
- ` slock action prepare --target "#channel" <<'EOF'`,
14457
+ ` slock action prepare --target "#channel" <<'${ACTION_HEREDOC_DELIMITER}'`,
14455
14458
  ' {"type":"channel:create","name":"demo","visibility":"public"}',
14456
- " EOF"
14459
+ ` ${ACTION_HEREDOC_DELIMITER}`
14457
14460
  ].join("\n");
14458
14461
  }
14459
14462
  async function resolveActionInput(input = process.stdin) {
@@ -14573,7 +14576,7 @@ function formatServerInfo(data) {
14573
14576
  text += " (none)\n";
14574
14577
  }
14575
14578
  text += "\n### Humans\n";
14576
- text += `To start a new DM: slock message send --target "dm:@name" <<'EOF' followed by the message body and EOF. To reply in an existing DM: reuse the target from received messages.
14579
+ text += `To start a new DM: slock message send --target "dm:@name" <<'SLOCKMSG' followed by the message body and SLOCKMSG. To reply in an existing DM: reuse the target from received messages.
14577
14580
  `;
14578
14581
  if (humans.length > 0) {
14579
14582
  for (const u of humans) {
@@ -15063,6 +15066,7 @@ function clearSavedDraft(agentId, target) {
15063
15066
  }
15064
15067
 
15065
15068
  // src/commands/message/send.ts
15069
+ var MESSAGE_HEREDOC_DELIMITER = "SLOCKMSG";
15066
15070
  var SendContentError = class extends Error {
15067
15071
  constructor(code, message) {
15068
15072
  super(message);
@@ -15082,9 +15086,9 @@ function missingContentMessage() {
15082
15086
  return [
15083
15087
  "No message content received on stdin.",
15084
15088
  "Use a heredoc or pipe content into slock message send:",
15085
- ` slock message send --target "#channel" <<'EOF'`,
15089
+ ` slock message send --target "#channel" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
15086
15090
  " message body",
15087
- " EOF"
15091
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
15088
15092
  ].join("\n");
15089
15093
  }
15090
15094
  async function resolveSendContent(input = process.stdin) {
@@ -15111,9 +15115,9 @@ function rejectArgContent(positionalContent, opts) {
15111
15115
  [
15112
15116
  "Message content must be provided on stdin, not as positional arguments.",
15113
15117
  "Use:",
15114
- ` slock message send --target "#channel" <<'EOF'`,
15118
+ ` slock message send --target "#channel" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
15115
15119
  " message body",
15116
- " EOF"
15120
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
15117
15121
  ].join("\n")
15118
15122
  );
15119
15123
  }
@@ -15149,9 +15153,9 @@ function rejectSendDraftStdin(content, target) {
15149
15153
  [
15150
15154
  "--send-draft sends the current saved draft and does not accept stdin.",
15151
15155
  "To update the draft, send the revised content normally without --send-draft:",
15152
- ` slock message send --target "${target}" <<'EOF'`,
15156
+ ` slock message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
15153
15157
  " revised message",
15154
- " EOF"
15158
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
15155
15159
  ].join("\n")
15156
15160
  );
15157
15161
  }
@@ -15159,9 +15163,9 @@ function formatHeldSendOutput(target, data) {
15159
15163
  return formatFreshnessHoldOutput(target, data, {
15160
15164
  heldAction: "Your message has been saved as a draft.",
15161
15165
  draftInstructions: `To update the draft, send revised content normally:
15162
- slock message send --target "${target}" <<'EOF'
15166
+ slock message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'
15163
15167
  revised message
15164
- EOF
15168
+ ${MESSAGE_HEREDOC_DELIMITER}
15165
15169
  To send the current draft unchanged:
15166
15170
  slock message send --send-draft --target "${target}"
15167
15171
  `,
@@ -15216,9 +15220,9 @@ function registerSendCommand(parent) {
15216
15220
  [
15217
15221
  "No saved draft exists for this target.",
15218
15222
  "To create or update a draft, send message content normally:",
15219
- ` slock message send --target "${opts.target}" <<'EOF'`,
15223
+ ` slock message send --target "${opts.target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
15220
15224
  " message body",
15221
- " EOF"
15225
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
15222
15226
  ].join("\n")
15223
15227
  );
15224
15228
  return;
@@ -16170,6 +16174,153 @@ function registerProfileUpdateCommand(parent) {
16170
16174
  });
16171
16175
  }
16172
16176
 
16177
+ // src/commands/integration/_format.ts
16178
+ function formatMaybe(value) {
16179
+ return value?.trim() || "-";
16180
+ }
16181
+ function buildAgentAppUrl(returnUrl, requestId) {
16182
+ if (!returnUrl?.trim()) return null;
16183
+ try {
16184
+ const url2 = new URL(returnUrl);
16185
+ url2.searchParams.set("code", requestId);
16186
+ return url2.toString();
16187
+ } catch {
16188
+ return null;
16189
+ }
16190
+ }
16191
+ function formatIntegrationList(data) {
16192
+ const activeByServiceId = new Map(data.activeLogins.map((login) => [login.serviceId, login]));
16193
+ const lines = [];
16194
+ lines.push("Registered services:");
16195
+ if (data.services.length === 0) {
16196
+ lines.push("- none");
16197
+ } else {
16198
+ for (const service of data.services) {
16199
+ const active = activeByServiceId.get(service.id);
16200
+ lines.push(`- ${service.name}`);
16201
+ lines.push(` service: ${service.clientId}`);
16202
+ lines.push(` id: ${service.id}`);
16203
+ lines.push(` status: ${active ? "active login" : "not logged in"}`);
16204
+ lines.push(` return URL: ${formatMaybe(service.returnUrl)}`);
16205
+ if (service.homepageUrl) lines.push(` homepage: ${service.homepageUrl}`);
16206
+ if (service.description) lines.push(` description: ${service.description}`);
16207
+ if (!active) lines.push(` next: slock integration login --service ${JSON.stringify(service.clientId)}`);
16208
+ }
16209
+ }
16210
+ lines.push("");
16211
+ lines.push("Active agent logins:");
16212
+ if (data.activeLogins.length === 0) {
16213
+ lines.push("- none");
16214
+ } else {
16215
+ for (const login of data.activeLogins) {
16216
+ lines.push(`- ${login.name}`);
16217
+ lines.push(` service: ${login.clientId}`);
16218
+ lines.push(` grant id: ${login.id}`);
16219
+ lines.push(` scopes: ${login.scopes.length > 0 ? login.scopes.join(", ") : "-"}`);
16220
+ lines.push(` return URL: ${formatMaybe(login.returnUrl)}`);
16221
+ lines.push(` created: ${login.createdAt}`);
16222
+ }
16223
+ }
16224
+ return lines.join("\n");
16225
+ }
16226
+ function formatIntegrationLogin(data) {
16227
+ const verb = data.status === "already_logged_in" ? "Already logged in" : "Agent login ready";
16228
+ const lines = [
16229
+ `${verb}: ${data.service.name}`,
16230
+ `service: ${data.service.clientId}`,
16231
+ `id: ${data.service.id}`,
16232
+ `scopes: ${data.scopes.length > 0 ? data.scopes.join(", ") : "-"}`,
16233
+ `return URL: ${formatMaybe(data.service.returnUrl)}`,
16234
+ "complete: this agent login is configured in Slock; no human OAuth is required",
16235
+ "identity: run `slock profile show` if the service or human asks for your Slock Agent identity card"
16236
+ ];
16237
+ const agentAppUrl = buildAgentAppUrl(data.service.returnUrl, data.requestId);
16238
+ if (agentAppUrl) {
16239
+ lines.push(`app URL: ${agentAppUrl}`);
16240
+ lines.push("next: open the app URL if you need the third-party app surface, or run `slock integration list` to confirm active login");
16241
+ } else {
16242
+ lines.push("next: use the registered service, or run `slock integration list` to confirm active login");
16243
+ }
16244
+ return lines.join("\n");
16245
+ }
16246
+
16247
+ // src/commands/integration/list.ts
16248
+ function registerIntegrationListCommand(parent) {
16249
+ parent.command("list").description("List registered third-party services and this agent's active logins").option("--json", "Emit machine-readable JSON").action(async (opts) => {
16250
+ let ctx;
16251
+ try {
16252
+ ctx = loadAgentContext();
16253
+ } catch (err) {
16254
+ if (err instanceof AgentBootstrapError) fail(err.code, err.message);
16255
+ throw err;
16256
+ }
16257
+ const client = new ApiClient(ctx);
16258
+ const res = await client.request(
16259
+ "GET",
16260
+ `/internal/agent/${encodeURIComponent(ctx.agentId)}/integrations`
16261
+ );
16262
+ if (!res.ok || !res.data) {
16263
+ const code = res.status >= 500 ? "SERVER_5XX" : "INTEGRATION_LIST_FAILED";
16264
+ fail(code, res.error ?? `HTTP ${res.status}`);
16265
+ }
16266
+ if (opts.json) {
16267
+ emit({ ok: true, data: res.data });
16268
+ return;
16269
+ }
16270
+ process.stdout.write(`${formatIntegrationList(res.data)}
16271
+ `);
16272
+ });
16273
+ }
16274
+
16275
+ // src/commands/integration/login.ts
16276
+ function normalizeScopes(raw) {
16277
+ if (!raw || raw.length === 0) return void 0;
16278
+ const scopes = Array.from(new Set(
16279
+ raw.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean)
16280
+ )).sort();
16281
+ if (scopes.length === 0) {
16282
+ fail("INVALID_ARG", "--scope must include at least one non-empty scope");
16283
+ }
16284
+ return scopes;
16285
+ }
16286
+ function registerIntegrationLoginCommand(parent) {
16287
+ parent.command("login").description("Provision or reuse this agent's login for a registered service").requiredOption("--service <id>", "Registered service id, client id, or exact service name").option("--scope <scope>", "Requested scope; can be repeated or comma-separated", (value, previous = []) => {
16288
+ previous.push(value);
16289
+ return previous;
16290
+ }).option("--json", "Emit machine-readable JSON").action(async (opts) => {
16291
+ let ctx;
16292
+ try {
16293
+ ctx = loadAgentContext();
16294
+ } catch (err) {
16295
+ if (err instanceof AgentBootstrapError) fail(err.code, err.message);
16296
+ throw err;
16297
+ }
16298
+ const service = opts.service.trim();
16299
+ if (!service) {
16300
+ fail("INVALID_ARG", "--service must not be empty");
16301
+ }
16302
+ const client = new ApiClient(ctx);
16303
+ const res = await client.request(
16304
+ "POST",
16305
+ `/internal/agent/${encodeURIComponent(ctx.agentId)}/integrations/login`,
16306
+ {
16307
+ service,
16308
+ scopes: normalizeScopes(opts.scope)
16309
+ }
16310
+ );
16311
+ if (!res.ok || !res.data) {
16312
+ const code = res.status >= 500 ? "SERVER_5XX" : "INTEGRATION_LOGIN_FAILED";
16313
+ fail(code, res.error ?? `HTTP ${res.status}`);
16314
+ }
16315
+ if (opts.json) {
16316
+ emit({ ok: true, data: res.data });
16317
+ return;
16318
+ }
16319
+ process.stdout.write(`${formatIntegrationLogin(res.data)}
16320
+ `);
16321
+ });
16322
+ }
16323
+
16173
16324
  // src/commands/reminder/_format.ts
16174
16325
  var MODIFY_HINT = "(to modify: snooze/update/cancel; slock reminder --help)";
16175
16326
  function formatReminder(r) {
@@ -16562,6 +16713,9 @@ registerTaskUpdateCommand(taskCmd);
16562
16713
  var profileCmd = program.command("profile").description("Profile operations");
16563
16714
  registerProfileShowCommand(profileCmd);
16564
16715
  registerProfileUpdateCommand(profileCmd);
16716
+ var integrationCmd = program.command("integration").description("Third-party service integration operations");
16717
+ registerIntegrationListCommand(integrationCmd);
16718
+ registerIntegrationLoginCommand(integrationCmd);
16565
16719
  var reminderCmd = program.command("reminder").description("Reminder operations");
16566
16720
  registerReminderScheduleCommand(reminderCmd);
16567
16721
  registerReminderListCommand(reminderCmd);
package/dist/core.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DAEMON_API_KEY_ENV,
2
3
  DAEMON_CLI_USAGE,
3
4
  DaemonCore,
4
5
  deleteWorkspaceDirectory,
@@ -8,12 +9,14 @@ import {
8
9
  resolveChatBridgePath,
9
10
  resolveSlockCliPath,
10
11
  resolveWorkspaceDirectoryPath,
11
- scanWorkspaceDirectories
12
- } from "./chunk-HSBOURQE.js";
12
+ scanWorkspaceDirectories,
13
+ scrubDaemonAuthEnv
14
+ } from "./chunk-AB3IDL5P.js";
13
15
  import {
14
16
  subscribeDaemonLogs
15
17
  } from "./chunk-KNMCE6WB.js";
16
18
  export {
19
+ DAEMON_API_KEY_ENV,
17
20
  DAEMON_CLI_USAGE,
18
21
  DaemonCore,
19
22
  deleteWorkspaceDirectory,
@@ -24,5 +27,6 @@ export {
24
27
  resolveSlockCliPath,
25
28
  resolveWorkspaceDirectoryPath,
26
29
  scanWorkspaceDirectories,
30
+ scrubDaemonAuthEnv,
27
31
  subscribeDaemonLogs
28
32
  };
@@ -0,0 +1,96 @@
1
+ // src/drivers/piSdkRunner.ts
2
+ import { readFile } from "fs/promises";
3
+ import path from "path";
4
+ import {
5
+ AuthStorage,
6
+ createAgentSessionFromServices,
7
+ createAgentSessionServices,
8
+ SessionManager
9
+ } from "@earendil-works/pi-coding-agent";
10
+ function writeJson(value) {
11
+ process.stdout.write(`${JSON.stringify(value)}
12
+ `);
13
+ }
14
+ function parseArgs(argv) {
15
+ const index = argv.indexOf("--config");
16
+ const configPath = index >= 0 ? argv[index + 1] : void 0;
17
+ if (!configPath) throw new Error("Missing --config <path>");
18
+ return { configPath };
19
+ }
20
+ function resolveConfiguredModel(modelId, modelRegistry) {
21
+ if (!modelId) return void 0;
22
+ const [provider, ...rest] = modelId.split("/");
23
+ const providerScopedId = rest.join("/");
24
+ if (provider && providerScopedId) {
25
+ const exact = modelRegistry.find(provider, providerScopedId);
26
+ if (exact) return exact;
27
+ }
28
+ return modelRegistry.getAll().find(
29
+ (model) => model.id === modelId || `${model.provider}/${model.id}` === modelId || (providerScopedId ? model.id === providerScopedId : false)
30
+ );
31
+ }
32
+ async function createSessionManager(config) {
33
+ if (!config.sessionId) return SessionManager.create(config.cwd, config.sessionDir);
34
+ const localSessions = await SessionManager.list(config.cwd, config.sessionDir);
35
+ const match = localSessions.find((session) => session.id.startsWith(config.sessionId));
36
+ if (match) return SessionManager.open(match.path, config.sessionDir);
37
+ return SessionManager.create(config.cwd, config.sessionDir);
38
+ }
39
+ async function run() {
40
+ const { configPath } = parseArgs(process.argv.slice(2));
41
+ const config = JSON.parse(await readFile(configPath, "utf8"));
42
+ const authStorage = AuthStorage.create(path.join(config.agentDir, "auth.json"));
43
+ const services = await createAgentSessionServices({
44
+ cwd: config.cwd,
45
+ agentDir: config.agentDir,
46
+ authStorage,
47
+ resourceLoaderOptions: {
48
+ appendSystemPrompt: [config.standingPrompt],
49
+ noContextFiles: true,
50
+ noExtensions: true,
51
+ noPromptTemplates: true,
52
+ noSkills: true,
53
+ noThemes: true
54
+ }
55
+ });
56
+ for (const diagnostic of services.diagnostics) {
57
+ const line = `[Pi SDK] ${diagnostic.type}: ${diagnostic.message}`;
58
+ if (diagnostic.type === "error") throw new Error(line);
59
+ process.stderr.write(`${line}
60
+ `);
61
+ }
62
+ const sessionManager = await createSessionManager(config);
63
+ const model = resolveConfiguredModel(config.model, services.modelRegistry);
64
+ if (config.model && !model) {
65
+ throw new Error(`Configured Pi model '${config.model}' was not found in Pi model registry.`);
66
+ }
67
+ const { session } = await createAgentSessionFromServices({
68
+ services,
69
+ sessionManager,
70
+ model
71
+ });
72
+ const header = session.sessionManager.getHeader();
73
+ if (header) writeJson(header);
74
+ const unsubscribe = session.subscribe((event) => writeJson(event));
75
+ try {
76
+ await session.prompt(config.prompt);
77
+ } finally {
78
+ unsubscribe();
79
+ session.dispose();
80
+ await services.settingsManager.flush();
81
+ }
82
+ }
83
+ run().catch((error) => {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ writeJson({
86
+ type: "message_end",
87
+ message: {
88
+ role: "assistant",
89
+ content: [],
90
+ stopReason: "error",
91
+ errorMessage: message
92
+ }
93
+ });
94
+ writeJson({ type: "turn_end" });
95
+ process.exitCode = 1;
96
+ });
package/dist/index.js CHANGED
@@ -2,12 +2,14 @@
2
2
  import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
- parseDaemonCliArgs
6
- } from "./chunk-HSBOURQE.js";
5
+ parseDaemonCliArgs,
6
+ scrubDaemonAuthEnv
7
+ } from "./chunk-AB3IDL5P.js";
7
8
  import "./chunk-KNMCE6WB.js";
8
9
 
9
10
  // src/index.ts
10
- var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
11
+ var parsedArgs = parseDaemonCliArgs(process.argv.slice(2), process.env);
12
+ scrubDaemonAuthEnv(process.env);
11
13
  if (!parsedArgs) {
12
14
  console.error(DAEMON_CLI_USAGE);
13
15
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/daemon",
3
- "version": "0.52.2",
3
+ "version": "0.53.0-play.20260524064439",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "slock-daemon": "dist/index.js"
@@ -36,6 +36,8 @@
36
36
  "release:alpha": "npm version prerelease --preid=alpha --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags"
37
37
  },
38
38
  "dependencies": {
39
+ "@earendil-works/pi-coding-agent": "0.74.0",
40
+ "@jackwener/opencli": "^1.8.0",
39
41
  "@modelcontextprotocol/sdk": "^1.29.0",
40
42
  "commander": "^12.1.0",
41
43
  "https-proxy-agent": "^7.0.6",