halfcycle 0.4.7 → 0.4.8
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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +191 -69
- package/dist/cli.js +10 -6
- package/dist/cli.js.map +2 -2
- package/dist/index.js +5 -5
- package/dist/index.js.map +2 -2
- package/dist/install.d.ts.map +1 -1
- package/dist/loopback-signin.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halfcycle",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Halfcycle Method bundle — resolution-stub slash commands, remote method-delivery registration, and governance-hook wiring for a Halfcycle engagement repo. It ships NO worker role files: a project's roles are authored from that project's own recorded decisions at orchestration kickoff (FX-2, W3-F-27).",
|
|
5
5
|
"commands": [
|
|
6
6
|
{
|
package/bin/bin.bundle.mjs
CHANGED
|
@@ -14899,8 +14899,8 @@ function readConfig(env = process.env) {
|
|
|
14899
14899
|
}
|
|
14900
14900
|
};
|
|
14901
14901
|
}
|
|
14902
|
-
function readNeverConfiguredReason() {
|
|
14903
|
-
return
|
|
14902
|
+
function readNeverConfiguredReason(env = process.env) {
|
|
14903
|
+
return env["HALFCYCLE_NOT_THIS_ACCOUNT"] === "1" ? "not-this-account" : "no-credential-yet";
|
|
14904
14904
|
}
|
|
14905
14905
|
function isHalfcycleOwnCi() {
|
|
14906
14906
|
return process.env["HALFCYCLE_INTERNAL_CI"] === "1";
|
|
@@ -16086,6 +16086,110 @@ function scopeNoticeText(scope, options) {
|
|
|
16086
16086
|
};
|
|
16087
16087
|
}
|
|
16088
16088
|
|
|
16089
|
+
// ../events/dist/device-auth.js
|
|
16090
|
+
var utcIso86012 = external_exports.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
|
|
16091
|
+
var DEVICE_AUTH_STATUS = {
|
|
16092
|
+
/** The poll: minted, nobody has acted yet. Keep polling. 200. */
|
|
16093
|
+
PENDING: "pending",
|
|
16094
|
+
/** The poll: approved, and the credential is in this body. Once only. 200. */
|
|
16095
|
+
APPROVED: "approved",
|
|
16096
|
+
/** Confirm: the decision was recorded (approve or decline). 200. */
|
|
16097
|
+
RECORDED: "recorded",
|
|
16098
|
+
/** The human refused at the confirmation page. 400 on the poll. */
|
|
16099
|
+
DECLINED: "declined",
|
|
16100
|
+
/** The code's absolute expiry has passed. 400. */
|
|
16101
|
+
EXPIRED: "expired",
|
|
16102
|
+
/** Never minted, or already spent. 400. */
|
|
16103
|
+
UNKNOWN: "unknown",
|
|
16104
|
+
/** Confirm: neither `approve` nor `decline` was named. Nothing was bound. 400. */
|
|
16105
|
+
INVALID_DECISION: "invalid-decision",
|
|
16106
|
+
/** Confirm: an approval arrived with no signed-in identity. 400. */
|
|
16107
|
+
IDENTITY_REQUIRED: "identity-required",
|
|
16108
|
+
/** This deployment has no `SIGNIN_BASE_URL` / `DEVICE_AUTH_CONFIRM_SECRET`. 503. */
|
|
16109
|
+
NOT_CONFIGURED: "not-configured",
|
|
16110
|
+
/** Confirm: the shared confirmation secret was missing or wrong. 401. */
|
|
16111
|
+
UNAUTHORIZED: "unauthorized",
|
|
16112
|
+
/** Confirm: the code was already approved, declined or claimed. 409. */
|
|
16113
|
+
ALREADY_DECIDED: "already-decided",
|
|
16114
|
+
/**
|
|
16115
|
+
* Confirm: an approval named a signed-in identity whose account has not accepted
|
|
16116
|
+
* the terms of service and privacy policy currently in force. 400.
|
|
16117
|
+
*
|
|
16118
|
+
* NOT BOUND TO THE DEVICE CODE. Unlike every other refusal in this const, this one
|
|
16119
|
+
* says nothing about the code itself — the code is still `pending` after this
|
|
16120
|
+
* response, exactly as it was before the request, so the SAME userCode can be
|
|
16121
|
+
* confirmed again once the caller has recorded acceptance. `deviceConfirmRequestSchema`'s
|
|
16122
|
+
* `acceptTerms` is how a second confirm says it did.
|
|
16123
|
+
*/
|
|
16124
|
+
TERMS_REQUIRED: "terms-required"
|
|
16125
|
+
};
|
|
16126
|
+
var DEVICE_POLL_REFUSALS = [
|
|
16127
|
+
DEVICE_AUTH_STATUS.DECLINED,
|
|
16128
|
+
DEVICE_AUTH_STATUS.EXPIRED,
|
|
16129
|
+
DEVICE_AUTH_STATUS.UNKNOWN
|
|
16130
|
+
];
|
|
16131
|
+
var deviceAuthStartResponseSchema = external_exports.object({
|
|
16132
|
+
deviceCode: external_exports.string().min(1),
|
|
16133
|
+
userCode: external_exports.string().min(1),
|
|
16134
|
+
verificationUrl: external_exports.string().min(1),
|
|
16135
|
+
expiresAt: utcIso86012,
|
|
16136
|
+
pollIntervalMs: external_exports.number().int().positive()
|
|
16137
|
+
}).strict();
|
|
16138
|
+
var devicePollPendingSchema = external_exports.object({
|
|
16139
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.PENDING),
|
|
16140
|
+
pollIntervalMs: external_exports.number().int().positive()
|
|
16141
|
+
}).strict();
|
|
16142
|
+
var devicePollApprovedSchema = external_exports.object({
|
|
16143
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.APPROVED),
|
|
16144
|
+
accountId: external_exports.string().min(1),
|
|
16145
|
+
credential: external_exports.string().min(1),
|
|
16146
|
+
expiresAt: utcIso86012
|
|
16147
|
+
}).strict();
|
|
16148
|
+
var deviceAuthRefusalSchema = external_exports.object({
|
|
16149
|
+
status: external_exports.enum([
|
|
16150
|
+
DEVICE_AUTH_STATUS.DECLINED,
|
|
16151
|
+
DEVICE_AUTH_STATUS.EXPIRED,
|
|
16152
|
+
DEVICE_AUTH_STATUS.UNKNOWN,
|
|
16153
|
+
DEVICE_AUTH_STATUS.INVALID_DECISION,
|
|
16154
|
+
DEVICE_AUTH_STATUS.IDENTITY_REQUIRED,
|
|
16155
|
+
DEVICE_AUTH_STATUS.NOT_CONFIGURED,
|
|
16156
|
+
DEVICE_AUTH_STATUS.UNAUTHORIZED,
|
|
16157
|
+
DEVICE_AUTH_STATUS.ALREADY_DECIDED,
|
|
16158
|
+
DEVICE_AUTH_STATUS.TERMS_REQUIRED
|
|
16159
|
+
]),
|
|
16160
|
+
message: external_exports.string().min(1)
|
|
16161
|
+
}).strict();
|
|
16162
|
+
var devicePollResponseSchema = external_exports.union([
|
|
16163
|
+
devicePollPendingSchema,
|
|
16164
|
+
devicePollApprovedSchema,
|
|
16165
|
+
deviceAuthRefusalSchema
|
|
16166
|
+
]);
|
|
16167
|
+
var deviceConfirmRequestSchema = external_exports.object({
|
|
16168
|
+
userCode: external_exports.string().min(1),
|
|
16169
|
+
decision: external_exports.enum(["approve", "decline"]),
|
|
16170
|
+
externalAuthId: external_exports.string().min(1).optional(),
|
|
16171
|
+
email: external_exports.string().optional(),
|
|
16172
|
+
acceptTerms: external_exports.boolean().optional()
|
|
16173
|
+
}).strict();
|
|
16174
|
+
var deviceConfirmRecordedSchema = external_exports.object({
|
|
16175
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.RECORDED),
|
|
16176
|
+
accountId: external_exports.string().min(1).optional()
|
|
16177
|
+
}).strict();
|
|
16178
|
+
var deviceConfirmResponseSchema = external_exports.union([
|
|
16179
|
+
deviceConfirmRecordedSchema,
|
|
16180
|
+
deviceAuthRefusalSchema
|
|
16181
|
+
]);
|
|
16182
|
+
var DASHBOARD_URL = "https://app.halfcycle.ai";
|
|
16183
|
+
|
|
16184
|
+
// ../events/dist/project-page.js
|
|
16185
|
+
function projectPageUrl(engagementId) {
|
|
16186
|
+
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
16187
|
+
}
|
|
16188
|
+
function requestAccessSentence(engagementId) {
|
|
16189
|
+
const page = projectPageUrl(engagementId) ?? "this project's page on Halfcycle";
|
|
16190
|
+
return `To ask for access, open ${page} signed in as this account and choose "Request access". Then let the project's owner know, so they can approve it.`;
|
|
16191
|
+
}
|
|
16192
|
+
|
|
16089
16193
|
// ../events/dist/credential-wire.js
|
|
16090
16194
|
var engagementCredentialResponseSchema = external_exports.object({
|
|
16091
16195
|
engagementId: external_exports.string(),
|
|
@@ -16224,8 +16328,8 @@ This is not a service outage: the guard service answered. The suspect is this re
|
|
|
16224
16328
|
}
|
|
16225
16329
|
var UNCONFIGURED_EXIT_TOOL_USE = 2;
|
|
16226
16330
|
var UNCONFIGURED_EXIT_STOP_FAMILY = 1;
|
|
16227
|
-
function emitNeverConfigured(exitCode, reason) {
|
|
16228
|
-
writeSync(2, neverConfiguredReport(reason));
|
|
16331
|
+
function emitNeverConfigured(exitCode, reason, engagementId) {
|
|
16332
|
+
writeSync(2, neverConfiguredReport(reason, void 0, engagementId));
|
|
16229
16333
|
process.exitCode = exitCode;
|
|
16230
16334
|
}
|
|
16231
16335
|
var SIGN_IN_COMMAND = '"npx halfcycle"';
|
|
@@ -16255,16 +16359,16 @@ ${NOT_A_SERVICE_OUTAGE} Nothing was sent: this job holds no credential and was n
|
|
|
16255
16359
|
${CI_OLDER_SETUP}
|
|
16256
16360
|
`;
|
|
16257
16361
|
}
|
|
16258
|
-
function notThisAccountReport(label) {
|
|
16259
|
-
return `${label} This project belongs to another Halfcycle account. Halfcycle is Solo today \u2014 one person works on a project at a time \u2014 so no credential exists for this machine and none will be issued. Nothing here needs fixing; this copy simply is not checked.
|
|
16362
|
+
function notThisAccountReport(label, engagementId) {
|
|
16363
|
+
return `${label} This project belongs to another Halfcycle account. Halfcycle is Solo today \u2014 one person works on a project at a time \u2014 so no credential exists for this machine and none will be issued. Nothing here needs fixing; this copy simply is not checked. ${requestAccessSentence(engagementId)} If this account is wrong, sign in as the one that owns the project and run "npx halfcycle" again.
|
|
16260
16364
|
`;
|
|
16261
16365
|
}
|
|
16262
|
-
function neverConfiguredReport(reason, label = "[Halfcycle]") {
|
|
16366
|
+
function neverConfiguredReport(reason, label = "[Halfcycle]", engagementId) {
|
|
16263
16367
|
switch (reason) {
|
|
16264
16368
|
case "no-credential-yet":
|
|
16265
16369
|
return neverConfiguredMessage(HOOK_REMEDY, label);
|
|
16266
16370
|
case "not-this-account":
|
|
16267
|
-
return notThisAccountReport(label);
|
|
16371
|
+
return notThisAccountReport(label, engagementId);
|
|
16268
16372
|
}
|
|
16269
16373
|
}
|
|
16270
16374
|
var CREDENTIAL_REJECTED_STATUSES = /* @__PURE__ */ new Set([401, 403]);
|
|
@@ -16315,14 +16419,14 @@ function credentialRenewalFailedMessage(remedy, label = "[Halfcycle]") {
|
|
|
16315
16419
|
${remedy}
|
|
16316
16420
|
`;
|
|
16317
16421
|
}
|
|
16318
|
-
function noCoverageStatement(reason, remedySaid = false) {
|
|
16422
|
+
function noCoverageStatement(reason, remedySaid = false, engagementId) {
|
|
16319
16423
|
if (reason === "not-this-account") {
|
|
16320
16424
|
return [
|
|
16321
16425
|
"[halfcycle] This project belongs to another Halfcycle account, so nothing here is checked.",
|
|
16322
16426
|
"[halfcycle] Your work carries on exactly as it would without Halfcycle \u2014 no edit is",
|
|
16323
16427
|
"[halfcycle] evaluated, and nothing you do is reported as having passed.",
|
|
16324
16428
|
"[halfcycle] Halfcycle is Solo today \u2014 one developer per project \u2014 with Team plans coming.",
|
|
16325
|
-
|
|
16429
|
+
`[halfcycle] ${requestAccessSentence(engagementId)}`,
|
|
16326
16430
|
"[halfcycle] If this account is wrong, sign in as the one that owns the project and run",
|
|
16327
16431
|
'[halfcycle] "npx halfcycle" again.'
|
|
16328
16432
|
].join("\n");
|
|
@@ -18108,8 +18212,36 @@ function cleanRunSummary(verdict, scope) {
|
|
|
18108
18212
|
return `[Halfcycle CI] ${verdict} ${files}, ${scope.signals} signal(s) checked.`;
|
|
18109
18213
|
}
|
|
18110
18214
|
|
|
18215
|
+
// dist/pinned-engagement.js
|
|
18216
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
18217
|
+
import { resolve } from "node:path";
|
|
18218
|
+
function readPinnedId(root) {
|
|
18219
|
+
let raw;
|
|
18220
|
+
try {
|
|
18221
|
+
raw = readFileSync5(resolve(root, BUNDLE_PIN_REL), "utf-8");
|
|
18222
|
+
} catch {
|
|
18223
|
+
return { problem: "no-pin" };
|
|
18224
|
+
}
|
|
18225
|
+
let pin;
|
|
18226
|
+
try {
|
|
18227
|
+
pin = JSON.parse(raw);
|
|
18228
|
+
} catch {
|
|
18229
|
+
return { problem: "no-id" };
|
|
18230
|
+
}
|
|
18231
|
+
const id = typeof pin === "object" && pin !== null ? pin[PIN_ENGAGEMENT_ID_FIELD] : void 0;
|
|
18232
|
+
return typeof id === "string" && id !== "" ? { id } : { problem: "no-id" };
|
|
18233
|
+
}
|
|
18234
|
+
function pinnedEngagementId(root) {
|
|
18235
|
+
const pinned = readPinnedId(root);
|
|
18236
|
+
return "id" in pinned && isEngagementId(pinned.id) ? pinned.id : void 0;
|
|
18237
|
+
}
|
|
18238
|
+
function projectFolder(env = process.env) {
|
|
18239
|
+
const dir = env["CLAUDE_PROJECT_DIR"];
|
|
18240
|
+
return dir !== void 0 && dir !== "" ? dir : process.cwd();
|
|
18241
|
+
}
|
|
18242
|
+
|
|
18111
18243
|
// dist/credential-store.js
|
|
18112
|
-
import { chmodSync, existsSync as existsSync3, readFileSync as
|
|
18244
|
+
import { chmodSync, existsSync as existsSync3, readFileSync as readFileSync6, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2, realpathSync } from "node:fs";
|
|
18113
18245
|
import { homedir as homedir2, platform } from "node:os";
|
|
18114
18246
|
import { dirname as dirname3, join as join5 } from "node:path";
|
|
18115
18247
|
var REFRESHED_TOKEN_KEYS = ["HALFCYCLE_TOKEN", "GUARD_SERVICE_TOKEN"];
|
|
@@ -18123,7 +18255,7 @@ function hasNotThisAccountMarker(engagementId, home) {
|
|
|
18123
18255
|
function readAccountCredential(controlOrigin, home) {
|
|
18124
18256
|
let raw;
|
|
18125
18257
|
try {
|
|
18126
|
-
raw =
|
|
18258
|
+
raw = readFileSync6(join5(home ?? homedir2(), HALFCYCLE_DIR_NAME, ACCOUNT_STORE_FILENAME), "utf-8");
|
|
18127
18259
|
} catch {
|
|
18128
18260
|
return void 0;
|
|
18129
18261
|
}
|
|
@@ -18140,7 +18272,7 @@ function readStoredEngagementToken(envFilePath) {
|
|
|
18140
18272
|
function readEngagementStore(envFilePath) {
|
|
18141
18273
|
let raw;
|
|
18142
18274
|
try {
|
|
18143
|
-
raw =
|
|
18275
|
+
raw = readFileSync6(envFilePath, "utf-8");
|
|
18144
18276
|
} catch {
|
|
18145
18277
|
return void 0;
|
|
18146
18278
|
}
|
|
@@ -18170,7 +18302,7 @@ function writeRefreshedToken(opts) {
|
|
|
18170
18302
|
}
|
|
18171
18303
|
let existing;
|
|
18172
18304
|
try {
|
|
18173
|
-
existing =
|
|
18305
|
+
existing = readFileSync6(declaredReal, "utf-8");
|
|
18174
18306
|
} catch {
|
|
18175
18307
|
existing = null;
|
|
18176
18308
|
}
|
|
@@ -18313,7 +18445,7 @@ async function evaluateWithRefresh(opts) {
|
|
|
18313
18445
|
|
|
18314
18446
|
// dist/hooks/marker.js
|
|
18315
18447
|
import { createHash } from "node:crypto";
|
|
18316
|
-
import { existsSync as existsSync4, readFileSync as
|
|
18448
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync } from "node:fs";
|
|
18317
18449
|
import { tmpdir } from "node:os";
|
|
18318
18450
|
import { join as join6 } from "node:path";
|
|
18319
18451
|
var MARKER_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -18345,7 +18477,7 @@ function readMarker(repoRoot, sessionId) {
|
|
|
18345
18477
|
if (!existsSync4(path))
|
|
18346
18478
|
return null;
|
|
18347
18479
|
try {
|
|
18348
|
-
return
|
|
18480
|
+
return readFileSync7(path, "utf-8").trim() || null;
|
|
18349
18481
|
} catch {
|
|
18350
18482
|
return null;
|
|
18351
18483
|
}
|
|
@@ -18391,7 +18523,7 @@ function readDedupe(repoRoot, sessionId) {
|
|
|
18391
18523
|
if (!existsSync4(path))
|
|
18392
18524
|
return null;
|
|
18393
18525
|
try {
|
|
18394
|
-
const parsed = JSON.parse(
|
|
18526
|
+
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
18395
18527
|
if (typeof parsed === "object" && parsed !== null && typeof parsed.base === "string" && typeof parsed.digest === "string") {
|
|
18396
18528
|
return parsed;
|
|
18397
18529
|
}
|
|
@@ -18436,7 +18568,7 @@ function orphanSweep(repoRoot, refKnown, keepSessionId, now = Date.now()) {
|
|
|
18436
18568
|
const full = join6(dir, name);
|
|
18437
18569
|
let unusable = false;
|
|
18438
18570
|
try {
|
|
18439
|
-
const ref =
|
|
18571
|
+
const ref = readFileSync7(full, "utf-8").trim();
|
|
18440
18572
|
if (!ref || !refKnown(ref))
|
|
18441
18573
|
unusable = true;
|
|
18442
18574
|
} catch {
|
|
@@ -18460,9 +18592,9 @@ function orphanSweep(repoRoot, refKnown, keepSessionId, now = Date.now()) {
|
|
|
18460
18592
|
}
|
|
18461
18593
|
|
|
18462
18594
|
// dist/seat-configuration.js
|
|
18463
|
-
import { existsSync as existsSync5, readFileSync as
|
|
18595
|
+
import { existsSync as existsSync5, readFileSync as readFileSync8, realpathSync as realpathSync2 } from "node:fs";
|
|
18464
18596
|
import { homedir as homedir3 } from "node:os";
|
|
18465
|
-
import { join as join7, relative as relative3, resolve } from "node:path";
|
|
18597
|
+
import { join as join7, relative as relative3, resolve as resolve2 } from "node:path";
|
|
18466
18598
|
function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration) {
|
|
18467
18599
|
try {
|
|
18468
18600
|
const facts = read(repoRoot);
|
|
@@ -18475,7 +18607,7 @@ function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration) {
|
|
|
18475
18607
|
}
|
|
18476
18608
|
}
|
|
18477
18609
|
function readSeatConfiguration(repoRoot) {
|
|
18478
|
-
const given =
|
|
18610
|
+
const given = resolve2(process.env["CLAUDE_PROJECT_DIR"] || process.cwd());
|
|
18479
18611
|
const projectDir = realpathSync2.native(given);
|
|
18480
18612
|
const home = homedir3();
|
|
18481
18613
|
let realHome = home;
|
|
@@ -18497,7 +18629,7 @@ function isPlainObject3(value) {
|
|
|
18497
18629
|
function readSettingsFile(projectDir, rel) {
|
|
18498
18630
|
let raw;
|
|
18499
18631
|
try {
|
|
18500
|
-
raw =
|
|
18632
|
+
raw = readFileSync8(join7(projectDir, rel), "utf-8");
|
|
18501
18633
|
} catch (err) {
|
|
18502
18634
|
const code = err.code;
|
|
18503
18635
|
const state = code === "ENOENT" || code === "ENOTDIR" ? "absent" : "unreadable";
|
|
@@ -18655,7 +18787,7 @@ async function evaluateEdit(reply, readSeat) {
|
|
|
18655
18787
|
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet });
|
|
18656
18788
|
if (!firstNoticeThisSession("credential-missing", repoRoot, input.session_id))
|
|
18657
18789
|
return;
|
|
18658
|
-
emitNeverConfigured(UNCONFIGURED_EXIT_TOOL_USE, readNeverConfiguredReason());
|
|
18790
|
+
emitNeverConfigured(UNCONFIGURED_EXIT_TOOL_USE, readNeverConfiguredReason(), pinnedEngagementId(projectFolder()));
|
|
18659
18791
|
return;
|
|
18660
18792
|
}
|
|
18661
18793
|
const { guardServiceUrl, guardServiceToken, guardEngagementId } = configResult.config;
|
|
@@ -18748,10 +18880,10 @@ ${guardLines}${notRunBlock}`);
|
|
|
18748
18880
|
}
|
|
18749
18881
|
}
|
|
18750
18882
|
function readStdin() {
|
|
18751
|
-
return new Promise((
|
|
18883
|
+
return new Promise((resolve5, reject) => {
|
|
18752
18884
|
const chunks = [];
|
|
18753
18885
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
18754
|
-
process.stdin.on("end", () =>
|
|
18886
|
+
process.stdin.on("end", () => resolve5(Buffer.concat(chunks).toString("utf-8")));
|
|
18755
18887
|
process.stdin.on("error", reject);
|
|
18756
18888
|
});
|
|
18757
18889
|
}
|
|
@@ -18836,7 +18968,7 @@ async function evaluateSession(input, kind, reply, readSeat) {
|
|
|
18836
18968
|
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet, diffBase });
|
|
18837
18969
|
if (!firstNoticeThisSession("credential-missing", repoRoot, sessionId))
|
|
18838
18970
|
return;
|
|
18839
|
-
emitNeverConfigured(UNCONFIGURED_EXIT_STOP_FAMILY, readNeverConfiguredReason());
|
|
18971
|
+
emitNeverConfigured(UNCONFIGURED_EXIT_STOP_FAMILY, readNeverConfiguredReason(), pinnedEngagementId(projectFolder()));
|
|
18840
18972
|
return;
|
|
18841
18973
|
}
|
|
18842
18974
|
const { guardServiceUrl, guardServiceToken, guardEngagementId } = configResult.config;
|
|
@@ -18947,9 +19079,9 @@ async function readHookStdin() {
|
|
|
18947
19079
|
}
|
|
18948
19080
|
}
|
|
18949
19081
|
function readStdin2() {
|
|
18950
|
-
return new Promise((
|
|
19082
|
+
return new Promise((resolve5) => {
|
|
18951
19083
|
if (process.stdin.isTTY) {
|
|
18952
|
-
|
|
19084
|
+
resolve5("");
|
|
18953
19085
|
return;
|
|
18954
19086
|
}
|
|
18955
19087
|
const chunks = [];
|
|
@@ -18959,7 +19091,7 @@ function readStdin2() {
|
|
|
18959
19091
|
return;
|
|
18960
19092
|
settled = true;
|
|
18961
19093
|
clearTimeout(timer);
|
|
18962
|
-
|
|
19094
|
+
resolve5(Buffer.concat(chunks).toString("utf-8"));
|
|
18963
19095
|
};
|
|
18964
19096
|
const timer = setTimeout(done, HOOK_STDIN_GRACE_MS);
|
|
18965
19097
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -18981,7 +19113,7 @@ async function runStop() {
|
|
|
18981
19113
|
}
|
|
18982
19114
|
|
|
18983
19115
|
// dist/hooks/user-prompt-submit.js
|
|
18984
|
-
import { readFileSync as
|
|
19116
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
18985
19117
|
import { homedir as homedir4 } from "node:os";
|
|
18986
19118
|
import { join as join8 } from "node:path";
|
|
18987
19119
|
|
|
@@ -19038,6 +19170,9 @@ function notAttendedLine(act) {
|
|
|
19038
19170
|
function notSignedInLine(act) {
|
|
19039
19171
|
return line(`${nothingDone(act)}: this project is not signed in on this computer. ${HOOK_REMEDY}`);
|
|
19040
19172
|
}
|
|
19173
|
+
function notOwnerLine(act) {
|
|
19174
|
+
return line(`${nothingDone(act)}: only the project's owner can approve or send back this scope.`);
|
|
19175
|
+
}
|
|
19041
19176
|
function showFirstLine(act) {
|
|
19042
19177
|
return line(`${nothingDone(act)}: that phase has not been listed here. List its parts first with \`${HALFCYCLE_COMMAND} plan <phase> --show\`, then type the line again.`);
|
|
19043
19178
|
}
|
|
@@ -19075,7 +19210,7 @@ function lineForAnswer(act, phase, answer) {
|
|
|
19075
19210
|
case "build-started":
|
|
19076
19211
|
return line(`${nothingDone(act)}: tasks in ${phase} have started, so its scope can no longer be sent back. A built part goes back at the phase's review.`);
|
|
19077
19212
|
case "not-owner":
|
|
19078
|
-
return
|
|
19213
|
+
return notOwnerLine(act);
|
|
19079
19214
|
case "no-owner":
|
|
19080
19215
|
return line(`${nothingDone(act)}: this project has no owner, so nobody can approve or send back its scope.`);
|
|
19081
19216
|
case "not-offered":
|
|
@@ -19115,8 +19250,9 @@ async function decide(shape, opts) {
|
|
|
19115
19250
|
if (!readSessionAttended(env))
|
|
19116
19251
|
return notAttendedLine(act);
|
|
19117
19252
|
const read = readConfig(env);
|
|
19118
|
-
if (read.config === null)
|
|
19119
|
-
return notSignedInLine(act);
|
|
19253
|
+
if (read.config === null) {
|
|
19254
|
+
return readNeverConfiguredReason(env) === "not-this-account" ? notOwnerLine(act) : notSignedInLine(act);
|
|
19255
|
+
}
|
|
19120
19256
|
const { guardServiceToken, guardEngagementId } = read.config;
|
|
19121
19257
|
const shown = readShownPlans(guardEngagementId, opts.home);
|
|
19122
19258
|
const match = matchScopePhraseShape(shape, shown);
|
|
@@ -19157,7 +19293,7 @@ function readShownPlans(engagementId, home) {
|
|
|
19157
19293
|
return [];
|
|
19158
19294
|
let text;
|
|
19159
19295
|
try {
|
|
19160
|
-
text =
|
|
19296
|
+
text = readFileSync9(join8(home ?? homedir4(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SHOWN_PLANS_FILENAME), "utf-8");
|
|
19161
19297
|
} catch {
|
|
19162
19298
|
return [];
|
|
19163
19299
|
}
|
|
@@ -19196,7 +19332,7 @@ async function post(act, entry, request, engagementId, credential, env, fetchFn
|
|
|
19196
19332
|
}
|
|
19197
19333
|
|
|
19198
19334
|
// dist/resolve-engagement.js
|
|
19199
|
-
import { existsSync as existsSync6, readFileSync as
|
|
19335
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10, realpathSync as realpathSync3 } from "node:fs";
|
|
19200
19336
|
import { join as join9, sep as sep2 } from "node:path";
|
|
19201
19337
|
import { homedir as homedir5 } from "node:os";
|
|
19202
19338
|
function defaultRegistryPath() {
|
|
@@ -19206,7 +19342,7 @@ function readRegistry(registryPath = defaultRegistryPath()) {
|
|
|
19206
19342
|
if (!existsSync6(registryPath))
|
|
19207
19343
|
return {};
|
|
19208
19344
|
try {
|
|
19209
|
-
const parsed = JSON.parse(
|
|
19345
|
+
const parsed = JSON.parse(readFileSync10(registryPath, "utf-8"));
|
|
19210
19346
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
19211
19347
|
return {};
|
|
19212
19348
|
const out = {};
|
|
@@ -19254,13 +19390,13 @@ function runResolveEngagement(cwd, registryPath) {
|
|
|
19254
19390
|
}
|
|
19255
19391
|
|
|
19256
19392
|
// dist/refresh-credential.js
|
|
19257
|
-
import { readFileSync as
|
|
19258
|
-
import { resolve as
|
|
19393
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
19394
|
+
import { resolve as resolve4 } from "node:path";
|
|
19259
19395
|
|
|
19260
19396
|
// dist/mcp-headers.js
|
|
19261
|
-
import { readFileSync as
|
|
19397
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
19262
19398
|
import { homedir as homedir6 } from "node:os";
|
|
19263
|
-
import { dirname as dirname4, resolve as
|
|
19399
|
+
import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
19264
19400
|
function defaultWriteErr(text) {
|
|
19265
19401
|
process.stderr.write(text);
|
|
19266
19402
|
}
|
|
@@ -19273,28 +19409,12 @@ function headerLine(bearer, clientVersion) {
|
|
|
19273
19409
|
}
|
|
19274
19410
|
function projectRootFromBinary(binaryPath) {
|
|
19275
19411
|
const depth = VENDORED_BIN_REL.split("/").length - 1;
|
|
19276
|
-
return
|
|
19277
|
-
}
|
|
19278
|
-
function readPinnedId(root) {
|
|
19279
|
-
let raw;
|
|
19280
|
-
try {
|
|
19281
|
-
raw = readFileSync10(resolve2(root, BUNDLE_PIN_REL), "utf-8");
|
|
19282
|
-
} catch {
|
|
19283
|
-
return { problem: "no-pin" };
|
|
19284
|
-
}
|
|
19285
|
-
let pin;
|
|
19286
|
-
try {
|
|
19287
|
-
pin = JSON.parse(raw);
|
|
19288
|
-
} catch {
|
|
19289
|
-
return { problem: "no-id" };
|
|
19290
|
-
}
|
|
19291
|
-
const id = typeof pin === "object" && pin !== null ? pin[PIN_ENGAGEMENT_ID_FIELD] : void 0;
|
|
19292
|
-
return typeof id === "string" && id !== "" ? { id } : { problem: "no-id" };
|
|
19412
|
+
return resolve3(dirname4(binaryPath), ...Array(depth).fill(".."));
|
|
19293
19413
|
}
|
|
19294
19414
|
function readPinnedVersion(root) {
|
|
19295
19415
|
let raw;
|
|
19296
19416
|
try {
|
|
19297
|
-
raw =
|
|
19417
|
+
raw = readFileSync11(resolve3(root, BUNDLE_PIN_REL), "utf-8");
|
|
19298
19418
|
} catch {
|
|
19299
19419
|
return void 0;
|
|
19300
19420
|
}
|
|
@@ -19336,7 +19456,7 @@ function sentences(lines) {
|
|
|
19336
19456
|
}
|
|
19337
19457
|
function badIdSentence(root) {
|
|
19338
19458
|
return sentences([
|
|
19339
|
-
`${
|
|
19459
|
+
`${resolve3(root, BUNDLE_PIN_REL)} names an engagement id that is not a Halfcycle project id,`,
|
|
19340
19460
|
'so no credential was read. Delete that file and run "npx halfcycle" again: this repository',
|
|
19341
19461
|
"is then set up as a new Halfcycle project."
|
|
19342
19462
|
]);
|
|
@@ -19350,7 +19470,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
19350
19470
|
]);
|
|
19351
19471
|
case "no-id":
|
|
19352
19472
|
return sentences([
|
|
19353
|
-
`${
|
|
19473
|
+
`${resolve3(root, BUNDLE_PIN_REL)} names no engagement id.`,
|
|
19354
19474
|
'run "npx halfcycle" here to rewrite it.'
|
|
19355
19475
|
]);
|
|
19356
19476
|
case "bad-id":
|
|
@@ -19359,13 +19479,15 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
19359
19479
|
return sentences([
|
|
19360
19480
|
"this project belongs to another Halfcycle account, so this machine has no",
|
|
19361
19481
|
"credential for it and the Halfcycle tools are not available here. Nothing is",
|
|
19362
|
-
"broken
|
|
19363
|
-
|
|
19482
|
+
"broken.",
|
|
19483
|
+
requestAccessSentence(engagementId),
|
|
19484
|
+
"If this account is wrong, sign in as the account that owns it and run",
|
|
19485
|
+
'"npx halfcycle" again.'
|
|
19364
19486
|
]);
|
|
19365
19487
|
case "no-credential":
|
|
19366
19488
|
return sentences([
|
|
19367
19489
|
`this machine holds no credential for engagement ${engagementId ?? ""}.`,
|
|
19368
|
-
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${
|
|
19490
|
+
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${resolve3(home, HALFCYCLE_DIR_NAME)}, outside this repository.`
|
|
19369
19491
|
]);
|
|
19370
19492
|
}
|
|
19371
19493
|
}
|
|
@@ -19518,7 +19640,7 @@ var INITIALIZE_BODY = JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initializ
|
|
|
19518
19640
|
function registeredMcpUrl(projectRoot) {
|
|
19519
19641
|
let parsed;
|
|
19520
19642
|
try {
|
|
19521
|
-
parsed = JSON.parse(
|
|
19643
|
+
parsed = JSON.parse(readFileSync12(resolve4(projectRoot, MCP_REGISTRATION_REL), "utf-8"));
|
|
19522
19644
|
} catch {
|
|
19523
19645
|
return void 0;
|
|
19524
19646
|
}
|
|
@@ -19723,7 +19845,7 @@ async function runRefreshCredential(opts) {
|
|
|
19723
19845
|
}
|
|
19724
19846
|
if (readConfig().config === null) {
|
|
19725
19847
|
const remedySaid = parts.some(namesTheSignInCommand);
|
|
19726
|
-
parts.push(noCoverageStatement(readNeverConfiguredReason(), remedySaid));
|
|
19848
|
+
parts.push(noCoverageStatement(readNeverConfiguredReason(), remedySaid, pinnedEngagementId(projectRootFromBinary(opts.binaryPath))));
|
|
19727
19849
|
}
|
|
19728
19850
|
for (const said of renewalSaid) {
|
|
19729
19851
|
if (namesTheSignInCommand(said) && parts.some(namesTheSignInCommand))
|
|
@@ -19747,7 +19869,7 @@ async function runRefreshCredential(opts) {
|
|
|
19747
19869
|
import { fileURLToPath } from "node:url";
|
|
19748
19870
|
|
|
19749
19871
|
// dist/capture.js
|
|
19750
|
-
import { readFileSync as
|
|
19872
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "node:fs";
|
|
19751
19873
|
import { dirname as dirname5 } from "node:path";
|
|
19752
19874
|
function runCapture(provider, endpoint, opts = {}) {
|
|
19753
19875
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -19815,7 +19937,7 @@ function readInputFile(fromFile) {
|
|
|
19815
19937
|
if (!fromFile)
|
|
19816
19938
|
return void 0;
|
|
19817
19939
|
try {
|
|
19818
|
-
return
|
|
19940
|
+
return readFileSync13(fromFile, "utf-8");
|
|
19819
19941
|
} catch {
|
|
19820
19942
|
return void 0;
|
|
19821
19943
|
}
|
|
@@ -19927,10 +20049,10 @@ Commit the fixture; the next guard evaluation of this endpoint will pass.
|
|
|
19927
20049
|
process.exit(1);
|
|
19928
20050
|
}
|
|
19929
20051
|
function readStdin3() {
|
|
19930
|
-
return new Promise((
|
|
20052
|
+
return new Promise((resolve5, reject) => {
|
|
19931
20053
|
const chunks = [];
|
|
19932
20054
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
19933
|
-
process.stdin.on("end", () =>
|
|
20055
|
+
process.stdin.on("end", () => resolve5(Buffer.concat(chunks).toString("utf-8")));
|
|
19934
20056
|
process.stdin.on("error", reject);
|
|
19935
20057
|
});
|
|
19936
20058
|
}
|
package/dist/cli.js
CHANGED
|
@@ -2067,6 +2067,15 @@ function isNotThisAccountRefusal(body) {
|
|
|
2067
2067
|
return typeof body === "object" && body !== null && body.reason === NOT_THIS_ACCOUNT_REASON;
|
|
2068
2068
|
}
|
|
2069
2069
|
|
|
2070
|
+
// ../events/dist/project-page.js
|
|
2071
|
+
function projectPageUrl(engagementId) {
|
|
2072
|
+
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
2073
|
+
}
|
|
2074
|
+
function requestAccessSentence(engagementId) {
|
|
2075
|
+
const page = projectPageUrl(engagementId) ?? "this project's page on Halfcycle";
|
|
2076
|
+
return `To ask for access, open ${page} signed in as this account and choose "Request access". Then let the project's owner know, so they can approve it.`;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2070
2079
|
// ../events/dist/account-identity.js
|
|
2071
2080
|
import { z as z12 } from "zod";
|
|
2072
2081
|
var accountIdentitySchema = z12.object({
|
|
@@ -2788,11 +2797,6 @@ function nodeFloorProgram(guarded) {
|
|
|
2788
2797
|
return `if(+process.versions.node.split('.')[0]<${NODE_FLOOR_MAJOR}){console.error('${NODE_FLOOR_SENTENCE_HEAD}'+process.versions.node);process.exitCode=1}else{${guarded}}`;
|
|
2789
2798
|
}
|
|
2790
2799
|
|
|
2791
|
-
// dist/project-page.js
|
|
2792
|
-
function projectPageUrl(engagementId) {
|
|
2793
|
-
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
2794
|
-
}
|
|
2795
|
-
|
|
2796
2800
|
// dist/merge-settings.js
|
|
2797
2801
|
function isHalfcycleCommand(hook, halfcycleCommands) {
|
|
2798
2802
|
if (typeof hook !== "object" || hook === null)
|
|
@@ -8886,7 +8890,7 @@ ${PROJECT_RESET_LINE}
|
|
|
8886
8890
|
`);
|
|
8887
8891
|
}
|
|
8888
8892
|
if (credential === void 0 && notThisAccountMessage !== void 0) {
|
|
8889
|
-
process.stdout.write(`[halfcycle] ${notThisAccountMessage} Your work carries on exactly as it would without Halfcycle: no edit is evaluated, and nothing you do here is reported as having passed.
|
|
8893
|
+
process.stdout.write(`[halfcycle] ${notThisAccountMessage} Your work carries on exactly as it would without Halfcycle: no edit is evaluated, and nothing you do here is reported as having passed. ${requestAccessSentence(engagementId)} ${identitySwitchRemedy(void 0, isInteractiveRun())}
|
|
8890
8894
|
`);
|
|
8891
8895
|
}
|
|
8892
8896
|
reportClaudeCodeVersion(verbose);
|