sisyphi 1.2.16 → 1.2.17
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 +3 -3
- package/dist/cli.js +202 -63
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +87 -4
- package/dist/daemon.js.map +1 -1
- package/dist/templates/orchestrator-base.md +2 -0
- package/package.json +1 -1
- package/templates/orchestrator-base.md +2 -0
package/README.md
CHANGED
|
@@ -330,13 +330,13 @@ Run `configure-upload` with that URL to write credentials to `~/.sisyphus/config
|
|
|
330
330
|
|
|
331
331
|
```bash
|
|
332
332
|
# Safest — no argv leak:
|
|
333
|
-
pbpaste | sis admin configure-upload --stdin
|
|
333
|
+
pbpaste | sis admin report configure-upload --stdin
|
|
334
334
|
|
|
335
335
|
# Interactive prompt:
|
|
336
|
-
sis admin configure-upload
|
|
336
|
+
sis admin report configure-upload
|
|
337
337
|
|
|
338
338
|
# Direct argv (triggers a leak warning — token visible via `ps` and shell history):
|
|
339
|
-
sis admin configure-upload "https://<worker-host>/upload?token=sisyphus_pat_..."
|
|
339
|
+
sis admin report configure-upload "https://<worker-host>/upload?token=sisyphus_pat_..."
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
**Config** — `configure-upload` always writes to `~/.sisyphus/config.json`. The `upload` block is only honored from the global config; a project-local `.sisyphus/config.json` with an `upload` block is ignored with a warning (security hardening — prevents project files from redirecting your uploads).
|
package/dist/cli.js
CHANGED
|
@@ -1038,6 +1038,51 @@ var init_version = __esm({
|
|
|
1038
1038
|
}
|
|
1039
1039
|
});
|
|
1040
1040
|
|
|
1041
|
+
// src/shared/upload.ts
|
|
1042
|
+
import { readFile } from "fs/promises";
|
|
1043
|
+
function parseWorkerError(body) {
|
|
1044
|
+
try {
|
|
1045
|
+
const parsed = JSON.parse(body);
|
|
1046
|
+
if (parsed && typeof parsed.error === "string") return parsed.error;
|
|
1047
|
+
} catch {
|
|
1048
|
+
}
|
|
1049
|
+
return body;
|
|
1050
|
+
}
|
|
1051
|
+
function isUploadConfigured(upload) {
|
|
1052
|
+
return !!upload && upload.url.length > 0 && upload.token.length > 0;
|
|
1053
|
+
}
|
|
1054
|
+
async function uploadSession(args2) {
|
|
1055
|
+
const { config, zipPath, manifest } = args2;
|
|
1056
|
+
const formData = new FormData();
|
|
1057
|
+
formData.append("manifest", new Blob([JSON.stringify(manifest)], { type: "application/json" }));
|
|
1058
|
+
formData.append("bundle", new Blob([await readFile(zipPath)], { type: "application/zip" }), `${manifest.sessionId}.zip`);
|
|
1059
|
+
const res = await fetch(`${config.url}/upload`, {
|
|
1060
|
+
method: "POST",
|
|
1061
|
+
headers: { Authorization: `Bearer ${config.token}` },
|
|
1062
|
+
body: formData
|
|
1063
|
+
});
|
|
1064
|
+
if (!res.ok) {
|
|
1065
|
+
const rawBody = await res.text();
|
|
1066
|
+
const body = rawBody.length > 4096 ? rawBody.slice(0, 4096) + "\u2026 [truncated]" : rawBody;
|
|
1067
|
+
throw new UploadError(res.status, body);
|
|
1068
|
+
}
|
|
1069
|
+
return res.json();
|
|
1070
|
+
}
|
|
1071
|
+
var UploadError;
|
|
1072
|
+
var init_upload = __esm({
|
|
1073
|
+
"src/shared/upload.ts"() {
|
|
1074
|
+
"use strict";
|
|
1075
|
+
UploadError = class extends Error {
|
|
1076
|
+
constructor(status, rawBody) {
|
|
1077
|
+
const parsed = parseWorkerError(rawBody);
|
|
1078
|
+
super(`HTTP ${status}: ${parsed}`);
|
|
1079
|
+
this.status = status;
|
|
1080
|
+
}
|
|
1081
|
+
status;
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1041
1086
|
// src/shared/session-export.ts
|
|
1042
1087
|
import { execFile as execFile2 } from "child_process";
|
|
1043
1088
|
import { promisify } from "util";
|
|
@@ -1166,51 +1211,6 @@ var init_session_export = __esm({
|
|
|
1166
1211
|
}
|
|
1167
1212
|
});
|
|
1168
1213
|
|
|
1169
|
-
// src/shared/upload.ts
|
|
1170
|
-
import { readFile } from "fs/promises";
|
|
1171
|
-
function parseWorkerError(body) {
|
|
1172
|
-
try {
|
|
1173
|
-
const parsed = JSON.parse(body);
|
|
1174
|
-
if (parsed && typeof parsed.error === "string") return parsed.error;
|
|
1175
|
-
} catch {
|
|
1176
|
-
}
|
|
1177
|
-
return body;
|
|
1178
|
-
}
|
|
1179
|
-
function isUploadConfigured(upload) {
|
|
1180
|
-
return !!upload && upload.url.length > 0 && upload.token.length > 0;
|
|
1181
|
-
}
|
|
1182
|
-
async function uploadSession(args2) {
|
|
1183
|
-
const { config, zipPath, manifest } = args2;
|
|
1184
|
-
const formData = new FormData();
|
|
1185
|
-
formData.append("manifest", new Blob([JSON.stringify(manifest)], { type: "application/json" }));
|
|
1186
|
-
formData.append("bundle", new Blob([await readFile(zipPath)], { type: "application/zip" }), `${manifest.sessionId}.zip`);
|
|
1187
|
-
const res = await fetch(`${config.url}/upload`, {
|
|
1188
|
-
method: "POST",
|
|
1189
|
-
headers: { Authorization: `Bearer ${config.token}` },
|
|
1190
|
-
body: formData
|
|
1191
|
-
});
|
|
1192
|
-
if (!res.ok) {
|
|
1193
|
-
const rawBody = await res.text();
|
|
1194
|
-
const body = rawBody.length > 4096 ? rawBody.slice(0, 4096) + "\u2026 [truncated]" : rawBody;
|
|
1195
|
-
throw new UploadError(res.status, body);
|
|
1196
|
-
}
|
|
1197
|
-
return res.json();
|
|
1198
|
-
}
|
|
1199
|
-
var UploadError;
|
|
1200
|
-
var init_upload = __esm({
|
|
1201
|
-
"src/shared/upload.ts"() {
|
|
1202
|
-
"use strict";
|
|
1203
|
-
UploadError = class extends Error {
|
|
1204
|
-
constructor(status, rawBody) {
|
|
1205
|
-
const parsed = parseWorkerError(rawBody);
|
|
1206
|
-
super(`HTTP ${status}: ${parsed}`);
|
|
1207
|
-
this.status = status;
|
|
1208
|
-
}
|
|
1209
|
-
status;
|
|
1210
|
-
};
|
|
1211
|
-
}
|
|
1212
|
-
});
|
|
1213
|
-
|
|
1214
1214
|
// src/shared/manifest.ts
|
|
1215
1215
|
import os2 from "os";
|
|
1216
1216
|
function mapEffortFallback(level) {
|
|
@@ -2446,12 +2446,12 @@ var init_tailscale = __esm({
|
|
|
2446
2446
|
});
|
|
2447
2447
|
|
|
2448
2448
|
// src/cli/deploy/runner.ts
|
|
2449
|
-
import { spawn as spawn2, spawnSync as
|
|
2449
|
+
import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
|
|
2450
2450
|
import { copyFileSync as copyFileSync3, existsSync as existsSync34, mkdirSync as mkdirSync17, readFileSync as readFileSync34 } from "fs";
|
|
2451
2451
|
function runTerraform(provider, args2, extraEnv) {
|
|
2452
2452
|
ensureProviderStateDir(provider);
|
|
2453
2453
|
ensureTerraformInstalled();
|
|
2454
|
-
const result =
|
|
2454
|
+
const result = spawnSync5("terraform", args2, {
|
|
2455
2455
|
cwd: providerModuleDir(provider),
|
|
2456
2456
|
stdio: "inherit",
|
|
2457
2457
|
env: { ...EXEC_ENV, ...extraEnv }
|
|
@@ -2460,7 +2460,7 @@ function runTerraform(provider, args2, extraEnv) {
|
|
|
2460
2460
|
return result.status === null ? 1 : result.status;
|
|
2461
2461
|
}
|
|
2462
2462
|
function ensureTerraformInstalled() {
|
|
2463
|
-
const result =
|
|
2463
|
+
const result = spawnSync5("terraform", ["version"], { stdio: "pipe", env: EXEC_ENV });
|
|
2464
2464
|
if (result.error || result.status !== 0) {
|
|
2465
2465
|
const platform = process.platform;
|
|
2466
2466
|
const hint = platform === "darwin" ? "brew install terraform" : "See https://developer.hashicorp.com/terraform/install";
|
|
@@ -2488,7 +2488,7 @@ or pass --ssh-key <path>.`
|
|
|
2488
2488
|
return readFileSync34(path, "utf-8").trim();
|
|
2489
2489
|
}
|
|
2490
2490
|
function readOutputs(provider) {
|
|
2491
|
-
const result =
|
|
2491
|
+
const result = spawnSync5("terraform", ["output", "-json", `-state=${deployStatePath(provider)}`], {
|
|
2492
2492
|
cwd: providerModuleDir(provider),
|
|
2493
2493
|
encoding: "utf-8",
|
|
2494
2494
|
env: EXEC_ENV
|
|
@@ -2672,7 +2672,7 @@ function effectiveSshTarget(provider) {
|
|
|
2672
2672
|
}
|
|
2673
2673
|
function deploySsh(provider, remoteCmd) {
|
|
2674
2674
|
const target = effectiveSshTarget(provider);
|
|
2675
|
-
const moshAvailable =
|
|
2675
|
+
const moshAvailable = spawnSync5("mosh", ["--version"], { stdio: "pipe", env: EXEC_ENV }).status === 0;
|
|
2676
2676
|
const bin = moshAvailable && remoteCmd.length === 0 ? "mosh" : "ssh";
|
|
2677
2677
|
const args2 = remoteCmd.length > 0 ? [target, ...remoteCmd] : [target];
|
|
2678
2678
|
const child = spawn2(bin, args2, { stdio: "inherit", env: EXEC_ENV });
|
|
@@ -2734,10 +2734,10 @@ var init_runner = __esm({
|
|
|
2734
2734
|
});
|
|
2735
2735
|
|
|
2736
2736
|
// src/cli/deploy/ssh-exec.ts
|
|
2737
|
-
import { spawn as spawn3, spawnSync as
|
|
2737
|
+
import { spawn as spawn3, spawnSync as spawnSync6 } from "child_process";
|
|
2738
2738
|
function runOnBox(provider, cmd) {
|
|
2739
2739
|
const target = effectiveSshTarget(provider);
|
|
2740
|
-
const result =
|
|
2740
|
+
const result = spawnSync6("ssh", [target, cmd], {
|
|
2741
2741
|
encoding: "utf-8",
|
|
2742
2742
|
env: EXEC_ENV
|
|
2743
2743
|
});
|
|
@@ -2798,11 +2798,11 @@ var init_grove = __esm({
|
|
|
2798
2798
|
});
|
|
2799
2799
|
|
|
2800
2800
|
// src/cli/cloud/repo.ts
|
|
2801
|
-
import { spawnSync as
|
|
2801
|
+
import { spawnSync as spawnSync7 } from "child_process";
|
|
2802
2802
|
import { existsSync as existsSync35 } from "fs";
|
|
2803
2803
|
import { basename as basename8, join as join30 } from "path";
|
|
2804
2804
|
function captureGit(args2, cwd) {
|
|
2805
|
-
const result =
|
|
2805
|
+
const result = spawnSync7("git", args2, {
|
|
2806
2806
|
encoding: "utf-8",
|
|
2807
2807
|
env: EXEC_ENV,
|
|
2808
2808
|
cwd: cwd ?? process.cwd()
|
|
@@ -9902,13 +9902,16 @@ Exit codes: 0 ok`
|
|
|
9902
9902
|
}
|
|
9903
9903
|
|
|
9904
9904
|
// src/cli/commands/bug.ts
|
|
9905
|
-
import {
|
|
9906
|
-
|
|
9907
|
-
|
|
9905
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
9906
|
+
|
|
9907
|
+
// src/cli/commands/report-shared.ts
|
|
9908
9908
|
init_version();
|
|
9909
9909
|
init_platform();
|
|
9910
9910
|
init_paths();
|
|
9911
9911
|
init_state();
|
|
9912
|
+
import { execFileSync as execFileSync3, spawnSync as spawnSync2 } from "child_process";
|
|
9913
|
+
import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
|
|
9914
|
+
import os from "os";
|
|
9912
9915
|
var REPO = "crouton-labs/sisyphus";
|
|
9913
9916
|
function tryCmd(bin, args2) {
|
|
9914
9917
|
try {
|
|
@@ -9974,8 +9977,8 @@ function tailLog(lines) {
|
|
|
9974
9977
|
return null;
|
|
9975
9978
|
}
|
|
9976
9979
|
}
|
|
9977
|
-
function deriveTitle(description) {
|
|
9978
|
-
const firstLine = description.split("\n").map((l) => l.trim()).find(Boolean) ??
|
|
9980
|
+
function deriveTitle(description, fallback = "Bug report") {
|
|
9981
|
+
const firstLine = description.split("\n").map((l) => l.trim()).find(Boolean) ?? fallback;
|
|
9979
9982
|
return firstLine.length > 80 ? firstLine.slice(0, 77) + "..." : firstLine;
|
|
9980
9983
|
}
|
|
9981
9984
|
function buildBody(args2) {
|
|
@@ -9986,7 +9989,7 @@ function buildBody(args2) {
|
|
|
9986
9989
|
---
|
|
9987
9990
|
|
|
9988
9991
|
<details>
|
|
9989
|
-
<summary>Environment (auto-collected
|
|
9992
|
+
<summary>Environment (auto-collected)</summary>
|
|
9990
9993
|
|
|
9991
9994
|
| field | value |
|
|
9992
9995
|
|---|---|
|
|
@@ -10028,7 +10031,7 @@ function fallbackUrl(title, body) {
|
|
|
10028
10031
|
let b = encodeURIComponent(body);
|
|
10029
10032
|
if (base.length + t.length + b.length > 7500) {
|
|
10030
10033
|
b = encodeURIComponent(
|
|
10031
|
-
body.split("\n\n---\n\n")[0] + "\n\n---\n\n_(diagnostics omitted \u2014 URL too long. Authenticate `gh` and re-run
|
|
10034
|
+
body.split("\n\n---\n\n")[0] + "\n\n---\n\n_(diagnostics omitted \u2014 URL too long. Authenticate `gh` and re-run to attach full telemetry.)_"
|
|
10032
10035
|
);
|
|
10033
10036
|
}
|
|
10034
10037
|
return `${base}?title=${t}&body=${b}`;
|
|
@@ -10038,6 +10041,8 @@ function ghReady() {
|
|
|
10038
10041
|
const auth = spawnSync2("gh", ["auth", "status"], { stdio: "ignore", timeout: 5e3 });
|
|
10039
10042
|
return auth.status === 0;
|
|
10040
10043
|
}
|
|
10044
|
+
|
|
10045
|
+
// src/cli/commands/bug.ts
|
|
10041
10046
|
function registerBug(program2) {
|
|
10042
10047
|
program2.command("bug").description("Report a sisyphus bug \u2014 files a GitHub issue with feedback + diagnostics").argument("[description]", "What went wrong (omit to read from stdin)").option("--message <message>", "Bug description (alternative to the positional argument)").option("--stdin", "Read the description from stdin (avoids shell escaping for long reports)").option("--title <title>", "Issue title (default: first line of the description)").option("--session <id>", "Attach stats for a specific session (default: active session for cwd)").option("--no-session", "Do not attach any session stats").option("--logs [n]", "Attach the last N lines of daemon.log (default 50)").option("--cwd <path>", "Project directory used to find the active session", process.cwd()).addHelpText(
|
|
10043
10048
|
"after",
|
|
@@ -10105,7 +10110,7 @@ Exit codes: 0 ok | 1 filing error | 2 usage`
|
|
|
10105
10110
|
emitJsonOk({ url, filed: false });
|
|
10106
10111
|
return;
|
|
10107
10112
|
}
|
|
10108
|
-
const result =
|
|
10113
|
+
const result = spawnSync3(
|
|
10109
10114
|
"gh",
|
|
10110
10115
|
["issue", "create", "--repo", REPO, "--title", title, "--body-file", "-"],
|
|
10111
10116
|
{ input: body, encoding: "utf-8", timeout: 3e4 }
|
|
@@ -10122,6 +10127,138 @@ Exit codes: 0 ok | 1 filing error | 2 usage`
|
|
|
10122
10127
|
);
|
|
10123
10128
|
}
|
|
10124
10129
|
|
|
10130
|
+
// src/cli/commands/feedback.ts
|
|
10131
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
10132
|
+
init_config();
|
|
10133
|
+
init_upload();
|
|
10134
|
+
init_version();
|
|
10135
|
+
init_platform();
|
|
10136
|
+
async function sendToCloud(config, payload) {
|
|
10137
|
+
const res = await fetch(`${config.url}/feedback`, {
|
|
10138
|
+
method: "POST",
|
|
10139
|
+
headers: {
|
|
10140
|
+
Authorization: `Bearer ${config.token}`,
|
|
10141
|
+
"Content-Type": "application/json"
|
|
10142
|
+
},
|
|
10143
|
+
body: JSON.stringify(payload)
|
|
10144
|
+
});
|
|
10145
|
+
if (!res.ok) {
|
|
10146
|
+
const raw = await res.text();
|
|
10147
|
+
const body = raw.length > 2048 ? raw.slice(0, 2048) + "\u2026 [truncated]" : raw;
|
|
10148
|
+
let detail = body;
|
|
10149
|
+
try {
|
|
10150
|
+
const parsed = JSON.parse(body);
|
|
10151
|
+
if (typeof parsed.error === "string") detail = parsed.error;
|
|
10152
|
+
} catch {
|
|
10153
|
+
}
|
|
10154
|
+
throw new Error(`HTTP ${res.status}: ${detail}`);
|
|
10155
|
+
}
|
|
10156
|
+
return await res.json();
|
|
10157
|
+
}
|
|
10158
|
+
function registerFeedback(program2) {
|
|
10159
|
+
program2.command("feedback").description("Send feedback about sisyphus itself \u2014 private cloud if registered, else a GitHub issue").argument("[message]", "The feedback (omit to read from stdin)").option("--message <message>", "Feedback text (alternative to the positional argument)").option("--stdin", "Read the feedback from stdin (avoids shell escaping for long notes)").option("--session <id>", "Attach stats for a specific session (default: active session for cwd)").option("--no-session", "Do not attach any session stats").option("--cwd <path>", "Project directory used to find the active session", process.cwd()).addHelpText(
|
|
10160
|
+
"after",
|
|
10161
|
+
`
|
|
10162
|
+
feedback: report a problem or suggestion about SISYPHUS ITSELF \u2014 the tool, the
|
|
10163
|
+
CLI, the orchestration workflow \u2014 not about the user's own task or codebase.
|
|
10164
|
+
|
|
10165
|
+
When to use (agent guidance)
|
|
10166
|
+
Run this whenever the user gripes about sisyphus: a daemon crash, a CLI that
|
|
10167
|
+
misbehaved, a confusing or broken workflow, a rough edge, a feature wish.
|
|
10168
|
+
Filing it is a low-cost, helpful side-action \u2014 do it WITHOUT asking the user
|
|
10169
|
+
first. Summarize their complaint in your own words as the message.
|
|
10170
|
+
NOT for the user's project work, code bugs, or task questions.
|
|
10171
|
+
|
|
10172
|
+
Input
|
|
10173
|
+
[message] optional positional \u2014 the feedback (omit to read from stdin or --message).
|
|
10174
|
+
--message <msg> feedback text (alternative to the positional argument).
|
|
10175
|
+
--stdin read the feedback from stdin (avoids shell escaping for long notes).
|
|
10176
|
+
--session <id> attach stats for a specific session (default: active session for cwd).
|
|
10177
|
+
--no-session do not attach any session stats.
|
|
10178
|
+
--cwd <path> project directory used to find the active session (default: cwd).
|
|
10179
|
+
|
|
10180
|
+
Where it goes
|
|
10181
|
+
- Cloud registered (sis admin report configure-upload set up):
|
|
10182
|
+
POSTs privately to the upload worker's /feedback endpoint. Stays private.
|
|
10183
|
+
- Not registered: falls back to a GitHub issue against ${REPO}
|
|
10184
|
+
(via \`gh\` if authenticated, else a prefilled "new issue" URL). PUBLIC.
|
|
10185
|
+
|
|
10186
|
+
Telemetry attached (non-sensitive): sisyphus version, platform, and session
|
|
10187
|
+
STATS only (counts/status) \u2014 never task/goal/context text.
|
|
10188
|
+
|
|
10189
|
+
Output (stdout, JSON envelope)
|
|
10190
|
+
cloud: { ok, data: { sent: true, channel: "cloud", feedbackId, receivedAt } }
|
|
10191
|
+
github: { ok, data: { sent, channel: "github", issueUrl | url } }
|
|
10192
|
+
|
|
10193
|
+
Exit codes: 0 ok | 1 filing error | 2 usage | 60 cloud unreachable (retry-safe)`
|
|
10194
|
+
).action(
|
|
10195
|
+
async (messageArg, opts) => {
|
|
10196
|
+
let message;
|
|
10197
|
+
if (opts.stdin) {
|
|
10198
|
+
message = await readStdin({ force: true });
|
|
10199
|
+
if (opts.message || messageArg) {
|
|
10200
|
+
exitUsage("stdin_conflict", "--stdin conflicts with --message / positional message; pass one source", {
|
|
10201
|
+
received: { stdin: true, message: opts.message ?? messageArg }
|
|
10202
|
+
});
|
|
10203
|
+
}
|
|
10204
|
+
} else {
|
|
10205
|
+
message = messageArg ?? opts.message ?? await readStdin();
|
|
10206
|
+
}
|
|
10207
|
+
if (!message || !message.trim()) {
|
|
10208
|
+
exitUsage("missing_message", "provide feedback (argument, --message, or piped stdin)", {
|
|
10209
|
+
next: 'sis feedback "what is wrong or could be better" \u2014 or: sis feedback --stdin < notes.md'
|
|
10210
|
+
});
|
|
10211
|
+
}
|
|
10212
|
+
message = message.trim();
|
|
10213
|
+
const sessionDisabled = opts.session === false;
|
|
10214
|
+
const session2 = sessionDisabled ? null : await resolveSessionStats(
|
|
10215
|
+
typeof opts.session === "string" ? opts.session : void 0,
|
|
10216
|
+
opts.cwd
|
|
10217
|
+
);
|
|
10218
|
+
const config = loadConfig(opts.cwd);
|
|
10219
|
+
if (isUploadConfigured(config.upload)) {
|
|
10220
|
+
try {
|
|
10221
|
+
const result2 = await sendToCloud(config.upload, {
|
|
10222
|
+
message,
|
|
10223
|
+
sisyphusVersion: getSisyphusVersion(),
|
|
10224
|
+
platform: platformLabel(),
|
|
10225
|
+
session: session2
|
|
10226
|
+
});
|
|
10227
|
+
emitJsonOk({ sent: true, channel: "cloud", ...result2 });
|
|
10228
|
+
return;
|
|
10229
|
+
} catch (err) {
|
|
10230
|
+
exitError({
|
|
10231
|
+
kind: "transient",
|
|
10232
|
+
code: "cloud_unreachable",
|
|
10233
|
+
message: `feedback upload failed: ${err.message}`,
|
|
10234
|
+
next: "retry shortly, or file publicly with `sis admin report bug`"
|
|
10235
|
+
});
|
|
10236
|
+
}
|
|
10237
|
+
}
|
|
10238
|
+
const env = collectEnv();
|
|
10239
|
+
const title = `Feedback: ${deriveTitle(message, "Feedback")}`;
|
|
10240
|
+
const body = buildBody({ description: message, env, session: session2, logTail: null });
|
|
10241
|
+
if (!ghReady()) {
|
|
10242
|
+
emitJsonOk({ sent: false, channel: "github", url: fallbackUrl(title, body) });
|
|
10243
|
+
return;
|
|
10244
|
+
}
|
|
10245
|
+
const result = spawnSync4(
|
|
10246
|
+
"gh",
|
|
10247
|
+
["issue", "create", "--repo", REPO, "--title", title, "--body-file", "-"],
|
|
10248
|
+
{ input: body, encoding: "utf-8", timeout: 3e4 }
|
|
10249
|
+
);
|
|
10250
|
+
if (result.status !== 0) {
|
|
10251
|
+
const url = fallbackUrl(title, body);
|
|
10252
|
+
const stderr = (result.stderr ?? "").trim();
|
|
10253
|
+
emitJsonOk({ sent: false, channel: "github", url, error: stderr });
|
|
10254
|
+
process.exit(1);
|
|
10255
|
+
}
|
|
10256
|
+
const issueUrl = (result.stdout ?? "").trim().split("\n").filter(Boolean).pop() ?? "";
|
|
10257
|
+
emitJsonOk({ sent: true, channel: "github", issueUrl });
|
|
10258
|
+
}
|
|
10259
|
+
);
|
|
10260
|
+
}
|
|
10261
|
+
|
|
10125
10262
|
// src/cli/commands/init.ts
|
|
10126
10263
|
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
10127
10264
|
import { join as join20 } from "path";
|
|
@@ -13525,6 +13662,7 @@ var RUBRICS = {
|
|
|
13525
13662
|
"companion": { short: "Companion-pane helper", useWhen: "driving the companion Claude pane" },
|
|
13526
13663
|
"deploy": { short: "Provision cloud boxes (Terraform)", useWhen: "standing up or tearing down infra" },
|
|
13527
13664
|
"cloud": { short: "Per-repo workflow on a deployed box", useWhen: "syncing work to/from the box" },
|
|
13665
|
+
"feedback": { short: "Report a problem with sisyphus itself", useWhen: "the user complains about the tool or workflow" },
|
|
13528
13666
|
"session lifecycle": { short: "Start/stop/advance a session", useWhen: "changing whether a session runs" },
|
|
13529
13667
|
"session inspect": { short: "Read session state", useWhen: "you need status/history/context without mutating" },
|
|
13530
13668
|
"session config": { short: "Change a session's settings", useWhen: "adjusting task, effort, or dangerous mode" },
|
|
@@ -13783,13 +13921,14 @@ registerCompanionProfile(program.commands.find((c) => c.name() === "companion"))
|
|
|
13783
13921
|
registerDeploy(program);
|
|
13784
13922
|
registerDeployList(program.commands.find((c) => c.name() === "deploy"));
|
|
13785
13923
|
registerCloud(program);
|
|
13924
|
+
registerFeedback(program);
|
|
13786
13925
|
var diagnostic = program.command("diagnostic", { hidden: true });
|
|
13787
13926
|
attachNotify(diagnostic);
|
|
13788
13927
|
attachTmuxSessions(diagnostic);
|
|
13789
13928
|
registerHomeInit(diagnostic);
|
|
13790
13929
|
var args = process.argv.slice(2);
|
|
13791
13930
|
var firstArg = args[0];
|
|
13792
|
-
var skipWelcome = ["session", "start", "dashboard", "agent", "orch", "ask", "ui", "segment", "admin", "help", "--help", "--version"];
|
|
13931
|
+
var skipWelcome = ["session", "start", "dashboard", "agent", "orch", "ask", "ui", "segment", "admin", "feedback", "help", "--help", "--version"];
|
|
13793
13932
|
if (!existsSync50(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
|
|
13794
13933
|
mkdirSync21(globalDir(), { recursive: true });
|
|
13795
13934
|
console.log("");
|