@stamn/stamn-plugin 0.1.0-alpha.20 → 0.1.0-alpha.22
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/index.js +241 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/stamn/SKILL.md +25 -3
package/dist/index.js
CHANGED
|
@@ -4764,7 +4764,7 @@ var StamnClient = class {
|
|
|
4764
4764
|
return Math.random() * capped;
|
|
4765
4765
|
}
|
|
4766
4766
|
sleep(ms) {
|
|
4767
|
-
return new Promise((
|
|
4767
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
4768
4768
|
}
|
|
4769
4769
|
async parseErrorResponse(res) {
|
|
4770
4770
|
const body = await res.text();
|
|
@@ -5337,6 +5337,124 @@ function requestService(ws) {
|
|
|
5337
5337
|
}
|
|
5338
5338
|
};
|
|
5339
5339
|
}
|
|
5340
|
+
function createServiceListing(ws, agentId) {
|
|
5341
|
+
return {
|
|
5342
|
+
name: "stamn_create_service_listing",
|
|
5343
|
+
description: "Create a persistent service listing on the marketplace. This is your storefront \u2014 buyers browse these listings and purchase your services. Include a compelling description, fair price, and usage examples.",
|
|
5344
|
+
parameters: {
|
|
5345
|
+
type: "object",
|
|
5346
|
+
properties: {
|
|
5347
|
+
serviceTag: param("string", "Unique identifier, lowercase with underscores (e.g. 'code_review', 'summarize')."),
|
|
5348
|
+
name: param("string", "Display name (e.g. 'Code Review', 'Text Summarization')."),
|
|
5349
|
+
description: param("string", "Short description of what the service does (1-2 sentences)."),
|
|
5350
|
+
priceCents: param("string", 'Price in USDC cents (e.g. "100" = $1.00).'),
|
|
5351
|
+
category: param("string", "Service category.", {
|
|
5352
|
+
enum: ["coding", "writing", "research", "analysis", "creative", "data", "other"]
|
|
5353
|
+
}),
|
|
5354
|
+
longDescription: param("string", "Detailed description shown on the service detail page. Markdown supported."),
|
|
5355
|
+
inputDescription: param("string", "What input the service expects from the buyer."),
|
|
5356
|
+
outputDescription: param("string", "What output the service produces."),
|
|
5357
|
+
usageExamples: param("string", 'JSON array of {input, output} example pairs, e.g. [{"input":"Review this code...","output":"Found 3 issues..."}]'),
|
|
5358
|
+
tags: param("string", 'Comma-separated tags for discovery (e.g. "python, fast, automated").'),
|
|
5359
|
+
rateLimitPerHour: param("string", "Max requests per hour (optional)."),
|
|
5360
|
+
estimatedDurationSeconds: param("string", "Estimated time to complete in seconds (optional).")
|
|
5361
|
+
},
|
|
5362
|
+
required: ["serviceTag", "name", "description", "priceCents"]
|
|
5363
|
+
},
|
|
5364
|
+
execute: (args) => {
|
|
5365
|
+
const payload = {
|
|
5366
|
+
participantId: agentId,
|
|
5367
|
+
serviceTag: args.serviceTag,
|
|
5368
|
+
name: args.name,
|
|
5369
|
+
description: args.description,
|
|
5370
|
+
priceCents: Number(args.priceCents)
|
|
5371
|
+
};
|
|
5372
|
+
if (args.category) payload.category = args.category;
|
|
5373
|
+
if (args.longDescription) payload.longDescription = args.longDescription;
|
|
5374
|
+
if (args.inputDescription) payload.inputDescription = args.inputDescription;
|
|
5375
|
+
if (args.outputDescription) payload.outputDescription = args.outputDescription;
|
|
5376
|
+
if (args.tags) {
|
|
5377
|
+
payload.tags = args.tags.split(",").map((t2) => t2.trim()).filter(Boolean);
|
|
5378
|
+
}
|
|
5379
|
+
if (args.rateLimitPerHour) payload.rateLimitPerHour = Number(args.rateLimitPerHour);
|
|
5380
|
+
if (args.estimatedDurationSeconds) payload.estimatedDurationSeconds = Number(args.estimatedDurationSeconds);
|
|
5381
|
+
if (args.usageExamples) {
|
|
5382
|
+
try {
|
|
5383
|
+
payload.usageExamples = JSON.parse(args.usageExamples);
|
|
5384
|
+
} catch {
|
|
5385
|
+
return text("Error: usageExamples must be valid JSON array of {input, output} objects.");
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
ws.send("participant:service_listing_create", payload);
|
|
5389
|
+
return text(`Service listing "${args.serviceTag}" creation sent. Check events for confirmation.`);
|
|
5390
|
+
}
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
function updateServiceListing(ws) {
|
|
5394
|
+
return {
|
|
5395
|
+
name: "stamn_update_service_listing",
|
|
5396
|
+
description: "Update an existing marketplace service listing. Use stamn_list_service_listings first to get the serviceId.",
|
|
5397
|
+
parameters: {
|
|
5398
|
+
type: "object",
|
|
5399
|
+
properties: {
|
|
5400
|
+
serviceId: param("string", "The service listing ID to update."),
|
|
5401
|
+
name: param("string", "New display name."),
|
|
5402
|
+
description: param("string", "New short description."),
|
|
5403
|
+
priceCents: param("string", "New price in USDC cents."),
|
|
5404
|
+
isActive: param("string", 'Set to "true" or "false" to enable/disable the listing.'),
|
|
5405
|
+
category: param("string", "Service category.", {
|
|
5406
|
+
enum: ["coding", "writing", "research", "analysis", "creative", "data", "other"]
|
|
5407
|
+
}),
|
|
5408
|
+
longDescription: param("string", "Detailed description (markdown supported)."),
|
|
5409
|
+
inputDescription: param("string", "What input the service expects."),
|
|
5410
|
+
outputDescription: param("string", "What output the service produces."),
|
|
5411
|
+
usageExamples: param("string", "JSON array of {input, output} example pairs."),
|
|
5412
|
+
tags: param("string", "Comma-separated tags."),
|
|
5413
|
+
rateLimitPerHour: param("string", "Max requests per hour."),
|
|
5414
|
+
estimatedDurationSeconds: param("string", "Estimated completion time in seconds.")
|
|
5415
|
+
},
|
|
5416
|
+
required: ["serviceId"]
|
|
5417
|
+
},
|
|
5418
|
+
execute: (args) => {
|
|
5419
|
+
const payload = {
|
|
5420
|
+
serviceId: args.serviceId
|
|
5421
|
+
};
|
|
5422
|
+
if (args.name) payload.name = args.name;
|
|
5423
|
+
if (args.description) payload.description = args.description;
|
|
5424
|
+
if (args.priceCents) payload.priceCents = Number(args.priceCents);
|
|
5425
|
+
if (args.isActive !== void 0) payload.isActive = args.isActive === "true";
|
|
5426
|
+
if (args.category) payload.category = args.category;
|
|
5427
|
+
if (args.longDescription) payload.longDescription = args.longDescription;
|
|
5428
|
+
if (args.inputDescription) payload.inputDescription = args.inputDescription;
|
|
5429
|
+
if (args.outputDescription) payload.outputDescription = args.outputDescription;
|
|
5430
|
+
if (args.tags) {
|
|
5431
|
+
payload.tags = args.tags.split(",").map((t2) => t2.trim()).filter(Boolean);
|
|
5432
|
+
}
|
|
5433
|
+
if (args.rateLimitPerHour) payload.rateLimitPerHour = Number(args.rateLimitPerHour);
|
|
5434
|
+
if (args.estimatedDurationSeconds) payload.estimatedDurationSeconds = Number(args.estimatedDurationSeconds);
|
|
5435
|
+
if (args.usageExamples) {
|
|
5436
|
+
try {
|
|
5437
|
+
payload.usageExamples = JSON.parse(args.usageExamples);
|
|
5438
|
+
} catch {
|
|
5439
|
+
return text("Error: usageExamples must be valid JSON array of {input, output} objects.");
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
ws.send("participant:service_listing_update", payload);
|
|
5443
|
+
return text(`Service listing update sent. Check events for confirmation.`);
|
|
5444
|
+
}
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5447
|
+
function listServiceListings(ws) {
|
|
5448
|
+
return {
|
|
5449
|
+
name: "stamn_list_service_listings",
|
|
5450
|
+
description: "List all your marketplace service listings (both active and inactive). Returns listing IDs, names, prices, and status.",
|
|
5451
|
+
parameters: NO_PARAMS,
|
|
5452
|
+
execute: () => {
|
|
5453
|
+
ws.send("participant:service_listing_list", {});
|
|
5454
|
+
return text("Service listing request sent. Check events for the list.");
|
|
5455
|
+
}
|
|
5456
|
+
};
|
|
5457
|
+
}
|
|
5340
5458
|
function chatReply(ws, agentId) {
|
|
5341
5459
|
return {
|
|
5342
5460
|
name: "stamn_chat_reply",
|
|
@@ -5405,6 +5523,9 @@ function allTools(ws, agentId) {
|
|
|
5405
5523
|
registerService(ws, agentId),
|
|
5406
5524
|
respondToService(ws),
|
|
5407
5525
|
requestService(ws),
|
|
5526
|
+
createServiceListing(ws, agentId),
|
|
5527
|
+
updateServiceListing(ws),
|
|
5528
|
+
listServiceListings(ws),
|
|
5408
5529
|
chatReply(ws, agentId),
|
|
5409
5530
|
spend(ws)
|
|
5410
5531
|
];
|
|
@@ -5459,13 +5580,16 @@ function readLogs(opts) {
|
|
|
5459
5580
|
try {
|
|
5460
5581
|
stat = statSync(file);
|
|
5461
5582
|
} catch {
|
|
5462
|
-
return { lines: [], cursor: 0, size: 0, file, truncated: false, reset: false };
|
|
5583
|
+
return { lines: [], cursor: 0, startCursor: 0, size: 0, file, truncated: false, reset: false };
|
|
5463
5584
|
}
|
|
5464
5585
|
const size = stat.size;
|
|
5465
5586
|
const reset = cursor > size;
|
|
5466
5587
|
if (reset) cursor = 0;
|
|
5588
|
+
if (opts.fromEnd) {
|
|
5589
|
+
cursor = Math.max(0, size - maxBytes);
|
|
5590
|
+
}
|
|
5467
5591
|
if (cursor >= size) {
|
|
5468
|
-
return { lines: [], cursor, size, file, truncated: false, reset };
|
|
5592
|
+
return { lines: [], cursor, startCursor: cursor, size, file, truncated: false, reset };
|
|
5469
5593
|
}
|
|
5470
5594
|
const bytesToRead = Math.min(maxBytes, size - cursor);
|
|
5471
5595
|
const buffer = Buffer.alloc(bytesToRead);
|
|
@@ -5500,6 +5624,7 @@ function readLogs(opts) {
|
|
|
5500
5624
|
return {
|
|
5501
5625
|
lines,
|
|
5502
5626
|
cursor: cursor + actualBytesConsumed,
|
|
5627
|
+
startCursor: cursor,
|
|
5503
5628
|
size,
|
|
5504
5629
|
file,
|
|
5505
5630
|
truncated: truncated || !atEof,
|
|
@@ -5507,6 +5632,57 @@ function readLogs(opts) {
|
|
|
5507
5632
|
};
|
|
5508
5633
|
}
|
|
5509
5634
|
|
|
5635
|
+
// src/workspace-files.ts
|
|
5636
|
+
import { readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync4, statSync as statSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
5637
|
+
import { join as join6, resolve, relative, dirname as dirname2 } from "path";
|
|
5638
|
+
import { homedir as homedir3 } from "os";
|
|
5639
|
+
var WORKSPACE_DIR = join6(homedir3(), ".openclaw", "workspace");
|
|
5640
|
+
function assertWithinWorkspace(relativePath) {
|
|
5641
|
+
const full = resolve(WORKSPACE_DIR, relativePath);
|
|
5642
|
+
if (!full.startsWith(WORKSPACE_DIR + "/") && full !== WORKSPACE_DIR) {
|
|
5643
|
+
throw new Error("Path outside workspace");
|
|
5644
|
+
}
|
|
5645
|
+
return full;
|
|
5646
|
+
}
|
|
5647
|
+
function walkDir(dir, base) {
|
|
5648
|
+
const results = [];
|
|
5649
|
+
let entries;
|
|
5650
|
+
try {
|
|
5651
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
5652
|
+
} catch {
|
|
5653
|
+
return results;
|
|
5654
|
+
}
|
|
5655
|
+
for (const entry of entries) {
|
|
5656
|
+
const fullPath = join6(dir, entry.name);
|
|
5657
|
+
if (entry.isDirectory()) {
|
|
5658
|
+
results.push(...walkDir(fullPath, base));
|
|
5659
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
5660
|
+
const stat = statSync2(fullPath);
|
|
5661
|
+
results.push({
|
|
5662
|
+
path: relative(base, fullPath),
|
|
5663
|
+
size: stat.size,
|
|
5664
|
+
modifiedAt: stat.mtime.toISOString()
|
|
5665
|
+
});
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
return results;
|
|
5669
|
+
}
|
|
5670
|
+
function listWorkspaceFiles() {
|
|
5671
|
+
return walkDir(WORKSPACE_DIR, WORKSPACE_DIR);
|
|
5672
|
+
}
|
|
5673
|
+
function readWorkspaceFile(relativePath) {
|
|
5674
|
+
const full = assertWithinWorkspace(relativePath);
|
|
5675
|
+
const content = readFileSync3(full, "utf-8");
|
|
5676
|
+
const stat = statSync2(full);
|
|
5677
|
+
return { path: relativePath, content, size: stat.size };
|
|
5678
|
+
}
|
|
5679
|
+
function writeWorkspaceFile(relativePath, content) {
|
|
5680
|
+
const full = assertWithinWorkspace(relativePath);
|
|
5681
|
+
mkdirSync3(dirname2(full), { recursive: true });
|
|
5682
|
+
writeFileSync4(full, content, "utf-8");
|
|
5683
|
+
return { path: relativePath, written: true };
|
|
5684
|
+
}
|
|
5685
|
+
|
|
5510
5686
|
// src/ws-service.ts
|
|
5511
5687
|
var MAX_EVENT_BUFFER_SIZE = 200;
|
|
5512
5688
|
var BASE_RECONNECT_DELAY_MS = 1e3;
|
|
@@ -5678,6 +5854,18 @@ var StamnWsService = class {
|
|
|
5678
5854
|
this.handleRequestLogs(payload.params);
|
|
5679
5855
|
return;
|
|
5680
5856
|
}
|
|
5857
|
+
if (payload.command === "list_files") {
|
|
5858
|
+
this.handleListFiles(payload.params);
|
|
5859
|
+
return;
|
|
5860
|
+
}
|
|
5861
|
+
if (payload.command === "read_file") {
|
|
5862
|
+
this.handleReadFile(payload.params);
|
|
5863
|
+
return;
|
|
5864
|
+
}
|
|
5865
|
+
if (payload.command === "write_file") {
|
|
5866
|
+
this.handleWriteFile(payload.params);
|
|
5867
|
+
return;
|
|
5868
|
+
}
|
|
5681
5869
|
this.logger.info(`Command received: ${payload.command} (${payload.commandId})`);
|
|
5682
5870
|
if (payload.command === "update_plugin") {
|
|
5683
5871
|
this.handleUpdatePlugin();
|
|
@@ -5702,7 +5890,8 @@ var StamnWsService = class {
|
|
|
5702
5890
|
const result = readLogs({
|
|
5703
5891
|
cursor: params.cursor,
|
|
5704
5892
|
limit: params.limit,
|
|
5705
|
-
maxBytes: params.maxBytes
|
|
5893
|
+
maxBytes: params.maxBytes,
|
|
5894
|
+
fromEnd: params.fromEnd
|
|
5706
5895
|
});
|
|
5707
5896
|
this.sendMessage("participant:log_response", {
|
|
5708
5897
|
requestId: params.requestId,
|
|
@@ -5722,6 +5911,54 @@ var StamnWsService = class {
|
|
|
5722
5911
|
});
|
|
5723
5912
|
}
|
|
5724
5913
|
}
|
|
5914
|
+
handleListFiles(params) {
|
|
5915
|
+
try {
|
|
5916
|
+
const files = listWorkspaceFiles();
|
|
5917
|
+
this.sendMessage("participant:file_response", {
|
|
5918
|
+
requestId: params.requestId,
|
|
5919
|
+
files
|
|
5920
|
+
});
|
|
5921
|
+
} catch (err) {
|
|
5922
|
+
this.sendMessage("participant:file_response", {
|
|
5923
|
+
requestId: params.requestId,
|
|
5924
|
+
files: [],
|
|
5925
|
+
error: err.message
|
|
5926
|
+
});
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
handleReadFile(params) {
|
|
5930
|
+
try {
|
|
5931
|
+
const result = readWorkspaceFile(params.path);
|
|
5932
|
+
this.sendMessage("participant:file_response", {
|
|
5933
|
+
requestId: params.requestId,
|
|
5934
|
+
...result
|
|
5935
|
+
});
|
|
5936
|
+
} catch (err) {
|
|
5937
|
+
this.sendMessage("participant:file_response", {
|
|
5938
|
+
requestId: params.requestId,
|
|
5939
|
+
path: params.path,
|
|
5940
|
+
content: "",
|
|
5941
|
+
size: 0,
|
|
5942
|
+
error: err.message
|
|
5943
|
+
});
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
handleWriteFile(params) {
|
|
5947
|
+
try {
|
|
5948
|
+
const result = writeWorkspaceFile(params.path, params.content);
|
|
5949
|
+
this.sendMessage("participant:file_response", {
|
|
5950
|
+
requestId: params.requestId,
|
|
5951
|
+
...result
|
|
5952
|
+
});
|
|
5953
|
+
} catch (err) {
|
|
5954
|
+
this.sendMessage("participant:file_response", {
|
|
5955
|
+
requestId: params.requestId,
|
|
5956
|
+
path: params.path,
|
|
5957
|
+
written: false,
|
|
5958
|
+
error: err.message
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5725
5962
|
onAuthError(payload) {
|
|
5726
5963
|
this.authFailed = true;
|
|
5727
5964
|
this.logger.error(`Authentication failed: ${payload.reason}`);
|