@genspark/cli 1.5.1 → 1.5.2
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/README.md +22 -14
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +107 -0
- package/dist/client.js.map +1 -1
- package/dist/commands/aidrive-upload.d.ts +10 -7
- package/dist/commands/aidrive-upload.d.ts.map +1 -1
- package/dist/commands/aidrive-upload.js +35 -8
- package/dist/commands/aidrive-upload.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +166 -19
- package/dist/index.js.map +1 -1
- package/dist/localFiles.d.ts +10 -0
- package/dist/localFiles.d.ts.map +1 -1
- package/dist/localFiles.js +17 -0
- package/dist/localFiles.js.map +1 -1
- package/dist/mesh/manifest.d.ts +4 -4
- package/dist/mesh/manifest.d.ts.map +1 -1
- package/dist/mesh/manifest.js +9 -9
- package/dist/mesh/manifest.js.map +1 -1
- package/dist/task-shim.d.ts +13 -0
- package/dist/task-shim.d.ts.map +1 -0
- package/dist/task-shim.js +40 -0
- package/dist/task-shim.js.map +1 -0
- package/docs/skills.md +7 -4
- package/package.json +1 -1
- package/skills/gsk-acp-agents/SKILL.md +2 -2
- package/skills/gsk-create-task/SKILL.md +7 -40
- package/skills/gsk-github/SKILL.md +4 -0
- package/skills/gsk-gmail/SKILL.md +4 -0
- package/skills/gsk-google-calendar/SKILL.md +5 -0
- package/skills/gsk-google-chat/SKILL.md +6 -2
- package/skills/gsk-google-docs/SKILL.md +4 -0
- package/skills/gsk-google-drive/SKILL.md +4 -0
- package/skills/gsk-google-sheets/SKILL.md +4 -0
- package/skills/gsk-google-slides/SKILL.md +4 -0
- package/skills/gsk-image-generation/SKILL.md +1 -1
- package/skills/gsk-microsoft-teams/SKILL.md +18 -5
- package/skills/gsk-notion/SKILL.md +4 -0
- package/skills/gsk-onedrive/SKILL.md +4 -0
- package/skills/gsk-outlook-calendar/SKILL.md +5 -0
- package/skills/gsk-outlook-email/SKILL.md +4 -0
- package/skills/gsk-shared/SKILL.md +5 -5
- package/skills/gsk-sharepoint/SKILL.md +4 -0
- package/skills/gsk-slack/SKILL.md +7 -1
- package/skills/gsk-task-artifacts/SKILL.md +35 -0
- package/skills/gsk-task-continue/SKILL.md +13 -10
- package/skills/gsk-task-info/SKILL.md +36 -0
- package/skills/gsk-task-status/SKILL.md +6 -6
- package/skills/gsk-task-stop/SKILL.md +35 -0
- package/skills/gsk-video-generation/SKILL.md +8 -5
package/dist/index.js
CHANGED
|
@@ -27,13 +27,14 @@ import * as pathModule from 'path';
|
|
|
27
27
|
import { createRequire } from 'module';
|
|
28
28
|
import { spawn } from 'child_process';
|
|
29
29
|
import { ApiClient, isAuthError, unauthenticatedRequest, } from './client.js';
|
|
30
|
-
import { classifyFileArg, awaitLocalFileReady, decideAfterWait, localFileNotReadyError, } from './localFiles.js';
|
|
30
|
+
import { classifyFileArg, awaitLocalFileReady, decideAfterWait, localFileNotReadyError, passthroughWarning, } from './localFiles.js';
|
|
31
31
|
import { setDebugEnabled, setOutputFormat, debug, info, warn, error as logError, output, } from './logger.js';
|
|
32
32
|
import { loadConfigFile, getConfigPath, loadToolsCache, normalizeBaseUrl, saveToolsCache, setConfigPathOverride, updateConfigFile, } from './config.js';
|
|
33
33
|
import { checkForUpdates } from './updater.js';
|
|
34
|
+
import { shimLegacyTaskInvocation } from './task-shim.js';
|
|
34
35
|
import { getSandboxRuntime } from './runtime.js';
|
|
35
36
|
import { registerDesignCommand } from './commands/design.js';
|
|
36
|
-
import {
|
|
37
|
+
import { collectUploadFiles, pickExistingUploadOperand, } from './commands/aidrive-upload.js';
|
|
37
38
|
import { parseLastSeenIndex, eventStdoutLine } from './commands/chat-events.js';
|
|
38
39
|
import { mediaItemsKeyFor, mediaSummaryLines } from './mediaSummary.js';
|
|
39
40
|
import { registerMeshCommand, getMeshInvocation, runMesh, } from './commands/mesh.js';
|
|
@@ -351,7 +352,7 @@ async function uploadLocalFile(filePath, client) {
|
|
|
351
352
|
*
|
|
352
353
|
* This avoids the roundabout blob-upload + download_file two-step approach.
|
|
353
354
|
*/
|
|
354
|
-
async function uploadToAiDrive(filePath, uploadPath, override = false) {
|
|
355
|
+
async function uploadToAiDrive(filePath, uploadPath, override = false, workspace = 'personal') {
|
|
355
356
|
const fileName = pathModule.basename(filePath);
|
|
356
357
|
const ext = pathModule.extname(filePath).toLowerCase();
|
|
357
358
|
const contentType = CONTENT_TYPE_MAP[ext] || 'application/octet-stream';
|
|
@@ -359,7 +360,7 @@ async function uploadToAiDrive(filePath, uploadPath, override = false) {
|
|
|
359
360
|
info(`Uploading ${fileName} (${formatFileSize(fileSize)}, ${contentType}) directly to AI Drive...`);
|
|
360
361
|
const globalOpts = getGlobalOptions();
|
|
361
362
|
const baseUrl = globalOpts.baseUrl.replace(/\/$/, '');
|
|
362
|
-
const uploadUrl = `${baseUrl}/api/tool_cli/aidrive/upload?upload_path=${encodeURIComponent(uploadPath)}${override ? '&override=true' : ''}`;
|
|
363
|
+
const uploadUrl = `${baseUrl}/api/tool_cli/aidrive/upload?upload_path=${encodeURIComponent(uploadPath)}&workspace=${encodeURIComponent(workspace)}${override ? '&override=true' : ''}`;
|
|
363
364
|
const headers = { 'Content-Type': contentType };
|
|
364
365
|
if (globalOpts.apiKey)
|
|
365
366
|
headers['X-Api-Key'] = globalOpts.apiKey;
|
|
@@ -417,7 +418,9 @@ async function resolveFileArg(value, client) {
|
|
|
417
418
|
case 'passthrough':
|
|
418
419
|
// No local evidence beyond the parent directory: let the backend try
|
|
419
420
|
// it as an AI Drive path (its failure mode is a per-URL actionable
|
|
420
|
-
// error, not a generic one).
|
|
421
|
+
// error, not a generic one). Warn first so a failed producer in the
|
|
422
|
+
// same batch is diagnosable from this call's own output.
|
|
423
|
+
warn(passthroughWarning(localPath, readiness));
|
|
421
424
|
return value;
|
|
422
425
|
}
|
|
423
426
|
}
|
|
@@ -754,9 +757,17 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
754
757
|
if (outputFileKeys.length > 0) {
|
|
755
758
|
cmd.option('-o, --output-file <path>', 'Download the generated file to a local path');
|
|
756
759
|
}
|
|
760
|
+
// task ask (task_continue) shares the async-first submit → --follow
|
|
761
|
+
// upgrades the stub into a live SSE follow, same as task create.
|
|
762
|
+
// (Named --follow, not --attach: tools with an attachments array param
|
|
763
|
+
// already own --attach as a file alias.)
|
|
764
|
+
if (tool.name === 'task_continue') {
|
|
765
|
+
cmd.option('--follow', 'After the async submit, follow the durable run live (SSE) and exit with the terminal result', false);
|
|
766
|
+
}
|
|
757
767
|
// For create_task, add --acp flag to enter ACP stdio bridge mode
|
|
758
768
|
if (tool.name === 'create_task') {
|
|
759
769
|
cmd.option('--acp', 'Start as ACP (Agent Client Protocol) stdio agent instead of one-shot execution', false);
|
|
770
|
+
cmd.option('--follow', 'After the async submit, follow the durable run live (SSE) and exit with the terminal result', false);
|
|
760
771
|
cmd.option('-o, --output-file <path>', 'Export the artifact (pptx/docx/xlsx) to a local file after task completes');
|
|
761
772
|
cmd.option('--session-id <id>', 'ACP session ID (used with get-project)');
|
|
762
773
|
cmd.option('--file <values...>', 'Import local files (Design: structured context; other tasks: CSV/Excel file_urls)');
|
|
@@ -774,6 +785,9 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
774
785
|
}
|
|
775
786
|
// For the aidrive tool, add client-side options used with --local_file upload
|
|
776
787
|
if (tool.name === 'aidrive') {
|
|
788
|
+
if (!Object.hasOwn(props, 'workspace')) {
|
|
789
|
+
cmd.option('--workspace <value>', 'AI Drive workspace: personal or public_brain');
|
|
790
|
+
}
|
|
777
791
|
cmd.option('--local_file <path>', 'Local file path to upload to AI Drive (supports files >5 MB; alternative to --file_content)');
|
|
778
792
|
cmd.option('--override', 'Overwrite an existing file at the destination path (used with --local_file)', false);
|
|
779
793
|
}
|
|
@@ -908,6 +922,11 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
908
922
|
const outputFilePath = opts.outputFile;
|
|
909
923
|
delete opts.outputFile;
|
|
910
924
|
delete opts.acp; // ACP flag is client-side only
|
|
925
|
+
// -o exports an artifact of the FINISHED project — an async submit
|
|
926
|
+
// stub has nothing to export yet, so an export request implies the
|
|
927
|
+
// live follow.
|
|
928
|
+
const attachTask = !!opts.follow || !!outputFilePath;
|
|
929
|
+
delete opts.follow; // client-side only
|
|
911
930
|
delete opts.sessionId; // get-project flag is client-side only
|
|
912
931
|
const argsFilePath = opts.argsFile;
|
|
913
932
|
delete opts.argsFile; // client-side only; merged below
|
|
@@ -1115,7 +1134,7 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
1115
1134
|
const operandCandidates = primaryArgValue !== undefined && primaryArgValue === args.action
|
|
1116
1135
|
? cmd.args.slice(1)
|
|
1117
1136
|
: cmd.args;
|
|
1118
|
-
const pathOperand =
|
|
1137
|
+
const pathOperand = pickExistingUploadOperand(operandCandidates);
|
|
1119
1138
|
if (pathOperand) {
|
|
1120
1139
|
opts.local_file = pathOperand;
|
|
1121
1140
|
}
|
|
@@ -1135,6 +1154,7 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
1135
1154
|
opts.local_file) {
|
|
1136
1155
|
const localFilePath = opts.local_file;
|
|
1137
1156
|
const override = !!opts.override;
|
|
1157
|
+
const workspace = args.workspace || 'personal';
|
|
1138
1158
|
if (!fs.existsSync(localFilePath)) {
|
|
1139
1159
|
logError(`File not found: ${localFilePath}`);
|
|
1140
1160
|
process.exit(1);
|
|
@@ -1146,9 +1166,35 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
1146
1166
|
const uploadPath = rawUploadPath.startsWith('/')
|
|
1147
1167
|
? rawUploadPath
|
|
1148
1168
|
: `/${rawUploadPath}`;
|
|
1149
|
-
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1169
|
+
const localStat = fs.statSync(localFilePath);
|
|
1170
|
+
const files = collectUploadFiles(localFilePath);
|
|
1171
|
+
if (localStat.isDirectory()) {
|
|
1172
|
+
if (files.length === 0) {
|
|
1173
|
+
logError(`Folder has no files to upload: ${localFilePath}`);
|
|
1174
|
+
process.exit(1);
|
|
1175
|
+
}
|
|
1176
|
+
info(`Uploading folder ${localFilePath} (${files.length} files)...`);
|
|
1177
|
+
const uploaded = [];
|
|
1178
|
+
for (const file of files) {
|
|
1179
|
+
const destination = pathModule.posix.join(uploadPath, file.relativePath);
|
|
1180
|
+
const result = await uploadToAiDrive(file.absolutePath, destination, override, workspace);
|
|
1181
|
+
if (result.status !== 'ok') {
|
|
1182
|
+
output(result);
|
|
1183
|
+
process.exit(1);
|
|
1184
|
+
}
|
|
1185
|
+
uploaded.push(destination);
|
|
1186
|
+
}
|
|
1187
|
+
output({
|
|
1188
|
+
status: 'ok',
|
|
1189
|
+
message: `Uploaded ${uploaded.length} files`,
|
|
1190
|
+
data: { workspace, root: uploadPath, files: uploaded },
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
else {
|
|
1194
|
+
// Stream directly to AI Drive — single request, no blob middleman
|
|
1195
|
+
const result = await uploadToAiDrive(localFilePath, uploadPath, override, workspace);
|
|
1196
|
+
output(result);
|
|
1197
|
+
}
|
|
1152
1198
|
return;
|
|
1153
1199
|
}
|
|
1154
1200
|
const designAttachmentArgs = collectDesignAttachmentArgs(process.argv);
|
|
@@ -1200,7 +1246,36 @@ function registerToolCommand(parentProgram, tool, clientFactory, vdProjectIdDefa
|
|
|
1200
1246
|
}
|
|
1201
1247
|
// Resolve local file paths to uploaded URLs
|
|
1202
1248
|
const resolvedArgs = await resolveLocalFiles(args, client);
|
|
1203
|
-
|
|
1249
|
+
// The server owns the async-first default: create_task /
|
|
1250
|
+
// task_continue return a submit stub ({status: "submitted",
|
|
1251
|
+
// run_id, stream_url}) unless `--wait true` was passed. --attach
|
|
1252
|
+
// upgrades the stub into a live SSE follow that exits with the
|
|
1253
|
+
// run's terminal result — the work still executes server-side.
|
|
1254
|
+
let result = await client.executeTool(tool.name, resolvedArgs);
|
|
1255
|
+
const stubData = result.data;
|
|
1256
|
+
if (attachTask &&
|
|
1257
|
+
result.status === 'ok' &&
|
|
1258
|
+
stubData &&
|
|
1259
|
+
typeof stubData.stream_url === 'string' &&
|
|
1260
|
+
(stubData.status === 'submitted' ||
|
|
1261
|
+
stubData.status === 'duplicate_submit_converged')) {
|
|
1262
|
+
const meta = await client.attachGskTaskRun(stubData.stream_url);
|
|
1263
|
+
const runStatus = String(meta.status || '');
|
|
1264
|
+
const summary = meta.result_summary && typeof meta.result_summary === 'object'
|
|
1265
|
+
? meta.result_summary
|
|
1266
|
+
: {};
|
|
1267
|
+
result = {
|
|
1268
|
+
status: runStatus === 'succeeded' ? 'ok' : 'error',
|
|
1269
|
+
message: runStatus === 'succeeded'
|
|
1270
|
+
? 'success'
|
|
1271
|
+
: `task ended with status ${runStatus || 'unknown'}`,
|
|
1272
|
+
data: {
|
|
1273
|
+
...summary,
|
|
1274
|
+
run_id: stubData.run_id,
|
|
1275
|
+
run_status: runStatus,
|
|
1276
|
+
},
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1204
1279
|
const isSbGitCloneUrl = tool.name === 'sb-git' &&
|
|
1205
1280
|
resolvedArgs.action === 'clone-url';
|
|
1206
1281
|
if (isSbGitCloneUrl &&
|
|
@@ -2105,19 +2180,23 @@ _groupCommands.set('phone-call', phoneCallCmd);
|
|
|
2105
2180
|
// gk_tool_cli_conversation) and attach as dynamic subcommands via the
|
|
2106
2181
|
// seeded _groupCommands entry; this static parent only gives the group a
|
|
2107
2182
|
// real description instead of the generated "Commands for chat".
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2183
|
+
// The task command tree. Verbs are server-registered (create / status /
|
|
2184
|
+
// info / ask / answer / messages / wait / stop / delete / rename attach as
|
|
2185
|
+
// dynamic subcommands via the seeded group); this static parent gives the
|
|
2186
|
+
// group a description, and hosts the one static verb below.
|
|
2187
|
+
const taskCmd = program
|
|
2188
|
+
.command('task')
|
|
2189
|
+
.description('Agent tasks and conversations: create one (submits and returns in ' +
|
|
2190
|
+
'seconds), poll status, read outputs, send follow-ups, answer ' +
|
|
2191
|
+
'agent questions, stop, delete, rename (see subcommands).');
|
|
2192
|
+
_groupCommands.set('task', taskCmd);
|
|
2193
|
+
// `task events` is static (not server-registered): it needs real-time
|
|
2115
2194
|
// line-by-line output the generic dynamic-command handler cannot provide
|
|
2116
2195
|
// (that path buffers intermediate NDJSON messages and only prints the
|
|
2117
2196
|
// final result).
|
|
2118
|
-
|
|
2197
|
+
taskCmd
|
|
2119
2198
|
.command('events <project_id>')
|
|
2120
|
-
.description("Attach to the
|
|
2199
|
+
.description("Attach to the task's in-flight run and stream its events " +
|
|
2121
2200
|
'live (one JSON line per event on stdout): the first line is a ' +
|
|
2122
2201
|
'project_data snapshot event, buffered events since run start ' +
|
|
2123
2202
|
'replay next, then live events follow until the run ends. Every ' +
|
|
@@ -2167,10 +2246,78 @@ chatCmd
|
|
|
2167
2246
|
process.exit(1);
|
|
2168
2247
|
}
|
|
2169
2248
|
});
|
|
2249
|
+
// `task export` is static: it composes two calls (task_status to resolve
|
|
2250
|
+
// the task type, then /export_artifact) plus an optional local download —
|
|
2251
|
+
// the generic dynamic handler maps one verb to one server tool.
|
|
2252
|
+
taskCmd
|
|
2253
|
+
.command('export <project_id>')
|
|
2254
|
+
.description("Convert and download a task's deliverable (docs → docx/pdf, " +
|
|
2255
|
+
'slides → pptx/pdf, sheets → xlsx). Prints the download URL; with ' +
|
|
2256
|
+
'-o <path> also saves the file locally. The task type is resolved ' +
|
|
2257
|
+
'automatically from the project; `gsk task artifacts <project_id>` ' +
|
|
2258
|
+
'lists what a task produced and which formats it can export.')
|
|
2259
|
+
.option('--format <format>', 'export format: auto | docx | pdf | pptx | xlsx (auto picks the ' +
|
|
2260
|
+
"task type's natural format)", 'auto')
|
|
2261
|
+
.option('-o, --output-file <path>', 'save the exported file to this path')
|
|
2262
|
+
.action(async (projectId, opts) => {
|
|
2263
|
+
try {
|
|
2264
|
+
const client = createClient();
|
|
2265
|
+
const statusResult = await client.executeTool('task_status', {
|
|
2266
|
+
id: projectId,
|
|
2267
|
+
});
|
|
2268
|
+
const statusData = statusResult.data;
|
|
2269
|
+
const taskType = statusResult.status === 'ok' && statusData
|
|
2270
|
+
? statusData.task_type
|
|
2271
|
+
: undefined;
|
|
2272
|
+
if (!taskType) {
|
|
2273
|
+
output(statusResult.status === 'ok'
|
|
2274
|
+
? {
|
|
2275
|
+
status: 'error',
|
|
2276
|
+
message: `Cannot resolve task type for ${projectId}`,
|
|
2277
|
+
data: null,
|
|
2278
|
+
}
|
|
2279
|
+
: statusResult);
|
|
2280
|
+
process.exit(1);
|
|
2281
|
+
}
|
|
2282
|
+
const exportResult = await client.exportArtifact(projectId, taskType, opts.format || 'auto');
|
|
2283
|
+
const expData = exportResult.data;
|
|
2284
|
+
if (exportResult.status === 'ok' && expData && opts.outputFile) {
|
|
2285
|
+
const downloadUrl = expData.download_url;
|
|
2286
|
+
if (downloadUrl) {
|
|
2287
|
+
expData.local_path = await downloadToFile(downloadUrl, opts.outputFile, client);
|
|
2288
|
+
}
|
|
2289
|
+
else {
|
|
2290
|
+
// The converter can report ok with an empty URL (e.g. the
|
|
2291
|
+
// share-link build failed server-side) — surface it instead
|
|
2292
|
+
// of printing ok with no file on disk.
|
|
2293
|
+
output({
|
|
2294
|
+
status: 'error',
|
|
2295
|
+
message: 'Export produced no download_url — nothing was saved ' +
|
|
2296
|
+
`to ${opts.outputFile}`,
|
|
2297
|
+
data: expData,
|
|
2298
|
+
});
|
|
2299
|
+
process.exit(1);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
output(exportResult);
|
|
2303
|
+
if (exportResult.status === 'error') {
|
|
2304
|
+
process.exit(1);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
catch (err) {
|
|
2308
|
+
logError(err.message);
|
|
2309
|
+
process.exit(1);
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2170
2312
|
// ============================================
|
|
2171
2313
|
// Dynamic Tool Registration & Startup
|
|
2172
2314
|
// ============================================
|
|
2173
2315
|
async function main() {
|
|
2316
|
+
// Pre-tree `gsk task <type>` compat (see shimLegacyTaskInvocation).
|
|
2317
|
+
process.argv = [
|
|
2318
|
+
...process.argv.slice(0, 2),
|
|
2319
|
+
...shimLegacyTaskInvocation(process.argv.slice(2)),
|
|
2320
|
+
];
|
|
2174
2321
|
// `gsk mesh ...` is a native-binary passthrough — intercept it before the
|
|
2175
2322
|
// tool-fetch path and npm self-update gating (it needs neither). Handling it
|
|
2176
2323
|
// outside commander keeps the rest of the CLI's option parsing intact (see
|