@ishlabs/cli 0.19.0 → 0.20.0
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/commands/ask.js +26 -2
- package/dist/commands/config.js +9 -1
- package/dist/commands/docs.js +6 -7
- package/dist/commands/person.js +123 -9
- package/dist/commands/secret.js +25 -2
- package/dist/commands/source.d.ts +1 -1
- package/dist/commands/source.js +10 -6
- package/dist/commands/study.js +19 -0
- package/dist/commands/workspace.js +41 -6
- package/dist/index.js +227 -44
- package/dist/lib/alias-store.js +23 -4
- package/dist/lib/auth.js +22 -4
- package/dist/lib/baggage.d.ts +15 -6
- package/dist/lib/baggage.js +14 -8
- package/dist/lib/command-helpers.d.ts +1 -0
- package/dist/lib/command-helpers.js +79 -7
- package/dist/lib/docs.js +211 -21
- package/dist/lib/output.js +61 -17
- package/dist/lib/profile-sources.js +18 -0
- package/dist/lib/skill-content.js +10 -2
- package/dist/upgrade.js +9 -2
- package/package.json +1 -1
|
@@ -164,6 +164,11 @@ export async function resolveSourceRef(client, value, opts) {
|
|
|
164
164
|
}
|
|
165
165
|
// --- Agentic generation jobs ---
|
|
166
166
|
const GENERATION_POLL_INTERVAL_MS = 2_500;
|
|
167
|
+
/** NEW-CP-3: emit a "still running" heartbeat at least this often even if
|
|
168
|
+
* status/progress_message hasn't changed. Backend often stays at
|
|
169
|
+
* `running` with no message for tens of seconds; without a breadcrumb
|
|
170
|
+
* the CLI looks frozen. */
|
|
171
|
+
const GENERATION_HEARTBEAT_MS = 15_000;
|
|
167
172
|
const GENERATION_TERMINAL_STATUSES = new Set(["completed", "failed"]);
|
|
168
173
|
/**
|
|
169
174
|
* Thrown when a generation job doesn't reach a terminal status before the
|
|
@@ -190,7 +195,9 @@ export class GenerationTimeoutError extends Error {
|
|
|
190
195
|
export async function pollGenerationJobUntilDone(client, jobId, opts = {}) {
|
|
191
196
|
const timeoutMs = opts.timeoutMs ?? 600_000;
|
|
192
197
|
const deadline = Date.now() + timeoutMs;
|
|
198
|
+
const startedAt = Date.now();
|
|
193
199
|
let lastReported = "";
|
|
200
|
+
let lastHeartbeatAt = Date.now();
|
|
194
201
|
while (true) {
|
|
195
202
|
const job = await client.get(`/people/generation-jobs/${jobId}`, undefined, { timeout: 60_000 });
|
|
196
203
|
if (!opts.quiet) {
|
|
@@ -198,8 +205,19 @@ export async function pollGenerationJobUntilDone(client, jobId, opts = {}) {
|
|
|
198
205
|
? `${job.status}: ${job.progress_message}`
|
|
199
206
|
: job.status;
|
|
200
207
|
if (line !== lastReported) {
|
|
208
|
+
// Status / message changed — emit it as a fresh breadcrumb.
|
|
201
209
|
process.stderr.write(` ${line}\n`);
|
|
202
210
|
lastReported = line;
|
|
211
|
+
lastHeartbeatAt = Date.now();
|
|
212
|
+
}
|
|
213
|
+
else if (Date.now() - lastHeartbeatAt >= GENERATION_HEARTBEAT_MS) {
|
|
214
|
+
// NEW-CP-3: the backend often holds at `status=running` with no
|
|
215
|
+
// `progress_message` for tens of seconds. Without a heartbeat the
|
|
216
|
+
// CLI looks frozen. Emit a "still running" line every 15s so the
|
|
217
|
+
// operator knows we're polling and not hung.
|
|
218
|
+
const elapsedSec = Math.round((Date.now() - startedAt) / 1000);
|
|
219
|
+
process.stderr.write(` still ${job.status} (${elapsedSec}s elapsed)…\n`);
|
|
220
|
+
lastHeartbeatAt = Date.now();
|
|
203
221
|
}
|
|
204
222
|
}
|
|
205
223
|
if (GENERATION_TERMINAL_STATUSES.has(job.status))
|
|
@@ -220,6 +220,10 @@ When in doubt: side-by-side comparison usually beats in-place edits. Ids are che
|
|
|
220
220
|
- **401 surfaces as fake blocker**: an unauthenticated endpoint produces "participant got stuck on auth screen" — looks like a UX blocker but is config. Always confirm endpoint auth before reading transcripts as user-research data.
|
|
221
221
|
- **No per-page/per-timestamp scoping for media**: there's no "evaluate just slide 14" or "react to seconds 0-30" API. State the focus explicitly in the \`assignment\` text, or pre-stitch the artifact (e.g. replace one slide locally, upload as a new iteration).
|
|
222
222
|
- **\`study get --json\` participants live at the top level**, not nested under \`iterations[*].participants\`. The backend split made \`/studies/{id}\` lite (metadata + iteration shells, no participant graph) and added \`/studies/{id}/participants\`; the CLI joins them so \`study get --json\` carries a flat \`participants[]\` with \`iteration_id\` on each row. Read \`.participants[]\`, not \`.iterations[].participants[]\`.
|
|
223
|
+
- **All destructive deletes require \`--yes\` in non-TTY mode**: \`ish workspace delete\`, \`study delete\`, \`ask delete\`, \`person delete\`, \`source delete\`, \`chat endpoint delete\`. In \`--json\` mode (or any piped/non-TTY invocation), omitting \`--yes\` refuses with \`error_kind: "ConfirmationRequired"\` + an \`example\` field showing the same command with \`--yes\` appended. \`workspace delete\` is the highest-blast-radius: it removes ALL nested studies, asks, people, secrets, configs, sources, and chat endpoints — the prompt names them explicitly.
|
|
224
|
+
- **\`ish login\` is idempotent**: with a valid saved token, \`ish login\` short-circuits with "Already logged in" and **does not open a new browser tab**. Use \`--force\` (or \`-f\`) only when actually switching accounts.
|
|
225
|
+
- **\`ish person create\` accepts inline flags** (mirrors \`person update\`): the file-only API (\`--file <path>\`) is preserved as an escape hatch but the common path is \`ish person create --name "X" --type ai --country US ...\` — \`--type\` defaults to \`ai\` when \`--file\` is omitted. See \`ish person create --help\` for the full inline-flag set including \`--household\` (MECE rule applies) and \`--accessibility-profile\`.
|
|
226
|
+
- **\`ish status\` now surfaces \`chat_endpoint\`** alongside \`workspace\`/\`study\`/\`ask\`. Stale or orphan active refs get a \`warning\` + \`hint\` field on the affected ref (instead of silently dropping the \`name\`). On \`workspace use <other>\`, the CLI cascade-clears \`study\`/\`ask\`/\`chat_endpoint\` (they belong to the previous workspace).
|
|
223
227
|
|
|
224
228
|
## When in doubt
|
|
225
229
|
|
|
@@ -376,9 +380,13 @@ ish person suggest-scenarios \\
|
|
|
376
380
|
# [{"text":"...","source":"situation","scenario_prompt":"..."}, ...]
|
|
377
381
|
# Valid source values: situation, voice, binary, micro-story
|
|
378
382
|
|
|
379
|
-
# 3. Save the person shell
|
|
383
|
+
# 3. Save the person shell — either from file:
|
|
380
384
|
ish person create --file ./persona.json
|
|
381
385
|
# → p-d4e
|
|
386
|
+
#
|
|
387
|
+
# …or inline (mirror of person update):
|
|
388
|
+
# ish person create --name "Alice" --type ai --country US \\
|
|
389
|
+
# --occupation founder --household single --bio "..."
|
|
382
390
|
|
|
383
391
|
# 4. Persist the answers as structured evidence
|
|
384
392
|
ish person evidence add p-d4e --traces-file ./answers.json
|
|
@@ -1042,7 +1050,7 @@ ish <command> --help
|
|
|
1042
1050
|
| \`mcp\` | Wire the hosted ish MCP server into local AI | guides/mcp-add |
|
|
1043
1051
|
| | clients (Cursor, VS Code, Claude Code, | |
|
|
1044
1052
|
| | Claude Desktop, Windsurf). Idempotent. | |
|
|
1045
|
-
| \`login\` | Browser-based auth
|
|
1053
|
+
| \`login\` | Browser-based auth. Idempotent: short-circuits on valid saved token. \`--force\` to switch accounts. | — |
|
|
1046
1054
|
| \`logout\` | Clear saved credentials | — |
|
|
1047
1055
|
| \`status\` | Show active session (user, workspace, | concepts/active-context |
|
|
1048
1056
|
| | study, ask, token validity) — alias \`whoami\` | |
|
package/dist/upgrade.js
CHANGED
|
@@ -32,11 +32,18 @@ export async function upgrade(currentVersion, targetVersion) {
|
|
|
32
32
|
const scriptUrl = import.meta.url;
|
|
33
33
|
const runningFromNodeModules = scriptUrl.includes("/node_modules/");
|
|
34
34
|
if (looksLikeNode || runningFromNodeModules) {
|
|
35
|
-
|
|
35
|
+
// Pattern C: tag as ValidationError so exitCodeFromError maps to 2
|
|
36
|
+
// (usage_error). Otherwise this would fall through to the generic
|
|
37
|
+
// exit 1 even with the wrapper in place (ISSUE-012).
|
|
38
|
+
const err = new Error("Cannot self-upgrade an npm-installed CLI (would overwrite the node binary). " +
|
|
36
39
|
"Run `npm install -g @ishlabs/cli@latest` instead.");
|
|
40
|
+
err.name = "ValidationError";
|
|
41
|
+
throw err;
|
|
37
42
|
}
|
|
38
43
|
if (targetVersion && !/^\d+\.\d+\.\d+/.test(targetVersion)) {
|
|
39
|
-
|
|
44
|
+
const err = new Error(`Invalid version format: ${targetVersion}`);
|
|
45
|
+
err.name = "ValidationError";
|
|
46
|
+
throw err;
|
|
40
47
|
}
|
|
41
48
|
const latest = targetVersion || (await getLatestVersion());
|
|
42
49
|
if (latest === currentVersion) {
|