insta 0.1.6 → 0.1.7
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 +1 -1
- package/dist/commands/feedback.js +63 -7
- package/dist/index.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,7 +231,7 @@ build never reaches a production installer.
|
|
|
231
231
|
| `insta billing` | Current cycle overview; `subscribe <tier>` · `portal` · `usage` |
|
|
232
232
|
| `insta agent` | `setup` (this machine's coding agents) · `manifest` · `policy …` · `approvals …` · `observe …` · `events` |
|
|
233
233
|
| `insta config` | `install-mcp` · `regions` · `autoupdate` |
|
|
234
|
-
| `insta feedback` | Report an InstaCloud-side hurdle (bug / feature-request / friction) to the team — never for the app you are building; on InstaCloud it needs `insta login`, so the team can reply |
|
|
234
|
+
| `insta feedback` | Report an InstaCloud-side hurdle (bug / feature-request / friction) to the team — never for the app you are building; on InstaCloud it needs `insta login`, so the team can reply, and prints the ticket it opened; `status <ticket-id>` — New / In Progress / Resolved / Closed (the replies are in the console) |
|
|
235
235
|
| `insta upgrade` | Update the CLI |
|
|
236
236
|
|
|
237
237
|
Every command accepts `--api-url <url>` for this invocation only (internal debugging); for `compute exec`, place it before `compute`. `insta --help` documents it.
|
|
@@ -13,7 +13,7 @@ import * as clack from '@clack/prompts';
|
|
|
13
13
|
import { ApiClient, ApiError } from '../api.js';
|
|
14
14
|
import { readGlobal, readProject } from '../config.js';
|
|
15
15
|
import { envForApiUrl } from '../env.js';
|
|
16
|
-
import { info, printJson, refuse, CliCancel } from '../util.js';
|
|
16
|
+
import { info, printJson, refuse, CliCancel, CliExit } from '../util.js';
|
|
17
17
|
import { clean } from '../redact.js';
|
|
18
18
|
import { cliVersion } from '../version.js';
|
|
19
19
|
export const TYPES = ['bug', 'feature-request', 'friction', 'other'];
|
|
@@ -186,20 +186,24 @@ export async function submit(payload, fetchImpl, assertion) {
|
|
|
186
186
|
catch { /* non-JSON body — fall through to status handling */ }
|
|
187
187
|
if (!res.ok)
|
|
188
188
|
return { status: 'error', error: body?.error ?? `HTTP ${res.status}` };
|
|
189
|
-
return { status: body?.status === 'duplicate' ? 'duplicate' : 'received', id: body?.id ?? null };
|
|
189
|
+
return { status: body?.status === 'duplicate' ? 'duplicate' : 'received', id: body?.id ?? null, ticket: body?.ticket };
|
|
190
190
|
}
|
|
191
191
|
const SIGNED_OUT = 'not signed in to InstaCloud — run `insta login`, then send this again so the team can reply to you';
|
|
192
192
|
const STAGING = 'not accepted from staging — send InstaCloud feedback from production';
|
|
193
|
+
// Bearer only: agent evidence adds a session round trip the timeout cannot bound, and 401s signing in cannot fix.
|
|
194
|
+
async function userAssertion(api) {
|
|
195
|
+
return (await api.request('GET', '/me/feedback-assertion', undefined, { evidence: false, signal: AbortSignal.timeout(ASSERTION_TIMEOUT_MS) })).token;
|
|
196
|
+
}
|
|
193
197
|
// Exit 2, not the submit path's 0: the caller can act on this one.
|
|
194
198
|
function refuseFeedback(message, json) {
|
|
195
199
|
if (json)
|
|
196
200
|
printJson({ status: 'refused', submitted: false, error: message });
|
|
197
201
|
refuse([`insta feedback: ${message}`]);
|
|
198
202
|
}
|
|
199
|
-
function inputError(e, json) {
|
|
203
|
+
function inputError(e, json, fields = { submitted: false }) {
|
|
200
204
|
if (!json)
|
|
201
205
|
throw e;
|
|
202
|
-
printJson({ status: 'error',
|
|
206
|
+
printJson({ status: 'error', ...fields, error: e instanceof Error ? e.message : String(e) });
|
|
203
207
|
process.exitCode = 1;
|
|
204
208
|
}
|
|
205
209
|
export async function feedback(opts, deps = {}) {
|
|
@@ -235,8 +239,7 @@ export async function feedback(opts, deps = {}) {
|
|
|
235
239
|
let assertion;
|
|
236
240
|
if (env === 'prod') {
|
|
237
241
|
try {
|
|
238
|
-
|
|
239
|
-
assertion = (await api.request('GET', '/me/feedback-assertion', undefined, { evidence: false, signal: AbortSignal.timeout(ASSERTION_TIMEOUT_MS) })).token;
|
|
242
|
+
assertion = await userAssertion(api);
|
|
240
243
|
}
|
|
241
244
|
catch (e) {
|
|
242
245
|
if (e instanceof ApiError && e.status === 401)
|
|
@@ -262,13 +265,66 @@ export async function feedback(opts, deps = {}) {
|
|
|
262
265
|
return;
|
|
263
266
|
}
|
|
264
267
|
if (opts.json)
|
|
265
|
-
return printJson({ status: result.status, id: result.id });
|
|
268
|
+
return printJson({ status: result.status, id: result.id, ticket: result.ticket });
|
|
266
269
|
if (result.status === 'duplicate') {
|
|
267
270
|
info(`already reported this week — bumped its count instead (id: ${result.id})`);
|
|
268
271
|
}
|
|
269
272
|
else {
|
|
270
273
|
info(`feedback submitted (id: ${result.id}) — thank you!`);
|
|
271
274
|
}
|
|
275
|
+
if (result.ticket) {
|
|
276
|
+
info(`ticket ${result.ticket.id} — the team's replies are in the console: ${result.ticket.url}`);
|
|
277
|
+
info(`check its status with \`insta feedback status ${result.ticket.id}\``);
|
|
278
|
+
}
|
|
272
279
|
info('PII (emails, tokens, keys, home paths) was redacted before sending.');
|
|
273
280
|
}
|
|
281
|
+
const STATUS_LABEL = { open: 'New', in_progress: 'In Progress', resolved: 'Resolved', closed: 'Closed' };
|
|
282
|
+
const SIGNED_OUT_STATUS = 'not signed in to InstaCloud — run `insta login` to check your ticket';
|
|
283
|
+
function refuseStatus(message, json) {
|
|
284
|
+
if (json)
|
|
285
|
+
printJson({ status: 'refused', error: message });
|
|
286
|
+
refuse([`insta feedback status: ${message}`]);
|
|
287
|
+
}
|
|
288
|
+
export async function feedbackStatus(id, opts, deps = {}) {
|
|
289
|
+
try {
|
|
290
|
+
const api = deps.api ?? await ApiClient.load();
|
|
291
|
+
const env = envForApiUrl(api.apiUrl);
|
|
292
|
+
if (env !== 'prod')
|
|
293
|
+
refuseStatus('ticket status is only available on production InstaCloud', opts.json);
|
|
294
|
+
if (!api.config.accessToken)
|
|
295
|
+
refuseStatus(SIGNED_OUT_STATUS, opts.json);
|
|
296
|
+
let assertion;
|
|
297
|
+
try {
|
|
298
|
+
assertion = await userAssertion(api);
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
if (e instanceof ApiError && e.status === 401)
|
|
302
|
+
refuseStatus(SIGNED_OUT_STATUS, opts.json);
|
|
303
|
+
throw e;
|
|
304
|
+
}
|
|
305
|
+
// Relative, so an endpoint served under a path prefix keeps it.
|
|
306
|
+
const res = await (deps.fetchImpl ?? fetch)(new URL(`tickets/${encodeURIComponent(id)}`, FEEDBACK_ENDPOINT), {
|
|
307
|
+
headers: { Authorization: `Bearer ${FEEDBACK_INGEST_TOKEN}`, 'Insta-User-Assertion': assertion },
|
|
308
|
+
signal: AbortSignal.timeout(FEEDBACK_TIMEOUT_MS),
|
|
309
|
+
});
|
|
310
|
+
if (res.status === 404)
|
|
311
|
+
throw new Error(`no ticket ${id} of yours — use the ticket id \`insta feedback\` printed`);
|
|
312
|
+
// The platform vouched for this login a moment ago: a 401 here is the service's, not a signed-out user.
|
|
313
|
+
if (res.status === 401)
|
|
314
|
+
throw new Error('the feedback service could not verify who you are — signing in again will not fix it');
|
|
315
|
+
const body = (await res.json().catch(() => ({})));
|
|
316
|
+
if (!res.ok || !body.status)
|
|
317
|
+
throw new Error(`the feedback service answered ${res.status}${body.error ? `: ${body.error}` : ''}`);
|
|
318
|
+
if (opts.json)
|
|
319
|
+
return printJson({ id: body.id, status: body.status, url: body.url });
|
|
320
|
+
info(`ticket ${body.id}: ${STATUS_LABEL[body.status] ?? body.status}`);
|
|
321
|
+
info(`open it in the console: ${body.url}`);
|
|
322
|
+
}
|
|
323
|
+
catch (e) {
|
|
324
|
+
// A refusal has already printed and set exit 2; handled again it would print twice and exit 1.
|
|
325
|
+
if (e instanceof CliExit)
|
|
326
|
+
throw e;
|
|
327
|
+
return inputError(e, opts.json, {});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
274
330
|
//# sourceMappingURL=feedback.js.map
|
package/dist/index.js
CHANGED
|
@@ -591,7 +591,7 @@ cfg.command('autoupdate [mode]').description('Show or set auto-update: on | off
|
|
|
591
591
|
const setupCompat = program.command('setup', { hidden: true }).description('Compatibility alias: `insta setup agent` is `insta agent setup`');
|
|
592
592
|
withSetupAgentOptions(setupCompat.command('agent').description('Alias of `insta agent setup`, kept for the console one-liner'));
|
|
593
593
|
// ---- feedback (agent + human hurdle reports → the InstaCloud team) ----
|
|
594
|
-
program.command('feedback')
|
|
594
|
+
const fb = program.command('feedback')
|
|
595
595
|
.description('Report an InstaCloud-side hurdle (bug / missing feature / friction) to the InstaCloud team — about the insta toolkit itself, NEVER about the app you are building. On InstaCloud it needs `insta login`, so the team can reply; works unlinked.')
|
|
596
596
|
.option('--type <type>', `what kind of hurdle: ${feedbackCmd.TYPES.join(' | ')}`)
|
|
597
597
|
.option('--component <component>', `which part of the toolkit: ${feedbackCmd.COMPONENTS.join(' | ')}`)
|
|
@@ -607,6 +607,12 @@ program.command('feedback')
|
|
|
607
607
|
.option('--severity <severity>', `${feedbackCmd.SEVERITIES.join(' | ')} (default: minor)`)
|
|
608
608
|
.option('--json')
|
|
609
609
|
.action(guard((o) => feedbackCmd.feedback(o)));
|
|
610
|
+
// As with billing: a mistyped subcommand must fail, not open the report wizard.
|
|
611
|
+
fb.allowExcessArguments(false);
|
|
612
|
+
fb.command('status <ticket-id>')
|
|
613
|
+
.description('Show the status of a ticket `insta feedback` opened: New, In Progress, Resolved or Closed. The replies are read and answered in the console.')
|
|
614
|
+
.option('--json')
|
|
615
|
+
.action(guard((id, o) => feedbackCmd.feedbackStatus(id, o)));
|
|
610
616
|
// ---- self-update ----
|
|
611
617
|
program.command('upgrade').description('Update the insta CLI to the latest release (binary or npm install)')
|
|
612
618
|
.action(guard(() => selfUpdate.upgrade(cliVersion())));
|