@nookplot/cli 0.6.19 → 0.6.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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `nookplot knowledge` — Semantic knowledge search and earnings.
3
+ *
4
+ * Usage:
5
+ * nookplot knowledge query <text> — Search all knowledge
6
+ * nookplot knowledge earnings — View attribution revenue
7
+ * nookplot knowledge topics — View inferred topic map
8
+ *
9
+ * @module commands/knowledge
10
+ */
11
+ import type { Command } from "commander";
12
+ export declare function registerKnowledgeCommand(program: Command): void;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * `nookplot knowledge` — Semantic knowledge search and earnings.
3
+ *
4
+ * Usage:
5
+ * nookplot knowledge query <text> — Search all knowledge
6
+ * nookplot knowledge earnings — View attribution revenue
7
+ * nookplot knowledge topics — View inferred topic map
8
+ *
9
+ * @module commands/knowledge
10
+ */
11
+ import chalk from "chalk";
12
+ import ora from "ora";
13
+ import { loadConfig, validateConfig } from "../config.js";
14
+ import { gatewayRequest, isGatewayError } from "../utils/http.js";
15
+ export function registerKnowledgeCommand(program) {
16
+ const cmd = program
17
+ .command("knowledge")
18
+ .description("Semantic knowledge search and earnings");
19
+ // ---- nookplot knowledge query <text> ----
20
+ cmd
21
+ .command("query <text...>")
22
+ .description("Search all published knowledge")
23
+ .option("--types <types>", "Filter by content types (comma-separated: bundle,project,paper,bounty,task,resource,teaching)")
24
+ .option("--limit <n>", "Max results (1-20)", "10")
25
+ .option("--min-quality <n>", "Minimum quality score (0-100)")
26
+ .option("--json", "Output raw JSON")
27
+ .action(async (textParts, opts) => {
28
+ const config = loadConfig();
29
+ const errors = validateConfig(config);
30
+ if (errors.length > 0) {
31
+ console.error(chalk.red("Configuration errors:"));
32
+ errors.forEach((e) => console.error(` - ${e}`));
33
+ process.exit(1);
34
+ }
35
+ const query = textParts.join(" ");
36
+ const spinner = ora(`Searching: "${query}"`).start();
37
+ const body = {
38
+ query,
39
+ limit: parseInt(opts.limit, 10),
40
+ };
41
+ if (opts.types) {
42
+ body.types = opts.types.split(",").map((t) => t.trim());
43
+ }
44
+ if (opts.minQuality) {
45
+ body.minQuality = parseInt(opts.minQuality, 10);
46
+ }
47
+ const res = await gatewayRequest(config.gateway, "POST", "/v1/knowledge/query", { body, apiKey: config.apiKey });
48
+ if (isGatewayError(res)) {
49
+ spinner.fail(`Query failed: ${res.error}`);
50
+ process.exit(1);
51
+ }
52
+ spinner.stop();
53
+ if (opts.json) {
54
+ console.log(JSON.stringify(res.data, null, 2));
55
+ return;
56
+ }
57
+ const data = res.data;
58
+ console.log(chalk.bold(`\n Knowledge Query Results (${data.mode})`));
59
+ console.log(chalk.dim(` ${data.totalResults} results in ${data.durationMs}ms — cost: ${data.costCredits} credits\n`));
60
+ if (data.results.length === 0) {
61
+ console.log(chalk.yellow(" No results found.\n"));
62
+ return;
63
+ }
64
+ for (let i = 0; i < data.results.length; i++) {
65
+ const r = data.results[i];
66
+ const typeLabel = chalk.cyan(`[${r.contentType}]`);
67
+ const score = chalk.dim(`score: ${r.compositeScore.toFixed(3)}`);
68
+ const creator = r.creatorName
69
+ ? chalk.green(r.creatorName) + chalk.dim(` ${r.creatorAddress?.slice(0, 6) ?? ""}`)
70
+ : chalk.dim(r.creatorAddress?.slice(0, 10) ?? "unknown");
71
+ console.log(` ${chalk.bold(`${i + 1}.`)} ${typeLabel} ${chalk.white(r.title)} ${score}`);
72
+ console.log(` ${chalk.dim(r.snippet.slice(0, 120))}`);
73
+ console.log(` by ${creator}`);
74
+ console.log();
75
+ }
76
+ });
77
+ // ---- nookplot knowledge earnings ----
78
+ cmd
79
+ .command("earnings")
80
+ .description("View your attribution revenue from knowledge queries")
81
+ .option("--days <n>", "Lookback period in days", "30")
82
+ .option("--json", "Output raw JSON")
83
+ .action(async (opts) => {
84
+ const config = loadConfig();
85
+ const errors = validateConfig(config);
86
+ if (errors.length > 0) {
87
+ console.error(chalk.red("Configuration errors:"));
88
+ errors.forEach((e) => console.error(` - ${e}`));
89
+ process.exit(1);
90
+ }
91
+ const spinner = ora("Fetching earnings...").start();
92
+ const res = await gatewayRequest(config.gateway, "GET", `/v1/knowledge/earnings?days=${opts.days}`, { apiKey: config.apiKey });
93
+ if (isGatewayError(res)) {
94
+ spinner.fail(`Failed: ${res.error}`);
95
+ process.exit(1);
96
+ }
97
+ spinner.stop();
98
+ if (opts.json) {
99
+ console.log(JSON.stringify(res.data, null, 2));
100
+ return;
101
+ }
102
+ const data = res.data;
103
+ console.log(chalk.bold(`\n Knowledge Query Earnings (last ${opts.days} days)`));
104
+ console.log(` Total earned: ${chalk.green(`${data.totalEarned.toFixed(2)} credits`)}`);
105
+ console.log(` Attributions: ${data.attributionCount}\n`);
106
+ if (data.topContent.length > 0) {
107
+ console.log(chalk.bold(" Top earning content:"));
108
+ for (const item of data.topContent) {
109
+ console.log(` ${chalk.cyan(`[${item.contentType}]`)} ${item.contentId} — ${chalk.green(`${item.totalEarned.toFixed(2)} credits`)} (${item.queryCount} queries)`);
110
+ }
111
+ console.log();
112
+ }
113
+ });
114
+ // ---- nookplot knowledge topics ----
115
+ cmd
116
+ .command("topics")
117
+ .description("View your inferred query topic map")
118
+ .option("--json", "Output raw JSON")
119
+ .action(async (opts) => {
120
+ const config = loadConfig();
121
+ const errors = validateConfig(config);
122
+ if (errors.length > 0) {
123
+ console.error(chalk.red("Configuration errors:"));
124
+ errors.forEach((e) => console.error(` - ${e}`));
125
+ process.exit(1);
126
+ }
127
+ const spinner = ora("Fetching topics...").start();
128
+ const res = await gatewayRequest(config.gateway, "GET", "/v1/knowledge/topics", { apiKey: config.apiKey });
129
+ if (isGatewayError(res)) {
130
+ spinner.fail(`Failed: ${res.error}`);
131
+ process.exit(1);
132
+ }
133
+ spinner.stop();
134
+ if (opts.json) {
135
+ console.log(JSON.stringify(res.data, null, 2));
136
+ return;
137
+ }
138
+ const topics = res.data.topics;
139
+ console.log(chalk.bold(`\n Your Query Topics (${topics.length} topics)\n`));
140
+ if (topics.length === 0) {
141
+ console.log(chalk.yellow(" No query topics yet. Make some knowledge queries first.\n"));
142
+ return;
143
+ }
144
+ for (const t of topics) {
145
+ const bar = "█".repeat(Math.min(t.queryCount, 30));
146
+ console.log(` ${chalk.white(t.topic.padEnd(40))} ${chalk.cyan(bar)} ${t.queryCount}`);
147
+ }
148
+ console.log();
149
+ });
150
+ }
151
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../src/commands/knowledge.ts"],"names":[],"mappings":"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"}
@@ -324,9 +324,9 @@ function getAvailableActions(signalType) {
324
324
  case "new_post_in_community":
325
325
  case "post_reply":
326
326
  case "reply_to_own_post":
327
- return ["reply", "vote", "publish", "ignore"];
327
+ return ["reply", "post_reply", "vote", "publish", "ignore"];
328
328
  case "bounty":
329
- return ["claim", "reply", "ignore"];
329
+ return ["claim", "apply_bounty", "create_bounty", "reply", "ignore"];
330
330
  case "community_gap":
331
331
  return ["create_community", "ignore"];
332
332
  case "potential_friend":
@@ -334,9 +334,9 @@ function getAvailableActions(signalType) {
334
334
  case "attestation_opportunity":
335
335
  return ["attest", "send_dm", "ignore"];
336
336
  case "directive":
337
- return ["execute", "reply", "publish", "create_project", "commit_files", "assemble_team", "ignore"];
337
+ return ["execute", "reply", "publish", "create_project", "commit_files", "create_bounty", "create_bundle", "propose_collab", "assemble_team", "ignore"];
338
338
  case "collab_request":
339
- return ["add_collaborator", "reply", "ignore"];
339
+ return ["add_collaborator", "propose_collab", "reply", "ignore"];
340
340
  case "team_assembly_suggested":
341
341
  return ["assemble_team", "ignore"];
342
342
  case "team_invitation":
@@ -345,9 +345,9 @@ function getAvailableActions(signalType) {
345
345
  case "team_invitation_declined":
346
346
  return ["reply", "ignore"];
347
347
  case "service":
348
- return ["reply", "ignore"];
348
+ return ["reply", "update_service", "ignore"];
349
349
  case "time_to_post":
350
- return ["create_post", "ignore"];
350
+ return ["create_post", "create_bounty", "create_bundle", "ignore"];
351
351
  case "time_to_create_project":
352
352
  return ["create_project", "assemble_team", "ignore"];
353
353
  // Marketplace signals
@@ -380,8 +380,11 @@ function getAvailableActions(signalType) {
380
380
  return ["ignore"];
381
381
  // On-chain bounty lifecycle signals
382
382
  case "bounty_claimed":
383
+ return ["approve_bounty_work", "dispute_bounty_work", "unclaim_bounty", "ignore"];
383
384
  case "bounty_work_approved":
385
+ return ["ignore"];
384
386
  case "bounty_disputed":
387
+ return ["cancel_bounty", "ignore"];
385
388
  case "bounty_cancelled":
386
389
  return ["ignore"];
387
390
  case "bounty_claimer_approved":
@@ -394,6 +397,13 @@ function getAvailableActions(signalType) {
394
397
  * Execute an action the agent decided to take in response to a trigger.
395
398
  * The agent returns a JSON object with { action, ... } and we route it.
396
399
  */
400
+ /** Validate an ID before URL interpolation — must be numeric or UUID. */
401
+ function validateId(id, name) {
402
+ const s = String(id ?? "");
403
+ if (/^\d+$/.test(s) || /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s))
404
+ return s;
405
+ throw new Error(`Invalid ${name}: ${s}`);
406
+ }
397
407
  async function executeAgentAction(runtime, action, signal, json) {
398
408
  const target = action.to || signal.senderAddress || "";
399
409
  const content = action.content || "";
@@ -459,30 +469,27 @@ async function executeAgentAction(runtime, action, signal, json) {
459
469
  }
460
470
  break;
461
471
  case "apply_bounty": {
462
- const bountyId = (action.bountyId || signal.bountyId);
463
- if (bountyId) {
464
- const applyMsg = action.message || content || "";
465
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/apply`, { message: applyMsg });
466
- if (!json)
467
- console.log(chalk.dim(` [reactive] Applied to bounty: ${bountyId}`));
468
- }
472
+ const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
473
+ const applyMsg = action.message || content || "";
474
+ await runtime.connection.request("POST", `/v1/bounties/${bountyId}/apply`, { message: applyMsg });
475
+ if (!json)
476
+ console.log(chalk.dim(` [reactive] Applied to bounty: ${bountyId}`));
469
477
  break;
470
478
  }
471
479
  case "submit_bounty_work": {
472
- const bountyId = (action.bountyId || signal.bountyId);
473
- if (bountyId) {
474
- const workContent = content || action.workContent || "";
475
- const cids = action.deliverableCids || [];
476
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions`, { content: workContent, deliverableCids: cids });
477
- if (!json)
478
- console.log(chalk.dim(` [reactive] Work submitted for bounty: ${bountyId}`));
479
- }
480
+ const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
481
+ const workContent = content || action.workContent || "";
482
+ const cids = action.deliverableCids || [];
483
+ await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions`, { content: workContent, deliverableCids: cids });
484
+ if (!json)
485
+ console.log(chalk.dim(` [reactive] Work submitted for bounty: ${bountyId}`));
480
486
  break;
481
487
  }
482
488
  case "claim":
483
489
  case "claim_bounty": {
484
- const bountyId = (action.bountyId || signal.bountyId);
485
- if (bountyId) {
490
+ const rawBountyId = action.bountyId || signal.bountyId;
491
+ if (rawBountyId) {
492
+ const bountyId = validateId(rawBountyId, "bountyId");
486
493
  const result = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/claim`, {});
487
494
  if (!json)
488
495
  console.log(chalk.dim(` [reactive] Bounty claimed: ${bountyId} (tx: ${result.txHash})`));
@@ -494,9 +501,10 @@ async function executeAgentAction(runtime, action, signal, json) {
494
501
  break;
495
502
  }
496
503
  case "approve_bounty_claimer": {
497
- const bountyId = (action.bountyId || signal.bountyId);
504
+ const rawBountyId = action.bountyId || signal.bountyId;
498
505
  const claimer = action.claimer;
499
- if (bountyId && claimer) {
506
+ if (rawBountyId && claimer) {
507
+ const bountyId = validateId(rawBountyId, "bountyId");
500
508
  const result = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve-claimer`, { claimer });
501
509
  if (!json)
502
510
  console.log(chalk.dim(` [reactive] Bounty claimer approved: ${bountyId} → ${claimer} (tx: ${result.txHash})`));
@@ -508,33 +516,27 @@ async function executeAgentAction(runtime, action, signal, json) {
508
516
  break;
509
517
  }
510
518
  case "approve_bounty_application": {
511
- const bountyId = (action.bountyId || signal.bountyId);
512
- const applicationId = action.applicationId;
513
- if (bountyId && applicationId) {
514
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/approve`, {});
515
- if (!json)
516
- console.log(chalk.dim(` [reactive] Approved bounty application: ${applicationId} on bounty ${bountyId}`));
517
- }
519
+ const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
520
+ const applicationId = validateId(action.applicationId, "applicationId");
521
+ await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/approve`, {});
522
+ if (!json)
523
+ console.log(chalk.dim(` [reactive] Approved bounty application: ${applicationId} on bounty ${bountyId}`));
518
524
  break;
519
525
  }
520
526
  case "reject_bounty_application": {
521
- const bountyId = (action.bountyId || signal.bountyId);
522
- const applicationId = action.applicationId;
523
- if (bountyId && applicationId) {
524
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/reject`, {});
525
- if (!json)
526
- console.log(chalk.dim(` [reactive] Rejected bounty application: ${applicationId} on bounty ${bountyId}`));
527
- }
527
+ const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
528
+ const applicationId = validateId(action.applicationId, "applicationId");
529
+ await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/reject`, {});
530
+ if (!json)
531
+ console.log(chalk.dim(` [reactive] Rejected bounty application: ${applicationId} on bounty ${bountyId}`));
528
532
  break;
529
533
  }
530
534
  case "select_bounty_submission": {
531
- const bountyId = (action.bountyId || signal.bountyId);
532
- const submissionId = action.submissionId;
533
- if (bountyId && submissionId) {
534
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions/${submissionId}/select`, {});
535
- if (!json)
536
- console.log(chalk.dim(` [reactive] Selected bounty submission: ${submissionId} on bounty ${bountyId}`));
537
- }
535
+ const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
536
+ const submissionId = validateId(action.submissionId, "submissionId");
537
+ await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions/${submissionId}/select`, {});
538
+ if (!json)
539
+ console.log(chalk.dim(` [reactive] Selected bounty submission: ${submissionId} on bounty ${bountyId}`));
538
540
  break;
539
541
  }
540
542
  case "create_community": {
@@ -632,6 +634,20 @@ async function executeAgentAction(runtime, action, signal, json) {
632
634
  await runtime.inbox.send({ to: target, content });
633
635
  }
634
636
  break;
637
+ case "accept": {
638
+ const ch = action.channelId || signal.channelId || "";
639
+ const msg = content || "Accepted — I'll get started.";
640
+ if (ch)
641
+ await runtime.channels.send(ch, msg);
642
+ break;
643
+ }
644
+ case "acknowledge": {
645
+ const ch = action.channelId || signal.channelId || "";
646
+ const msg = content || "Got it, thanks for the mention!";
647
+ if (ch)
648
+ await runtime.channels.send(ch, msg);
649
+ break;
650
+ }
635
651
  case "deploy_preview": {
636
652
  const projId = (action.projectId || signal.projectId);
637
653
  if (projId) {
@@ -854,6 +870,150 @@ async function executeAgentAction(runtime, action, signal, json) {
854
870
  }
855
871
  break;
856
872
  }
873
+ case "create_bounty": {
874
+ const payload = action;
875
+ const title = payload?.title;
876
+ const description = payload?.description ?? content ?? "";
877
+ const community = payload?.community ?? "";
878
+ const deadline = payload?.deadline ?? Math.floor(Date.now() / 1000) + 604800; // 7 days
879
+ const tokenRewardAmount = payload?.tokenRewardAmount ?? "0";
880
+ if (!title)
881
+ throw new Error("create_bounty requires title");
882
+ const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bounty", {
883
+ title, description, community, deadline, tokenRewardAmount,
884
+ });
885
+ if (!json)
886
+ console.log(chalk.green(` [reactive] Created bounty "${title}" (tx: ${relay.txHash})`));
887
+ break;
888
+ }
889
+ case "post_reply": {
890
+ const parentCid = (action.parentCid ?? action.sourceId ?? "");
891
+ if (!parentCid)
892
+ throw new Error("post_reply requires parentCid");
893
+ const replyContent = (content ?? action.body ?? "");
894
+ const replyCommunity = (action.community ?? "");
895
+ await runtime.memory.publishComment({ parentCid, body: replyContent, community: replyCommunity });
896
+ break;
897
+ }
898
+ case "propose_collab": {
899
+ const collabTarget = (action.targetAddress ?? action.recipientAddress ?? target);
900
+ if (!collabTarget)
901
+ throw new Error("propose_collab requires targetAddress");
902
+ const msg = content || "I'd like to collaborate with you!";
903
+ await runtime.inbox.send({ to: collabTarget, content: msg });
904
+ break;
905
+ }
906
+ case "create_bundle": {
907
+ const bundleTitle = action.title;
908
+ if (!bundleTitle)
909
+ throw new Error("create_bundle requires title");
910
+ const bundleDesc = content || action.description || "";
911
+ const domain = action.domain || "";
912
+ const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bundle", {
913
+ title: bundleTitle, description: bundleDesc, domain,
914
+ });
915
+ if (!json)
916
+ console.log(chalk.green(` [reactive] Created bundle "${bundleTitle}" (tx: ${relay.txHash})`));
917
+ break;
918
+ }
919
+ case "update_service": {
920
+ const listingId = action.listingId;
921
+ if (!listingId)
922
+ throw new Error("update_service requires listingId");
923
+ const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/update", {
924
+ listingId, ...action,
925
+ });
926
+ if (!json)
927
+ console.log(chalk.green(` [reactive] Updated service listing #${listingId} (tx: ${relay.txHash})`));
928
+ break;
929
+ }
930
+ case "approve_bounty_work": {
931
+ const bountyId = (action.bountyId || signal.bountyId);
932
+ if (!bountyId)
933
+ throw new Error("approve_bounty_work requires bountyId");
934
+ const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve`, {});
935
+ if (!json)
936
+ console.log(chalk.green(` [reactive] Approved bounty work: ${bountyId} (tx: ${relay.txHash})`));
937
+ break;
938
+ }
939
+ case "dispute_bounty_work": {
940
+ const bountyId = (action.bountyId || signal.bountyId);
941
+ if (!bountyId)
942
+ throw new Error("dispute_bounty_work requires bountyId");
943
+ const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/dispute`, {});
944
+ if (!json)
945
+ console.log(chalk.green(` [reactive] Disputed bounty work: ${bountyId} (tx: ${relay.txHash})`));
946
+ break;
947
+ }
948
+ case "cancel_bounty": {
949
+ const bountyId = (action.bountyId || signal.bountyId);
950
+ if (!bountyId)
951
+ throw new Error("cancel_bounty requires bountyId");
952
+ const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/cancel`, {});
953
+ if (!json)
954
+ console.log(chalk.green(` [reactive] Cancelled bounty: ${bountyId} (tx: ${relay.txHash})`));
955
+ break;
956
+ }
957
+ case "unclaim_bounty": {
958
+ const bountyId = (action.bountyId || signal.bountyId);
959
+ if (!bountyId)
960
+ throw new Error("unclaim_bounty requires bountyId");
961
+ const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/unclaim`, {});
962
+ if (!json)
963
+ console.log(chalk.green(` [reactive] Unclaimed bounty: ${bountyId} (tx: ${relay.txHash})`));
964
+ break;
965
+ }
966
+ case "grant": {
967
+ const projId = action.projectId;
968
+ const bountyId = (action.bountyId || signal.bountyId);
969
+ const reqId = action.requestId;
970
+ if (!projId || !bountyId || !reqId)
971
+ throw new Error("grant requires projectId, bountyId, requestId");
972
+ await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bountyId}/grant-access`, { requestId: reqId });
973
+ if (!json)
974
+ console.log(chalk.green(` [reactive] Granted bounty access: ${bountyId} request ${reqId}`));
975
+ break;
976
+ }
977
+ case "deny": {
978
+ const projId = action.projectId;
979
+ const bountyId = (action.bountyId || signal.bountyId);
980
+ const reqId = action.requestId;
981
+ if (!projId || !bountyId || !reqId)
982
+ throw new Error("deny requires projectId, bountyId, requestId");
983
+ await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bountyId}/deny-access`, { requestId: reqId });
984
+ if (!json)
985
+ console.log(chalk.green(` [reactive] Denied bounty access: ${bountyId} request ${reqId}`));
986
+ break;
987
+ }
988
+ case "workspace_create": {
989
+ const wsName = (action.name || content);
990
+ if (wsName) {
991
+ const ws = await runtime.workspaces.create({ name: wsName, description: action.description });
992
+ if (!json)
993
+ console.log(chalk.green(` [reactive] Created workspace: ${ws.id}`));
994
+ }
995
+ break;
996
+ }
997
+ case "workspace_set": {
998
+ const wsId = action.workspaceId;
999
+ const wsKey = action.key;
1000
+ const wsVal = action.value ?? content;
1001
+ if (wsId && wsKey) {
1002
+ await runtime.workspaces.setState(wsId, wsKey, wsVal);
1003
+ if (!json)
1004
+ console.log(chalk.green(` [reactive] Set ${wsKey} in workspace ${wsId}`));
1005
+ }
1006
+ break;
1007
+ }
1008
+ case "workspace_snapshot": {
1009
+ const snapWsId = action.workspaceId;
1010
+ if (snapWsId) {
1011
+ await runtime.workspaces.createSnapshot(snapWsId, action.label);
1012
+ if (!json)
1013
+ console.log(chalk.green(` [reactive] Created snapshot in workspace ${snapWsId}`));
1014
+ }
1015
+ break;
1016
+ }
857
1017
  case "ignore":
858
1018
  break;
859
1019
  default: