@memfork/cli 0.1.52 → 0.1.54
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/cli.js +22 -2
- package/dist/commands/ops.js +40 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -182,9 +182,29 @@ program.parseAsync(process.argv).catch((e) => {
|
|
|
182
182
|
process.exit(1);
|
|
183
183
|
});
|
|
184
184
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
185
|
+
/**
|
|
186
|
+
* Flush stdout/stderr, then exit with `code`.
|
|
187
|
+
*
|
|
188
|
+
* Commands like `commit` open keep-alive sockets to the relayer / Sui RPC that
|
|
189
|
+
* hold Node's event loop open long after the work is done — so the process
|
|
190
|
+
* would otherwise hang for ~minutes instead of returning. Agents (Codex) read
|
|
191
|
+
* this as a stuck command and retry, producing duplicate commits. We exit
|
|
192
|
+
* explicitly once the command resolves.
|
|
193
|
+
*
|
|
194
|
+
* We can't use a bare `process.exit()` because it truncates buffered output
|
|
195
|
+
* when stdout is a pipe (which it always is under an agent). Writing an empty
|
|
196
|
+
* chunk with a callback guarantees the prior writes have drained first.
|
|
197
|
+
*/
|
|
198
|
+
function flushAndExit(code) {
|
|
199
|
+
let pending = 2;
|
|
200
|
+
const done = () => { if (--pending === 0)
|
|
201
|
+
process.exit(code); };
|
|
202
|
+
process.stdout.write("", done);
|
|
203
|
+
process.stderr.write("", done);
|
|
204
|
+
}
|
|
185
205
|
function wrap(fn) {
|
|
186
206
|
return (...args) => {
|
|
187
|
-
fn(...args).
|
|
207
|
+
fn(...args).then(() => flushAndExit(0), (e) => {
|
|
188
208
|
if (e.name === "ConfigError") {
|
|
189
209
|
console.error(chalk.red("\n " + String(e.message)));
|
|
190
210
|
console.error(chalk.cyan(" → Run `memfork init` to configure.\n"));
|
|
@@ -192,7 +212,7 @@ function wrap(fn) {
|
|
|
192
212
|
else {
|
|
193
213
|
console.error(chalk.red("\nError: " + String(e)));
|
|
194
214
|
}
|
|
195
|
-
|
|
215
|
+
flushAndExit(1);
|
|
196
216
|
});
|
|
197
217
|
};
|
|
198
218
|
}
|
package/dist/commands/ops.js
CHANGED
|
@@ -161,25 +161,26 @@ export async function cmdCommit(opts) {
|
|
|
161
161
|
...(artifacts.length > 0 ? { artifacts } : {}),
|
|
162
162
|
});
|
|
163
163
|
const out = { blobId, branch, artifacts: refs };
|
|
164
|
-
|
|
164
|
+
// Always print the human-readable confirmation so agents and CI can recognise
|
|
165
|
+
// success without parsing JSON. In non-TTY contexts (subprocesses, pipes) we
|
|
166
|
+
// additionally emit the JSON on the following line for machine consumption.
|
|
167
|
+
console.log("");
|
|
168
|
+
console.log(chalk.green("✓") + " Committed to " + chalk.bold(branch));
|
|
169
|
+
console.log(chalk.dim(` blob: ${blobId}`));
|
|
170
|
+
if (refs.length > 0) {
|
|
165
171
|
console.log("");
|
|
166
|
-
console.log(chalk.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
chalk.dim(`blob: ${ref.blobId.slice(0, 16)}… `) +
|
|
175
|
-
chalk.dim(`sha256: ${ref.sha256.slice(0, 16)}…`));
|
|
176
|
-
console.log(chalk.dim(` Retrieve with: `) +
|
|
177
|
-
chalk.white(`memfork cat ${ref.blobId} --output ${ref.path} --sha256 ${ref.sha256}`));
|
|
178
|
-
}
|
|
172
|
+
console.log(chalk.bold(" Artifacts:"));
|
|
173
|
+
for (const ref of refs) {
|
|
174
|
+
console.log(` ${chalk.cyan(ref.path)} ` +
|
|
175
|
+
chalk.dim(`${(ref.size / 1024).toFixed(1)} KiB `) +
|
|
176
|
+
chalk.dim(`blob: ${ref.blobId.slice(0, 16)}… `) +
|
|
177
|
+
chalk.dim(`sha256: ${ref.sha256.slice(0, 16)}…`));
|
|
178
|
+
console.log(chalk.dim(` Retrieve with: `) +
|
|
179
|
+
chalk.white(`memfork cat ${ref.blobId} --output ${ref.path} --sha256 ${ref.sha256}`));
|
|
179
180
|
}
|
|
180
|
-
console.log("");
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
console.log("");
|
|
183
|
+
if (!process.stdout.isTTY) {
|
|
183
184
|
console.log(JSON.stringify(out));
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -695,12 +696,29 @@ export async function cmdBranch(name, opts = {}) {
|
|
|
695
696
|
const { client, cfg } = await getClient();
|
|
696
697
|
const from = resolveBranch({ explicit: opts.from, configDefault: cfg.defaultBranch });
|
|
697
698
|
process.stdout.write(chalk.dim(`Creating branch ${chalk.green(name)} from ${chalk.green(from)} … `));
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
699
|
+
try {
|
|
700
|
+
const digest = await client.branch(name, { from });
|
|
701
|
+
console.log(chalk.green("done"));
|
|
702
|
+
console.log("");
|
|
703
|
+
console.log(chalk.dim(` tx: ${digest}`));
|
|
704
|
+
console.log(chalk.dim(` Run ${chalk.white("memfork checkout " + name)} to switch to it.`));
|
|
705
|
+
console.log("");
|
|
706
|
+
}
|
|
707
|
+
catch (err) {
|
|
708
|
+
// E_BRANCH_EXISTS (Move abort code 7) — treat as success so `memfork branch`
|
|
709
|
+
// is safe to run idempotently in scripts and runbooks.
|
|
710
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
711
|
+
if (msg.includes("MoveAbort") && msg.match(/,\s*7\)/)) {
|
|
712
|
+
console.log(chalk.dim("already exists"));
|
|
713
|
+
console.log("");
|
|
714
|
+
console.log(chalk.dim(` Branch "${name}" is already on this tree — no action needed.`));
|
|
715
|
+
console.log(chalk.dim(` Run ${chalk.white("memfork checkout " + name)} to switch to it.`));
|
|
716
|
+
console.log("");
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
throw err;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
704
722
|
}
|
|
705
723
|
// ─── checkout ─────────────────────────────────────────────────────────────────
|
|
706
724
|
export async function cmdCheckout(name, opts = {}) {
|