teamshift 0.1.0 → 0.1.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 +12 -9
- package/dist/api.js +3 -0
- package/dist/bin.js +9 -0
- package/dist/cli.js +17 -14
- package/dist/run.js +30 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,9 +11,11 @@ npx teamshift add code-audit-swarm # adds it to your workspace
|
|
|
11
11
|
npx teamshift run <team-id> "review services/api for auth mistakes"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
`teamshift teams` lists
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
`teamshift teams` lists callable teams, including teams you built yourself in the
|
|
15
|
+
portal; `teamshift agents` lists callable individual agents. Keeping the two
|
|
16
|
+
inventories separate prevents a large internal agent library from burying the
|
|
17
|
+
teams a customer actually runs. `add` is idempotent — running it twice will not
|
|
18
|
+
duplicate a team or overwrite edits you have made to it.
|
|
17
19
|
|
|
18
20
|
## Parallel fan-out
|
|
19
21
|
|
|
@@ -36,7 +38,9 @@ completed $1.20 4.0s find dead code
|
|
|
36
38
|
```
|
|
37
39
|
|
|
38
40
|
`--file prompts.txt` reads one prompt per line. Concurrency is bounded (default
|
|
39
|
-
5) so a large batch does not trip the API's write rate limit.
|
|
41
|
+
5) so a large batch does not trip the API's write rate limit. Completed runs
|
|
42
|
+
print their scrubbed deliverable after the status table; `--json` includes it as
|
|
43
|
+
the outcome's `output` field.
|
|
40
44
|
|
|
41
45
|
## Already using Claude Code or Codex?
|
|
42
46
|
|
|
@@ -54,12 +58,11 @@ agent, with no second CLI to learn. Both install commands are in the portal unde
|
|
|
54
58
|
|
|
55
59
|
| Code | Meaning |
|
|
56
60
|
| --- | --- |
|
|
57
|
-
| `0` | every run
|
|
58
|
-
| `1` | usage error,
|
|
61
|
+
| `0` | every run completed and returned its deliverable |
|
|
62
|
+
| `1` | usage/auth error, timeout, failed run, or missing deliverable |
|
|
59
63
|
| `2` | out of credit — add credits and rerun |
|
|
60
64
|
|
|
61
65
|
## Releasing
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
`npm publish`.
|
|
67
|
+
Published on npm as `teamshift`. To release: bump `version`, `pnpm build`, run
|
|
68
|
+
the package tests, then `npm publish --access public` from this directory.
|
package/dist/api.js
CHANGED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The bin entrypoint runs main() unconditionally. Detecting "was I executed
|
|
3
|
+
// directly?" from argv[1] is exactly the 0.1.0 release bug: npm invokes a bin
|
|
4
|
+
// through node_modules/.bin/<command> — a symlink named after the COMMAND — so
|
|
5
|
+
// any filename-based guard fails and the CLI exits silently. Library consumers
|
|
6
|
+
// import from index.ts / cli.ts, which must never self-execute; only this file
|
|
7
|
+
// may have side effects on import.
|
|
8
|
+
import { main } from './cli.js';
|
|
9
|
+
void main();
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
import { createInterface } from 'node:readline/promises';
|
|
3
2
|
import { PaymentRequiredError, TeamShiftClient } from './api.js';
|
|
4
3
|
import { DEFAULT_API_URL, loadCredentials, maskKey, saveCredentials } from './config.js';
|
|
@@ -11,7 +10,8 @@ const USAGE = `teamshift — run agent teams from your terminal
|
|
|
11
10
|
teamshift whoami Show the active key and endpoint
|
|
12
11
|
teamshift catalog Browse prebuilt teams you can add
|
|
13
12
|
teamshift add <catalog-id> Add a prebuilt team to your workspace
|
|
14
|
-
teamshift teams List callable teams
|
|
13
|
+
teamshift teams List callable teams
|
|
14
|
+
teamshift agents List callable agents
|
|
15
15
|
teamshift run <id> "<prompt>" Run one team, wait, print status and charge
|
|
16
16
|
teamshift run <id> -p "a" -p "b" Fan out prompts in parallel
|
|
17
17
|
teamshift run <id> --file prompts.txt One prompt per line, run in parallel
|
|
@@ -72,18 +72,16 @@ async function login() {
|
|
|
72
72
|
rl.close();
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
async function listCallable(json) {
|
|
75
|
+
async function listCallable(kind, json) {
|
|
76
76
|
const payload = await requireClient().interop();
|
|
77
|
+
const items = kind === 'team' ? payload.teams : payload.agents;
|
|
77
78
|
if (json) {
|
|
78
|
-
console.log(JSON.stringify(
|
|
79
|
+
console.log(JSON.stringify(items, null, 2));
|
|
79
80
|
return;
|
|
80
81
|
}
|
|
81
|
-
const rows = [
|
|
82
|
-
...payload.teams.map((item) => ['team', item.id, item.name]),
|
|
83
|
-
...payload.agents.map((item) => ['agent', item.id, item.name]),
|
|
84
|
-
];
|
|
82
|
+
const rows = items.map((item) => [kind, item.id, item.name]);
|
|
85
83
|
if (rows.length === 0) {
|
|
86
|
-
console.log(
|
|
84
|
+
console.log(`No callable ${kind}s yet${kind === 'team' ? ' — add one with `teamshift add <id>`.' : '.'}`);
|
|
87
85
|
return;
|
|
88
86
|
}
|
|
89
87
|
console.log(table(['KIND', 'ID', 'NAME'], rows));
|
|
@@ -153,9 +151,15 @@ async function run(args) {
|
|
|
153
151
|
const serial = outcomes.reduce((sum, outcome) => sum + outcome.elapsedMs, 0);
|
|
154
152
|
console.log(`\n${outcomes.length} run(s) · ${money(total)} total · ${duration(Date.now() - startedAt)} wall clock ` +
|
|
155
153
|
`(${duration(serial)} if run one at a time)`);
|
|
154
|
+
for (const outcome of outcomes) {
|
|
155
|
+
if (outcome.output === null || outcome.output === undefined)
|
|
156
|
+
continue;
|
|
157
|
+
const output = typeof outcome.output === 'string' ? outcome.output : JSON.stringify(outcome.output, null, 2);
|
|
158
|
+
console.log(`\n${outcomes.length > 1 ? `[${outcome.prompt}]\n` : ''}${output}`);
|
|
159
|
+
}
|
|
156
160
|
const failed = outcomes.filter((outcome) => outcome.error).length;
|
|
157
161
|
if (failed > 0) {
|
|
158
|
-
console.log(`${failed} run(s)
|
|
162
|
+
console.log(`${failed} run(s) need attention — inspect the status above before retrying.`);
|
|
159
163
|
process.exitCode = 1;
|
|
160
164
|
}
|
|
161
165
|
}
|
|
@@ -187,7 +191,9 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
187
191
|
case 'add':
|
|
188
192
|
return await addFromCatalog(args);
|
|
189
193
|
case 'teams':
|
|
190
|
-
return await listCallable(args.json);
|
|
194
|
+
return await listCallable('team', args.json);
|
|
195
|
+
case 'agents':
|
|
196
|
+
return await listCallable('agent', args.json);
|
|
191
197
|
case 'run':
|
|
192
198
|
return await run(args);
|
|
193
199
|
default:
|
|
@@ -204,6 +210,3 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
204
210
|
process.exit(1);
|
|
205
211
|
}
|
|
206
212
|
}
|
|
207
|
-
const invokedDirectly = process.argv[1]?.endsWith('cli.js') || process.argv[1]?.endsWith('cli.ts');
|
|
208
|
-
if (invokedDirectly)
|
|
209
|
-
void main();
|
package/dist/run.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { isTerminal } from './format.js';
|
|
2
2
|
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
export class RunPollingTimeoutError extends Error {
|
|
4
|
+
runId;
|
|
5
|
+
latest;
|
|
6
|
+
constructor(runId, latest) {
|
|
7
|
+
super(`run ${runId} did not finish before the polling timeout (last status: ${latest.status ?? 'unknown'})`);
|
|
8
|
+
this.runId = runId;
|
|
9
|
+
this.latest = latest;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
3
12
|
/** Poll one run to a terminal status, or give up at the timeout. */
|
|
4
13
|
export async function waitForRun(client, runId, options = {}) {
|
|
5
14
|
const { intervalMs = 2000, timeoutMs = 900_000, now = Date.now, sleep = defaultSleep } = options;
|
|
@@ -7,7 +16,7 @@ export async function waitForRun(client, runId, options = {}) {
|
|
|
7
16
|
let latest = await client.getRun(runId);
|
|
8
17
|
while (!isTerminal(latest.status)) {
|
|
9
18
|
if (now() - startedAt >= timeoutMs)
|
|
10
|
-
|
|
19
|
+
throw new RunPollingTimeoutError(runId, latest);
|
|
11
20
|
await sleep(intervalMs);
|
|
12
21
|
latest = await client.getRun(runId);
|
|
13
22
|
}
|
|
@@ -34,22 +43,39 @@ export async function runBatch(client, kind, id, prompts, options = {}) {
|
|
|
34
43
|
if (prompt === undefined)
|
|
35
44
|
return;
|
|
36
45
|
const startedAt = now();
|
|
46
|
+
let runId = null;
|
|
37
47
|
try {
|
|
38
|
-
|
|
48
|
+
runId = await client.startRun(kind, id, prompt);
|
|
39
49
|
const summary = await waitForRun(client, runId, { ...pollOptions, now });
|
|
50
|
+
let output = null;
|
|
51
|
+
let resultError;
|
|
52
|
+
if (summary.status === 'completed') {
|
|
53
|
+
try {
|
|
54
|
+
const result = await client.getRunResult(runId);
|
|
55
|
+
output = result.text ?? result.document;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
resultError = `result unavailable: ${error instanceof Error ? error.message : String(error)}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
resultError = `run ended with status ${summary.status ?? 'unknown'}`;
|
|
63
|
+
}
|
|
40
64
|
results[index] = {
|
|
41
65
|
prompt,
|
|
42
66
|
runId,
|
|
43
67
|
status: String(summary.status ?? 'unknown'),
|
|
44
68
|
costUsd: summary.cost_estimate_usd ?? null,
|
|
45
69
|
elapsedMs: now() - startedAt,
|
|
70
|
+
output,
|
|
71
|
+
...(resultError ? { error: resultError } : {}),
|
|
46
72
|
};
|
|
47
73
|
}
|
|
48
74
|
catch (error) {
|
|
49
75
|
results[index] = {
|
|
50
76
|
prompt,
|
|
51
|
-
runId
|
|
52
|
-
status: 'dispatch_failed',
|
|
77
|
+
runId,
|
|
78
|
+
status: error instanceof RunPollingTimeoutError ? 'poll_timeout' : 'dispatch_failed',
|
|
53
79
|
costUsd: null,
|
|
54
80
|
elapsedMs: now() - startedAt,
|
|
55
81
|
error: error instanceof Error ? error.message : String(error),
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamshift",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"description": "Run TeamShift agent teams from your terminal. Metered by usage
|
|
4
|
+
"version": "0.1.2",
|
|
5
|
+
"description": "Run TeamShift agent teams from your terminal. Metered by usage \u2014 no model key of your own required.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"teamshift": "dist/
|
|
8
|
+
"teamshift": "dist/bin.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "src/index.ts",
|
|
11
11
|
"types": "src/index.ts",
|