halfcycle 0.10.0 → 0.11.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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +1391 -867
- package/commands/agent-teams-orchestration.md +1 -1
- package/commands/consistency-check.md +1 -1
- package/commands/context-update.md +1 -1
- package/commands/halfcycle-design.md +1 -1
- package/commands/halfcycle-setup.md +1 -1
- package/commands/stack-assembly-worker.md +1 -1
- package/commands/task-execution.md +1 -1
- package/commands/task-graph.md +1 -1
- package/commands/write-spec.md +1 -1
- package/dist/bin.js +0 -0
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/check-tasks.d.ts +28 -5
- package/dist/check-tasks.d.ts.map +1 -1
- package/dist/cli-contract.d.ts +1 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +2346 -1312
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +4 -4
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/index.js +127 -68
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/local-allow.d.ts +108 -0
- package/dist/local-allow.d.ts.map +1 -0
- package/dist/open-phase.d.ts +8 -2
- package/dist/open-phase.d.ts.map +1 -1
- package/dist/pace.d.ts +11 -6
- package/dist/pace.d.ts.map +1 -1
- package/dist/review.d.ts +3 -2
- package/dist/review.d.ts.map +1 -1
- package/dist/size.d.ts +72 -0
- package/dist/size.d.ts.map +1 -0
- package/dist/uninstall.d.ts.map +1 -1
- package/package.json +11 -11
package/bin/bin.bundle.mjs
CHANGED
|
@@ -17302,6 +17302,28 @@ var timeTaskSummarySchema = external_exports.object({
|
|
|
17302
17302
|
usage: timeUsageTotalsSchema
|
|
17303
17303
|
}).strict();
|
|
17304
17304
|
var TIME_KINDS_MAX = buildTaskKindSchema.options.length + 1;
|
|
17305
|
+
var timeSharePercentSchema = external_exports.number().nonnegative().finite();
|
|
17306
|
+
var timeShareKindSchema = external_exports.object({
|
|
17307
|
+
kind: external_exports.enum(TIME_ROW_KEYS),
|
|
17308
|
+
percent: timeSharePercentSchema
|
|
17309
|
+
}).strict();
|
|
17310
|
+
var timeShareKindsSchema = external_exports.array(timeShareKindSchema).max(TIME_ROW_KEYS.length).superRefine((kinds, ctx) => {
|
|
17311
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17312
|
+
kinds.forEach((entry, i) => {
|
|
17313
|
+
if (seen.has(entry.kind))
|
|
17314
|
+
ctx.addIssue({ code: "custom", path: [i, "kind"], message: "lists one kind twice" });
|
|
17315
|
+
seen.add(entry.kind);
|
|
17316
|
+
});
|
|
17317
|
+
});
|
|
17318
|
+
var timeSummaryShareSchema = external_exports.discriminatedUnion("state", [
|
|
17319
|
+
external_exports.object({ state: external_exports.literal("unknown") }).strict(),
|
|
17320
|
+
external_exports.object({
|
|
17321
|
+
state: external_exports.literal("known"),
|
|
17322
|
+
weekCeilingTokens: external_exports.number().int().positive(),
|
|
17323
|
+
spentPercent: timeSharePercentSchema,
|
|
17324
|
+
kinds: timeShareKindsSchema
|
|
17325
|
+
}).strict()
|
|
17326
|
+
]);
|
|
17305
17327
|
var timeSummarySchema = external_exports.object({
|
|
17306
17328
|
phase: phaseNameSchema,
|
|
17307
17329
|
closed: external_exports.boolean(),
|
|
@@ -17319,7 +17341,8 @@ var timeSummarySchema = external_exports.object({
|
|
|
17319
17341
|
notTiedToATask: external_exports.object({
|
|
17320
17342
|
totals: timeTotalsSchema,
|
|
17321
17343
|
usage: timeUsageTotalsSchema
|
|
17322
|
-
}).strict()
|
|
17344
|
+
}).strict(),
|
|
17345
|
+
share: timeSummaryShareSchema.optional()
|
|
17323
17346
|
}).strict().superRefine((v, ctx) => {
|
|
17324
17347
|
if (v.closed !== (v.closedAt !== null)) {
|
|
17325
17348
|
ctx.addIssue({ code: "custom", path: ["closedAt"], message: "must be set exactly when the phase is closed" });
|
|
@@ -17384,6 +17407,16 @@ function timeDurationLabelOf(seconds) {
|
|
|
17384
17407
|
return `${String(hours)} h ${String(minutes).padStart(2, "0")} min`;
|
|
17385
17408
|
}
|
|
17386
17409
|
|
|
17410
|
+
// ../events/dist/repository-facts.js
|
|
17411
|
+
var REPOSITORY_FACTS = Object.freeze(["database", "browser-app", "inbound-webhooks"]);
|
|
17412
|
+
var repositoryFactSchema = external_exports.enum(REPOSITORY_FACTS);
|
|
17413
|
+
var repositoryFactsSchema = external_exports.array(repositoryFactSchema).max(REPOSITORY_FACTS.length).refine((facts) => new Set(facts).size === facts.length, { message: "must name each fact once" });
|
|
17414
|
+
var REPOSITORY_FACT_WORDS = Object.freeze({
|
|
17415
|
+
database: "database",
|
|
17416
|
+
"browser-app": "web front end",
|
|
17417
|
+
"inbound-webhooks": "incoming webhooks"
|
|
17418
|
+
});
|
|
17419
|
+
|
|
17387
17420
|
// ../events/dist/code-link.js
|
|
17388
17421
|
var codeLinkAddressSchema = external_exports.string().regex(GITHUB_REPOSITORY_ADDRESS, { message: "must be a GitHub repository address: https://github.com/<owner>/<repo>" }).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key, so it is not sent" });
|
|
17389
17422
|
var codeLinkFactsSchema = external_exports.object({
|
|
@@ -18113,7 +18146,7 @@ var phaseWorkSchema = external_exports.object({
|
|
|
18113
18146
|
var STANDING_RULE_FILE = "docs/invariants.md";
|
|
18114
18147
|
var CHANGE_MOVED_BY = Object.freeze(["sort", "person", "self"]);
|
|
18115
18148
|
var changeMovedBySchema = external_exports.enum(CHANGE_MOVED_BY);
|
|
18116
|
-
var PHASE_PATH_SET_BY = Object.freeze(["open", "person", "self"]);
|
|
18149
|
+
var PHASE_PATH_SET_BY = Object.freeze(["open", "person", "self", "size"]);
|
|
18117
18150
|
var phasePathSetBySchema = external_exports.enum(PHASE_PATH_SET_BY);
|
|
18118
18151
|
var SMALL_CHANGE_OUTCOMES = Object.freeze(["done", "moved-up", "stopped"]);
|
|
18119
18152
|
var smallChangeOutcomeSchema = external_exports.enum(SMALL_CHANGE_OUTCOMES);
|
|
@@ -18684,789 +18717,963 @@ function shownReviewEntryOf(view, shownAt) {
|
|
|
18684
18717
|
};
|
|
18685
18718
|
}
|
|
18686
18719
|
|
|
18687
|
-
// ../events/dist/
|
|
18688
|
-
var
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
var TYPED_REVIEW_OFF_SENTENCE = "Reviewing by typing is switched off for now.";
|
|
18692
|
-
var CLIENT_UPDATE_SENTENCE = `To approve by typing in a session, Halfcycle needs updating: run \`${HALFCYCLE_COMMAND}\` in this project's folder, then reopen your session and ask again.`;
|
|
18693
|
-
|
|
18694
|
-
// ../events/dist/device-auth.js
|
|
18695
|
-
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");
|
|
18696
|
-
var DEVICE_AUTH_STATUS = {
|
|
18697
|
-
/** The poll: minted, nobody has acted yet. Keep polling. 200. */
|
|
18698
|
-
PENDING: "pending",
|
|
18699
|
-
/** The poll: approved, and the credential is in this body. Once only. 200. */
|
|
18700
|
-
APPROVED: "approved",
|
|
18701
|
-
/** Confirm: the decision was recorded (approve or decline). 200. */
|
|
18702
|
-
RECORDED: "recorded",
|
|
18703
|
-
/** The human refused at the confirmation page. 400 on the poll. */
|
|
18704
|
-
DECLINED: "declined",
|
|
18705
|
-
/** The code's absolute expiry has passed. 400. */
|
|
18706
|
-
EXPIRED: "expired",
|
|
18707
|
-
/** Never minted, or already spent. 400. */
|
|
18708
|
-
UNKNOWN: "unknown",
|
|
18709
|
-
/** Confirm: neither `approve` nor `decline` was named. Nothing was bound. 400. */
|
|
18710
|
-
INVALID_DECISION: "invalid-decision",
|
|
18711
|
-
/** Confirm: an approval arrived with no signed-in identity. 400. */
|
|
18712
|
-
IDENTITY_REQUIRED: "identity-required",
|
|
18713
|
-
/** This deployment has no `SIGNIN_BASE_URL` / `DEVICE_AUTH_CONFIRM_SECRET`. 503. */
|
|
18714
|
-
NOT_CONFIGURED: "not-configured",
|
|
18715
|
-
/** Confirm: the shared confirmation secret was missing or wrong. 401. */
|
|
18716
|
-
UNAUTHORIZED: "unauthorized",
|
|
18717
|
-
/** Confirm: the code was already approved, declined or claimed. 409. */
|
|
18718
|
-
ALREADY_DECIDED: "already-decided",
|
|
18719
|
-
/**
|
|
18720
|
-
* Confirm: an approval named a signed-in identity whose account has not accepted
|
|
18721
|
-
* the terms of service and privacy policy currently in force. 400.
|
|
18722
|
-
*
|
|
18723
|
-
* NOT BOUND TO THE DEVICE CODE. Unlike every other refusal in this const, this one
|
|
18724
|
-
* says nothing about the code itself — the code is still `pending` after this
|
|
18725
|
-
* response, exactly as it was before the request, so the SAME userCode can be
|
|
18726
|
-
* confirmed again once the caller has recorded acceptance. `deviceConfirmRequestSchema`'s
|
|
18727
|
-
* `acceptTerms` is how a second confirm says it did.
|
|
18728
|
-
*/
|
|
18729
|
-
TERMS_REQUIRED: "terms-required"
|
|
18730
|
-
};
|
|
18731
|
-
var DEVICE_POLL_REFUSALS = [
|
|
18732
|
-
DEVICE_AUTH_STATUS.DECLINED,
|
|
18733
|
-
DEVICE_AUTH_STATUS.EXPIRED,
|
|
18734
|
-
DEVICE_AUTH_STATUS.UNKNOWN
|
|
18735
|
-
];
|
|
18736
|
-
var deviceAuthStartResponseSchema = external_exports.object({
|
|
18737
|
-
deviceCode: external_exports.string().min(1),
|
|
18738
|
-
userCode: external_exports.string().min(1),
|
|
18739
|
-
verificationUrl: external_exports.string().min(1),
|
|
18740
|
-
expiresAt: utcIso86012,
|
|
18741
|
-
pollIntervalMs: external_exports.number().int().positive()
|
|
18742
|
-
}).strict();
|
|
18743
|
-
var devicePollPendingSchema = external_exports.object({
|
|
18744
|
-
status: external_exports.literal(DEVICE_AUTH_STATUS.PENDING),
|
|
18745
|
-
pollIntervalMs: external_exports.number().int().positive()
|
|
18746
|
-
}).strict();
|
|
18747
|
-
var devicePollApprovedSchema = external_exports.object({
|
|
18748
|
-
status: external_exports.literal(DEVICE_AUTH_STATUS.APPROVED),
|
|
18749
|
-
accountId: external_exports.string().min(1),
|
|
18750
|
-
credential: external_exports.string().min(1),
|
|
18751
|
-
expiresAt: utcIso86012
|
|
18752
|
-
}).strict();
|
|
18753
|
-
var deviceAuthRefusalSchema = external_exports.object({
|
|
18754
|
-
status: external_exports.enum([
|
|
18755
|
-
DEVICE_AUTH_STATUS.DECLINED,
|
|
18756
|
-
DEVICE_AUTH_STATUS.EXPIRED,
|
|
18757
|
-
DEVICE_AUTH_STATUS.UNKNOWN,
|
|
18758
|
-
DEVICE_AUTH_STATUS.INVALID_DECISION,
|
|
18759
|
-
DEVICE_AUTH_STATUS.IDENTITY_REQUIRED,
|
|
18760
|
-
DEVICE_AUTH_STATUS.NOT_CONFIGURED,
|
|
18761
|
-
DEVICE_AUTH_STATUS.UNAUTHORIZED,
|
|
18762
|
-
DEVICE_AUTH_STATUS.ALREADY_DECIDED,
|
|
18763
|
-
DEVICE_AUTH_STATUS.TERMS_REQUIRED
|
|
18764
|
-
]),
|
|
18765
|
-
message: external_exports.string().min(1)
|
|
18766
|
-
}).strict();
|
|
18767
|
-
var devicePollResponseSchema = external_exports.union([
|
|
18768
|
-
devicePollPendingSchema,
|
|
18769
|
-
devicePollApprovedSchema,
|
|
18770
|
-
deviceAuthRefusalSchema
|
|
18771
|
-
]);
|
|
18772
|
-
var deviceConfirmRequestSchema = external_exports.object({
|
|
18773
|
-
userCode: external_exports.string().min(1),
|
|
18774
|
-
decision: external_exports.enum(["approve", "decline"]),
|
|
18775
|
-
externalAuthId: external_exports.string().min(1).optional(),
|
|
18776
|
-
email: external_exports.string().optional(),
|
|
18777
|
-
acceptTerms: external_exports.boolean().optional()
|
|
18778
|
-
}).strict();
|
|
18779
|
-
var deviceConfirmRecordedSchema = external_exports.object({
|
|
18780
|
-
status: external_exports.literal(DEVICE_AUTH_STATUS.RECORDED),
|
|
18781
|
-
accountId: external_exports.string().min(1).optional()
|
|
18782
|
-
}).strict();
|
|
18783
|
-
var deviceConfirmResponseSchema = external_exports.union([
|
|
18784
|
-
deviceConfirmRecordedSchema,
|
|
18785
|
-
deviceAuthRefusalSchema
|
|
18786
|
-
]);
|
|
18787
|
-
var DASHBOARD_URL = "https://app.halfcycle.ai";
|
|
18788
|
-
|
|
18789
|
-
// ../events/dist/project-page.js
|
|
18790
|
-
function projectPageUrl(engagementId) {
|
|
18791
|
-
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
18720
|
+
// ../events/dist/stop-words.js
|
|
18721
|
+
var NOTHING_NEEDED = "Nothing is needed from you.";
|
|
18722
|
+
function isOneLine(v) {
|
|
18723
|
+
return !/[\r\n]/.test(v);
|
|
18792
18724
|
}
|
|
18793
|
-
function
|
|
18794
|
-
|
|
18795
|
-
if (page === void 0)
|
|
18796
|
-
return void 0;
|
|
18797
|
-
return `${page}/console/system-view?${new URLSearchParams({ phase }).toString()}`;
|
|
18725
|
+
function asksSomething(v) {
|
|
18726
|
+
return v.includes("?");
|
|
18798
18727
|
}
|
|
18799
|
-
function
|
|
18800
|
-
|
|
18801
|
-
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.`;
|
|
18728
|
+
function saysNothingIsNeeded(yourPart) {
|
|
18729
|
+
return yourPart === null || typeof yourPart === "string" && yourPart.trim() === NOTHING_NEEDED;
|
|
18802
18730
|
}
|
|
18803
|
-
|
|
18804
|
-
|
|
18805
|
-
|
|
18806
|
-
|
|
18807
|
-
|
|
18808
|
-
|
|
18809
|
-
|
|
18810
|
-
|
|
18811
|
-
phase: scopePhaseSchema,
|
|
18812
|
-
number: external_exports.number().int().min(1),
|
|
18813
|
-
notes: external_exports.array(scopeNoteEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX + 1)
|
|
18814
|
-
}).strict().superRefine((entry, ctx) => {
|
|
18815
|
-
entry.notes.forEach((n, i) => {
|
|
18816
|
-
if (n.part === void 0 && i !== entry.notes.length - 1) {
|
|
18817
|
-
ctx.addIssue({
|
|
18818
|
-
code: external_exports.ZodIssueCode.custom,
|
|
18819
|
-
path: ["notes", i],
|
|
18820
|
-
message: "the note on the whole phase comes after every note on a part"
|
|
18821
|
-
});
|
|
18822
|
-
}
|
|
18823
|
-
});
|
|
18824
|
-
});
|
|
18825
|
-
var scopeWaitingSchema = external_exports.object({
|
|
18826
|
-
phase: scopePhaseSchema,
|
|
18827
|
-
number: external_exports.number().int().min(1),
|
|
18828
|
-
changedParts: external_exports.array(scopePartNameSchema).max(PHASE_PLAN_CHANGES_MAX)
|
|
18829
|
-
}).strict();
|
|
18830
|
-
var scopeNoticesSchema = external_exports.object({
|
|
18831
|
-
sentBack: external_exports.array(scopeSentBackSchema),
|
|
18832
|
-
waiting: external_exports.array(scopeWaitingSchema),
|
|
18833
|
-
typedApprovalOffered: external_exports.boolean()
|
|
18834
|
-
}).strict().refine((v) => v.sentBack.length > 0 || v.waiting.length > 0, {
|
|
18835
|
-
message: "carried only when a phase was sent back or waits for the owner"
|
|
18731
|
+
var stopPartSchema = external_exports.string().refine((v) => v.trim().length > 0, { message: "must say something" }).refine(isOneLine, { message: "must be one line" });
|
|
18732
|
+
var stopWordsSchema = external_exports.object({
|
|
18733
|
+
happened: stopPartSchema,
|
|
18734
|
+
yourPart: stopPartSchema.nullable(),
|
|
18735
|
+
next: stopPartSchema
|
|
18736
|
+
}).strict().refine((w) => !(saysNothingIsNeeded(w.yourPart) && (asksSomething(w.happened) || asksSomething(w.next))), {
|
|
18737
|
+
message: "asks the person something, so it cannot say nothing is needed from them",
|
|
18738
|
+
path: ["yourPart"]
|
|
18836
18739
|
});
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
function approvedInConsoleSentence(phase) {
|
|
18840
|
-
return `Scope for ${phaseWords(phase)} was approved in the console; continuing. Say so to the person, then carry on with the next step; they do not need to tell you.`;
|
|
18841
|
-
}
|
|
18842
|
-
function quotedParts(parts) {
|
|
18843
|
-
return parts.map((p) => `"${p}"`).join(", ");
|
|
18844
|
-
}
|
|
18845
|
-
function approvalSentence(phase, offerTyping) {
|
|
18846
|
-
if (offerTyping === "off")
|
|
18847
|
-
return TYPED_APPROVAL_OFF_SENTENCE;
|
|
18848
|
-
if (offerTyping === "update")
|
|
18849
|
-
return CLIENT_UPDATE_SENTENCE;
|
|
18850
|
-
return `In their own interactive session ${HEADLESS_CANNOT_APPROVE}, they ask to see the plan, check each part, and then type: approve ${phase}.`;
|
|
18740
|
+
function stopTextOf(words) {
|
|
18741
|
+
return `${words.happened} ${words.yourPart ?? NOTHING_NEEDED} ${words.next}`;
|
|
18851
18742
|
}
|
|
18852
|
-
|
|
18853
|
-
|
|
18743
|
+
|
|
18744
|
+
// ../events/dist/pacing.js
|
|
18745
|
+
var CAREFUL_START_AGENTS = 3;
|
|
18746
|
+
var KEEP_FREE_MAX = 90;
|
|
18747
|
+
var keepFreePercentSchema = external_exports.number().int().min(0).max(KEEP_FREE_MAX);
|
|
18748
|
+
var KEEP_FREE_DEFAULT = 20;
|
|
18749
|
+
var PACE_AGENTS_MAX = 20;
|
|
18750
|
+
var FIVE_HOUR_WINDOW_MINUTES = 300;
|
|
18751
|
+
var SEVEN_DAY_WINDOW_MINUTES = 10080;
|
|
18752
|
+
var PACE_WINDOW_MINUTES_MAX = 525600;
|
|
18753
|
+
var MINUTE_KEY = /^([1-9][0-9]{0,6})-minute$/;
|
|
18754
|
+
function isPaceWindowKind(value) {
|
|
18755
|
+
if (value === "five-hour" || value === "seven-day")
|
|
18756
|
+
return true;
|
|
18757
|
+
if (typeof value !== "string")
|
|
18758
|
+
return false;
|
|
18759
|
+
const match = MINUTE_KEY.exec(value);
|
|
18760
|
+
if (match === null)
|
|
18761
|
+
return false;
|
|
18762
|
+
const minutes = Number(match[1]);
|
|
18763
|
+
return minutes <= PACE_WINDOW_MINUTES_MAX && minutes !== FIVE_HOUR_WINDOW_MINUTES && minutes !== SEVEN_DAY_WINDOW_MINUTES;
|
|
18854
18764
|
}
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18765
|
+
var paceWindowKindSchema = external_exports.custom((value) => isPaceWindowKind(value), {
|
|
18766
|
+
message: "not a usage window key"
|
|
18767
|
+
});
|
|
18768
|
+
function paceWindowMinutesOf(kind) {
|
|
18769
|
+
if (kind === "five-hour")
|
|
18770
|
+
return FIVE_HOUR_WINDOW_MINUTES;
|
|
18771
|
+
if (kind === "seven-day")
|
|
18772
|
+
return SEVEN_DAY_WINDOW_MINUTES;
|
|
18773
|
+
return Number(MINUTE_KEY.exec(kind)?.[1] ?? 0);
|
|
18861
18774
|
}
|
|
18862
|
-
function
|
|
18863
|
-
if (
|
|
18864
|
-
return
|
|
18865
|
-
|
|
18775
|
+
function paceWindowKindOf(minutes) {
|
|
18776
|
+
if (!Number.isInteger(minutes) || minutes < 1 || minutes > PACE_WINDOW_MINUTES_MAX)
|
|
18777
|
+
return null;
|
|
18778
|
+
if (minutes === FIVE_HOUR_WINDOW_MINUTES)
|
|
18779
|
+
return "five-hour";
|
|
18780
|
+
if (minutes === SEVEN_DAY_WINDOW_MINUTES)
|
|
18781
|
+
return "seven-day";
|
|
18782
|
+
return `${String(minutes)}-minute`;
|
|
18866
18783
|
}
|
|
18867
|
-
function
|
|
18868
|
-
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
18784
|
+
function paceWindowWordsOf(kind) {
|
|
18785
|
+
const minutes = paceWindowMinutesOf(kind);
|
|
18786
|
+
if (minutes === FIVE_HOUR_WINDOW_MINUTES)
|
|
18787
|
+
return "5-hour window";
|
|
18788
|
+
if (minutes === SEVEN_DAY_WINDOW_MINUTES)
|
|
18789
|
+
return "weekly window";
|
|
18790
|
+
if (minutes % 1440 === 0)
|
|
18791
|
+
return `${String(minutes / 1440)}-day window`;
|
|
18792
|
+
if (minutes % 60 === 0)
|
|
18793
|
+
return `${String(minutes / 60)}-hour window`;
|
|
18794
|
+
return `${String(minutes)}-minute window`;
|
|
18874
18795
|
}
|
|
18875
|
-
function
|
|
18876
|
-
|
|
18877
|
-
return {
|
|
18878
|
-
sentBack: scope.sentBack.map(sentBackNotice),
|
|
18879
|
-
waiting: scope.waiting.filter((w) => omit2 === void 0 || w.phase !== omit2).map((w) => waitingNotice(w, options.offerTyping, options.engagementId))
|
|
18880
|
-
};
|
|
18796
|
+
function paceShareWordsOf(keepFreePercent) {
|
|
18797
|
+
return keepFreePercent === 20 ? "a fifth" : `${String(keepFreePercent)}%`;
|
|
18881
18798
|
}
|
|
18882
|
-
|
|
18883
|
-
|
|
18884
|
-
var
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18799
|
+
var PACE_STATES = ["full", "slowing", "holding"];
|
|
18800
|
+
var paceStateSchema = external_exports.enum(PACE_STATES);
|
|
18801
|
+
var PACE_SHARE_GIVEN_IN = ["chat", "agent", "relayed"];
|
|
18802
|
+
var paceShareGivenInSchema = external_exports.enum(PACE_SHARE_GIVEN_IN);
|
|
18803
|
+
var paceShareRequestSchema = external_exports.object({ keepFreePercent: keepFreePercentSchema, givenIn: paceShareGivenInSchema }).strict();
|
|
18804
|
+
var paceShareResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
18805
|
+
external_exports.object({
|
|
18806
|
+
outcome: external_exports.literal("recorded"),
|
|
18807
|
+
keepFreePercent: keepFreePercentSchema,
|
|
18808
|
+
moreAllowance: external_exports.boolean().optional()
|
|
18809
|
+
}).strict(),
|
|
18810
|
+
external_exports.object({ outcome: external_exports.literal("needs-the-person"), keepFreePercent: keepFreePercentSchema }).strict(),
|
|
18811
|
+
external_exports.object({ outcome: external_exports.literal("not-owner") }).strict(),
|
|
18812
|
+
external_exports.object({ outcome: external_exports.literal("no-owner") }).strict(),
|
|
18813
|
+
external_exports.object({ outcome: external_exports.literal("unavailable") }).strict()
|
|
18814
|
+
]);
|
|
18815
|
+
var pacingBasisTaskSchema = external_exports.object({
|
|
18816
|
+
id: buildTaskIdSchema,
|
|
18817
|
+
dependsOn: external_exports.array(buildTaskIdSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
18818
|
+
budgetMinutes: external_exports.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
|
|
18819
|
+
human: external_exports.boolean(),
|
|
18820
|
+
kind: buildTaskKindSchema.optional()
|
|
18897
18821
|
}).strict();
|
|
18898
|
-
var
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
const answer = `${HALFCYCLE_COMMAND} review ${quoteForShell(entry.phase)} --answer ${quoteForShell(entry.part)} "<your answer>"`;
|
|
18909
|
-
return `Before anything else: the project's owner asked about "${entry.partName}" in the review of ${phaseCalled(entry.phase)}: ${entry.question} Answer it with ${answer}.`;
|
|
18910
|
-
}
|
|
18911
|
-
function sentBackNotice2(entry) {
|
|
18912
|
-
return `Before anything else: the project's owner sent "${entry.partName}" in ${phaseCalled(entry.phase)} back to building: ${entry.note} Rebuild it: add or reopen the tasks that build it. For each task that rebuilds it, add a task that reviews the rebuild, held by a different agent from the one that built it. When each review has passed, report the build with the time each task finished, then run the close step again.`;
|
|
18822
|
+
var PACE_DEFAULT_TASK_MINUTES = 30;
|
|
18823
|
+
var PACE_DURATION_ROUND_MINUTES = 10;
|
|
18824
|
+
function taskMinutesOf(task, medianTaskMinutes) {
|
|
18825
|
+
if (task.human)
|
|
18826
|
+
return 0;
|
|
18827
|
+
if (task.budgetMinutes !== void 0)
|
|
18828
|
+
return task.budgetMinutes;
|
|
18829
|
+
if (medianTaskMinutes !== null && medianTaskMinutes > 0)
|
|
18830
|
+
return medianTaskMinutes;
|
|
18831
|
+
return PACE_DEFAULT_TASK_MINUTES;
|
|
18913
18832
|
}
|
|
18914
|
-
function
|
|
18915
|
-
return
|
|
18833
|
+
function paceDurationRoundedOf(minutes) {
|
|
18834
|
+
return Math.ceil(minutes / PACE_DURATION_ROUND_MINUTES) * PACE_DURATION_ROUND_MINUTES;
|
|
18916
18835
|
}
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
18926
|
-
consoleUrl: external_exports.string().optional()
|
|
18927
|
-
}).strict();
|
|
18928
|
-
var ciTokenExchangeResponseSchema = external_exports.object({
|
|
18929
|
-
token: external_exports.string(),
|
|
18930
|
-
expiresAt: utcIso8601,
|
|
18931
|
-
engagementId: external_exports.string()
|
|
18932
|
-
}).strict();
|
|
18933
|
-
var NO_CREDENTIAL_PLACEHOLDER = "halfcycle:no-credential";
|
|
18934
|
-
var NOT_THIS_ACCOUNT_PLACEHOLDER = "halfcycle:not-this-account";
|
|
18935
|
-
var UPDATE_CLAUDE_CODE_PLACEHOLDER = "halfcycle:update-claude-code";
|
|
18936
|
-
var CREDENTIAL_PLACEHOLDERS = [
|
|
18937
|
-
NO_CREDENTIAL_PLACEHOLDER,
|
|
18938
|
-
NOT_THIS_ACCOUNT_PLACEHOLDER,
|
|
18939
|
-
UPDATE_CLAUDE_CODE_PLACEHOLDER
|
|
18940
|
-
];
|
|
18941
|
-
var SWITCH_ACCOUNT_ANSWER = 'answer "s" when asked';
|
|
18942
|
-
var NO_CREDENTIAL_SENTENCE = 'Halfcycle is not connected: this machine has no working Halfcycle credential for this project. Run "npx halfcycle" in the project folder to sign in again.';
|
|
18943
|
-
var NOT_THIS_ACCOUNT_SENTENCE = `Halfcycle is not connected: this project belongs to another Halfcycle account. To switch, run "npx halfcycle" in this project and ${SWITCH_ACCOUNT_ANSWER}.`;
|
|
18944
|
-
var UPDATE_CLAUDE_CODE_SENTENCE = "Halfcycle is not connected: this Claude Code version does not name the server it connects to, so no credential was sent. Update Claude Code, then reopen.";
|
|
18945
|
-
var CANNOT_REACH_SENTENCE = "Halfcycle is not connected: its server could not be reached, so its tools are unavailable in this session. Check your network, then reopen the project.";
|
|
18946
|
-
var SERVICE_PROBLEM_SENTENCE = "Halfcycle is not connected: its service had a problem just now, so nothing in this session is being checked. Reopen the project to try again.";
|
|
18947
|
-
var FOLDER_NOT_TRUSTED_SENTENCE = "Folder not yet trusted. Open this folder once in interactive Claude Code and trust it; then headless runs work.";
|
|
18948
|
-
var SCOPE_UNCHECKED_SENTENCE = "If this project needs approval before building, that cannot be checked either, so work done now shows as built without approval unless already approved.";
|
|
18949
|
-
var PLACEHOLDER_SENTENCES = Object.freeze({
|
|
18950
|
-
[NO_CREDENTIAL_PLACEHOLDER]: NO_CREDENTIAL_SENTENCE,
|
|
18951
|
-
[NOT_THIS_ACCOUNT_PLACEHOLDER]: NOT_THIS_ACCOUNT_SENTENCE,
|
|
18952
|
-
[UPDATE_CLAUDE_CODE_PLACEHOLDER]: UPDATE_CLAUDE_CODE_SENTENCE
|
|
18953
|
-
});
|
|
18954
|
-
|
|
18955
|
-
// ../events/dist/scope-chat.js
|
|
18956
|
-
var chatScopeApproveRequestSchema = external_exports.object({
|
|
18957
|
-
act: external_exports.literal("approve"),
|
|
18958
|
-
reference: phaseIdentitySchema,
|
|
18959
|
-
planVersion: planVersionSchema
|
|
18960
|
-
}).strict();
|
|
18961
|
-
var chatScopeSendBackRequestSchema = external_exports.object({
|
|
18962
|
-
act: external_exports.literal("send-back"),
|
|
18963
|
-
reference: phaseIdentitySchema,
|
|
18964
|
-
planVersion: planVersionSchema,
|
|
18965
|
-
note: scopeNoteWireSchema.optional()
|
|
18966
|
-
}).strict();
|
|
18967
|
-
var chatScopeRequestSchema = external_exports.discriminatedUnion("act", [
|
|
18968
|
-
chatScopeApproveRequestSchema,
|
|
18969
|
-
chatScopeSendBackRequestSchema
|
|
18970
|
-
]);
|
|
18971
|
-
var CHAT_SCOPE_ACTS = SCOPE_ACTS;
|
|
18972
|
-
var chatScopeRecordedSchema = external_exports.object({
|
|
18973
|
-
outcome: external_exports.literal("recorded"),
|
|
18974
|
-
act: external_exports.enum(CHAT_SCOPE_ACTS),
|
|
18975
|
-
phase: scopePhaseSchema,
|
|
18976
|
-
planVersion: planVersionSchema
|
|
18836
|
+
var pacingBasisSchema = external_exports.object({
|
|
18837
|
+
outcome: external_exports.literal("basis"),
|
|
18838
|
+
claudePlan: external_exports.string().nullable().optional(),
|
|
18839
|
+
keepFreePercent: keepFreePercentSchema,
|
|
18840
|
+
settingsUrl: external_exports.string().optional(),
|
|
18841
|
+
phase: phaseNameSchema.nullable(),
|
|
18842
|
+
tasks: external_exports.array(pacingBasisTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
18843
|
+
medianTaskMinutes: external_exports.number().nonnegative().nullable(),
|
|
18844
|
+
medianTaskTokens: external_exports.number().nonnegative().nullable()
|
|
18977
18845
|
}).strict();
|
|
18978
|
-
var
|
|
18979
|
-
|
|
18980
|
-
|
|
18846
|
+
var paceSuggestionSchema = external_exports.object({
|
|
18847
|
+
number: external_exports.number().int().min(1).max(PACE_AGENTS_MAX),
|
|
18848
|
+
minutes: external_exports.number().int().nonnegative().nullable(),
|
|
18849
|
+
pauses: external_exports.number().int().nonnegative(),
|
|
18850
|
+
keepFreePercent: keepFreePercentSchema,
|
|
18851
|
+
knownWindow: paceWindowKindSchema.nullable(),
|
|
18852
|
+
expectedTokens: external_exports.number().int().nonnegative().optional(),
|
|
18853
|
+
limitTokens: external_exports.number().int().positive().optional(),
|
|
18854
|
+
multiple: external_exports.number().positive().nullable().optional(),
|
|
18855
|
+
firstGuess: external_exports.boolean().optional(),
|
|
18856
|
+
limitSetBy: external_exports.enum(["default", "person", "other"]).optional(),
|
|
18857
|
+
weekCeilingTokens: external_exports.number().int().positive().optional(),
|
|
18858
|
+
workMinutes: external_exports.number().int().nonnegative().nullable().optional()
|
|
18981
18859
|
}).strict();
|
|
18982
|
-
var
|
|
18983
|
-
|
|
18984
|
-
|
|
18860
|
+
var PACE_NOT_PACED_REASONS = ["not-configured", "unreadable"];
|
|
18861
|
+
var limitHeldSchema = external_exports.object({
|
|
18862
|
+
used: external_exports.number().int().nonnegative(),
|
|
18863
|
+
limit: external_exports.number().int().positive(),
|
|
18864
|
+
raiseBy: external_exports.number().int().nonnegative(),
|
|
18865
|
+
working: external_exports.number().int().nonnegative(),
|
|
18866
|
+
weekCeilingTokens: external_exports.number().int().positive().optional()
|
|
18985
18867
|
}).strict();
|
|
18986
|
-
var
|
|
18987
|
-
|
|
18988
|
-
|
|
18868
|
+
var paceUsageSchema = external_exports.object({
|
|
18869
|
+
used: external_exports.number().int().nonnegative(),
|
|
18870
|
+
limit: external_exports.number().int().positive(),
|
|
18871
|
+
weekCeilingTokens: external_exports.number().int().positive().optional()
|
|
18989
18872
|
}).strict();
|
|
18990
|
-
|
|
18991
|
-
|
|
18992
|
-
|
|
18993
|
-
|
|
18994
|
-
|
|
18995
|
-
|
|
18996
|
-
|
|
18997
|
-
|
|
18998
|
-
|
|
18999
|
-
|
|
19000
|
-
|
|
19001
|
-
|
|
19002
|
-
|
|
19003
|
-
|
|
19004
|
-
|
|
18873
|
+
var paceRunResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
18874
|
+
external_exports.object({
|
|
18875
|
+
outcome: external_exports.literal("paced"),
|
|
18876
|
+
pace: paceStateSchema,
|
|
18877
|
+
number: external_exports.number().int().min(1).max(PACE_AGENTS_MAX),
|
|
18878
|
+
allowedNow: external_exports.number().int().nonnegative(),
|
|
18879
|
+
windowKind: paceWindowKindSchema.optional(),
|
|
18880
|
+
until: utcIso8601.optional(),
|
|
18881
|
+
keepFreePercent: keepFreePercentSchema.optional(),
|
|
18882
|
+
suggestion: paceSuggestionSchema.optional(),
|
|
18883
|
+
limit: external_exports.literal("reached").optional(),
|
|
18884
|
+
limitHeld: limitHeldSchema.optional(),
|
|
18885
|
+
usage: paceUsageSchema.optional()
|
|
18886
|
+
}).strict(),
|
|
18887
|
+
external_exports.object({ outcome: external_exports.literal("not-paced"), reason: external_exports.enum(PACE_NOT_PACED_REASONS) }).strict()
|
|
19005
18888
|
]);
|
|
19006
|
-
|
|
19007
|
-
|
|
19008
|
-
|
|
19009
|
-
|
|
19010
|
-
|
|
19011
|
-
|
|
19012
|
-
parts: external_exports.array(systemPartIdSchema).max(REVIEW_PARTS_MAX),
|
|
19013
|
-
waitingClaims: external_exports.literal(true).optional()
|
|
19014
|
-
}).strict();
|
|
19015
|
-
function notedRequest(act) {
|
|
19016
|
-
return external_exports.object({
|
|
19017
|
-
act: external_exports.literal(act),
|
|
19018
|
-
reference: phaseIdentitySchema,
|
|
19019
|
-
reviewVersion: external_exports.number().int().min(0),
|
|
19020
|
-
part: systemPartIdSchema,
|
|
19021
|
-
note: reviewNoteWireSchema
|
|
19022
|
-
}).strict();
|
|
18889
|
+
function tokenCountWordsOf(n) {
|
|
18890
|
+
if (n < 1e3)
|
|
18891
|
+
return String(Math.max(0, Math.round(n)));
|
|
18892
|
+
const rounded = Number(n.toPrecision(2));
|
|
18893
|
+
const [unit, word] = rounded >= 1e9 ? [1e9, "billion"] : rounded >= 1e6 ? [1e6, "million"] : [1e3, "thousand"];
|
|
18894
|
+
return `${String(Number((rounded / unit).toPrecision(2)))} ${word}`;
|
|
19023
18895
|
}
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
var chatReviewCarryRequestSchema = notedRequest("carry");
|
|
19027
|
-
var chatReviewDropRequestSchema = notedRequest("drop");
|
|
19028
|
-
var chatReviewRejectRequestSchema = external_exports.object({
|
|
19029
|
-
act: external_exports.literal("reject"),
|
|
19030
|
-
reference: phaseIdentitySchema,
|
|
19031
|
-
reviewVersion: external_exports.number().int().min(0),
|
|
19032
|
-
task: buildTaskIdSchema,
|
|
19033
|
-
note: reviewNoteWireSchema
|
|
19034
|
-
}).strict();
|
|
19035
|
-
var chatReviewRequestSchema = external_exports.discriminatedUnion("act", [
|
|
19036
|
-
chatReviewAcceptRequestSchema,
|
|
19037
|
-
chatReviewQuestionRequestSchema,
|
|
19038
|
-
chatReviewSendBackRequestSchema,
|
|
19039
|
-
chatReviewCarryRequestSchema,
|
|
19040
|
-
chatReviewDropRequestSchema,
|
|
19041
|
-
chatReviewRejectRequestSchema
|
|
19042
|
-
]);
|
|
19043
|
-
function bareOutcome2(outcome) {
|
|
19044
|
-
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
18896
|
+
function paceAgentsOf(n) {
|
|
18897
|
+
return n === 1 ? "1 agent" : `${String(n)} agents`;
|
|
19045
18898
|
}
|
|
19046
|
-
|
|
19047
|
-
|
|
18899
|
+
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
18900
|
+
var MONTH_NAMES = [
|
|
18901
|
+
"January",
|
|
18902
|
+
"February",
|
|
18903
|
+
"March",
|
|
18904
|
+
"April",
|
|
18905
|
+
"May",
|
|
18906
|
+
"June",
|
|
18907
|
+
"July",
|
|
18908
|
+
"August",
|
|
18909
|
+
"September",
|
|
18910
|
+
"October",
|
|
18911
|
+
"November",
|
|
18912
|
+
"December"
|
|
18913
|
+
];
|
|
18914
|
+
var SIX_DAYS_MS = 6 * 24 * 60 * 60 * 1e3;
|
|
18915
|
+
function paceClockOf(at, now) {
|
|
18916
|
+
const hours = at.getHours();
|
|
18917
|
+
const clock = `${String(hours % 12 === 0 ? 12 : hours % 12)}:${String(at.getMinutes()).padStart(2, "0")} ${hours < 12 ? "am" : "pm"}`;
|
|
18918
|
+
const sameDay = at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate();
|
|
18919
|
+
if (sameDay)
|
|
18920
|
+
return clock;
|
|
18921
|
+
const day = DAY_NAMES[at.getDay()] ?? "";
|
|
18922
|
+
if (at.getTime() - now.getTime() > SIX_DAYS_MS) {
|
|
18923
|
+
return `${day} ${String(at.getDate())} ${MONTH_NAMES[at.getMonth()] ?? ""} ${clock}`;
|
|
18924
|
+
}
|
|
18925
|
+
return `${day} ${clock}`;
|
|
19048
18926
|
}
|
|
19049
|
-
var
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
18927
|
+
var PACE_P5 = "This build may use all of your allowance. It will not slow down to leave room for you.";
|
|
18928
|
+
function paceS1Of(window, k, until, now, keepFreePercent) {
|
|
18929
|
+
return `Halfcycle is slowing this build so you keep about ${paceShareWordsOf(keepFreePercent)} of this ${paceWindowWordsOf(window)} for your own work. It will run at most ${paceAgentsOf(k)} at once until ${paceClockOf(until, now)}.`;
|
|
18930
|
+
}
|
|
18931
|
+
function paceS2Of(window, k, until, now, keepFreePercent) {
|
|
18932
|
+
const head = `Halfcycle has paused new work in this build until ${paceClockOf(until, now)}, when your ${paceWindowWordsOf(window)} resets, so you keep about ${paceShareWordsOf(keepFreePercent)} of it for your own work.`;
|
|
18933
|
+
if (k === 0)
|
|
18934
|
+
return head;
|
|
18935
|
+
return k === 1 ? `${head} The 1 agent already working will finish its task.` : `${head} The ${String(k)} agents already working will finish their tasks.`;
|
|
18936
|
+
}
|
|
18937
|
+
function paceS3Of(window, n) {
|
|
18938
|
+
return `Your ${paceWindowWordsOf(window)} has reset. Halfcycle is starting new work again, up to ${paceAgentsOf(n)} at once.`;
|
|
18939
|
+
}
|
|
18940
|
+
function paceOfferTextOf(input) {
|
|
18941
|
+
const canFaster = input.number < PACE_AGENTS_MAX;
|
|
18942
|
+
const canUseMore = input.keepFreePercent > 0;
|
|
18943
|
+
if (!canFaster && !canUseMore)
|
|
18944
|
+
return null;
|
|
18945
|
+
const head = `You have used only ${String(Math.floor(input.percentUsed))}% of this ${paceWindowWordsOf(input.window)}, and more than half of it has passed.`;
|
|
18946
|
+
const useUpTo = `"use up to ${String(Math.min(100, 100 - input.keepFreePercent + 10))}%" to let this build use more of it`;
|
|
18947
|
+
if (canFaster && canUseMore)
|
|
18948
|
+
return `${head} Say "faster" for one more agent, or ${useUpTo}.`;
|
|
18949
|
+
if (canFaster)
|
|
18950
|
+
return `${head} Say "faster" for one more agent.`;
|
|
18951
|
+
return `${head} Say ${useUpTo}.`;
|
|
18952
|
+
}
|
|
18953
|
+
function paceF1Of(k) {
|
|
18954
|
+
return `This build runs at most ${paceAgentsOf(k)} at once.`;
|
|
18955
|
+
}
|
|
18956
|
+
function paceAgentLineOf(pace, allowance, until, now) {
|
|
18957
|
+
const fewer = `once fewer than ${paceAgentsOf(allowance)} are working.`;
|
|
18958
|
+
if (until === null)
|
|
18959
|
+
return `Start it ${fewer}`;
|
|
18960
|
+
if (pace === "holding")
|
|
18961
|
+
return `Start it after ${paceClockOf(until, now)}.`;
|
|
18962
|
+
return `Start it after ${paceClockOf(until, now)}, or ${fewer}`;
|
|
18963
|
+
}
|
|
18964
|
+
var PACE_NOTHING_CHANGED = "Nothing was changed.";
|
|
18965
|
+
function paceHeldStartTextOf(input) {
|
|
18966
|
+
const { pace, allowance, working, window, until, now, keepFreePercent } = input;
|
|
18967
|
+
if (pace === "full" || window === null || until === null) {
|
|
18968
|
+
return `${paceF1Of(allowance)} ${paceAgentLineOf("full", allowance, null, now)} ${PACE_NOTHING_CHANGED}`;
|
|
18969
|
+
}
|
|
18970
|
+
const head = pace === "slowing" ? paceS1Of(window, allowance, until, now, keepFreePercent) : paceS2Of(window, working, until, now, keepFreePercent);
|
|
18971
|
+
return `${head} ${paceAgentLineOf(pace, allowance, until, now)} ${PACE_NOTHING_CHANGED}`;
|
|
18972
|
+
}
|
|
18973
|
+
var PACE_FIRST_READ = "Reading this computer's usage records for the first time. This can take a minute.";
|
|
18974
|
+
var PACE_AGENTS_TOO_MANY = `Run at most ${String(PACE_AGENTS_MAX)} agents at once.`;
|
|
18975
|
+
var PACE_ONLY_PERSON_RAISES = 'Only the person can raise the number of agents, by typing "faster" or "run 5 agents" in the chat. Nothing was changed.';
|
|
18976
|
+
function paceStatusLineOf(percent, window) {
|
|
18977
|
+
return `Halfcycle \xB7 ${String(Math.round(percent))}% of this ${paceWindowWordsOf(window)} used`;
|
|
18978
|
+
}
|
|
18979
|
+
var STARTING_TOKENS_PER_TASK = 9e6;
|
|
18980
|
+
var LIMIT_MULTIPLE_DEFAULT = 2;
|
|
18981
|
+
var LIMIT_MULTIPLE_RANGE = { min: 1, max: 20 };
|
|
18982
|
+
var LIMIT_FIGURE_RANGE = { min: 1e6, max: 1e11 };
|
|
18983
|
+
var LIMIT_HISTORY_MAX = 20;
|
|
18984
|
+
var LIMIT_ROUND_TOKENS = 1e3;
|
|
18985
|
+
var LIMIT_COUNTED_KINDS = ["build", "review", "check"];
|
|
18986
|
+
var LIMIT_PARTS = ["half", "three-quarters", "nine-tenths", "limit"];
|
|
18987
|
+
var limitPartSchema = external_exports.enum(LIMIT_PARTS);
|
|
18988
|
+
var LIMIT_PART_SHARE = {
|
|
18989
|
+
half: 0.5,
|
|
18990
|
+
"three-quarters": 0.75,
|
|
18991
|
+
"nine-tenths": 0.9,
|
|
18992
|
+
limit: 1
|
|
18993
|
+
};
|
|
18994
|
+
var LIMIT_SET_BY = ["default", "person", "other"];
|
|
18995
|
+
var limitSetBySchema = external_exports.enum(LIMIT_SET_BY);
|
|
18996
|
+
var LIMIT_TYPED_BY = ["person", "not-attended", "cannot-tell"];
|
|
18997
|
+
var limitTypedBySchema = external_exports.enum(LIMIT_TYPED_BY);
|
|
18998
|
+
var limitHistoryEntrySchema = external_exports.object({
|
|
18999
|
+
at: utcIso8601,
|
|
19000
|
+
kind: external_exports.enum(["raised", "set", "stopped"]),
|
|
19001
|
+
limit: external_exports.number().int().positive(),
|
|
19002
|
+
by: limitTypedBySchema,
|
|
19003
|
+
relayed: external_exports.literal(true).optional()
|
|
19060
19004
|
}).strict();
|
|
19061
|
-
var
|
|
19062
|
-
|
|
19063
|
-
|
|
19005
|
+
var PHASE_LIMIT_FILENAME = "limit.json";
|
|
19006
|
+
var phaseLimitFileSchema = external_exports.object({
|
|
19007
|
+
phase: phaseNameSchema,
|
|
19008
|
+
expected: external_exports.number().int().nonnegative(),
|
|
19009
|
+
expectedMinutes: external_exports.number().nonnegative().nullable(),
|
|
19010
|
+
limit: external_exports.number().int().positive(),
|
|
19011
|
+
multiple: external_exports.number().positive().nullable(),
|
|
19012
|
+
setBy: limitSetBySchema,
|
|
19013
|
+
firstGuess: external_exports.boolean(),
|
|
19014
|
+
shown: external_exports.array(limitPartSchema).max(LIMIT_PARTS.length),
|
|
19015
|
+
awaiting: external_exports.boolean(),
|
|
19016
|
+
history: external_exports.array(limitHistoryEntrySchema).max(LIMIT_HISTORY_MAX)
|
|
19064
19017
|
}).strict();
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19018
|
+
function phaseLimitFileOf(raw, phase) {
|
|
19019
|
+
const parsed = phaseLimitFileSchema.safeParse(raw);
|
|
19020
|
+
if (!parsed.success)
|
|
19021
|
+
return null;
|
|
19022
|
+
return phase === null || parsed.data.phase === phase ? parsed.data : null;
|
|
19023
|
+
}
|
|
19024
|
+
var phaseUsageFileSchema = external_exports.object({
|
|
19025
|
+
phase: phaseNameSchema,
|
|
19026
|
+
openedAt: utcIso8601,
|
|
19027
|
+
tokens: external_exports.number().int().nonnegative(),
|
|
19028
|
+
at: utcIso8601
|
|
19029
|
+
}).strict();
|
|
19030
|
+
function limitPartLineOf(part, used, weekCeilingTokens = null) {
|
|
19031
|
+
return limitPartShareTextOf(part, used, weekCeilingTokens);
|
|
19032
|
+
}
|
|
19033
|
+
function limitReachedPartsOf(input) {
|
|
19034
|
+
const { figure, caveat } = limitReachedFigureOf(input.limit, input.weekCeilingTokens);
|
|
19035
|
+
const finish = input.working === 0 ? "" : input.working === 1 ? " The 1 agent already working will finish its task." : ` The ${String(input.working)} agents already working will finish their tasks.`;
|
|
19036
|
+
return {
|
|
19037
|
+
happened: `This phase has reached its usage limit${figure}. No new work will start.${finish}`,
|
|
19038
|
+
yourPart: 'Say "keep going" to raise the limit and carry on, or "stop" to leave the phase paused here.',
|
|
19039
|
+
next: `Nothing is lost either way; the work waits for your answer.${caveat}`
|
|
19040
|
+
};
|
|
19041
|
+
}
|
|
19042
|
+
function limitReachedLineOf(input) {
|
|
19043
|
+
return stopTextOf(limitReachedPartsOf(input));
|
|
19044
|
+
}
|
|
19045
|
+
function limitHeldStartTextOf(limit, weekCeilingTokens = null) {
|
|
19046
|
+
return `${limitHeldShareTextOf(limit, weekCeilingTokens)} Ask the person to say "keep going" or "stop", and start nothing until they have. ${PACE_NOTHING_CHANGED}`;
|
|
19047
|
+
}
|
|
19071
19048
|
|
|
19072
|
-
// ../events/dist/
|
|
19073
|
-
var
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
words: "Changing what the product promises its users, such as pricing, terms or privacy."
|
|
19078
|
-
}),
|
|
19079
|
-
Object.freeze({ id: "spend-or-sign-up", words: "Anything that costs money or signs up for a service." }),
|
|
19080
|
-
Object.freeze({ id: "publish-or-release", words: "Publishing or releasing to users." }),
|
|
19081
|
-
Object.freeze({ id: "reshape-shared-data", words: "Dropping or reshaping stored data that other parts read." }),
|
|
19082
|
-
Object.freeze({ id: "change-standing-rule", words: "Changing a standing rule." })
|
|
19083
|
-
]);
|
|
19084
|
-
var OWNER_WAIT_ITEM_IDS = Object.freeze(OWNER_WAIT_ITEMS.map((item) => item.id));
|
|
19085
|
-
var ownerWaitItemIdSchema = external_exports.enum(OWNER_WAIT_ITEM_IDS);
|
|
19086
|
-
var OWNER_WAIT_FIXED_COUNT = OWNER_WAIT_ITEMS.length;
|
|
19087
|
-
var OWNER_WAIT_ADDITIONS_MAX = 20;
|
|
19088
|
-
var OWNER_WAIT_TEXT_MAX = 240;
|
|
19089
|
-
var ownerWaitItemRefSchema = external_exports.union([
|
|
19090
|
-
external_exports.number().int().min(1),
|
|
19091
|
-
external_exports.string().uuid({ message: "must be a number from 1 to 6, or the id shown beside an added item" })
|
|
19092
|
-
]);
|
|
19093
|
-
var ownerWaitText = descriptionText(OWNER_WAIT_TEXT_MAX);
|
|
19094
|
-
var ownerWaitAddRequestSchema = external_exports.object({
|
|
19095
|
-
engagementId: external_exports.string().min(1),
|
|
19096
|
-
text: ownerWaitText,
|
|
19097
|
-
reason: ownerWaitText
|
|
19049
|
+
// ../events/dist/plan-usage.js
|
|
19050
|
+
var windowPercentSchema = external_exports.number().min(0).max(100);
|
|
19051
|
+
var planUsageWindowSchema = external_exports.object({
|
|
19052
|
+
usedPercent: windowPercentSchema,
|
|
19053
|
+
resetsAt: utcIso8601
|
|
19098
19054
|
}).strict();
|
|
19099
|
-
var
|
|
19100
|
-
|
|
19101
|
-
external_exports.object({ outcome: external_exports.literal("refused"), reason: external_exports.literal("too-many") }).strict()
|
|
19102
|
-
]);
|
|
19103
|
-
var ownerWaitUndoableSchema = external_exports.enum(["yes", "no"]);
|
|
19104
|
-
var ownerWaitDeclareRequestSchema = external_exports.object({
|
|
19105
|
-
engagementId: external_exports.string().min(1),
|
|
19106
|
-
item: ownerWaitItemRefSchema,
|
|
19107
|
-
question: ownerWaitText,
|
|
19108
|
-
recommendation: ownerWaitText,
|
|
19109
|
-
task: buildTaskIdSchema.optional(),
|
|
19110
|
-
by: agentNameSchema.optional(),
|
|
19111
|
-
undoable: ownerWaitUndoableSchema.optional(),
|
|
19112
|
-
how: statementText(STATEMENT_MAX).optional()
|
|
19113
|
-
}).strict().refine((r) => r.undoable === "yes" === (r.how !== void 0), {
|
|
19114
|
-
message: "says how to undo it exactly when it can be undone",
|
|
19115
|
-
path: ["how"]
|
|
19116
|
-
});
|
|
19117
|
-
var OWNER_WAIT_DECLARE_REFUSALS = ["no-open-phase", "unknown-item", "say-if-undoable"];
|
|
19118
|
-
var ownerWaitDeclareResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19119
|
-
external_exports.object({ outcome: external_exports.literal("recorded"), id: external_exports.string().uuid(), say: external_exports.string().min(1) }).strict(),
|
|
19120
|
-
external_exports.object({
|
|
19121
|
-
outcome: external_exports.literal("go-ahead"),
|
|
19122
|
-
id: external_exports.string().uuid(),
|
|
19123
|
-
callId: external_exports.number().int().positive(),
|
|
19124
|
-
say: external_exports.string().min(1)
|
|
19125
|
-
}).strict(),
|
|
19126
|
-
external_exports.object({ outcome: external_exports.literal("refused"), reason: external_exports.enum(OWNER_WAIT_DECLARE_REFUSALS) }).strict()
|
|
19127
|
-
]);
|
|
19128
|
-
var ownerWaitAddedItemSchema = external_exports.object({
|
|
19129
|
-
id: external_exports.string().uuid(),
|
|
19130
|
-
words: external_exports.string().min(1),
|
|
19131
|
-
reason: external_exports.string().min(1),
|
|
19132
|
-
addedAt: utcIso8601
|
|
19055
|
+
var planUsageWeekSchema = planUsageWindowSchema.extend({
|
|
19056
|
+
ceilingTokens: external_exports.number().int().positive().nullable()
|
|
19133
19057
|
}).strict();
|
|
19134
|
-
var
|
|
19135
|
-
|
|
19136
|
-
|
|
19058
|
+
var planUsageReportSchema = external_exports.object({
|
|
19059
|
+
fiveHour: planUsageWindowSchema.nullable(),
|
|
19060
|
+
week: planUsageWeekSchema.nullable(),
|
|
19061
|
+
readAt: utcIso8601
|
|
19137
19062
|
}).strict();
|
|
19138
|
-
var
|
|
19139
|
-
|
|
19140
|
-
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19148
|
-
|
|
19063
|
+
var planKeepFreePercentSchema = external_exports.number().int().min(0).max(90);
|
|
19064
|
+
var workMinutesSchema = external_exports.number().int().nonnegative().nullable();
|
|
19065
|
+
var planUsagePhaseSchema = external_exports.object({
|
|
19066
|
+
phase: phaseNameSchema,
|
|
19067
|
+
spentPercent: timeSharePercentSchema,
|
|
19068
|
+
expectedPercent: timeSharePercentSchema.optional(),
|
|
19069
|
+
kinds: timeShareKindsSchema
|
|
19070
|
+
}).strict();
|
|
19071
|
+
var PLAN_USAGE_PHASES_MAX = 100;
|
|
19072
|
+
var planUsageUnknownSchema = external_exports.object({
|
|
19073
|
+
state: external_exports.literal("unknown"),
|
|
19074
|
+
windowsRead: external_exports.boolean(),
|
|
19075
|
+
workMinutes: workMinutesSchema,
|
|
19076
|
+
keepFreePercent: planKeepFreePercentSchema
|
|
19077
|
+
}).strict();
|
|
19078
|
+
var planUsageKnownSchema = external_exports.object({
|
|
19079
|
+
state: external_exports.literal("known"),
|
|
19080
|
+
workMinutes: workMinutesSchema,
|
|
19081
|
+
keepFreePercent: planKeepFreePercentSchema,
|
|
19082
|
+
weekCeilingTokens: external_exports.number().int().positive(),
|
|
19083
|
+
fiveHourPercent: windowPercentSchema.nullable(),
|
|
19084
|
+
weekPercent: windowPercentSchema.nullable(),
|
|
19085
|
+
readAt: utcIso8601,
|
|
19086
|
+
phases: external_exports.array(planUsagePhaseSchema).max(PLAN_USAGE_PHASES_MAX)
|
|
19087
|
+
}).strict().superRefine((v, ctx) => {
|
|
19088
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19089
|
+
v.phases.forEach((entry, i) => {
|
|
19090
|
+
if (seen.has(entry.phase))
|
|
19091
|
+
ctx.addIssue({ code: "custom", path: ["phases", i, "phase"], message: "lists one phase twice" });
|
|
19092
|
+
seen.add(entry.phase);
|
|
19093
|
+
});
|
|
19149
19094
|
});
|
|
19150
|
-
var
|
|
19151
|
-
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
function ownerWaitShortIdOf(declarationId) {
|
|
19157
|
-
return declarationId.slice(0, OWNER_WAIT_SHORT_ID_LENGTH).toLowerCase();
|
|
19095
|
+
var planUsageSchema = external_exports.discriminatedUnion("state", [planUsageUnknownSchema, planUsageKnownSchema]);
|
|
19096
|
+
function agentWorkMinutesOf(tasks, medianTaskMinutes) {
|
|
19097
|
+
if (tasks === null || tasks.length === 0)
|
|
19098
|
+
return null;
|
|
19099
|
+
const sum2 = tasks.reduce((total, task) => total + taskMinutesOf(task, medianTaskMinutes), 0);
|
|
19100
|
+
return paceDurationRoundedOf(sum2);
|
|
19158
19101
|
}
|
|
19159
|
-
|
|
19160
|
-
|
|
19161
|
-
function ownerWaitApproveLineOf(declarationId) {
|
|
19162
|
-
return `approve wait ${ownerWaitShortIdOf(declarationId)}`;
|
|
19102
|
+
function weekPercentOf(tokens, weekCeilingTokens) {
|
|
19103
|
+
return weekCeilingTokens > 0 ? tokens / weekCeilingTokens * 100 : 0;
|
|
19163
19104
|
}
|
|
19164
|
-
function
|
|
19165
|
-
return
|
|
19105
|
+
function planSharePercentWordsOf(percent) {
|
|
19106
|
+
return percent < 0.5 ? "under 1%" : `${String(Math.round(percent))}%`;
|
|
19166
19107
|
}
|
|
19167
|
-
|
|
19168
|
-
|
|
19169
|
-
external_exports.object({ act: external_exports.literal("decline"), wait: ownerWaitShortIdSchema, note: scopeNoteWireSchema }).strict()
|
|
19170
|
-
]);
|
|
19171
|
-
function bareOutcome3(outcome) {
|
|
19172
|
-
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
19108
|
+
function aboutShareOf(percent) {
|
|
19109
|
+
return percent < 0.5 ? planSharePercentWordsOf(percent) : `about ${planSharePercentWordsOf(percent)}`;
|
|
19173
19110
|
}
|
|
19174
|
-
var
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
act: ownerWaitAnswerActSchema,
|
|
19178
|
-
question: external_exports.string().min(1)
|
|
19179
|
-
}).strict(),
|
|
19180
|
-
external_exports.object({ outcome: external_exports.literal("refused"), problems: external_exports.array(systemDescriptionProblemSchema).min(1) }).strict(),
|
|
19181
|
-
bareOutcome3("not-owner"),
|
|
19182
|
-
bareOutcome3("no-owner"),
|
|
19183
|
-
bareOutcome3("not-found"),
|
|
19184
|
-
bareOutcome3("ambiguous"),
|
|
19185
|
-
bareOutcome3("not-offered"),
|
|
19186
|
-
bareOutcome3("unavailable")
|
|
19187
|
-
]);
|
|
19188
|
-
|
|
19189
|
-
// ../events/dist/pacing.js
|
|
19190
|
-
var CAREFUL_START_AGENTS = 3;
|
|
19191
|
-
var KEEP_FREE_MAX = 90;
|
|
19192
|
-
var keepFreePercentSchema = external_exports.number().int().min(0).max(KEEP_FREE_MAX);
|
|
19193
|
-
var KEEP_FREE_DEFAULT = 20;
|
|
19194
|
-
var PACE_AGENTS_MAX = 20;
|
|
19195
|
-
var FIVE_HOUR_WINDOW_MINUTES = 300;
|
|
19196
|
-
var SEVEN_DAY_WINDOW_MINUTES = 10080;
|
|
19197
|
-
var PACE_WINDOW_MINUTES_MAX = 525600;
|
|
19198
|
-
var MINUTE_KEY = /^([1-9][0-9]{0,6})-minute$/;
|
|
19199
|
-
function isPaceWindowKind(value) {
|
|
19200
|
-
if (value === "five-hour" || value === "seven-day")
|
|
19201
|
-
return true;
|
|
19202
|
-
if (typeof value !== "string")
|
|
19203
|
-
return false;
|
|
19204
|
-
const match = MINUTE_KEY.exec(value);
|
|
19205
|
-
if (match === null)
|
|
19206
|
-
return false;
|
|
19207
|
-
const minutes = Number(match[1]);
|
|
19208
|
-
return minutes <= PACE_WINDOW_MINUTES_MAX && minutes !== FIVE_HOUR_WINDOW_MINUTES && minutes !== SEVEN_DAY_WINDOW_MINUTES;
|
|
19111
|
+
var PLAN_USAGE_CAVEAT = "These figures are estimates. Many things affect usage, and some of them are outside Halfcycle's control.";
|
|
19112
|
+
function ofYourWeek(tokens, weekCeilingTokens) {
|
|
19113
|
+
return `${aboutShareOf(weekPercentOf(tokens, weekCeilingTokens))} of your week`;
|
|
19209
19114
|
}
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
});
|
|
19213
|
-
function paceWindowMinutesOf(kind) {
|
|
19214
|
-
if (kind === "five-hour")
|
|
19215
|
-
return FIVE_HOUR_WINDOW_MINUTES;
|
|
19216
|
-
if (kind === "seven-day")
|
|
19217
|
-
return SEVEN_DAY_WINDOW_MINUTES;
|
|
19218
|
-
return Number(MINUTE_KEY.exec(kind)?.[1] ?? 0);
|
|
19115
|
+
function ceilingKnown(weekCeilingTokens) {
|
|
19116
|
+
return typeof weekCeilingTokens === "number" && weekCeilingTokens > 0;
|
|
19219
19117
|
}
|
|
19220
|
-
function
|
|
19221
|
-
|
|
19222
|
-
return null;
|
|
19223
|
-
if (minutes === FIVE_HOUR_WINDOW_MINUTES)
|
|
19224
|
-
return "five-hour";
|
|
19225
|
-
if (minutes === SEVEN_DAY_WINDOW_MINUTES)
|
|
19226
|
-
return "seven-day";
|
|
19227
|
-
return `${String(minutes)}-minute`;
|
|
19118
|
+
function figureThenCaveat(sentence) {
|
|
19119
|
+
return `${sentence} ${PLAN_USAGE_CAVEAT}`;
|
|
19228
19120
|
}
|
|
19229
|
-
function
|
|
19230
|
-
const
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
if (minutes === SEVEN_DAY_WINDOW_MINUTES)
|
|
19234
|
-
return "weekly window";
|
|
19235
|
-
if (minutes % 1440 === 0)
|
|
19236
|
-
return `${String(minutes / 1440)}-day window`;
|
|
19237
|
-
if (minutes % 60 === 0)
|
|
19238
|
-
return `${String(minutes / 60)}-hour window`;
|
|
19239
|
-
return `${String(minutes)}-minute window`;
|
|
19121
|
+
function limitPartShareTextOf(part, used, weekCeilingTokens) {
|
|
19122
|
+
const words = part === "half" ? "half" : part === "three-quarters" ? "three quarters" : "nine tenths";
|
|
19123
|
+
const head = ceilingKnown(weekCeilingTokens) ? figureThenCaveat(`This phase has used ${words} of its usage limit: ${ofYourWeek(used, weekCeilingTokens)}.`) : `This phase has used ${words} of its usage limit.`;
|
|
19124
|
+
return part === "nine-tenths" ? `${head} New work stops at the limit.` : head;
|
|
19240
19125
|
}
|
|
19241
|
-
function
|
|
19242
|
-
|
|
19126
|
+
function limitReachedFigureOf(limit, weekCeilingTokens) {
|
|
19127
|
+
if (!ceilingKnown(weekCeilingTokens))
|
|
19128
|
+
return { figure: "", caveat: "" };
|
|
19129
|
+
return { figure: `: ${ofYourWeek(limit, weekCeilingTokens)}`, caveat: ` ${PLAN_USAGE_CAVEAT}` };
|
|
19243
19130
|
}
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
var paceShareRequestSchema = external_exports.object({ keepFreePercent: keepFreePercentSchema, givenIn: paceShareGivenInSchema }).strict();
|
|
19249
|
-
var paceShareResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19250
|
-
external_exports.object({
|
|
19251
|
-
outcome: external_exports.literal("recorded"),
|
|
19252
|
-
keepFreePercent: keepFreePercentSchema,
|
|
19253
|
-
moreAllowance: external_exports.boolean().optional()
|
|
19254
|
-
}).strict(),
|
|
19255
|
-
external_exports.object({ outcome: external_exports.literal("needs-the-person"), keepFreePercent: keepFreePercentSchema }).strict(),
|
|
19256
|
-
external_exports.object({ outcome: external_exports.literal("not-owner") }).strict(),
|
|
19257
|
-
external_exports.object({ outcome: external_exports.literal("no-owner") }).strict(),
|
|
19258
|
-
external_exports.object({ outcome: external_exports.literal("unavailable") }).strict()
|
|
19259
|
-
]);
|
|
19260
|
-
var pacingBasisTaskSchema = external_exports.object({
|
|
19261
|
-
id: buildTaskIdSchema,
|
|
19262
|
-
dependsOn: external_exports.array(buildTaskIdSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
19263
|
-
budgetMinutes: external_exports.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
|
|
19264
|
-
human: external_exports.boolean(),
|
|
19265
|
-
kind: buildTaskKindSchema.optional()
|
|
19266
|
-
}).strict();
|
|
19267
|
-
var pacingBasisSchema = external_exports.object({
|
|
19268
|
-
outcome: external_exports.literal("basis"),
|
|
19269
|
-
claudePlan: external_exports.string().nullable().optional(),
|
|
19270
|
-
keepFreePercent: keepFreePercentSchema,
|
|
19271
|
-
settingsUrl: external_exports.string().optional(),
|
|
19272
|
-
phase: phaseNameSchema.nullable(),
|
|
19273
|
-
tasks: external_exports.array(pacingBasisTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
|
|
19274
|
-
medianTaskMinutes: external_exports.number().nonnegative().nullable(),
|
|
19275
|
-
medianTaskTokens: external_exports.number().nonnegative().nullable()
|
|
19276
|
-
}).strict();
|
|
19277
|
-
var paceSuggestionSchema = external_exports.object({
|
|
19278
|
-
number: external_exports.number().int().min(1).max(PACE_AGENTS_MAX),
|
|
19279
|
-
minutes: external_exports.number().int().nonnegative().nullable(),
|
|
19280
|
-
pauses: external_exports.number().int().nonnegative(),
|
|
19281
|
-
keepFreePercent: keepFreePercentSchema,
|
|
19282
|
-
knownWindow: paceWindowKindSchema.nullable(),
|
|
19283
|
-
expectedTokens: external_exports.number().int().nonnegative().optional(),
|
|
19284
|
-
limitTokens: external_exports.number().int().positive().optional(),
|
|
19285
|
-
multiple: external_exports.number().positive().nullable().optional(),
|
|
19286
|
-
firstGuess: external_exports.boolean().optional(),
|
|
19287
|
-
limitSetBy: external_exports.enum(["default", "person", "other"]).optional()
|
|
19288
|
-
}).strict();
|
|
19289
|
-
var PACE_NOT_PACED_REASONS = ["not-configured", "unreadable"];
|
|
19290
|
-
var limitHeldSchema = external_exports.object({
|
|
19291
|
-
used: external_exports.number().int().nonnegative(),
|
|
19292
|
-
limit: external_exports.number().int().positive(),
|
|
19293
|
-
raiseBy: external_exports.number().int().nonnegative(),
|
|
19294
|
-
working: external_exports.number().int().nonnegative()
|
|
19295
|
-
}).strict();
|
|
19296
|
-
var paceUsageSchema = external_exports.object({
|
|
19297
|
-
used: external_exports.number().int().nonnegative(),
|
|
19298
|
-
limit: external_exports.number().int().positive()
|
|
19299
|
-
}).strict();
|
|
19300
|
-
var paceRunResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19301
|
-
external_exports.object({
|
|
19302
|
-
outcome: external_exports.literal("paced"),
|
|
19303
|
-
pace: paceStateSchema,
|
|
19304
|
-
number: external_exports.number().int().min(1).max(PACE_AGENTS_MAX),
|
|
19305
|
-
allowedNow: external_exports.number().int().nonnegative(),
|
|
19306
|
-
windowKind: paceWindowKindSchema.optional(),
|
|
19307
|
-
until: utcIso8601.optional(),
|
|
19308
|
-
keepFreePercent: keepFreePercentSchema.optional(),
|
|
19309
|
-
suggestion: paceSuggestionSchema.optional(),
|
|
19310
|
-
limit: external_exports.literal("reached").optional(),
|
|
19311
|
-
limitHeld: limitHeldSchema.optional(),
|
|
19312
|
-
usage: paceUsageSchema.optional()
|
|
19313
|
-
}).strict(),
|
|
19314
|
-
external_exports.object({ outcome: external_exports.literal("not-paced"), reason: external_exports.enum(PACE_NOT_PACED_REASONS) }).strict()
|
|
19315
|
-
]);
|
|
19316
|
-
function tokenCountWordsOf(n) {
|
|
19317
|
-
if (n < 1e3)
|
|
19318
|
-
return String(Math.max(0, Math.round(n)));
|
|
19319
|
-
const rounded = Number(n.toPrecision(2));
|
|
19320
|
-
const [unit, word] = rounded >= 1e9 ? [1e9, "billion"] : rounded >= 1e6 ? [1e6, "million"] : [1e3, "thousand"];
|
|
19321
|
-
return `${String(Number((rounded / unit).toPrecision(2)))} ${word}`;
|
|
19131
|
+
function limitKeepGoingShareText(limit, used, weekCeilingTokens) {
|
|
19132
|
+
if (!ceilingKnown(weekCeilingTokens))
|
|
19133
|
+
return "Done. The limit is raised. New work can start again.";
|
|
19134
|
+
return `${figureThenCaveat(`Done. The limit is now ${ofYourWeek(limit, weekCeilingTokens)}.`)} This phase has used ${aboutShareOf(weekPercentOf(used, weekCeilingTokens))}. New work can start again.`;
|
|
19322
19135
|
}
|
|
19323
|
-
function
|
|
19324
|
-
|
|
19136
|
+
function limitAlreadyUsedShareSuffix(limit, used, weekCeilingTokens) {
|
|
19137
|
+
if (limit > used)
|
|
19138
|
+
return "";
|
|
19139
|
+
return ceilingKnown(weekCeilingTokens) ? ` This phase has already used ${ofYourWeek(used, weekCeilingTokens)}, so no new work will start until you raise it.` : " This phase has already used that much, so no new work will start until you raise it.";
|
|
19325
19140
|
}
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19330
|
-
"March",
|
|
19331
|
-
"April",
|
|
19332
|
-
"May",
|
|
19333
|
-
"June",
|
|
19334
|
-
"July",
|
|
19335
|
-
"August",
|
|
19336
|
-
"September",
|
|
19337
|
-
"October",
|
|
19338
|
-
"November",
|
|
19339
|
-
"December"
|
|
19340
|
-
];
|
|
19341
|
-
var SIX_DAYS_MS = 6 * 24 * 60 * 60 * 1e3;
|
|
19342
|
-
function paceClockOf(at, now) {
|
|
19343
|
-
const hours = at.getHours();
|
|
19344
|
-
const clock = `${String(hours % 12 === 0 ? 12 : hours % 12)}:${String(at.getMinutes()).padStart(2, "0")} ${hours < 12 ? "am" : "pm"}`;
|
|
19345
|
-
const sameDay = at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate();
|
|
19346
|
-
if (sameDay)
|
|
19347
|
-
return clock;
|
|
19348
|
-
const day = DAY_NAMES[at.getDay()] ?? "";
|
|
19349
|
-
if (at.getTime() - now.getTime() > SIX_DAYS_MS) {
|
|
19350
|
-
return `${day} ${String(at.getDate())} ${MONTH_NAMES[at.getMonth()] ?? ""} ${clock}`;
|
|
19141
|
+
function limitTimesShareText(limit, typed, used, weekCeilingTokens) {
|
|
19142
|
+
const suffix = limitAlreadyUsedShareSuffix(limit, used, weekCeilingTokens);
|
|
19143
|
+
if (!ceilingKnown(weekCeilingTokens)) {
|
|
19144
|
+
return `Done. The limit for this phase is now ${typed} times what it is expected to use.${suffix}`;
|
|
19351
19145
|
}
|
|
19352
|
-
return `${
|
|
19353
|
-
}
|
|
19354
|
-
var PACE_P5 = "This build may use all of your allowance. It will not slow down to leave room for you.";
|
|
19355
|
-
function paceS1Of(window, k, until, now, keepFreePercent) {
|
|
19356
|
-
return `Halfcycle is slowing this build so you keep about ${paceShareWordsOf(keepFreePercent)} of this ${paceWindowWordsOf(window)} for your own work. It will run at most ${paceAgentsOf(k)} at once until ${paceClockOf(until, now)}.`;
|
|
19357
|
-
}
|
|
19358
|
-
function paceS2Of(window, k, until, now, keepFreePercent) {
|
|
19359
|
-
const head = `Halfcycle has paused new work in this build until ${paceClockOf(until, now)}, when your ${paceWindowWordsOf(window)} resets, so you keep about ${paceShareWordsOf(keepFreePercent)} of it for your own work.`;
|
|
19360
|
-
if (k === 0)
|
|
19361
|
-
return head;
|
|
19362
|
-
return k === 1 ? `${head} The 1 agent already working will finish its task.` : `${head} The ${String(k)} agents already working will finish their tasks.`;
|
|
19363
|
-
}
|
|
19364
|
-
function paceS3Of(window, n) {
|
|
19365
|
-
return `Your ${paceWindowWordsOf(window)} has reset. Halfcycle is starting new work again, up to ${paceAgentsOf(n)} at once.`;
|
|
19366
|
-
}
|
|
19367
|
-
function paceOfferTextOf(input) {
|
|
19368
|
-
const canFaster = input.number < PACE_AGENTS_MAX;
|
|
19369
|
-
const canUseMore = input.keepFreePercent > 0;
|
|
19370
|
-
if (!canFaster && !canUseMore)
|
|
19371
|
-
return null;
|
|
19372
|
-
const head = `You have used only ${String(Math.floor(input.percentUsed))}% of this ${paceWindowWordsOf(input.window)}, and more than half of it has passed.`;
|
|
19373
|
-
const useUpTo = `"use up to ${String(Math.min(100, 100 - input.keepFreePercent + 10))}%" to let this build use more of it`;
|
|
19374
|
-
if (canFaster && canUseMore)
|
|
19375
|
-
return `${head} Say "faster" for one more agent, or ${useUpTo}.`;
|
|
19376
|
-
if (canFaster)
|
|
19377
|
-
return `${head} Say "faster" for one more agent.`;
|
|
19378
|
-
return `${head} Say ${useUpTo}.`;
|
|
19146
|
+
return `${figureThenCaveat(`Done. The limit for this phase is now ${ofYourWeek(limit, weekCeilingTokens)}.`)} That is ${typed} times what it is expected to use.${suffix}`;
|
|
19379
19147
|
}
|
|
19380
|
-
function
|
|
19381
|
-
|
|
19148
|
+
function limitFigureShareText(limit, used, weekCeilingTokens) {
|
|
19149
|
+
const suffix = limitAlreadyUsedShareSuffix(limit, used, weekCeilingTokens);
|
|
19150
|
+
if (!ceilingKnown(weekCeilingTokens))
|
|
19151
|
+
return `Done. The limit for this phase is set.${suffix}`;
|
|
19152
|
+
return `${figureThenCaveat(`Done. The limit for this phase is now ${ofYourWeek(limit, weekCeilingTokens)}.`)}${suffix}`;
|
|
19382
19153
|
}
|
|
19383
|
-
function
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
if (pace === "holding")
|
|
19388
|
-
return `Start it after ${paceClockOf(until, now)}.`;
|
|
19389
|
-
return `Start it after ${paceClockOf(until, now)}, or ${fewer}`;
|
|
19154
|
+
function limitHeldShareTextOf(limit, weekCeilingTokens) {
|
|
19155
|
+
if (!ceilingKnown(weekCeilingTokens))
|
|
19156
|
+
return "This phase has reached its usage limit, so no new agent starts.";
|
|
19157
|
+
return figureThenCaveat(`This phase has reached its usage limit of ${ofYourWeek(limit, weekCeilingTokens)}, so no new agent starts.`);
|
|
19390
19158
|
}
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
const { pace, allowance, working, window, until, now, keepFreePercent } = input;
|
|
19394
|
-
if (pace === "full" || window === null || until === null) {
|
|
19395
|
-
return `${paceF1Of(allowance)} ${paceAgentLineOf("full", allowance, null, now)} ${PACE_NOTHING_CHANGED}`;
|
|
19396
|
-
}
|
|
19397
|
-
const head = pace === "slowing" ? paceS1Of(window, allowance, until, now, keepFreePercent) : paceS2Of(window, working, until, now, keepFreePercent);
|
|
19398
|
-
return `${head} ${paceAgentLineOf(pace, allowance, until, now)} ${PACE_NOTHING_CHANGED}`;
|
|
19159
|
+
function limitNoExpectedShareText(weekCeilingTokens) {
|
|
19160
|
+
return ceilingKnown(weekCeilingTokens) ? 'Nothing changed: there is no expected usage yet, so say a share of the week, like "limit it to 10% of the week".' : "Nothing changed: there is no expected usage for this phase yet.";
|
|
19399
19161
|
}
|
|
19400
|
-
|
|
19401
|
-
|
|
19402
|
-
|
|
19403
|
-
function paceStatusLineOf(percent, window) {
|
|
19404
|
-
return `Halfcycle \xB7 ${String(Math.round(percent))}% of this ${paceWindowWordsOf(window)} used`;
|
|
19162
|
+
function limitTimesRangeShareText(range, weekCeilingTokens) {
|
|
19163
|
+
const head = `Nothing changed: a limit is between ${String(range.min)} and ${String(range.max)} times what is expected.`;
|
|
19164
|
+
return ceilingKnown(weekCeilingTokens) ? `${head} Say a share of the week instead, like "limit it to 10% of the week".` : head;
|
|
19405
19165
|
}
|
|
19406
|
-
var
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
var
|
|
19410
|
-
var
|
|
19411
|
-
var
|
|
19412
|
-
var
|
|
19413
|
-
var
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
|
|
19166
|
+
var LIMIT_SHARE_NOT_SET_TEXT = 'Nothing changed. To set a limit now, say "limit it to 2 times".';
|
|
19167
|
+
|
|
19168
|
+
// ../events/dist/client-version.js
|
|
19169
|
+
var CLIENT_VERSION_HEADER = "x-halfcycle-client";
|
|
19170
|
+
var TYPED_APPROVAL_OFF_SENTENCE = "Approving by typing is switched off for now.";
|
|
19171
|
+
var HEADLESS_CANNOT_APPROVE = "(a headless session cannot approve, by design)";
|
|
19172
|
+
var TYPED_REVIEW_OFF_SENTENCE = "Reviewing by typing is switched off for now.";
|
|
19173
|
+
var CLIENT_UPDATE_SENTENCE = `To approve by typing in a session, Halfcycle needs updating: run \`${HALFCYCLE_COMMAND}\` in this project's folder, then reopen your session and ask again.`;
|
|
19174
|
+
|
|
19175
|
+
// ../events/dist/device-auth.js
|
|
19176
|
+
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");
|
|
19177
|
+
var DEVICE_AUTH_STATUS = {
|
|
19178
|
+
/** The poll: minted, nobody has acted yet. Keep polling. 200. */
|
|
19179
|
+
PENDING: "pending",
|
|
19180
|
+
/** The poll: approved, and the credential is in this body. Once only. 200. */
|
|
19181
|
+
APPROVED: "approved",
|
|
19182
|
+
/** Confirm: the decision was recorded (approve or decline). 200. */
|
|
19183
|
+
RECORDED: "recorded",
|
|
19184
|
+
/** The human refused at the confirmation page. 400 on the poll. */
|
|
19185
|
+
DECLINED: "declined",
|
|
19186
|
+
/** The code's absolute expiry has passed. 400. */
|
|
19187
|
+
EXPIRED: "expired",
|
|
19188
|
+
/** Never minted, or already spent. 400. */
|
|
19189
|
+
UNKNOWN: "unknown",
|
|
19190
|
+
/** Confirm: neither `approve` nor `decline` was named. Nothing was bound. 400. */
|
|
19191
|
+
INVALID_DECISION: "invalid-decision",
|
|
19192
|
+
/** Confirm: an approval arrived with no signed-in identity. 400. */
|
|
19193
|
+
IDENTITY_REQUIRED: "identity-required",
|
|
19194
|
+
/** This deployment has no `SIGNIN_BASE_URL` / `DEVICE_AUTH_CONFIRM_SECRET`. 503. */
|
|
19195
|
+
NOT_CONFIGURED: "not-configured",
|
|
19196
|
+
/** Confirm: the shared confirmation secret was missing or wrong. 401. */
|
|
19197
|
+
UNAUTHORIZED: "unauthorized",
|
|
19198
|
+
/** Confirm: the code was already approved, declined or claimed. 409. */
|
|
19199
|
+
ALREADY_DECIDED: "already-decided",
|
|
19200
|
+
/**
|
|
19201
|
+
* Confirm: an approval named a signed-in identity whose account has not accepted
|
|
19202
|
+
* the terms of service and privacy policy currently in force. 400.
|
|
19203
|
+
*
|
|
19204
|
+
* NOT BOUND TO THE DEVICE CODE. Unlike every other refusal in this const, this one
|
|
19205
|
+
* says nothing about the code itself — the code is still `pending` after this
|
|
19206
|
+
* response, exactly as it was before the request, so the SAME userCode can be
|
|
19207
|
+
* confirmed again once the caller has recorded acceptance. `deviceConfirmRequestSchema`'s
|
|
19208
|
+
* `acceptTerms` is how a second confirm says it did.
|
|
19209
|
+
*/
|
|
19210
|
+
TERMS_REQUIRED: "terms-required"
|
|
19420
19211
|
};
|
|
19421
|
-
var
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19212
|
+
var DEVICE_POLL_REFUSALS = [
|
|
19213
|
+
DEVICE_AUTH_STATUS.DECLINED,
|
|
19214
|
+
DEVICE_AUTH_STATUS.EXPIRED,
|
|
19215
|
+
DEVICE_AUTH_STATUS.UNKNOWN
|
|
19216
|
+
];
|
|
19217
|
+
var deviceAuthStartResponseSchema = external_exports.object({
|
|
19218
|
+
deviceCode: external_exports.string().min(1),
|
|
19219
|
+
userCode: external_exports.string().min(1),
|
|
19220
|
+
verificationUrl: external_exports.string().min(1),
|
|
19221
|
+
expiresAt: utcIso86012,
|
|
19222
|
+
pollIntervalMs: external_exports.number().int().positive()
|
|
19431
19223
|
}).strict();
|
|
19432
|
-
var
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
expected: external_exports.number().int().nonnegative(),
|
|
19436
|
-
expectedMinutes: external_exports.number().nonnegative().nullable(),
|
|
19437
|
-
limit: external_exports.number().int().positive(),
|
|
19438
|
-
multiple: external_exports.number().positive().nullable(),
|
|
19439
|
-
setBy: limitSetBySchema,
|
|
19440
|
-
firstGuess: external_exports.boolean(),
|
|
19441
|
-
shown: external_exports.array(limitPartSchema).max(LIMIT_PARTS.length),
|
|
19442
|
-
awaiting: external_exports.boolean(),
|
|
19443
|
-
history: external_exports.array(limitHistoryEntrySchema).max(LIMIT_HISTORY_MAX)
|
|
19224
|
+
var devicePollPendingSchema = external_exports.object({
|
|
19225
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.PENDING),
|
|
19226
|
+
pollIntervalMs: external_exports.number().int().positive()
|
|
19444
19227
|
}).strict();
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19228
|
+
var devicePollApprovedSchema = external_exports.object({
|
|
19229
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.APPROVED),
|
|
19230
|
+
accountId: external_exports.string().min(1),
|
|
19231
|
+
credential: external_exports.string().min(1),
|
|
19232
|
+
expiresAt: utcIso86012
|
|
19233
|
+
}).strict();
|
|
19234
|
+
var deviceAuthRefusalSchema = external_exports.object({
|
|
19235
|
+
status: external_exports.enum([
|
|
19236
|
+
DEVICE_AUTH_STATUS.DECLINED,
|
|
19237
|
+
DEVICE_AUTH_STATUS.EXPIRED,
|
|
19238
|
+
DEVICE_AUTH_STATUS.UNKNOWN,
|
|
19239
|
+
DEVICE_AUTH_STATUS.INVALID_DECISION,
|
|
19240
|
+
DEVICE_AUTH_STATUS.IDENTITY_REQUIRED,
|
|
19241
|
+
DEVICE_AUTH_STATUS.NOT_CONFIGURED,
|
|
19242
|
+
DEVICE_AUTH_STATUS.UNAUTHORIZED,
|
|
19243
|
+
DEVICE_AUTH_STATUS.ALREADY_DECIDED,
|
|
19244
|
+
DEVICE_AUTH_STATUS.TERMS_REQUIRED
|
|
19245
|
+
]),
|
|
19246
|
+
message: external_exports.string().min(1)
|
|
19247
|
+
}).strict();
|
|
19248
|
+
var devicePollResponseSchema = external_exports.union([
|
|
19249
|
+
devicePollPendingSchema,
|
|
19250
|
+
devicePollApprovedSchema,
|
|
19251
|
+
deviceAuthRefusalSchema
|
|
19252
|
+
]);
|
|
19253
|
+
var deviceConfirmRequestSchema = external_exports.object({
|
|
19254
|
+
userCode: external_exports.string().min(1),
|
|
19255
|
+
decision: external_exports.enum(["approve", "decline"]),
|
|
19256
|
+
externalAuthId: external_exports.string().min(1).optional(),
|
|
19257
|
+
email: external_exports.string().optional(),
|
|
19258
|
+
acceptTerms: external_exports.boolean().optional()
|
|
19259
|
+
}).strict();
|
|
19260
|
+
var deviceConfirmRecordedSchema = external_exports.object({
|
|
19261
|
+
status: external_exports.literal(DEVICE_AUTH_STATUS.RECORDED),
|
|
19262
|
+
accountId: external_exports.string().min(1).optional()
|
|
19263
|
+
}).strict();
|
|
19264
|
+
var deviceConfirmResponseSchema = external_exports.union([
|
|
19265
|
+
deviceConfirmRecordedSchema,
|
|
19266
|
+
deviceAuthRefusalSchema
|
|
19267
|
+
]);
|
|
19268
|
+
var DASHBOARD_URL = "https://app.halfcycle.ai";
|
|
19269
|
+
|
|
19270
|
+
// ../events/dist/project-page.js
|
|
19271
|
+
function projectPageUrl(engagementId) {
|
|
19272
|
+
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
19273
|
+
}
|
|
19274
|
+
function systemViewUrl(engagementId, phase) {
|
|
19275
|
+
const page = projectPageUrl(engagementId);
|
|
19276
|
+
if (page === void 0)
|
|
19277
|
+
return void 0;
|
|
19278
|
+
return `${page}/console/system-view?${new URLSearchParams({ phase }).toString()}`;
|
|
19279
|
+
}
|
|
19280
|
+
function requestAccessSentence(engagementId) {
|
|
19281
|
+
const page = projectPageUrl(engagementId) ?? "this project's page on Halfcycle";
|
|
19282
|
+
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.`;
|
|
19283
|
+
}
|
|
19284
|
+
|
|
19285
|
+
// ../events/dist/scope-notices.js
|
|
19286
|
+
var scopePartNameSchema = external_exports.string().min(1).max(SYSTEM_PART_NAME_MAX);
|
|
19287
|
+
var scopeNoteEntrySchema = external_exports.object({
|
|
19288
|
+
part: scopePartNameSchema.optional(),
|
|
19289
|
+
note: external_exports.string().min(1).max(SCOPE_NOTE_MAX)
|
|
19290
|
+
}).strict();
|
|
19291
|
+
var scopeSentBackSchema = external_exports.object({
|
|
19292
|
+
phase: scopePhaseSchema,
|
|
19293
|
+
number: external_exports.number().int().min(1),
|
|
19294
|
+
notes: external_exports.array(scopeNoteEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX + 1)
|
|
19295
|
+
}).strict().superRefine((entry, ctx) => {
|
|
19296
|
+
entry.notes.forEach((n, i) => {
|
|
19297
|
+
if (n.part === void 0 && i !== entry.notes.length - 1) {
|
|
19298
|
+
ctx.addIssue({
|
|
19299
|
+
code: external_exports.ZodIssueCode.custom,
|
|
19300
|
+
path: ["notes", i],
|
|
19301
|
+
message: "the note on the whole phase comes after every note on a part"
|
|
19302
|
+
});
|
|
19303
|
+
}
|
|
19304
|
+
});
|
|
19305
|
+
});
|
|
19306
|
+
var scopeWaitingSchema = external_exports.object({
|
|
19307
|
+
phase: scopePhaseSchema,
|
|
19308
|
+
number: external_exports.number().int().min(1),
|
|
19309
|
+
changedParts: external_exports.array(scopePartNameSchema).max(PHASE_PLAN_CHANGES_MAX)
|
|
19310
|
+
}).strict();
|
|
19311
|
+
var scopeNoticesSchema = external_exports.object({
|
|
19312
|
+
sentBack: external_exports.array(scopeSentBackSchema),
|
|
19313
|
+
waiting: external_exports.array(scopeWaitingSchema),
|
|
19314
|
+
typedApprovalOffered: external_exports.boolean()
|
|
19315
|
+
}).strict().refine((v) => v.sentBack.length > 0 || v.waiting.length > 0, {
|
|
19316
|
+
message: "carried only when a phase was sent back or waits for the owner"
|
|
19317
|
+
});
|
|
19318
|
+
var scopeApprovedNoticeSchema = external_exports.object({ phase: scopePhaseSchema }).strict();
|
|
19319
|
+
var scopeApprovedNoticesSchema = external_exports.array(scopeApprovedNoticeSchema);
|
|
19320
|
+
function approvedInConsoleSentence(phase) {
|
|
19321
|
+
return `Scope for ${phaseWords(phase)} was approved in the console; continuing. Say so to the person, then carry on with the next step; they do not need to tell you.`;
|
|
19322
|
+
}
|
|
19323
|
+
function quotedParts(parts) {
|
|
19324
|
+
return parts.map((p) => `"${p}"`).join(", ");
|
|
19325
|
+
}
|
|
19326
|
+
function approvalSentence(phase, offerTyping) {
|
|
19327
|
+
if (offerTyping === "off")
|
|
19328
|
+
return TYPED_APPROVAL_OFF_SENTENCE;
|
|
19329
|
+
if (offerTyping === "update")
|
|
19330
|
+
return CLIENT_UPDATE_SENTENCE;
|
|
19331
|
+
return `In their own interactive session ${HEADLESS_CANNOT_APPROVE}, they ask to see the plan, check each part, and then type: approve ${phase}.`;
|
|
19332
|
+
}
|
|
19333
|
+
function phaseWords(phase) {
|
|
19334
|
+
return `phase "${phase}"`;
|
|
19335
|
+
}
|
|
19336
|
+
function sentBackNotice(entry) {
|
|
19337
|
+
return [
|
|
19338
|
+
`Before anything else: the project's owner sent the scope of ${phaseWords(entry.phase)} back with these notes.`,
|
|
19339
|
+
...entry.notes.map((n) => n.part === void 0 ? `- ${n.note}` : `- "${n.part}": ${n.note}`),
|
|
19340
|
+
`Change the plan to answer every note, then send it again: say "plan the next phase" to start. It then waits for the owner's approval again.`
|
|
19341
|
+
].join("\n");
|
|
19342
|
+
}
|
|
19343
|
+
function systemViewSentence(offerTyping, address) {
|
|
19344
|
+
if (address === void 0)
|
|
19345
|
+
return [];
|
|
19346
|
+
return [offerTyping === "yes" ? `Or they approve it in the System view: ${address}` : `They approve it in the System view: ${address}`];
|
|
19347
|
+
}
|
|
19348
|
+
function waitingNotice(entry, offerTyping, engagementId) {
|
|
19349
|
+
return [
|
|
19350
|
+
...entry.changedParts.length > 0 ? [`These parts changed since the owner last decided on this phase, and wait for their approval: ${quotedParts(entry.changedParts)}.`] : [],
|
|
19351
|
+
`The scope of ${phaseWords(entry.phase)} is waiting for the project's owner to approve it.`,
|
|
19352
|
+
approvalSentence(entry.phase, offerTyping),
|
|
19353
|
+
...systemViewSentence(offerTyping, systemViewUrl(engagementId, entry.phase))
|
|
19354
|
+
].join(" ");
|
|
19355
|
+
}
|
|
19356
|
+
function scopeNoticeText(scope, options) {
|
|
19357
|
+
const omit2 = options.omitActivePhase === true ? options.activePhase : void 0;
|
|
19358
|
+
return {
|
|
19359
|
+
sentBack: scope.sentBack.map(sentBackNotice),
|
|
19360
|
+
waiting: scope.waiting.filter((w) => omit2 === void 0 || w.phase !== omit2).map((w) => waitingNotice(w, options.offerTyping, options.engagementId))
|
|
19361
|
+
};
|
|
19362
|
+
}
|
|
19363
|
+
|
|
19364
|
+
// ../events/dist/review-notices.js
|
|
19365
|
+
var reviewNoticeQuestionSchema = external_exports.object({
|
|
19366
|
+
phase: scopePhaseSchema,
|
|
19367
|
+
number: reviewPhaseNumberSchema,
|
|
19368
|
+
part: systemPartIdSchema,
|
|
19369
|
+
partName: systemPartSchema.shape.name,
|
|
19370
|
+
question: reviewNoteSchema
|
|
19371
|
+
}).strict();
|
|
19372
|
+
var reviewNoticeSentBackSchema = external_exports.object({
|
|
19373
|
+
phase: scopePhaseSchema,
|
|
19374
|
+
number: reviewPhaseNumberSchema,
|
|
19375
|
+
part: systemPartIdSchema,
|
|
19376
|
+
partName: systemPartSchema.shape.name,
|
|
19377
|
+
note: reviewNoteSchema
|
|
19378
|
+
}).strict();
|
|
19379
|
+
var reviewNoticesSchema = external_exports.object({
|
|
19380
|
+
questions: external_exports.array(reviewNoticeQuestionSchema).max(REVIEW_PARTS_MAX),
|
|
19381
|
+
sentBack: external_exports.array(reviewNoticeSentBackSchema).max(REVIEW_PARTS_MAX)
|
|
19382
|
+
}).strict().refine((v) => v.questions.length > 0 || v.sentBack.length > 0, {
|
|
19383
|
+
message: "carried only when a question waits or a part was sent back"
|
|
19384
|
+
});
|
|
19385
|
+
function phaseCalled(phase) {
|
|
19386
|
+
return `phase "${phase}"`;
|
|
19387
|
+
}
|
|
19388
|
+
function questionNotice(entry) {
|
|
19389
|
+
const answer = `${HALFCYCLE_COMMAND} review ${quoteForShell(entry.phase)} --answer ${quoteForShell(entry.part)} "<your answer>"`;
|
|
19390
|
+
return `Before anything else: the project's owner asked about "${entry.partName}" in the review of ${phaseCalled(entry.phase)}: ${entry.question} Answer it with ${answer}.`;
|
|
19391
|
+
}
|
|
19392
|
+
function sentBackNotice2(entry) {
|
|
19393
|
+
return `Before anything else: the project's owner sent "${entry.partName}" in ${phaseCalled(entry.phase)} back to building: ${entry.note} Rebuild it: add or reopen the tasks that build it. For each task that rebuilds it, add a task that reviews the rebuild, held by a different agent from the one that built it. When each review has passed, report the build with the time each task finished, then run the close step again.`;
|
|
19394
|
+
}
|
|
19395
|
+
function reviewNoticeText(review) {
|
|
19396
|
+
return [...review.questions.map(questionNotice), ...review.sentBack.map(sentBackNotice2)];
|
|
19397
|
+
}
|
|
19398
|
+
|
|
19399
|
+
// ../events/dist/credential-wire.js
|
|
19400
|
+
var engagementCredentialResponseSchema = external_exports.object({
|
|
19401
|
+
engagementId: external_exports.string(),
|
|
19402
|
+
sessionToken: external_exports.string(),
|
|
19403
|
+
mcpUrl: external_exports.string(),
|
|
19404
|
+
guardUrl: external_exports.string(),
|
|
19405
|
+
controlTelemetryUrl: external_exports.string(),
|
|
19406
|
+
methodVersion: external_exports.string().optional(),
|
|
19407
|
+
consoleUrl: external_exports.string().optional()
|
|
19408
|
+
}).strict();
|
|
19409
|
+
var ciTokenExchangeResponseSchema = external_exports.object({
|
|
19410
|
+
token: external_exports.string(),
|
|
19411
|
+
expiresAt: utcIso8601,
|
|
19412
|
+
engagementId: external_exports.string()
|
|
19413
|
+
}).strict();
|
|
19414
|
+
var NO_CREDENTIAL_PLACEHOLDER = "halfcycle:no-credential";
|
|
19415
|
+
var NOT_THIS_ACCOUNT_PLACEHOLDER = "halfcycle:not-this-account";
|
|
19416
|
+
var UPDATE_CLAUDE_CODE_PLACEHOLDER = "halfcycle:update-claude-code";
|
|
19417
|
+
var CREDENTIAL_PLACEHOLDERS = [
|
|
19418
|
+
NO_CREDENTIAL_PLACEHOLDER,
|
|
19419
|
+
NOT_THIS_ACCOUNT_PLACEHOLDER,
|
|
19420
|
+
UPDATE_CLAUDE_CODE_PLACEHOLDER
|
|
19421
|
+
];
|
|
19422
|
+
var SWITCH_ACCOUNT_ANSWER = 'answer "s" when asked';
|
|
19423
|
+
var NO_CREDENTIAL_SENTENCE = 'Halfcycle is not connected: this machine has no working Halfcycle credential for this project. Run "npx halfcycle" in the project folder to sign in again.';
|
|
19424
|
+
var NOT_THIS_ACCOUNT_SENTENCE = `Halfcycle is not connected: this project belongs to another Halfcycle account. To switch, run "npx halfcycle" in this project and ${SWITCH_ACCOUNT_ANSWER}.`;
|
|
19425
|
+
var UPDATE_CLAUDE_CODE_SENTENCE = "Halfcycle is not connected: this Claude Code version does not name the server it connects to, so no credential was sent. Update Claude Code, then reopen.";
|
|
19426
|
+
var CANNOT_REACH_SENTENCE = "Halfcycle is not connected: its server could not be reached, so its tools are unavailable in this session. Check your network, then reopen the project.";
|
|
19427
|
+
var SERVICE_PROBLEM_SENTENCE = "Halfcycle is not connected: its service had a problem just now, so nothing in this session is being checked. Reopen the project to try again.";
|
|
19428
|
+
var FOLDER_NOT_TRUSTED_SENTENCE = "Folder not yet trusted. Open this folder once in interactive Claude Code and trust it; then headless runs work.";
|
|
19429
|
+
var SCOPE_UNCHECKED_SENTENCE = "If this project needs approval before building, that cannot be checked either, so work done now shows as built without approval unless already approved.";
|
|
19430
|
+
var PLACEHOLDER_SENTENCES = Object.freeze({
|
|
19431
|
+
[NO_CREDENTIAL_PLACEHOLDER]: NO_CREDENTIAL_SENTENCE,
|
|
19432
|
+
[NOT_THIS_ACCOUNT_PLACEHOLDER]: NOT_THIS_ACCOUNT_SENTENCE,
|
|
19433
|
+
[UPDATE_CLAUDE_CODE_PLACEHOLDER]: UPDATE_CLAUDE_CODE_SENTENCE
|
|
19434
|
+
});
|
|
19435
|
+
|
|
19436
|
+
// ../events/dist/scope-chat.js
|
|
19437
|
+
var chatScopeApproveRequestSchema = external_exports.object({
|
|
19438
|
+
act: external_exports.literal("approve"),
|
|
19439
|
+
reference: phaseIdentitySchema,
|
|
19440
|
+
planVersion: planVersionSchema
|
|
19441
|
+
}).strict();
|
|
19442
|
+
var chatScopeSendBackRequestSchema = external_exports.object({
|
|
19443
|
+
act: external_exports.literal("send-back"),
|
|
19444
|
+
reference: phaseIdentitySchema,
|
|
19445
|
+
planVersion: planVersionSchema,
|
|
19446
|
+
note: scopeNoteWireSchema.optional()
|
|
19447
|
+
}).strict();
|
|
19448
|
+
var chatScopeRequestSchema = external_exports.discriminatedUnion("act", [
|
|
19449
|
+
chatScopeApproveRequestSchema,
|
|
19450
|
+
chatScopeSendBackRequestSchema
|
|
19451
|
+
]);
|
|
19452
|
+
var CHAT_SCOPE_ACTS = SCOPE_ACTS;
|
|
19453
|
+
var chatScopeRecordedSchema = external_exports.object({
|
|
19454
|
+
outcome: external_exports.literal("recorded"),
|
|
19455
|
+
act: external_exports.enum(CHAT_SCOPE_ACTS),
|
|
19456
|
+
phase: scopePhaseSchema,
|
|
19457
|
+
planVersion: planVersionSchema
|
|
19458
|
+
}).strict();
|
|
19459
|
+
var chatScopeAlreadyApprovedSchema = external_exports.object({
|
|
19460
|
+
outcome: external_exports.literal("already-approved"),
|
|
19461
|
+
replanNeeded: external_exports.boolean()
|
|
19462
|
+
}).strict();
|
|
19463
|
+
var chatScopeRefusedSchema = external_exports.object({
|
|
19464
|
+
outcome: external_exports.literal("refused"),
|
|
19465
|
+
problems: external_exports.array(systemDescriptionProblemSchema).min(1)
|
|
19466
|
+
}).strict();
|
|
19467
|
+
var chatAmbiguousSchema = external_exports.object({
|
|
19468
|
+
outcome: external_exports.literal("ambiguous"),
|
|
19469
|
+
phases: external_exports.array(scopePhaseSchema).min(2)
|
|
19470
|
+
}).strict();
|
|
19471
|
+
function bareOutcome(outcome) {
|
|
19472
|
+
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
19473
|
+
}
|
|
19474
|
+
var chatScopeResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19475
|
+
chatScopeRecordedSchema,
|
|
19476
|
+
chatScopeAlreadyApprovedSchema,
|
|
19477
|
+
chatScopeRefusedSchema,
|
|
19478
|
+
chatAmbiguousSchema,
|
|
19479
|
+
bareOutcome("show-first"),
|
|
19480
|
+
bareOutcome("plan-changed"),
|
|
19481
|
+
bareOutcome("build-started"),
|
|
19482
|
+
bareOutcome("not-owner"),
|
|
19483
|
+
bareOutcome("no-owner"),
|
|
19484
|
+
bareOutcome("not-offered"),
|
|
19485
|
+
bareOutcome("unavailable")
|
|
19486
|
+
]);
|
|
19487
|
+
|
|
19488
|
+
// ../events/dist/review-chat.js
|
|
19489
|
+
var chatReviewAcceptRequestSchema = external_exports.object({
|
|
19490
|
+
act: external_exports.literal("accept"),
|
|
19491
|
+
reference: phaseIdentitySchema,
|
|
19492
|
+
reviewVersion: external_exports.number().int().min(0),
|
|
19493
|
+
parts: external_exports.array(systemPartIdSchema).max(REVIEW_PARTS_MAX),
|
|
19494
|
+
waitingClaims: external_exports.literal(true).optional()
|
|
19495
|
+
}).strict();
|
|
19496
|
+
function notedRequest(act) {
|
|
19497
|
+
return external_exports.object({
|
|
19498
|
+
act: external_exports.literal(act),
|
|
19499
|
+
reference: phaseIdentitySchema,
|
|
19500
|
+
reviewVersion: external_exports.number().int().min(0),
|
|
19501
|
+
part: systemPartIdSchema,
|
|
19502
|
+
note: reviewNoteWireSchema
|
|
19503
|
+
}).strict();
|
|
19504
|
+
}
|
|
19505
|
+
var chatReviewQuestionRequestSchema = notedRequest("question");
|
|
19506
|
+
var chatReviewSendBackRequestSchema = notedRequest("send-back");
|
|
19507
|
+
var chatReviewCarryRequestSchema = notedRequest("carry");
|
|
19508
|
+
var chatReviewDropRequestSchema = notedRequest("drop");
|
|
19509
|
+
var chatReviewRejectRequestSchema = external_exports.object({
|
|
19510
|
+
act: external_exports.literal("reject"),
|
|
19511
|
+
reference: phaseIdentitySchema,
|
|
19512
|
+
reviewVersion: external_exports.number().int().min(0),
|
|
19513
|
+
task: buildTaskIdSchema,
|
|
19514
|
+
note: reviewNoteWireSchema
|
|
19515
|
+
}).strict();
|
|
19516
|
+
var chatReviewRequestSchema = external_exports.discriminatedUnion("act", [
|
|
19517
|
+
chatReviewAcceptRequestSchema,
|
|
19518
|
+
chatReviewQuestionRequestSchema,
|
|
19519
|
+
chatReviewSendBackRequestSchema,
|
|
19520
|
+
chatReviewCarryRequestSchema,
|
|
19521
|
+
chatReviewDropRequestSchema,
|
|
19522
|
+
chatReviewRejectRequestSchema
|
|
19523
|
+
]);
|
|
19524
|
+
function bareOutcome2(outcome) {
|
|
19525
|
+
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
19526
|
+
}
|
|
19527
|
+
function notTheConsoleNotDecidable(option) {
|
|
19528
|
+
return option !== reviewNotDecidableSchema;
|
|
19529
|
+
}
|
|
19530
|
+
var chatReviewResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19531
|
+
reviewPartsNotDecidableSchema,
|
|
19532
|
+
...reviewDecisionResultSchema.options.filter(notTheConsoleNotDecidable),
|
|
19533
|
+
bareOutcome2("show-first"),
|
|
19534
|
+
bareOutcome2("not-offered"),
|
|
19535
|
+
chatAmbiguousSchema,
|
|
19536
|
+
bareOutcome2("nothing-waiting")
|
|
19537
|
+
]);
|
|
19538
|
+
var reviewAnswerRequestSchema = external_exports.object({
|
|
19539
|
+
part: systemPartIdSchema,
|
|
19540
|
+
answer: statementText(REVIEW_ANSWER_MAX)
|
|
19541
|
+
}).strict();
|
|
19542
|
+
var reviewAnswerRecordedSchema = external_exports.object({
|
|
19543
|
+
outcome: external_exports.literal("recorded"),
|
|
19544
|
+
name: systemPartSchema.shape.name
|
|
19545
|
+
}).strict();
|
|
19546
|
+
var reviewAnswerResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19547
|
+
reviewAnswerRecordedSchema,
|
|
19548
|
+
bareOutcome2("no-question"),
|
|
19549
|
+
reviewRefusedSchema,
|
|
19550
|
+
bareOutcome2("unavailable")
|
|
19551
|
+
]);
|
|
19552
|
+
|
|
19553
|
+
// ../events/dist/owner-wait-answer.js
|
|
19554
|
+
var OWNER_WAIT_SHORT_ID_LENGTH = 8;
|
|
19555
|
+
var ownerWaitShortIdSchema = external_exports.string().regex(/^[0-9a-f]{8}$/);
|
|
19556
|
+
function ownerWaitShortIdOf(declarationId) {
|
|
19557
|
+
return declarationId.slice(0, OWNER_WAIT_SHORT_ID_LENGTH).toLowerCase();
|
|
19450
19558
|
}
|
|
19451
|
-
var
|
|
19452
|
-
|
|
19453
|
-
|
|
19454
|
-
|
|
19455
|
-
at: utcIso8601
|
|
19456
|
-
}).strict();
|
|
19457
|
-
function limitPartLineOf(part, used, limit) {
|
|
19458
|
-
const words = part === "half" ? "half" : part === "three-quarters" ? "three quarters" : "nine tenths";
|
|
19459
|
-
const line2 = `This phase has used ${words} of its usage limit: ${tokenCountWordsOf(used)} of ${tokenCountWordsOf(limit)} tokens.`;
|
|
19460
|
-
return part === "nine-tenths" ? `${line2} New work stops at the limit.` : line2;
|
|
19559
|
+
var OWNER_WAIT_ANSWER_ACTS = ["approve", "decline"];
|
|
19560
|
+
var ownerWaitAnswerActSchema = external_exports.enum(OWNER_WAIT_ANSWER_ACTS);
|
|
19561
|
+
function ownerWaitApproveLineOf(declarationId) {
|
|
19562
|
+
return `approve wait ${ownerWaitShortIdOf(declarationId)}`;
|
|
19461
19563
|
}
|
|
19462
|
-
function
|
|
19463
|
-
|
|
19464
|
-
const finish = working === 0 ? "" : working === 1 ? " The 1 agent already working will finish its task." : ` The ${String(working)} agents already working will finish their tasks.`;
|
|
19465
|
-
return `${head}${finish} Say "keep going" to raise the limit by about ${tokenCountWordsOf(raiseBy)} tokens and carry on, or "stop" to leave the phase paused here. Nothing is lost either way.`;
|
|
19564
|
+
function ownerWaitDeclineLineOf(declarationId) {
|
|
19565
|
+
return `decline wait ${ownerWaitShortIdOf(declarationId)}: <why>`;
|
|
19466
19566
|
}
|
|
19467
|
-
|
|
19468
|
-
|
|
19567
|
+
var ownerWaitChatRequestSchema = external_exports.discriminatedUnion("act", [
|
|
19568
|
+
external_exports.object({ act: external_exports.literal("approve"), wait: ownerWaitShortIdSchema }).strict(),
|
|
19569
|
+
external_exports.object({ act: external_exports.literal("decline"), wait: ownerWaitShortIdSchema, note: scopeNoteWireSchema }).strict()
|
|
19570
|
+
]);
|
|
19571
|
+
function bareOutcome3(outcome) {
|
|
19572
|
+
return external_exports.object({ outcome: external_exports.literal(outcome) }).strict();
|
|
19469
19573
|
}
|
|
19574
|
+
var ownerWaitChatResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19575
|
+
external_exports.object({
|
|
19576
|
+
outcome: external_exports.literal("recorded"),
|
|
19577
|
+
act: ownerWaitAnswerActSchema,
|
|
19578
|
+
question: external_exports.string().min(1)
|
|
19579
|
+
}).strict(),
|
|
19580
|
+
external_exports.object({ outcome: external_exports.literal("refused"), problems: external_exports.array(systemDescriptionProblemSchema).min(1) }).strict(),
|
|
19581
|
+
bareOutcome3("not-owner"),
|
|
19582
|
+
bareOutcome3("no-owner"),
|
|
19583
|
+
bareOutcome3("not-found"),
|
|
19584
|
+
bareOutcome3("ambiguous"),
|
|
19585
|
+
bareOutcome3("not-offered"),
|
|
19586
|
+
bareOutcome3("unavailable")
|
|
19587
|
+
]);
|
|
19588
|
+
|
|
19589
|
+
// ../events/dist/owner-waits.js
|
|
19590
|
+
var OWNER_WAIT_ITEMS = Object.freeze([
|
|
19591
|
+
Object.freeze({ id: "delete-users-data", words: "Deleting or replacing data people already have." }),
|
|
19592
|
+
Object.freeze({
|
|
19593
|
+
id: "change-promises",
|
|
19594
|
+
words: "Changing what the product promises its users, such as pricing, terms or privacy."
|
|
19595
|
+
}),
|
|
19596
|
+
Object.freeze({ id: "spend-or-sign-up", words: "Anything that costs money or signs up for a service." }),
|
|
19597
|
+
Object.freeze({ id: "publish-or-release", words: "Publishing or releasing to users." }),
|
|
19598
|
+
Object.freeze({ id: "reshape-shared-data", words: "Dropping or reshaping stored data that other parts read." }),
|
|
19599
|
+
Object.freeze({ id: "change-standing-rule", words: "Changing a standing rule." })
|
|
19600
|
+
]);
|
|
19601
|
+
var OWNER_WAIT_ITEM_IDS = Object.freeze(OWNER_WAIT_ITEMS.map((item) => item.id));
|
|
19602
|
+
var ownerWaitItemIdSchema = external_exports.enum(OWNER_WAIT_ITEM_IDS);
|
|
19603
|
+
var OWNER_WAIT_FIXED_COUNT = OWNER_WAIT_ITEMS.length;
|
|
19604
|
+
var OWNER_WAIT_ADDITIONS_MAX = 20;
|
|
19605
|
+
var OWNER_WAIT_TEXT_MAX = 240;
|
|
19606
|
+
var ownerWaitItemRefSchema = external_exports.union([
|
|
19607
|
+
external_exports.number().int().min(1),
|
|
19608
|
+
external_exports.string().uuid({ message: "must be a number from 1 to 6, or the id shown beside an added item" })
|
|
19609
|
+
]);
|
|
19610
|
+
var ownerWaitText = descriptionText(OWNER_WAIT_TEXT_MAX);
|
|
19611
|
+
var ownerWaitAddRequestSchema = external_exports.object({
|
|
19612
|
+
engagementId: external_exports.string().min(1),
|
|
19613
|
+
text: ownerWaitText,
|
|
19614
|
+
reason: ownerWaitText
|
|
19615
|
+
}).strict();
|
|
19616
|
+
var ownerWaitAddResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19617
|
+
external_exports.object({ outcome: external_exports.literal("added"), id: external_exports.string().uuid(), addedAt: utcIso8601 }).strict(),
|
|
19618
|
+
external_exports.object({ outcome: external_exports.literal("refused"), reason: external_exports.literal("too-many") }).strict()
|
|
19619
|
+
]);
|
|
19620
|
+
var ownerWaitUndoableSchema = external_exports.enum(["yes", "no"]);
|
|
19621
|
+
var ownerWaitDeclareRequestSchema = external_exports.object({
|
|
19622
|
+
engagementId: external_exports.string().min(1),
|
|
19623
|
+
item: ownerWaitItemRefSchema,
|
|
19624
|
+
question: ownerWaitText,
|
|
19625
|
+
recommendation: ownerWaitText,
|
|
19626
|
+
task: buildTaskIdSchema.optional(),
|
|
19627
|
+
by: agentNameSchema.optional(),
|
|
19628
|
+
undoable: ownerWaitUndoableSchema.optional(),
|
|
19629
|
+
how: statementText(STATEMENT_MAX).optional()
|
|
19630
|
+
}).strict().refine((r) => r.undoable === "yes" === (r.how !== void 0), {
|
|
19631
|
+
message: "says how to undo it exactly when it can be undone",
|
|
19632
|
+
path: ["how"]
|
|
19633
|
+
});
|
|
19634
|
+
var OWNER_WAIT_DECLARE_REFUSALS = ["no-open-phase", "unknown-item", "say-if-undoable"];
|
|
19635
|
+
var ownerWaitDeclareResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
19636
|
+
external_exports.object({ outcome: external_exports.literal("recorded"), id: external_exports.string().uuid(), say: external_exports.string().min(1) }).strict(),
|
|
19637
|
+
external_exports.object({
|
|
19638
|
+
outcome: external_exports.literal("go-ahead"),
|
|
19639
|
+
id: external_exports.string().uuid(),
|
|
19640
|
+
callId: external_exports.number().int().positive(),
|
|
19641
|
+
say: external_exports.string().min(1)
|
|
19642
|
+
}).strict(),
|
|
19643
|
+
external_exports.object({ outcome: external_exports.literal("refused"), reason: external_exports.enum(OWNER_WAIT_DECLARE_REFUSALS) }).strict()
|
|
19644
|
+
]);
|
|
19645
|
+
var ownerWaitAddedItemSchema = external_exports.object({
|
|
19646
|
+
id: external_exports.string().uuid(),
|
|
19647
|
+
words: external_exports.string().min(1),
|
|
19648
|
+
reason: external_exports.string().min(1),
|
|
19649
|
+
addedAt: utcIso8601
|
|
19650
|
+
}).strict();
|
|
19651
|
+
var ownerWaitListSchema = external_exports.object({
|
|
19652
|
+
fixed: external_exports.array(external_exports.object({ id: ownerWaitItemIdSchema, words: external_exports.string().min(1) }).strict()).length(OWNER_WAIT_FIXED_COUNT),
|
|
19653
|
+
added: external_exports.array(ownerWaitAddedItemSchema).max(OWNER_WAIT_ADDITIONS_MAX)
|
|
19654
|
+
}).strict();
|
|
19655
|
+
var ownerWaitDeclarationSchema = external_exports.object({
|
|
19656
|
+
id: external_exports.string().uuid(),
|
|
19657
|
+
fixedItem: ownerWaitItemIdSchema.nullable(),
|
|
19658
|
+
addition: external_exports.object({ id: external_exports.string().uuid(), words: external_exports.string().min(1) }).strict().nullable(),
|
|
19659
|
+
question: external_exports.string().min(1),
|
|
19660
|
+
recommendation: external_exports.string().min(1),
|
|
19661
|
+
task: buildTaskIdSchema.nullable(),
|
|
19662
|
+
declaredAt: utcIso8601
|
|
19663
|
+
}).strict().refine((d) => d.fixedItem === null !== (d.addition === null), {
|
|
19664
|
+
message: "names exactly one item: a fixed one or an added one",
|
|
19665
|
+
path: ["fixedItem"]
|
|
19666
|
+
});
|
|
19667
|
+
var ownerWaitDeclarationsSchema = external_exports.object({ declarations: external_exports.array(ownerWaitDeclarationSchema) }).strict();
|
|
19668
|
+
var ownerWaitOpenSchema = external_exports.object({
|
|
19669
|
+
wait: ownerWaitShortIdSchema,
|
|
19670
|
+
task: buildTaskIdSchema.nullable(),
|
|
19671
|
+
question: external_exports.string().min(1),
|
|
19672
|
+
recommendation: external_exports.string().min(1),
|
|
19673
|
+
declaredAt: utcIso8601
|
|
19674
|
+
}).strict();
|
|
19675
|
+
var ownerWaitsOpenSchema = external_exports.object({ waits: external_exports.array(ownerWaitOpenSchema) }).strict();
|
|
19676
|
+
var OWNER_WAIT_TOO_MANY = `This project already has ${String(OWNER_WAIT_ADDITIONS_MAX)} things added to what waits for the owner. Ask the owner to take one off on their settings page in the console first; it cannot be done by typing in chat.`;
|
|
19470
19677
|
|
|
19471
19678
|
// ../events/dist/autonomy.js
|
|
19472
19679
|
var AUTONOMY_CHANGED_IN = ["console", "chat"];
|
|
@@ -21650,6 +21857,110 @@ function toAstShapes(markers) {
|
|
|
21650
21857
|
// dist/extract/context.js
|
|
21651
21858
|
import { readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
21652
21859
|
import { join as join4, relative as relative2, sep } from "node:path";
|
|
21860
|
+
|
|
21861
|
+
// dist/extract/repo-facts.js
|
|
21862
|
+
var DATABASE_FILE = /\.sql$|^schema\.prisma$|^drizzle\.config\.|^alembic\.ini$|^knexfile\./i;
|
|
21863
|
+
var BROWSER_FILE = /\.(tsx|jsx|vue|svelte|astro)$|^index\.html$|^(next|vite|nuxt|svelte|astro)\.config\.|^angular\.json$/i;
|
|
21864
|
+
var WEBHOOK_NAME = /webhook/i;
|
|
21865
|
+
var DATABASE_DEPS = /* @__PURE__ */ new Set([
|
|
21866
|
+
"pg",
|
|
21867
|
+
"mysql",
|
|
21868
|
+
"mysql2",
|
|
21869
|
+
"mongodb",
|
|
21870
|
+
"mongoose",
|
|
21871
|
+
"sqlite3",
|
|
21872
|
+
"better-sqlite3",
|
|
21873
|
+
"prisma",
|
|
21874
|
+
"@prisma/client",
|
|
21875
|
+
"drizzle-orm",
|
|
21876
|
+
"typeorm",
|
|
21877
|
+
"sequelize",
|
|
21878
|
+
"knex",
|
|
21879
|
+
"postgres",
|
|
21880
|
+
"psycopg",
|
|
21881
|
+
"psycopg2",
|
|
21882
|
+
"sqlalchemy",
|
|
21883
|
+
"pymysql",
|
|
21884
|
+
"asyncpg",
|
|
21885
|
+
"pymongo",
|
|
21886
|
+
"github.com/lib/pq",
|
|
21887
|
+
"github.com/jackc/pgx",
|
|
21888
|
+
"github.com/go-sql-driver/mysql",
|
|
21889
|
+
"gorm.io/gorm",
|
|
21890
|
+
"diesel",
|
|
21891
|
+
"sqlx",
|
|
21892
|
+
"activerecord"
|
|
21893
|
+
]);
|
|
21894
|
+
var BROWSER_DEPS = /* @__PURE__ */ new Set([
|
|
21895
|
+
"react",
|
|
21896
|
+
"react-dom",
|
|
21897
|
+
"next",
|
|
21898
|
+
"vue",
|
|
21899
|
+
"nuxt",
|
|
21900
|
+
"svelte",
|
|
21901
|
+
"@sveltejs/kit",
|
|
21902
|
+
"@angular/core",
|
|
21903
|
+
"solid-js",
|
|
21904
|
+
"preact",
|
|
21905
|
+
"astro",
|
|
21906
|
+
"vite"
|
|
21907
|
+
]);
|
|
21908
|
+
var MANIFEST_NAMES = /* @__PURE__ */ new Set(["package.json", "go.mod", "requirements.txt", "pyproject.toml", "Gemfile", "Cargo.toml"]);
|
|
21909
|
+
function isFactManifest(fileName) {
|
|
21910
|
+
return MANIFEST_NAMES.has(fileName);
|
|
21911
|
+
}
|
|
21912
|
+
function newFactCollector() {
|
|
21913
|
+
return { found: /* @__PURE__ */ new Set() };
|
|
21914
|
+
}
|
|
21915
|
+
function noteFileName(c, fileName, underDocs) {
|
|
21916
|
+
if (underDocs)
|
|
21917
|
+
return;
|
|
21918
|
+
if (DATABASE_FILE.test(fileName))
|
|
21919
|
+
c.found.add("database");
|
|
21920
|
+
if (BROWSER_FILE.test(fileName))
|
|
21921
|
+
c.found.add("browser-app");
|
|
21922
|
+
if (WEBHOOK_NAME.test(fileName))
|
|
21923
|
+
c.found.add("inbound-webhooks");
|
|
21924
|
+
}
|
|
21925
|
+
function noteDirName(c, dirName, underDocs) {
|
|
21926
|
+
if (underDocs)
|
|
21927
|
+
return;
|
|
21928
|
+
if (WEBHOOK_NAME.test(dirName))
|
|
21929
|
+
c.found.add("inbound-webhooks");
|
|
21930
|
+
if (dirName === "migrations")
|
|
21931
|
+
c.found.add("database");
|
|
21932
|
+
}
|
|
21933
|
+
function dependencyNames(fileName, content) {
|
|
21934
|
+
if (fileName === "package.json") {
|
|
21935
|
+
try {
|
|
21936
|
+
const parsed = JSON.parse(content);
|
|
21937
|
+
const names = [];
|
|
21938
|
+
for (const key of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
21939
|
+
const block = parsed[key];
|
|
21940
|
+
if (block !== null && typeof block === "object")
|
|
21941
|
+
names.push(...Object.keys(block));
|
|
21942
|
+
}
|
|
21943
|
+
return names;
|
|
21944
|
+
} catch {
|
|
21945
|
+
return [];
|
|
21946
|
+
}
|
|
21947
|
+
}
|
|
21948
|
+
return content.split(/[\s"'=<>~^,;:\[\]()]+/).filter((t) => t.length > 0);
|
|
21949
|
+
}
|
|
21950
|
+
function noteManifest(c, fileName, content) {
|
|
21951
|
+
for (const name of dependencyNames(fileName, content)) {
|
|
21952
|
+
const lower = name.toLowerCase();
|
|
21953
|
+
if (DATABASE_DEPS.has(lower))
|
|
21954
|
+
c.found.add("database");
|
|
21955
|
+
if (BROWSER_DEPS.has(lower))
|
|
21956
|
+
c.found.add("browser-app");
|
|
21957
|
+
}
|
|
21958
|
+
}
|
|
21959
|
+
function factsOf(c) {
|
|
21960
|
+
return REPOSITORY_FACTS.filter((f) => c.found.has(f));
|
|
21961
|
+
}
|
|
21962
|
+
|
|
21963
|
+
// dist/extract/context.js
|
|
21653
21964
|
var EXCLUDED_DIRS2 = /* @__PURE__ */ new Set([
|
|
21654
21965
|
"node_modules",
|
|
21655
21966
|
".git",
|
|
@@ -21663,6 +21974,7 @@ var EXCLUDED_DIRS2 = /* @__PURE__ */ new Set([
|
|
|
21663
21974
|
"coverage",
|
|
21664
21975
|
".cache"
|
|
21665
21976
|
]);
|
|
21977
|
+
var PROSE_DIRS = /* @__PURE__ */ new Set(["docs", "skills", "runbooks", "method"]);
|
|
21666
21978
|
function classifyFile(fileName) {
|
|
21667
21979
|
if (fileName === "Dockerfile" || fileName.startsWith("Dockerfile."))
|
|
21668
21980
|
return "dockerfile";
|
|
@@ -21672,7 +21984,7 @@ function classifyFile(fileName) {
|
|
|
21672
21984
|
return "env-example";
|
|
21673
21985
|
return null;
|
|
21674
21986
|
}
|
|
21675
|
-
function walk(dir, repoRoot, acc) {
|
|
21987
|
+
function walk(dir, repoRoot, acc, facts, underDocs = false) {
|
|
21676
21988
|
let entries;
|
|
21677
21989
|
try {
|
|
21678
21990
|
entries = readdirSync2(dir, { withFileTypes: true });
|
|
@@ -21683,11 +21995,21 @@ function walk(dir, repoRoot, acc) {
|
|
|
21683
21995
|
if (entry.isDirectory()) {
|
|
21684
21996
|
if (EXCLUDED_DIRS2.has(entry.name))
|
|
21685
21997
|
continue;
|
|
21686
|
-
|
|
21998
|
+
const lower = entry.name.toLowerCase();
|
|
21999
|
+
noteDirName(facts, lower, underDocs);
|
|
22000
|
+
walk(join4(dir, entry.name), repoRoot, acc, facts, underDocs || PROSE_DIRS.has(lower));
|
|
21687
22001
|
continue;
|
|
21688
22002
|
}
|
|
21689
22003
|
if (!entry.isFile())
|
|
21690
22004
|
continue;
|
|
22005
|
+
noteFileName(facts, entry.name, underDocs);
|
|
22006
|
+
if (!underDocs && isFactManifest(entry.name)) {
|
|
22007
|
+
try {
|
|
22008
|
+
noteManifest(facts, entry.name, readFileSync4(join4(dir, entry.name), "utf-8"));
|
|
22009
|
+
} catch {
|
|
22010
|
+
continue;
|
|
22011
|
+
}
|
|
22012
|
+
}
|
|
21691
22013
|
const kind = classifyFile(entry.name);
|
|
21692
22014
|
if (!kind)
|
|
21693
22015
|
continue;
|
|
@@ -21707,8 +22029,9 @@ function loadChangeSetContext(repoRoot) {
|
|
|
21707
22029
|
if (cached2)
|
|
21708
22030
|
return cached2;
|
|
21709
22031
|
const declarationFiles = [];
|
|
21710
|
-
|
|
21711
|
-
|
|
22032
|
+
const facts = newFactCollector();
|
|
22033
|
+
walk(repoRoot, repoRoot, declarationFiles, facts);
|
|
22034
|
+
const context = { declarationFiles, repoRoot, repoFacts: factsOf(facts) };
|
|
21712
22035
|
cache.set(repoRoot, context);
|
|
21713
22036
|
return context;
|
|
21714
22037
|
}
|
|
@@ -21803,6 +22126,7 @@ function buildGuardEvalRun(opts) {
|
|
|
21803
22126
|
...opts.failureReason !== void 0 ? { failureReason: opts.failureReason } : {},
|
|
21804
22127
|
phase: opts.phase,
|
|
21805
22128
|
scope,
|
|
22129
|
+
...opts.repoFacts !== void 0 ? { repoFacts: [...opts.repoFacts] } : {},
|
|
21806
22130
|
// cost is optional (D6: live cost signal lands later; ingest works without it)
|
|
21807
22131
|
// result present IFF the run was evaluated (schema-enforced refinement).
|
|
21808
22132
|
...opts.outcome === "evaluated" && opts.result !== void 0 ? { result: opts.result } : {}
|
|
@@ -21822,7 +22146,8 @@ async function emitRunRecord(opts) {
|
|
|
21822
22146
|
outcome: opts.outcome,
|
|
21823
22147
|
failureReason: opts.failureReason,
|
|
21824
22148
|
changeSet: opts.changeSet,
|
|
21825
|
-
diffBase: opts.diffBase
|
|
22149
|
+
diffBase: opts.diffBase,
|
|
22150
|
+
repoFacts: opts.repoFacts
|
|
21826
22151
|
});
|
|
21827
22152
|
await emitTelemetry(run, {
|
|
21828
22153
|
controlTelemetryUrl: telemetryConfig.controlTelemetryUrl,
|
|
@@ -21888,7 +22213,8 @@ async function runCi() {
|
|
|
21888
22213
|
runType: "ci",
|
|
21889
22214
|
outcome: acquired.kind === "contract" ? "contract-error" : "infra-error",
|
|
21890
22215
|
failureReason: `ci credential: ${acquired.kind}: ${acquired.message}`,
|
|
21891
|
-
changeSet
|
|
22216
|
+
changeSet,
|
|
22217
|
+
repoFacts: context.repoFacts
|
|
21892
22218
|
});
|
|
21893
22219
|
process.stderr.write(credentialExchangeFailureMessage(acquired));
|
|
21894
22220
|
return 1;
|
|
@@ -21903,7 +22229,7 @@ async function runCi() {
|
|
|
21903
22229
|
}
|
|
21904
22230
|
}
|
|
21905
22231
|
if (!configResult.config) {
|
|
21906
|
-
await emitRunRecord({ runType: "ci", outcome: "unconfigured", changeSet });
|
|
22232
|
+
await emitRunRecord({ runType: "ci", outcome: "unconfigured", changeSet, repoFacts: context.repoFacts });
|
|
21907
22233
|
process.stderr.write(isHalfcycleOwnCi() ? ciNeverConfiguredMessage() : CI_NOT_SUPPORTED_MESSAGE);
|
|
21908
22234
|
return 1;
|
|
21909
22235
|
}
|
|
@@ -21920,6 +22246,7 @@ async function evaluateAndAct(args2) {
|
|
|
21920
22246
|
outcome: outcomeForClientFailure(clientResult.kind),
|
|
21921
22247
|
failureReason: failure.reason,
|
|
21922
22248
|
changeSet,
|
|
22249
|
+
repoFacts: context.repoFacts,
|
|
21923
22250
|
credentialRefused: failure.kind === "credential"
|
|
21924
22251
|
});
|
|
21925
22252
|
if (failure.kind === "credential") {
|
|
@@ -21946,6 +22273,7 @@ async function evaluateAndAct(args2) {
|
|
|
21946
22273
|
phase: telemetryConfig.phase,
|
|
21947
22274
|
outcome: "evaluated",
|
|
21948
22275
|
changeSet,
|
|
22276
|
+
repoFacts: context.repoFacts,
|
|
21949
22277
|
result: clientResult.envelope
|
|
21950
22278
|
});
|
|
21951
22279
|
await emitTelemetry(run, {
|
|
@@ -24311,19 +24639,19 @@ function settled(dir, file2, tokens) {
|
|
|
24311
24639
|
writePhaseLimit(dir, next);
|
|
24312
24640
|
return next;
|
|
24313
24641
|
}
|
|
24314
|
-
function turnEndLimitLine(file2, tokens, working) {
|
|
24642
|
+
function turnEndLimitLine(file2, tokens, working, weekCeilingTokens = null) {
|
|
24315
24643
|
if (file2.awaiting) {
|
|
24316
24644
|
if (file2.shown.includes("limit"))
|
|
24317
24645
|
return { text: null, file: file2 };
|
|
24318
24646
|
return {
|
|
24319
|
-
text: limitReachedLineOf(
|
|
24647
|
+
text: limitReachedLineOf({ limit: file2.limit, working, weekCeilingTokens }),
|
|
24320
24648
|
file: { ...file2, shown: [...LIMIT_PARTS] }
|
|
24321
24649
|
};
|
|
24322
24650
|
}
|
|
24323
24651
|
const r = partsReached(tokens, file2.limit, file2.shown);
|
|
24324
24652
|
if (r.show === null)
|
|
24325
24653
|
return { text: null, file: file2 };
|
|
24326
|
-
return { text: limitPartLineOf(r.show, tokens,
|
|
24654
|
+
return { text: limitPartLineOf(r.show, tokens, weekCeilingTokens), file: { ...file2, shown: r.shown } };
|
|
24327
24655
|
}
|
|
24328
24656
|
function openPhaseLimit(dir, remembered) {
|
|
24329
24657
|
if (remembered !== null && remembered.phase === null)
|
|
@@ -26562,7 +26890,7 @@ async function evaluateEdit(reply, readSeat, at, profile) {
|
|
|
26562
26890
|
});
|
|
26563
26891
|
const configResult = readConfig();
|
|
26564
26892
|
if (!configResult.config) {
|
|
26565
|
-
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet });
|
|
26893
|
+
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet, repoFacts: context.repoFacts });
|
|
26566
26894
|
if (!firstNoticeThisSession("credential-missing", repoRoot, input.session_id))
|
|
26567
26895
|
return;
|
|
26568
26896
|
emitNeverConfigured(UNCONFIGURED_EXIT_TOOL_USE, readNeverConfiguredReason(), pinnedEngagementId(projectFolder()), reply);
|
|
@@ -26586,6 +26914,7 @@ async function evaluateEdit(reply, readSeat, at, profile) {
|
|
|
26586
26914
|
outcome: outcomeForClientFailure(clientResult.kind),
|
|
26587
26915
|
failureReason: failure.reason,
|
|
26588
26916
|
changeSet,
|
|
26917
|
+
repoFacts: context.repoFacts,
|
|
26589
26918
|
credential: evaluation.token,
|
|
26590
26919
|
credentialRefused: failure.kind === "credential"
|
|
26591
26920
|
});
|
|
@@ -26620,6 +26949,7 @@ async function evaluateEdit(reply, readSeat, at, profile) {
|
|
|
26620
26949
|
phase: telemetryConfig.phase,
|
|
26621
26950
|
outcome: "evaluated",
|
|
26622
26951
|
changeSet,
|
|
26952
|
+
repoFacts: context.repoFacts,
|
|
26623
26953
|
result: clientResult.envelope
|
|
26624
26954
|
});
|
|
26625
26955
|
await emitTelemetry(run, {
|
|
@@ -26867,29 +27197,171 @@ function runsBesideOtherWork(toolInput, record2) {
|
|
|
26867
27197
|
}
|
|
26868
27198
|
|
|
26869
27199
|
// dist/pace-hook.js
|
|
26870
|
-
import { mkdirSync as
|
|
26871
|
-
import
|
|
27200
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync21, renameSync as renameSync11, unlinkSync as unlinkSync8, writeFileSync as writeFileSync13 } from "node:fs";
|
|
27201
|
+
import nodePath6 from "node:path";
|
|
26872
27202
|
|
|
26873
27203
|
// dist/pace-verb.js
|
|
26874
|
-
import { mkdirSync as
|
|
27204
|
+
import { mkdirSync as mkdirSync8, readdirSync as readdirSync8, readFileSync as readFileSync20, renameSync as renameSync10, statSync as statSync6, writeFileSync as writeFileSync12 } from "node:fs";
|
|
26875
27205
|
import { homedir as homedir9 } from "node:os";
|
|
27206
|
+
import nodePath5 from "node:path";
|
|
27207
|
+
|
|
27208
|
+
// dist/plan-report.js
|
|
27209
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync19, renameSync as renameSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26876
27210
|
import nodePath4 from "node:path";
|
|
26877
|
-
var
|
|
26878
|
-
var
|
|
27211
|
+
var PLAN_REPORT_MIN_INTERVAL_MS = 10 * 60 * 1e3;
|
|
27212
|
+
var PLAN_MIN_GAIN_POINTS = 2;
|
|
27213
|
+
var PLAN_FIRST_READ_FILENAME = "plan-first-read.json";
|
|
27214
|
+
var PLAN_DERIVED_FILENAME = "plan-derived-ceiling.json";
|
|
27215
|
+
var PLAN_REPORT_THROTTLE_FILENAME = "plan-report.json";
|
|
27216
|
+
function isNum2(v) {
|
|
27217
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
27218
|
+
}
|
|
27219
|
+
function isTime(v) {
|
|
27220
|
+
return typeof v === "string" && !Number.isNaN(Date.parse(v));
|
|
27221
|
+
}
|
|
27222
|
+
function readAccounts(path) {
|
|
27223
|
+
try {
|
|
27224
|
+
const v = JSON.parse(readFileSync19(path, "utf-8"));
|
|
27225
|
+
const accounts = typeof v === "object" && v !== null ? v["accounts"] : void 0;
|
|
27226
|
+
return typeof accounts === "object" && accounts !== null && !Array.isArray(accounts) ? { ...accounts } : {};
|
|
27227
|
+
} catch {
|
|
27228
|
+
return {};
|
|
27229
|
+
}
|
|
27230
|
+
}
|
|
27231
|
+
function writeAccount(path, key, entry) {
|
|
27232
|
+
const accounts = readAccounts(path);
|
|
27233
|
+
accounts[key] = entry;
|
|
27234
|
+
mkdirSync7(nodePath4.dirname(path), { recursive: true, mode: 448 });
|
|
27235
|
+
const tmp = `${path}.${String(process.pid)}.${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
27236
|
+
writeFileSync11(tmp, JSON.stringify({ accounts }), { mode: 384 });
|
|
27237
|
+
renameSync9(tmp, path);
|
|
27238
|
+
}
|
|
27239
|
+
function firstReadOf(key, home) {
|
|
27240
|
+
const v = readAccounts(nodePath4.join(pacingDir(home), PLAN_FIRST_READ_FILENAME))[key];
|
|
27241
|
+
if (typeof v !== "object" || v === null)
|
|
27242
|
+
return null;
|
|
27243
|
+
const o = v;
|
|
27244
|
+
return isNum2(o["usedPercent"]) && isTime(o["resetsAt"]) && isTime(o["at"]) ? { usedPercent: o["usedPercent"], resetsAt: o["resetsAt"], at: o["at"] } : null;
|
|
27245
|
+
}
|
|
27246
|
+
function derivedOf(key, home) {
|
|
27247
|
+
const v = readAccounts(nodePath4.join(pacingDir(home), PLAN_DERIVED_FILENAME))[key];
|
|
27248
|
+
if (typeof v !== "object" || v === null)
|
|
27249
|
+
return null;
|
|
27250
|
+
const o = v;
|
|
27251
|
+
return isNum2(o["tokens"]) && Number.isInteger(o["tokens"]) && o["tokens"] > 0 && isTime(o["resetsAt"]) ? { tokens: o["tokens"], resetsAt: o["resetsAt"] } : null;
|
|
27252
|
+
}
|
|
27253
|
+
function weeklyCeilingOf(key, deps = {}) {
|
|
27254
|
+
const learned = readLearnedAccount(key, deps)?.ceilings["seven-day"];
|
|
27255
|
+
if (learned !== void 0)
|
|
27256
|
+
return learned.tokens;
|
|
27257
|
+
const week = readReportedAccount(key, deps)["seven-day"];
|
|
27258
|
+
const derived = derivedOf(key, deps.home);
|
|
27259
|
+
if (week === void 0 || derived === null)
|
|
27260
|
+
return null;
|
|
27261
|
+
return Date.parse(derived.resetsAt) === Date.parse(week.resetsAt) ? derived.tokens : null;
|
|
27262
|
+
}
|
|
27263
|
+
function derivedBetweenReads(key, week, deps, nowMs) {
|
|
27264
|
+
const first = firstReadOf(key, deps.home);
|
|
27265
|
+
if (first === null || Date.parse(first.resetsAt) !== Date.parse(week.resetsAt)) {
|
|
27266
|
+
const thisRead = { usedPercent: week.usedPercentage, resetsAt: week.resetsAt, at: week.savedAt };
|
|
27267
|
+
writeAccount(nodePath4.join(pacingDir(deps.home), PLAN_FIRST_READ_FILENAME), key, thisRead);
|
|
27268
|
+
return null;
|
|
27269
|
+
}
|
|
27270
|
+
if (deps.configFolder === "codex-home")
|
|
27271
|
+
return null;
|
|
27272
|
+
const gain = week.usedPercentage - first.usedPercent;
|
|
27273
|
+
if (gain < PLAN_MIN_GAIN_POINTS)
|
|
27274
|
+
return null;
|
|
27275
|
+
if (readLearnedAccount(key, { home: deps.home }) === null)
|
|
27276
|
+
return null;
|
|
27277
|
+
const scanned = scanUnderLock(key, { ...deps.home === void 0 ? {} : { home: deps.home }, now: () => new Date(nowMs) }, 0);
|
|
27278
|
+
if (scanned === null)
|
|
27279
|
+
return null;
|
|
27280
|
+
const fromSec = Math.floor(Date.parse(first.at) / 1e3);
|
|
27281
|
+
const toSec = Math.floor(Date.parse(week.savedAt) / 1e3);
|
|
27282
|
+
if (!(toSec > fromSec) || scanned.coveredFrom > fromSec)
|
|
27283
|
+
return null;
|
|
27284
|
+
const tokens = tokensBetween(scanned.minutes, fromSec, toSec);
|
|
27285
|
+
if (!(tokens > 0))
|
|
27286
|
+
return null;
|
|
27287
|
+
const ceiling = Math.round(tokens * 100 / gain);
|
|
27288
|
+
return ceiling > 0 ? ceiling : null;
|
|
27289
|
+
}
|
|
27290
|
+
async function planUsageReport(input, deps = {}) {
|
|
27291
|
+
try {
|
|
27292
|
+
const code = process.exitCode;
|
|
27293
|
+
if (code !== void 0 && code !== null && Number(code) !== 0)
|
|
27294
|
+
return;
|
|
27295
|
+
const env = deps.env ?? process.env;
|
|
27296
|
+
const configured = readConfig(env);
|
|
27297
|
+
if (configured.config === null)
|
|
27298
|
+
return;
|
|
27299
|
+
const { guardEngagementId: engagementId, guardServiceToken: token } = configured.config;
|
|
27300
|
+
const dir = enginePacingDir(engagementId, deps.home);
|
|
27301
|
+
if (dir === null)
|
|
27302
|
+
return;
|
|
27303
|
+
const nowMs = (deps.now ?? Date.now)();
|
|
27304
|
+
const said = typeof input === "object" && input !== null ? input["transcript_path"] : void 0;
|
|
27305
|
+
const key = configFolderKey({
|
|
27306
|
+
env,
|
|
27307
|
+
transcriptPath: typeof said === "string" && said !== "" ? said : null,
|
|
27308
|
+
home: deps.home,
|
|
27309
|
+
rule: deps.configFolder
|
|
27310
|
+
});
|
|
27311
|
+
const throttlePath = nodePath4.join(dir, PLAN_REPORT_THROTTLE_FILENAME);
|
|
27312
|
+
const last = readAccounts(throttlePath)[key];
|
|
27313
|
+
if (isNum2(last) && nowMs >= last && nowMs - last < PLAN_REPORT_MIN_INTERVAL_MS)
|
|
27314
|
+
return;
|
|
27315
|
+
writeAccount(throttlePath, key, nowMs);
|
|
27316
|
+
const now = new Date(nowMs);
|
|
27317
|
+
if (deps.configFolder === "codex-home")
|
|
27318
|
+
refreshCodexWindows(key, { home: deps.home, now: () => now });
|
|
27319
|
+
const reported = readReportedAccount(key, { home: deps.home });
|
|
27320
|
+
const five = reported["five-hour"];
|
|
27321
|
+
const week = reported["seven-day"];
|
|
27322
|
+
const freshWeek = reportedFresh(week, now) ? week : void 0;
|
|
27323
|
+
let ceiling = null;
|
|
27324
|
+
if (freshWeek !== void 0) {
|
|
27325
|
+
const learned = readLearnedAccount(key, { home: deps.home })?.ceilings["seven-day"];
|
|
27326
|
+
ceiling = weeklyCeilingOf(key, { home: deps.home });
|
|
27327
|
+
let derived = null;
|
|
27328
|
+
if (learned === void 0) {
|
|
27329
|
+
try {
|
|
27330
|
+
derived = derivedBetweenReads(key, freshWeek, deps, nowMs);
|
|
27331
|
+
} catch {
|
|
27332
|
+
derived = null;
|
|
27333
|
+
}
|
|
27334
|
+
}
|
|
27335
|
+
if (derived !== null) {
|
|
27336
|
+
try {
|
|
27337
|
+
writeAccount(nodePath4.join(pacingDir(deps.home), PLAN_DERIVED_FILENAME), key, { tokens: derived, resetsAt: freshWeek.resetsAt });
|
|
27338
|
+
} catch {
|
|
27339
|
+
}
|
|
27340
|
+
ceiling = derived;
|
|
27341
|
+
}
|
|
27342
|
+
}
|
|
27343
|
+
const report = {
|
|
27344
|
+
fiveHour: reportedFresh(five, now) ? { usedPercent: five.usedPercentage, resetsAt: five.resetsAt } : null,
|
|
27345
|
+
week: freshWeek === void 0 ? null : { usedPercent: freshWeek.usedPercentage, resetsAt: freshWeek.resetsAt, ceilingTokens: ceiling },
|
|
27346
|
+
readAt: now.toISOString()
|
|
27347
|
+
};
|
|
27348
|
+
if (!planUsageReportSchema.safeParse(report).success)
|
|
27349
|
+
return;
|
|
27350
|
+
await requestJson(deps.fetchFn ?? globalThis.fetch, `${readControlOrigin(env).origin}/engagements/${encodeURIComponent(engagementId)}/plan-usage`, {
|
|
27351
|
+
method: "PUT",
|
|
27352
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
27353
|
+
body: JSON.stringify(report)
|
|
27354
|
+
}, OBSERVE_REQUEST_DEADLINE_MS);
|
|
27355
|
+
} catch {
|
|
27356
|
+
}
|
|
27357
|
+
}
|
|
27358
|
+
|
|
27359
|
+
// dist/pace-verb.js
|
|
26879
27360
|
var PACE_WINDOW_MINUTES = 300;
|
|
26880
27361
|
var PACE_BASIS_DEADLINE_MS = 5e3;
|
|
26881
27362
|
var PACE_FIRST_READ_WAIT_MS = 10 * 60 * 1e3;
|
|
26882
27363
|
var PACE_LATER_READ_WAIT_MS = 5e3;
|
|
26883
27364
|
var BUILD_NUMBER_FILENAME = "build.json";
|
|
26884
|
-
function taskMinutesOf(task, medianTaskMinutes) {
|
|
26885
|
-
if (task.human)
|
|
26886
|
-
return 0;
|
|
26887
|
-
if (task.budgetMinutes !== void 0)
|
|
26888
|
-
return task.budgetMinutes;
|
|
26889
|
-
if (medianTaskMinutes !== null && medianTaskMinutes > 0)
|
|
26890
|
-
return medianTaskMinutes;
|
|
26891
|
-
return PACE_DEFAULT_TASK_MINUTES;
|
|
26892
|
-
}
|
|
26893
27365
|
function layoutGraph(tasks, agents, medianTaskMinutes) {
|
|
26894
27366
|
const index = /* @__PURE__ */ new Map();
|
|
26895
27367
|
tasks.forEach((t2, i) => {
|
|
@@ -26973,7 +27445,7 @@ function suggestedNumberOf(input) {
|
|
|
26973
27445
|
function suggestPace(input) {
|
|
26974
27446
|
const tasks = input.tasks !== null && input.tasks.length > 0 ? input.tasks : null;
|
|
26975
27447
|
const number4 = input.named !== null ? clampAgents(input.named, PACE_AGENTS_MAX) : suggestedNumberOf(input);
|
|
26976
|
-
const minutes = tasks === null ? null :
|
|
27448
|
+
const minutes = tasks === null ? null : paceDurationRoundedOf(layoutGraph(tasks, number4, input.medianTaskMinutes).minutes);
|
|
26977
27449
|
let pauses = 0;
|
|
26978
27450
|
const ceiling = input.learned?.ceilings["five-hour"];
|
|
26979
27451
|
if (tasks !== null && ceiling !== void 0 && input.medianTaskTokens !== null) {
|
|
@@ -26989,20 +27461,32 @@ function suggestPace(input) {
|
|
|
26989
27461
|
minutes,
|
|
26990
27462
|
pauses,
|
|
26991
27463
|
keepFreePercent: input.keepFreePercent,
|
|
26992
|
-
knownWindow
|
|
27464
|
+
knownWindow,
|
|
27465
|
+
workMinutes: agentWorkMinutesOf(tasks, input.medianTaskMinutes)
|
|
26993
27466
|
};
|
|
26994
27467
|
}
|
|
27468
|
+
function weekCeilingFor(key, home) {
|
|
27469
|
+
try {
|
|
27470
|
+
const tokens = weeklyCeilingOf(key, home === void 0 ? {} : { home });
|
|
27471
|
+
if (tokens === null || !Number.isFinite(tokens))
|
|
27472
|
+
return null;
|
|
27473
|
+
const whole = Math.round(tokens);
|
|
27474
|
+
return whole > 0 ? whole : null;
|
|
27475
|
+
} catch {
|
|
27476
|
+
return null;
|
|
27477
|
+
}
|
|
27478
|
+
}
|
|
26995
27479
|
function enginePacingDir(engagementId, home) {
|
|
26996
27480
|
if (!isEngagementId(engagementId))
|
|
26997
27481
|
return null;
|
|
26998
|
-
return
|
|
27482
|
+
return nodePath5.join(home ?? homedir9(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
26999
27483
|
}
|
|
27000
27484
|
function readBuildNumber(engagementId, home) {
|
|
27001
27485
|
const dir = enginePacingDir(engagementId, home);
|
|
27002
27486
|
if (dir === null)
|
|
27003
27487
|
return null;
|
|
27004
27488
|
try {
|
|
27005
|
-
const v = JSON.parse(
|
|
27489
|
+
const v = JSON.parse(readFileSync20(nodePath5.join(dir, BUILD_NUMBER_FILENAME), "utf-8"));
|
|
27006
27490
|
const n = v["number"];
|
|
27007
27491
|
if (typeof v["phase"] === "string" && typeof n === "number" && Number.isInteger(n) && n >= 1 && n <= PACE_AGENTS_MAX && typeof v["namedByOwner"] === "boolean") {
|
|
27008
27492
|
return { phase: v["phase"], number: n, namedByOwner: v["namedByOwner"] };
|
|
@@ -27019,11 +27503,11 @@ function writeBuildNumber(engagementId, value, home) {
|
|
|
27019
27503
|
const dir = enginePacingDir(engagementId, home);
|
|
27020
27504
|
if (dir === null)
|
|
27021
27505
|
throw new Error("not an engagement id");
|
|
27022
|
-
|
|
27023
|
-
const path =
|
|
27506
|
+
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
27507
|
+
const path = nodePath5.join(dir, BUILD_NUMBER_FILENAME);
|
|
27024
27508
|
const tmp = `${path}.${String(process.pid)}.tmp`;
|
|
27025
|
-
|
|
27026
|
-
|
|
27509
|
+
writeFileSync12(tmp, JSON.stringify(value), { mode: 384 });
|
|
27510
|
+
renameSync10(tmp, path);
|
|
27027
27511
|
}
|
|
27028
27512
|
function liveSubAgentsIn(cwd, deps = {}) {
|
|
27029
27513
|
try {
|
|
@@ -27039,7 +27523,7 @@ function liveSubAgentsIn(cwd, deps = {}) {
|
|
|
27039
27523
|
if (p === null || p.key !== key || p.agentId === null)
|
|
27040
27524
|
continue;
|
|
27041
27525
|
try {
|
|
27042
|
-
if (now - statSync6(
|
|
27526
|
+
if (now - statSync6(nodePath5.join(dir, name)).mtimeMs <= LIVE_WINDOW_MS)
|
|
27043
27527
|
n += 1;
|
|
27044
27528
|
} catch {
|
|
27045
27529
|
}
|
|
@@ -27190,6 +27674,8 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
27190
27674
|
refreshCodexWindows(key, scanDeps);
|
|
27191
27675
|
const learned = codex ? null : readThisAccount(key, scanDeps, stderr);
|
|
27192
27676
|
const reported = readReportedAccount(key, scanDeps);
|
|
27677
|
+
const weekCeilingTokens = weekCeilingFor(key, deps.home);
|
|
27678
|
+
const ceiling = weekCeilingTokens === null ? {} : { weekCeilingTokens };
|
|
27193
27679
|
let number4;
|
|
27194
27680
|
let suggestion;
|
|
27195
27681
|
let limitFile = null;
|
|
@@ -27212,7 +27698,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
27212
27698
|
return { stdout: null, stderr: [...stderr, PACE_ONLY_PERSON_RAISES], code: 2 };
|
|
27213
27699
|
}
|
|
27214
27700
|
const named = parsed.agents ?? kept;
|
|
27215
|
-
suggestion = named === null ? suggested : suggestFor(named);
|
|
27701
|
+
suggestion = { ...named === null ? suggested : suggestFor(named), ...ceiling };
|
|
27216
27702
|
number4 = suggestion.number;
|
|
27217
27703
|
writeBuildNumber(engagementId, { phase: parsed.phase, number: number4, namedByOwner: named !== null }, deps.home);
|
|
27218
27704
|
const limitBasis = basis === null ? null : { tasks: sameGraph ? basis.tasks : [], medianTaskTokens: basis.medianTaskTokens };
|
|
@@ -27266,14 +27752,15 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
27266
27752
|
...decision.until !== null ? { until: decision.until.toISOString() } : {},
|
|
27267
27753
|
keepFreePercent,
|
|
27268
27754
|
...suggestion !== void 0 ? { suggestion } : {},
|
|
27269
|
-
...limitFile !== null ? { usage: { used: readPhaseUsage(pacingDir2, limitFile.phase), limit: limitFile.limit } } : {},
|
|
27755
|
+
...limitFile !== null ? { usage: { used: readPhaseUsage(pacingDir2, limitFile.phase), limit: limitFile.limit, ...ceiling } } : {},
|
|
27270
27756
|
...atLimit ? {
|
|
27271
27757
|
limit: "reached",
|
|
27272
27758
|
limitHeld: {
|
|
27273
27759
|
used: readPhaseUsage(pacingDir2, limitFile.phase),
|
|
27274
27760
|
limit: limitFile.limit,
|
|
27275
27761
|
raiseBy: estimateOf(limitFile),
|
|
27276
|
-
working: live
|
|
27762
|
+
working: live,
|
|
27763
|
+
...ceiling
|
|
27277
27764
|
}
|
|
27278
27765
|
} : {}
|
|
27279
27766
|
};
|
|
@@ -27298,17 +27785,17 @@ function objectOf2(v) {
|
|
|
27298
27785
|
}
|
|
27299
27786
|
function readJson(path) {
|
|
27300
27787
|
try {
|
|
27301
|
-
return objectOf2(JSON.parse(
|
|
27788
|
+
return objectOf2(JSON.parse(readFileSync21(path, "utf-8")));
|
|
27302
27789
|
} catch {
|
|
27303
27790
|
return null;
|
|
27304
27791
|
}
|
|
27305
27792
|
}
|
|
27306
27793
|
function writeJsonWhole2(path, value) {
|
|
27307
|
-
|
|
27794
|
+
mkdirSync9(nodePath6.dirname(path), { recursive: true, mode: 448 });
|
|
27308
27795
|
const tmp = `${path}.${String(process.pid)}.${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
27309
27796
|
try {
|
|
27310
|
-
|
|
27311
|
-
|
|
27797
|
+
writeFileSync13(tmp, JSON.stringify(value), { mode: 384 });
|
|
27798
|
+
renameSync11(tmp, path);
|
|
27312
27799
|
} catch (err) {
|
|
27313
27800
|
try {
|
|
27314
27801
|
unlinkSync8(tmp);
|
|
@@ -27421,7 +27908,7 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
27421
27908
|
return;
|
|
27422
27909
|
}
|
|
27423
27910
|
const working = liveCount(readLiveness(field2(input, "session_id"), field2(input, "cwd") ?? process.cwd(), deps.liveness));
|
|
27424
|
-
const limitText = limitAtTurnEnd(dir, basis.phase, read !== null && read.phase === basis.phase ? { tasks: read.tasks, medianTaskTokens: read.medianTaskTokens } : null, working);
|
|
27911
|
+
const limitText = limitAtTurnEnd(dir, basis.phase, read !== null && read.phase === basis.phase ? { tasks: read.tasks, medianTaskTokens: read.medianTaskTokens } : null, working, key, deps.home);
|
|
27425
27912
|
let learned = null;
|
|
27426
27913
|
if (deps.configFolder === "codex-home") {
|
|
27427
27914
|
refreshCodexWindows(key, { home: deps.home, now: () => now });
|
|
@@ -27471,13 +27958,13 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
27471
27958
|
} catch {
|
|
27472
27959
|
}
|
|
27473
27960
|
}
|
|
27474
|
-
function limitAtTurnEnd(dir, phase, basis, working) {
|
|
27961
|
+
function limitAtTurnEnd(dir, phase, basis, working, key, home) {
|
|
27475
27962
|
try {
|
|
27476
27963
|
const tokens = readPhaseUsage(dir, phase);
|
|
27477
27964
|
const file2 = limitInForce(dir, phase, basis, tokens);
|
|
27478
27965
|
if (file2 === null)
|
|
27479
27966
|
return null;
|
|
27480
|
-
const step = turnEndLimitLine(file2, tokens, working);
|
|
27967
|
+
const step = turnEndLimitLine(file2, tokens, working, weekCeilingFor(key, home));
|
|
27481
27968
|
if (step.text === null)
|
|
27482
27969
|
return null;
|
|
27483
27970
|
writePhaseLimit(dir, step.file);
|
|
@@ -27488,7 +27975,7 @@ function limitAtTurnEnd(dir, phase, basis, working) {
|
|
|
27488
27975
|
}
|
|
27489
27976
|
function readStarts(dir) {
|
|
27490
27977
|
const out = {};
|
|
27491
|
-
for (const [key, sessions] of Object.entries(objectOf2(readJson(
|
|
27978
|
+
for (const [key, sessions] of Object.entries(objectOf2(readJson(nodePath6.join(dir, PACE_STARTS_FILENAME))?.["accounts"]) ?? {})) {
|
|
27492
27979
|
const s = {};
|
|
27493
27980
|
for (const [session, list] of Object.entries(objectOf2(sessions) ?? {})) {
|
|
27494
27981
|
if (Array.isArray(list))
|
|
@@ -27516,7 +28003,7 @@ function sleepSync3(ms) {
|
|
|
27516
28003
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
27517
28004
|
}
|
|
27518
28005
|
function underStartsLock(dir, giveUpMs, fn) {
|
|
27519
|
-
const lock =
|
|
28006
|
+
const lock = nodePath6.join(dir, PACE_STARTS_LOCK_FILENAME);
|
|
27520
28007
|
const giveUpAt = Date.now() + giveUpMs;
|
|
27521
28008
|
while (!tryTakeLockFile(lock, PACE_STARTS_LOCK_STALE_MS)) {
|
|
27522
28009
|
if (Date.now() >= giveUpAt)
|
|
@@ -27554,7 +28041,7 @@ function retirePendingStart(input, deps = {}) {
|
|
|
27554
28041
|
if (list === void 0 || list.length === 0)
|
|
27555
28042
|
return false;
|
|
27556
28043
|
list.shift();
|
|
27557
|
-
writeJsonWhole2(
|
|
28044
|
+
writeJsonWhole2(nodePath6.join(where.dir, PACE_STARTS_FILENAME), { accounts: pruneStarts(file2, nowMs) });
|
|
27558
28045
|
return true;
|
|
27559
28046
|
}) ?? false;
|
|
27560
28047
|
} catch {
|
|
@@ -27573,7 +28060,7 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
27573
28060
|
const beside = () => runsBesideOtherWork(toolInput, withoutAgent(record2, field2(input, "agent_id")));
|
|
27574
28061
|
const atLimit = openPhaseLimit(where.dir, stateFile.basis);
|
|
27575
28062
|
if (atLimit !== null && atLimit.awaiting && beside())
|
|
27576
|
-
return limitHeldStartTextOf(atLimit.limit);
|
|
28063
|
+
return limitHeldStartTextOf(atLimit.limit, weekCeilingFor(where.key, deps.home));
|
|
27577
28064
|
const entry = stateFile.accounts[where.key];
|
|
27578
28065
|
if (entry === void 0)
|
|
27579
28066
|
return null;
|
|
@@ -27606,7 +28093,7 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
27606
28093
|
if (live + list.length >= allowance)
|
|
27607
28094
|
return true;
|
|
27608
28095
|
const sessions = { ...file2[where.key] ?? {}, [session]: [...list, nowMs] };
|
|
27609
|
-
writeJsonWhole2(
|
|
28096
|
+
writeJsonWhole2(nodePath6.join(where.dir, PACE_STARTS_FILENAME), { accounts: { ...file2, [where.key]: sessions } });
|
|
27610
28097
|
return false;
|
|
27611
28098
|
});
|
|
27612
28099
|
return pending === true ? held() : null;
|
|
@@ -27617,12 +28104,12 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
27617
28104
|
|
|
27618
28105
|
// dist/risky/account-names.js
|
|
27619
28106
|
import { randomBytes } from "node:crypto";
|
|
27620
|
-
import { mkdirSync as
|
|
28107
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync23, renameSync as renameSync12, rmSync as rmSync3, statSync as statSync8, writeFileSync as writeFileSync14 } from "node:fs";
|
|
27621
28108
|
import { homedir as homedir11 } from "node:os";
|
|
27622
28109
|
import { isAbsolute as isAbsolute5, join as join16, posix as posix2, resolve as resolve7, sep as sep6 } from "node:path";
|
|
27623
28110
|
|
|
27624
28111
|
// dist/risky/facts.js
|
|
27625
|
-
import { existsSync as existsSync8, lstatSync as lstatSync3, readdirSync as readdirSync9, readFileSync as
|
|
28112
|
+
import { existsSync as existsSync8, lstatSync as lstatSync3, readdirSync as readdirSync9, readFileSync as readFileSync22, realpathSync as realpathSync7, statSync as statSync7 } from "node:fs";
|
|
27626
28113
|
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
27627
28114
|
import { basename as pathBasename, dirname as dirname6, isAbsolute as isAbsolute4, join as join15, relative as relative7, resolve as resolve6, sep as sep5 } from "node:path";
|
|
27628
28115
|
|
|
@@ -29860,7 +30347,7 @@ var Env = class {
|
|
|
29860
30347
|
return this.description;
|
|
29861
30348
|
this.description = null;
|
|
29862
30349
|
try {
|
|
29863
|
-
const raw = JSON.parse(
|
|
30350
|
+
const raw = JSON.parse(readFileSync22(join15(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
29864
30351
|
const checked = checkSystemDescription(raw);
|
|
29865
30352
|
if (checked.ok)
|
|
29866
30353
|
this.description = checked.description;
|
|
@@ -31046,7 +31533,7 @@ function publishFacts(m, env) {
|
|
|
31046
31533
|
const start = startFolder(m, env);
|
|
31047
31534
|
if (start !== null && PACKAGE_JSON_PROGRAMS.has(m.program)) {
|
|
31048
31535
|
try {
|
|
31049
|
-
const pkg = JSON.parse(
|
|
31536
|
+
const pkg = JSON.parse(readFileSync22(join15(start, "package.json"), "utf-8"));
|
|
31050
31537
|
if (typeof pkg["name"] === "string" && typeof pkg["version"] === "string" && pkg["name"] !== "" && pkg["version"] !== "") {
|
|
31051
31538
|
name = pkg["name"];
|
|
31052
31539
|
version2 = pkg["version"];
|
|
@@ -31096,7 +31583,7 @@ function shrinkRecordFacts(m, env) {
|
|
|
31096
31583
|
try {
|
|
31097
31584
|
if (!lstatSync3(file2.abs).isFile())
|
|
31098
31585
|
continue;
|
|
31099
|
-
before =
|
|
31586
|
+
before = readFileSync22(file2.abs, "utf-8");
|
|
31100
31587
|
} catch {
|
|
31101
31588
|
continue;
|
|
31102
31589
|
}
|
|
@@ -31331,7 +31818,7 @@ function canonical(stored) {
|
|
|
31331
31818
|
function readSource(path, parse3) {
|
|
31332
31819
|
let text;
|
|
31333
31820
|
try {
|
|
31334
|
-
text =
|
|
31821
|
+
text = readFileSync23(path, "utf-8");
|
|
31335
31822
|
} catch (e) {
|
|
31336
31823
|
const code = e.code;
|
|
31337
31824
|
return { names: [], broken: code !== "ENOENT" && code !== "ENOTDIR" };
|
|
@@ -31360,7 +31847,7 @@ function namesFromList(p) {
|
|
|
31360
31847
|
}
|
|
31361
31848
|
let lines2;
|
|
31362
31849
|
try {
|
|
31363
|
-
lines2 =
|
|
31850
|
+
lines2 = readFileSync23(p.list, "utf-8").split("\n");
|
|
31364
31851
|
} catch {
|
|
31365
31852
|
return null;
|
|
31366
31853
|
}
|
|
@@ -31376,10 +31863,10 @@ function writeList(p, names) {
|
|
|
31376
31863
|
const lines2 = [p.firstLine, ...comparable.length === names.length ? [] : [ACCOUNT_NAMES_ANY], ...comparable];
|
|
31377
31864
|
const temp = `${p.list}.${String(process.pid)}.${randomBytes(4).toString("hex")}`;
|
|
31378
31865
|
try {
|
|
31379
|
-
|
|
31380
|
-
|
|
31866
|
+
mkdirSync10(join16(p.home, HALFCYCLE_DIR_NAME), { recursive: true, mode: 448 });
|
|
31867
|
+
writeFileSync14(temp, `${lines2.join("\n")}
|
|
31381
31868
|
`, { mode: 384, flag: "wx" });
|
|
31382
|
-
|
|
31869
|
+
renameSync12(temp, p.list);
|
|
31383
31870
|
} catch {
|
|
31384
31871
|
try {
|
|
31385
31872
|
rmSync3(temp, { force: true });
|
|
@@ -31438,7 +31925,7 @@ function sumOf(texts, name) {
|
|
|
31438
31925
|
}
|
|
31439
31926
|
function textOf(path) {
|
|
31440
31927
|
try {
|
|
31441
|
-
return
|
|
31928
|
+
return readFileSync23(path, "utf-8");
|
|
31442
31929
|
} catch {
|
|
31443
31930
|
return "";
|
|
31444
31931
|
}
|
|
@@ -32061,7 +32548,7 @@ function isOneCall(call) {
|
|
|
32061
32548
|
|
|
32062
32549
|
// dist/risky/allow-once.js
|
|
32063
32550
|
import { createHash as createHash5 } from "node:crypto";
|
|
32064
|
-
import { appendFileSync as appendFileSync5, readFileSync as
|
|
32551
|
+
import { appendFileSync as appendFileSync5, readFileSync as readFileSync24, realpathSync as realpathSync8, renameSync as renameSync13, statSync as statSync9, unlinkSync as unlinkSync9, writeFileSync as writeFileSync15 } from "node:fs";
|
|
32065
32552
|
import { isAbsolute as isAbsolute6, relative as relative8, resolve as resolve8, sep as sep7 } from "node:path";
|
|
32066
32553
|
var ALLOW_ONCE_MS = 5 * 60 * 1e3;
|
|
32067
32554
|
var HELD_STEP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
@@ -32222,7 +32709,7 @@ function numberKept(path, key) {
|
|
|
32222
32709
|
function readNumbers(path) {
|
|
32223
32710
|
let text;
|
|
32224
32711
|
try {
|
|
32225
|
-
text =
|
|
32712
|
+
text = readFileSync24(path, "utf8");
|
|
32226
32713
|
} catch (err) {
|
|
32227
32714
|
return err.code === "ENOENT" ? { next: 1, steps: /* @__PURE__ */ new Map() } : null;
|
|
32228
32715
|
}
|
|
@@ -32334,13 +32821,13 @@ function distinctSteps(held, numbersPath) {
|
|
|
32334
32821
|
function claimHeld(path, session, now) {
|
|
32335
32822
|
const claimed = `${path}.${process.pid}.${now}.claim`;
|
|
32336
32823
|
try {
|
|
32337
|
-
|
|
32824
|
+
renameSync13(path, claimed);
|
|
32338
32825
|
} catch {
|
|
32339
32826
|
return [];
|
|
32340
32827
|
}
|
|
32341
32828
|
let text = "";
|
|
32342
32829
|
try {
|
|
32343
|
-
text =
|
|
32830
|
+
text = readFileSync24(claimed, "utf8");
|
|
32344
32831
|
} catch {
|
|
32345
32832
|
text = "";
|
|
32346
32833
|
}
|
|
@@ -32395,7 +32882,7 @@ function nowOf(deps) {
|
|
|
32395
32882
|
}
|
|
32396
32883
|
function readRecord2(path, session) {
|
|
32397
32884
|
try {
|
|
32398
|
-
return parseRecord(
|
|
32885
|
+
return parseRecord(readFileSync24(path, "utf8"), session);
|
|
32399
32886
|
} catch {
|
|
32400
32887
|
return null;
|
|
32401
32888
|
}
|
|
@@ -32433,8 +32920,8 @@ function writeRecord(path, record2) {
|
|
|
32433
32920
|
function writeWhole2(path, body) {
|
|
32434
32921
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
32435
32922
|
try {
|
|
32436
|
-
|
|
32437
|
-
|
|
32923
|
+
writeFileSync15(tmp, body, { mode: 384 });
|
|
32924
|
+
renameSync13(tmp, path);
|
|
32438
32925
|
return true;
|
|
32439
32926
|
} catch {
|
|
32440
32927
|
removeQuietly(tmp);
|
|
@@ -32534,7 +33021,7 @@ function decideAutonomous(facts, mayPublishNow) {
|
|
|
32534
33021
|
}
|
|
32535
33022
|
|
|
32536
33023
|
// dist/risky/own-copy.js
|
|
32537
|
-
import { readFileSync as
|
|
33024
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
32538
33025
|
import { join as join17, posix as posix3, win32 as win322 } from "node:path";
|
|
32539
33026
|
var OWN_COPY_START_TOOL = "Agent";
|
|
32540
33027
|
var OWN_COPY_WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
@@ -32556,7 +33043,7 @@ function stringField2(o, key) {
|
|
|
32556
33043
|
}
|
|
32557
33044
|
function readOr(deps, path) {
|
|
32558
33045
|
try {
|
|
32559
|
-
return (deps.readFile ?? ((p) =>
|
|
33046
|
+
return (deps.readFile ?? ((p) => readFileSync25(p, "utf-8")))(path);
|
|
32560
33047
|
} catch {
|
|
32561
33048
|
return null;
|
|
32562
33049
|
}
|
|
@@ -32702,7 +33189,7 @@ function judgeChange(input, call, deps) {
|
|
|
32702
33189
|
|
|
32703
33190
|
// dist/risky/save.js
|
|
32704
33191
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
32705
|
-
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as
|
|
33192
|
+
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as mkdirSync11, readdirSync as readdirSync10, readFileSync as readFileSync26, readlinkSync, realpathSync as realpathSync9, renameSync as renameSync14, rmSync as rmSync4, statSync as statSync10, symlinkSync, writeFileSync as writeFileSync16 } from "node:fs";
|
|
32706
33193
|
import { homedir as homedir12 } from "node:os";
|
|
32707
33194
|
import { dirname as dirname7, isAbsolute as isAbsolute7, join as join18, resolve as resolve9 } from "node:path";
|
|
32708
33195
|
var SAVE_LIMIT_BYTES = 2e8;
|
|
@@ -32748,7 +33235,7 @@ function saveFirst(staked, ctx) {
|
|
|
32748
33235
|
const repository = repositoryOf(g);
|
|
32749
33236
|
if (repository === null)
|
|
32750
33237
|
return failed(saveDir);
|
|
32751
|
-
|
|
33238
|
+
writeFileSync16(join18(saveDir, SAVED_REPOSITORY_FILE_NAME), `${repository}
|
|
32752
33239
|
`, { mode: 384 });
|
|
32753
33240
|
const privateIndex = join18(saveDir, PRIVATE_INDEX_NAME);
|
|
32754
33241
|
const commit = saveCommit(id, headCommit2, found2.tracked, plan.lines, privateIndex, g, now());
|
|
@@ -32774,9 +33261,9 @@ function saveFirst(staked, ctx) {
|
|
|
32774
33261
|
if (!description.success)
|
|
32775
33262
|
return failed(saveDir);
|
|
32776
33263
|
const file2 = join18(saveDir, SAVED_FILE_NAME);
|
|
32777
|
-
|
|
33264
|
+
writeFileSync16(`${file2}.part`, `${JSON.stringify(description.data, null, 2)}
|
|
32778
33265
|
`, { mode: 384 });
|
|
32779
|
-
|
|
33266
|
+
renameSync14(`${file2}.part`, file2);
|
|
32780
33267
|
ctx.beforeRef?.();
|
|
32781
33268
|
const ref = g.run(["update-ref", "--no-deref", savedRefOf(id), commit, ""]);
|
|
32782
33269
|
if (!ref.ok)
|
|
@@ -32896,7 +33383,7 @@ function copyOne(src, dst) {
|
|
|
32896
33383
|
const st = lstatOrNull(src);
|
|
32897
33384
|
if (st === null)
|
|
32898
33385
|
return false;
|
|
32899
|
-
|
|
33386
|
+
mkdirSync11(dirname7(dst), { recursive: true, mode: 448 });
|
|
32900
33387
|
if (st.isSymbolicLink()) {
|
|
32901
33388
|
symlinkSync(readlinkSync(src), dst);
|
|
32902
33389
|
return true;
|
|
@@ -32972,13 +33459,13 @@ var SaveGit = class {
|
|
|
32972
33459
|
}
|
|
32973
33460
|
};
|
|
32974
33461
|
function freshId(folder2, newId) {
|
|
32975
|
-
|
|
33462
|
+
mkdirSync11(folder2, { recursive: true, mode: 448 });
|
|
32976
33463
|
for (let i = 0; i < 5; i++) {
|
|
32977
33464
|
const id = newId?.() ?? defaultId();
|
|
32978
33465
|
if (!savedIdSchema.safeParse(id).success)
|
|
32979
33466
|
return null;
|
|
32980
33467
|
try {
|
|
32981
|
-
|
|
33468
|
+
mkdirSync11(join18(folder2, id), { mode: 448 });
|
|
32982
33469
|
return id;
|
|
32983
33470
|
} catch (e) {
|
|
32984
33471
|
if (e.code !== "EEXIST")
|
|
@@ -33003,7 +33490,7 @@ function repositoryOf(g) {
|
|
|
33003
33490
|
}
|
|
33004
33491
|
function markedRepository(dir) {
|
|
33005
33492
|
try {
|
|
33006
|
-
const text =
|
|
33493
|
+
const text = readFileSync26(join18(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
|
|
33007
33494
|
return text === "" ? null : text;
|
|
33008
33495
|
} catch {
|
|
33009
33496
|
return null;
|
|
@@ -33076,7 +33563,7 @@ function realOrSelf3(p) {
|
|
|
33076
33563
|
|
|
33077
33564
|
// dist/autonomy-state.js
|
|
33078
33565
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
33079
|
-
import { chmodSync as chmodSync3, mkdirSync as
|
|
33566
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync27, renameSync as renameSync15, rmSync as rmSync5, writeFileSync as writeFileSync17 } from "node:fs";
|
|
33080
33567
|
import { homedir as homedir13, platform as platform2 } from "node:os";
|
|
33081
33568
|
import { dirname as dirname8, join as join19 } from "node:path";
|
|
33082
33569
|
var AUTONOMY_STATE_FILENAME = "autonomy.json";
|
|
@@ -33088,7 +33575,7 @@ function readCachedAutonomy(engagementId, nowMs, home) {
|
|
|
33088
33575
|
if (!isEngagementId(engagementId))
|
|
33089
33576
|
return null;
|
|
33090
33577
|
try {
|
|
33091
|
-
const parsed = autonomyStateFileSchema.safeParse(JSON.parse(
|
|
33578
|
+
const parsed = autonomyStateFileSchema.safeParse(JSON.parse(readFileSync27(autonomyStateFilePath(engagementId, home), "utf-8")));
|
|
33092
33579
|
if (!parsed.success || !parsed.data.on)
|
|
33093
33580
|
return null;
|
|
33094
33581
|
const age = nowMs - Date.parse(parsed.data.readAt);
|
|
@@ -33137,12 +33624,12 @@ function writeAutonomyStateFile(engagementId, file2, home) {
|
|
|
33137
33624
|
const target = autonomyStateFilePath(engagementId, home);
|
|
33138
33625
|
const temp = join19(dirname8(target), `.${AUTONOMY_STATE_FILENAME}.${process.pid}.tmp`);
|
|
33139
33626
|
try {
|
|
33140
|
-
|
|
33141
|
-
|
|
33627
|
+
mkdirSync12(dirname8(target), { recursive: true, mode: 448 });
|
|
33628
|
+
writeFileSync17(temp, `${JSON.stringify(file2)}
|
|
33142
33629
|
`, { mode: 384 });
|
|
33143
33630
|
if (platform2() !== "win32")
|
|
33144
33631
|
chmodSync3(temp, 384);
|
|
33145
|
-
|
|
33632
|
+
renameSync15(temp, target);
|
|
33146
33633
|
return true;
|
|
33147
33634
|
} catch {
|
|
33148
33635
|
try {
|
|
@@ -33618,7 +34105,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
33618
34105
|
const changeSet = buildChangeSet(fileDiffEntries, { ...context, excerpts: readExcerptConfig() });
|
|
33619
34106
|
const configResult = readConfig();
|
|
33620
34107
|
if (!configResult.config) {
|
|
33621
|
-
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet, diffBase });
|
|
34108
|
+
await emitRunRecord({ runType: "hook", outcome: "unconfigured", changeSet, diffBase, repoFacts: context.repoFacts });
|
|
33622
34109
|
if (!firstNoticeThisSession("credential-missing", repoRoot, sessionId))
|
|
33623
34110
|
return;
|
|
33624
34111
|
emitNeverConfigured(UNCONFIGURED_EXIT_STOP_FAMILY, readNeverConfiguredReason(), pinnedEngagementId(projectFolder()), reply);
|
|
@@ -33642,6 +34129,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
33642
34129
|
outcome: outcomeForClientFailure(clientResult.kind),
|
|
33643
34130
|
failureReason: failure.reason,
|
|
33644
34131
|
changeSet,
|
|
34132
|
+
repoFacts: context.repoFacts,
|
|
33645
34133
|
diffBase,
|
|
33646
34134
|
credential: evaluation.token,
|
|
33647
34135
|
credentialRefused: failure.kind === "credential"
|
|
@@ -33675,6 +34163,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
33675
34163
|
phase: telemetryConfig.phase,
|
|
33676
34164
|
outcome: "evaluated",
|
|
33677
34165
|
changeSet,
|
|
34166
|
+
repoFacts: context.repoFacts,
|
|
33678
34167
|
result: clientResult.envelope,
|
|
33679
34168
|
diffBase
|
|
33680
34169
|
});
|
|
@@ -33793,18 +34282,19 @@ function subagentStopped(input, deps = {}) {
|
|
|
33793
34282
|
}
|
|
33794
34283
|
|
|
33795
34284
|
// dist/hooks/stop.js
|
|
33796
|
-
async function runStop(observeDeps = {}, timeDeps = {}, paceDeps = {}, profile = AGENT_PROFILES["claude-code"]) {
|
|
34285
|
+
async function runStop(observeDeps = {}, timeDeps = {}, paceDeps = {}, profile = AGENT_PROFILES["claude-code"], planDeps = {}) {
|
|
33797
34286
|
const input = hookInputForRule(await readHookStdin(), profile.configFolder);
|
|
33798
34287
|
recordTimeEvent("turn-end", input);
|
|
33799
34288
|
await runSessionDiff(input, "stop", readSeatConfiguration, async (reply) => {
|
|
33800
34289
|
await observeChanges(input.session_id, reply, observeDeps);
|
|
33801
34290
|
await sendTimeRecord(timeDeps, { agent: profile.id });
|
|
33802
34291
|
await paceAtTurnEnd(input, reply, { configFolder: profile.configFolder, ...paceDeps });
|
|
34292
|
+
await planUsageReport(input, { configFolder: profile.configFolder, ...planDeps });
|
|
33803
34293
|
}, profile);
|
|
33804
34294
|
}
|
|
33805
34295
|
|
|
33806
34296
|
// dist/relayed-choices.js
|
|
33807
|
-
import { mkdirSync as
|
|
34297
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync28, renameSync as renameSync16, rmSync as rmSync6, writeFileSync as writeFileSync18 } from "node:fs";
|
|
33808
34298
|
import { homedir as homedir15 } from "node:os";
|
|
33809
34299
|
import { dirname as dirname9, join as join21 } from "node:path";
|
|
33810
34300
|
function relayedChoicesFilePath(engagementId, home) {
|
|
@@ -33817,7 +34307,7 @@ function readRelayedChoices(engagementId, phase, home) {
|
|
|
33817
34307
|
if (path === null)
|
|
33818
34308
|
return null;
|
|
33819
34309
|
try {
|
|
33820
|
-
const parsed = relayedChoicesFileSchema.safeParse(JSON.parse(
|
|
34310
|
+
const parsed = relayedChoicesFileSchema.safeParse(JSON.parse(readFileSync28(path, "utf-8")));
|
|
33821
34311
|
return parsed.success && parsed.data.phase === phase ? parsed.data : null;
|
|
33822
34312
|
} catch {
|
|
33823
34313
|
return null;
|
|
@@ -33848,10 +34338,10 @@ function recordRelayedChoice(opts) {
|
|
|
33848
34338
|
return false;
|
|
33849
34339
|
const temp = join21(dirname9(target), `.${RELAYED_CHOICES_FILENAME}.${process.pid}.tmp`);
|
|
33850
34340
|
try {
|
|
33851
|
-
|
|
33852
|
-
|
|
34341
|
+
mkdirSync13(dirname9(target), { recursive: true, mode: 448 });
|
|
34342
|
+
writeFileSync18(temp, `${JSON.stringify(file2.data)}
|
|
33853
34343
|
`, { mode: 384 });
|
|
33854
|
-
|
|
34344
|
+
renameSync16(temp, target);
|
|
33855
34345
|
return true;
|
|
33856
34346
|
} catch {
|
|
33857
34347
|
try {
|
|
@@ -33915,6 +34405,7 @@ var KEEP_GOING = /^keep going$/i;
|
|
|
33915
34405
|
var STOP = /^stop(?: here)?$/i;
|
|
33916
34406
|
var TIMES = /^limit it to ([0-9]{1,9}(?:\.[0-9]{1,2})?) times$/i;
|
|
33917
34407
|
var FIGURE = /^limit it to ([0-9]{1,9}(?:\.[0-9]{1,2})?) (million|billion)(?: tokens)?$/i;
|
|
34408
|
+
var SHARE = /^limit it to ([0-9]{1,3})% of the week$/i;
|
|
33918
34409
|
function limitPhraseShape(prompt) {
|
|
33919
34410
|
if (typeof prompt !== "string")
|
|
33920
34411
|
return null;
|
|
@@ -33933,6 +34424,11 @@ function limitPhraseShape(prompt) {
|
|
|
33933
34424
|
const unit = figure[2].toLowerCase() === "billion" ? 1e9 : 1e6;
|
|
33934
34425
|
return { kind: "figure", tokens: Math.round(Number(figure[1]) * unit) };
|
|
33935
34426
|
}
|
|
34427
|
+
const share = SHARE.exec(line2);
|
|
34428
|
+
if (share !== null) {
|
|
34429
|
+
const percent = Number(share[1]);
|
|
34430
|
+
return percent >= 1 && percent <= 100 ? { kind: "share", percent } : null;
|
|
34431
|
+
}
|
|
33936
34432
|
return null;
|
|
33937
34433
|
}
|
|
33938
34434
|
|
|
@@ -34074,7 +34570,7 @@ function matchReviewPhraseShape(shape, reviews) {
|
|
|
34074
34570
|
}
|
|
34075
34571
|
|
|
34076
34572
|
// dist/hooks/shown-record.js
|
|
34077
|
-
import { chmodSync as chmodSync4, readFileSync as
|
|
34573
|
+
import { chmodSync as chmodSync4, readFileSync as readFileSync29, renameSync as renameSync17, unlinkSync as unlinkSync11, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34078
34574
|
import { homedir as homedir16, platform as platform3 } from "node:os";
|
|
34079
34575
|
import { join as join22 } from "node:path";
|
|
34080
34576
|
function recordDir(engagementId, home) {
|
|
@@ -34087,7 +34583,7 @@ function readShownRecord(engagementId, home) {
|
|
|
34087
34583
|
if (dir === null)
|
|
34088
34584
|
return { entries: [], reviews: [] };
|
|
34089
34585
|
try {
|
|
34090
|
-
return parseShownRecord(
|
|
34586
|
+
return parseShownRecord(readFileSync29(join22(dir, SHOWN_PLANS_FILENAME), "utf-8"));
|
|
34091
34587
|
} catch {
|
|
34092
34588
|
return { entries: [], reviews: [] };
|
|
34093
34589
|
}
|
|
@@ -34109,7 +34605,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
34109
34605
|
if (dir === null)
|
|
34110
34606
|
return false;
|
|
34111
34607
|
const path = join22(dir, SHOWN_PLANS_FILENAME);
|
|
34112
|
-
const current = parseShownRecord(
|
|
34608
|
+
const current = parseShownRecord(readFileSync29(path, "utf-8"));
|
|
34113
34609
|
const at = current.reviews.findIndex((r) => r.phase === listed.phase && r.shownAt === listed.shownAt && r.reviewVersion === listed.reviewVersion);
|
|
34114
34610
|
if (at === -1)
|
|
34115
34611
|
return false;
|
|
@@ -34117,10 +34613,10 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
34117
34613
|
const reviews = current.reviews.map((review, i) => i === at ? { ...review, reviewVersion, parts: review.parts.map((p) => movedPart(p, acts.get(p.part))) } : review);
|
|
34118
34614
|
const body = serialiseShownRecord({ entries: current.entries, reviews });
|
|
34119
34615
|
temp = join22(dir, `.${SHOWN_PLANS_FILENAME}.${process.pid}.tmp`);
|
|
34120
|
-
|
|
34616
|
+
writeFileSync19(temp, body, { mode: 384 });
|
|
34121
34617
|
if (platform3() !== "win32")
|
|
34122
34618
|
chmodSync4(temp, 384);
|
|
34123
|
-
|
|
34619
|
+
renameSync17(temp, path);
|
|
34124
34620
|
return true;
|
|
34125
34621
|
} catch {
|
|
34126
34622
|
if (temp !== null) {
|
|
@@ -34639,20 +35135,17 @@ function paceNoOwnerText() {
|
|
|
34639
35135
|
function paceCannotReachText() {
|
|
34640
35136
|
return `${PACE_NOTHING_CHANGED_OPENING}: Halfcycle could not be reached just now. Type the line again in a minute.`;
|
|
34641
35137
|
}
|
|
34642
|
-
function
|
|
34643
|
-
return limit
|
|
34644
|
-
}
|
|
34645
|
-
function limitKeepGoingDoneText(limit, used) {
|
|
34646
|
-
return `Done. The limit is now ${tokenCountWordsOf(limit)} tokens. This phase has used ${tokenCountWordsOf(used)}. New work can start again.`;
|
|
35138
|
+
function limitKeepGoingDoneText(limit, used, weekCeilingTokens = null) {
|
|
35139
|
+
return limitKeepGoingShareText(limit, used, weekCeilingTokens);
|
|
34647
35140
|
}
|
|
34648
35141
|
function limitStopDoneText() {
|
|
34649
35142
|
return 'Done. This phase is paused at its usage limit. Nothing is lost, and the agents already working will finish. Say "keep going" whenever you want to carry on.';
|
|
34650
35143
|
}
|
|
34651
|
-
function limitTimesDoneText(limit, typed, used) {
|
|
34652
|
-
return
|
|
35144
|
+
function limitTimesDoneText(limit, typed, used, weekCeilingTokens = null) {
|
|
35145
|
+
return limitTimesShareText(limit, typed, used, weekCeilingTokens);
|
|
34653
35146
|
}
|
|
34654
|
-
function limitFigureDoneText(limit, used) {
|
|
34655
|
-
return
|
|
35147
|
+
function limitFigureDoneText(limit, used, weekCeilingTokens = null) {
|
|
35148
|
+
return limitFigureShareText(limit, used, weekCeilingTokens);
|
|
34656
35149
|
}
|
|
34657
35150
|
function limitNotReachedText() {
|
|
34658
35151
|
return `${PACE_NOTHING_CHANGED_OPENING}: this phase has not reached its usage limit, so there is nothing to answer.`;
|
|
@@ -34660,11 +35153,14 @@ function limitNotReachedText() {
|
|
|
34660
35153
|
function limitNoBuildText() {
|
|
34661
35154
|
return `${PACE_NOTHING_CHANGED_OPENING}: no build is running in this project yet.`;
|
|
34662
35155
|
}
|
|
34663
|
-
function limitTimesRangeText() {
|
|
34664
|
-
return
|
|
35156
|
+
function limitTimesRangeText(weekCeilingTokens = null) {
|
|
35157
|
+
return limitTimesRangeShareText(LIMIT_MULTIPLE_RANGE, weekCeilingTokens);
|
|
35158
|
+
}
|
|
35159
|
+
function limitNoExpectedText(weekCeilingTokens = null) {
|
|
35160
|
+
return limitNoExpectedShareText(weekCeilingTokens);
|
|
34665
35161
|
}
|
|
34666
|
-
function
|
|
34667
|
-
return
|
|
35162
|
+
function limitShareNotSetText() {
|
|
35163
|
+
return LIMIT_SHARE_NOT_SET_TEXT;
|
|
34668
35164
|
}
|
|
34669
35165
|
function limitFigureRangeText() {
|
|
34670
35166
|
return `${PACE_NOTHING_CHANGED_OPENING}: a limit is between ${tokenCountWordsOf(LIMIT_FIGURE_RANGE.min)} and ${tokenCountWordsOf(LIMIT_FIGURE_RANGE.max)} tokens.`;
|
|
@@ -34941,8 +35437,11 @@ function decideLimit(shape, opts) {
|
|
|
34941
35437
|
const file2 = dir === null ? null : openPhaseLimit(dir, readPaceStateFile(dir).basis);
|
|
34942
35438
|
if (dir === null || file2 === null)
|
|
34943
35439
|
return say(limitNoBuildText());
|
|
35440
|
+
const ceiling = weeklyCeilingHere(opts, agent);
|
|
35441
|
+
if (shape.kind === "share" && ceiling === null)
|
|
35442
|
+
return say(limitShareNotSetText());
|
|
34944
35443
|
if (shape.kind === "times" && !multipleInRange(shape.multiple))
|
|
34945
|
-
return say(limitTimesRangeText());
|
|
35444
|
+
return say(limitTimesRangeText(ceiling));
|
|
34946
35445
|
if (shape.kind === "figure" && !figureInRange(shape.tokens))
|
|
34947
35446
|
return say(limitFigureRangeText());
|
|
34948
35447
|
const used = readPhaseUsage(dir, file2.phase);
|
|
@@ -34966,11 +35465,11 @@ function decideLimit(shape, opts) {
|
|
|
34966
35465
|
return say(limitNotSavedText());
|
|
34967
35466
|
if (typed === "cannot-tell")
|
|
34968
35467
|
relay();
|
|
34969
|
-
return say(limitKeepGoingDoneText(next2.limit, used));
|
|
35468
|
+
return say(limitKeepGoingDoneText(next2.limit, used, ceiling));
|
|
34970
35469
|
}
|
|
34971
35470
|
if (shape.kind === "times" && !(file2.expected > 0))
|
|
34972
|
-
return say(limitNoExpectedText());
|
|
34973
|
-
const limit = shape.kind === "times" ? limitOf(file2.expected, shape.multiple) : shape.tokens;
|
|
35471
|
+
return say(limitNoExpectedText(ceiling));
|
|
35472
|
+
const limit = shape.kind === "times" ? limitOf(file2.expected, shape.multiple) : shape.kind === "share" ? Math.max(1, Math.round(shape.percent / 100 * (ceiling ?? 0))) : shape.tokens;
|
|
34974
35473
|
const raise = limit > file2.limit;
|
|
34975
35474
|
if (raise && typed === "not-attended")
|
|
34976
35475
|
return say(limitNotAttendedText());
|
|
@@ -34979,7 +35478,32 @@ function decideLimit(shape, opts) {
|
|
|
34979
35478
|
return say(limitNotSavedText());
|
|
34980
35479
|
if (raise && typed === "cannot-tell")
|
|
34981
35480
|
relay();
|
|
34982
|
-
return say(shape.kind === "times" ? limitTimesDoneText(limit, shape.typed, used) : limitFigureDoneText(limit, used));
|
|
35481
|
+
return say(shape.kind === "times" ? limitTimesDoneText(limit, shape.typed, used, ceiling) : limitFigureDoneText(limit, used, ceiling));
|
|
35482
|
+
}
|
|
35483
|
+
function weeklyCeilingHere(opts, agent) {
|
|
35484
|
+
try {
|
|
35485
|
+
const said = promptRecordPath(opts.input);
|
|
35486
|
+
const key = configFolderKey({
|
|
35487
|
+
env: opts.env ?? process.env,
|
|
35488
|
+
transcriptPath: said,
|
|
35489
|
+
home: opts.home,
|
|
35490
|
+
...agent === "codex" ? { rule: "codex-home" } : {}
|
|
35491
|
+
});
|
|
35492
|
+
return weeklyCeilingOf(key, { home: opts.home });
|
|
35493
|
+
} catch {
|
|
35494
|
+
return null;
|
|
35495
|
+
}
|
|
35496
|
+
}
|
|
35497
|
+
function promptRecordPath(input) {
|
|
35498
|
+
try {
|
|
35499
|
+
const parsed = JSON.parse(input);
|
|
35500
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
35501
|
+
return null;
|
|
35502
|
+
const said = parsed["transcript_path"];
|
|
35503
|
+
return typeof said === "string" && said !== "" ? said : null;
|
|
35504
|
+
} catch {
|
|
35505
|
+
return null;
|
|
35506
|
+
}
|
|
34983
35507
|
}
|
|
34984
35508
|
function adjustPaceState(dir, opts, number4) {
|
|
34985
35509
|
try {
|
|
@@ -35302,7 +35826,7 @@ function runUserPromptFindings(opts) {
|
|
|
35302
35826
|
}
|
|
35303
35827
|
|
|
35304
35828
|
// dist/resolve-engagement.js
|
|
35305
|
-
import { existsSync as existsSync9, readFileSync as
|
|
35829
|
+
import { existsSync as existsSync9, readFileSync as readFileSync30, realpathSync as realpathSync10 } from "node:fs";
|
|
35306
35830
|
import { join as join23, sep as sep8 } from "node:path";
|
|
35307
35831
|
import { homedir as homedir17 } from "node:os";
|
|
35308
35832
|
function defaultRegistryPath() {
|
|
@@ -35312,7 +35836,7 @@ function readRegistry(registryPath = defaultRegistryPath()) {
|
|
|
35312
35836
|
if (!existsSync9(registryPath))
|
|
35313
35837
|
return {};
|
|
35314
35838
|
try {
|
|
35315
|
-
const parsed = JSON.parse(
|
|
35839
|
+
const parsed = JSON.parse(readFileSync30(registryPath, "utf-8"));
|
|
35316
35840
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
35317
35841
|
return {};
|
|
35318
35842
|
const out = {};
|
|
@@ -35360,12 +35884,12 @@ function runResolveEngagement(cwd, registryPath) {
|
|
|
35360
35884
|
}
|
|
35361
35885
|
|
|
35362
35886
|
// dist/refresh-credential.js
|
|
35363
|
-
import { lstatSync as lstatSync5, readFileSync as
|
|
35887
|
+
import { lstatSync as lstatSync5, readFileSync as readFileSync32, realpathSync as realpathSync11 } from "node:fs";
|
|
35364
35888
|
import { homedir as homedir19 } from "node:os";
|
|
35365
35889
|
import { join as join24, resolve as resolve12 } from "node:path";
|
|
35366
35890
|
|
|
35367
35891
|
// dist/mcp-headers.js
|
|
35368
|
-
import { readFileSync as
|
|
35892
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
35369
35893
|
import { homedir as homedir18 } from "node:os";
|
|
35370
35894
|
import { dirname as dirname10, resolve as resolve11 } from "node:path";
|
|
35371
35895
|
var URL_FLAG = "--url";
|
|
@@ -35399,7 +35923,7 @@ function projectRootFromBinary(binaryPath) {
|
|
|
35399
35923
|
function readPinnedVersion(root) {
|
|
35400
35924
|
let raw;
|
|
35401
35925
|
try {
|
|
35402
|
-
raw =
|
|
35926
|
+
raw = readFileSync31(resolve11(root, BUNDLE_PIN_REL), "utf-8");
|
|
35403
35927
|
} catch {
|
|
35404
35928
|
return void 0;
|
|
35405
35929
|
}
|
|
@@ -35661,7 +36185,7 @@ var SESSION_START_PROBE_ATTEMPTS = 2;
|
|
|
35661
36185
|
function registeredMcpUrl(projectRoot) {
|
|
35662
36186
|
let parsed;
|
|
35663
36187
|
try {
|
|
35664
|
-
parsed = JSON.parse(
|
|
36188
|
+
parsed = JSON.parse(readFileSync32(resolve12(projectRoot, MCP_REGISTRATION_REL), "utf-8"));
|
|
35665
36189
|
} catch {
|
|
35666
36190
|
return void 0;
|
|
35667
36191
|
}
|
|
@@ -35850,7 +36374,7 @@ function headlessInUntrustedFolder(input, profile, opts) {
|
|
|
35850
36374
|
const cwd = input["cwd"];
|
|
35851
36375
|
const folder2 = typeof cwd === "string" && cwd !== "" ? cwd : projectRootFromBinary(opts.binaryPath);
|
|
35852
36376
|
const stateFile = join24(readClaudeConfigFolder() ?? opts.home ?? homedir19(), CLAUDE_STATE_FILENAME);
|
|
35853
|
-
return trustOfWorkingFolder(folder2, stateFile, process.platform, { lstatSync: lstatSync5, readFileSync:
|
|
36377
|
+
return trustOfWorkingFolder(folder2, stateFile, process.platform, { lstatSync: lstatSync5, readFileSync: readFileSync32, realpathSync: realpathSync11 }) === "not-trusted";
|
|
35854
36378
|
}
|
|
35855
36379
|
async function runRefreshCredential(opts) {
|
|
35856
36380
|
const writeErr = opts.writeErr ?? defaultWriteErr2;
|
|
@@ -35943,7 +36467,7 @@ async function runRefreshCredential(opts) {
|
|
|
35943
36467
|
import { fileURLToPath } from "node:url";
|
|
35944
36468
|
|
|
35945
36469
|
// dist/capture.js
|
|
35946
|
-
import { readFileSync as
|
|
36470
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync20, mkdirSync as mkdirSync14, existsSync as existsSync10 } from "node:fs";
|
|
35947
36471
|
import { dirname as dirname11 } from "node:path";
|
|
35948
36472
|
function runCapture(provider, endpoint, opts = {}) {
|
|
35949
36473
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -35979,8 +36503,8 @@ function runCapture(provider, endpoint, opts = {}) {
|
|
|
35979
36503
|
const fixture = fixturePath(repoRoot, provider, slug);
|
|
35980
36504
|
const manifestFile = manifestPath(repoRoot);
|
|
35981
36505
|
try {
|
|
35982
|
-
|
|
35983
|
-
|
|
36506
|
+
mkdirSync14(dirname11(fixture), { recursive: true });
|
|
36507
|
+
writeFileSync20(fixture, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
35984
36508
|
} catch (err) {
|
|
35985
36509
|
const msg = err instanceof Error ? err.message : String(err);
|
|
35986
36510
|
return { ok: false, kind: "write-failed", message: `could not write fixture: ${msg}` };
|
|
@@ -36011,7 +36535,7 @@ function readInputFile(fromFile) {
|
|
|
36011
36535
|
if (!fromFile)
|
|
36012
36536
|
return void 0;
|
|
36013
36537
|
try {
|
|
36014
|
-
return
|
|
36538
|
+
return readFileSync33(fromFile, "utf-8");
|
|
36015
36539
|
} catch {
|
|
36016
36540
|
return void 0;
|
|
36017
36541
|
}
|
|
@@ -36024,7 +36548,7 @@ function relativeFixturePath(repoRoot, fixture) {
|
|
|
36024
36548
|
// dist/prove.js
|
|
36025
36549
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
36026
36550
|
import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
|
|
36027
|
-
import { createWriteStream, mkdirSync as
|
|
36551
|
+
import { createWriteStream, mkdirSync as mkdirSync15, readdirSync as readdirSync11, readFileSync as readFileSync34, renameSync as renameSync18, unlinkSync as unlinkSync12, writeFileSync as writeFileSync21 } from "node:fs";
|
|
36028
36552
|
import { homedir as homedir20 } from "node:os";
|
|
36029
36553
|
import { dirname as dirname12, join as join25 } from "node:path";
|
|
36030
36554
|
|
|
@@ -36221,10 +36745,10 @@ function parseProveArgs(args2) {
|
|
|
36221
36745
|
};
|
|
36222
36746
|
}
|
|
36223
36747
|
function writeJsonFile2(path, value) {
|
|
36224
|
-
|
|
36748
|
+
mkdirSync15(dirname12(path), { recursive: true, mode: 448 });
|
|
36225
36749
|
const tmp = `${path}.${process.pid}.${randomUUID3()}.tmp`;
|
|
36226
|
-
|
|
36227
|
-
|
|
36750
|
+
writeFileSync21(tmp, JSON.stringify(value), { mode: 384 });
|
|
36751
|
+
renameSync18(tmp, path);
|
|
36228
36752
|
}
|
|
36229
36753
|
function subjectKey(subject) {
|
|
36230
36754
|
return subject.kind === "task" ? ["task", subject.phase, subject.task] : ["change", subject.change];
|
|
@@ -36235,7 +36759,7 @@ function keptCheckPath(dir, subject, label) {
|
|
|
36235
36759
|
}
|
|
36236
36760
|
function readKeptCheck(dir, subject, label) {
|
|
36237
36761
|
try {
|
|
36238
|
-
const raw = JSON.parse(
|
|
36762
|
+
const raw = JSON.parse(readFileSync34(keptCheckPath(dir, subject, label), "utf-8"));
|
|
36239
36763
|
if (typeof raw.command !== "string" || raw.command === "" || typeof raw.commandId !== "string")
|
|
36240
36764
|
return null;
|
|
36241
36765
|
const b = raw.before;
|
|
@@ -36260,7 +36784,7 @@ function readQueue(dir) {
|
|
|
36260
36784
|
const path = join25(dir, QUEUE_DIR_NAME, name);
|
|
36261
36785
|
let parsed = null;
|
|
36262
36786
|
try {
|
|
36263
|
-
parsed = testRunReportSchema.safeParse(JSON.parse(
|
|
36787
|
+
parsed = testRunReportSchema.safeParse(JSON.parse(readFileSync34(path, "utf-8")));
|
|
36264
36788
|
} catch {
|
|
36265
36789
|
parsed = null;
|
|
36266
36790
|
}
|
|
@@ -36337,7 +36861,7 @@ function runCommand(command, repoRoot, logPath2, env, deps) {
|
|
|
36337
36861
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
36338
36862
|
const childEnv = { ...env };
|
|
36339
36863
|
delete childEnv[SERVICE_TOKEN_VAR];
|
|
36340
|
-
|
|
36864
|
+
mkdirSync15(dirname12(logPath2), { recursive: true, mode: 448 });
|
|
36341
36865
|
const log = createWriteStream(logPath2, { mode: 384 });
|
|
36342
36866
|
const began = process.hrtime.bigint();
|
|
36343
36867
|
return new Promise((resolve13) => {
|
|
@@ -36503,7 +37027,7 @@ ${PROVE_USAGE}`);
|
|
|
36503
37027
|
const end = await runCommand(command, repoRoot, logPath2, env, deps);
|
|
36504
37028
|
let output = "";
|
|
36505
37029
|
try {
|
|
36506
|
-
output =
|
|
37030
|
+
output = readFileSync34(logPath2, "utf-8");
|
|
36507
37031
|
} catch {
|
|
36508
37032
|
output = "";
|
|
36509
37033
|
}
|
|
@@ -36553,8 +37077,8 @@ ${PROVE_USAGE}`);
|
|
|
36553
37077
|
|
|
36554
37078
|
// dist/statusline.js
|
|
36555
37079
|
import { spawn as spawn3 } from "node:child_process";
|
|
36556
|
-
import { readFileSync as
|
|
36557
|
-
import
|
|
37080
|
+
import { readFileSync as readFileSync35 } from "node:fs";
|
|
37081
|
+
import nodePath7 from "node:path";
|
|
36558
37082
|
var OWN_STATUS_LINE_DEADLINE_MS = 5e3;
|
|
36559
37083
|
var PERSON_SETTINGS_FILENAME = "settings.json";
|
|
36560
37084
|
var OWN_COMMAND_MARK = /guard-runner\.sh["']?\s+statusline\b/;
|
|
@@ -36591,7 +37115,7 @@ function halfcycleStatusLineOf(figures) {
|
|
|
36591
37115
|
}
|
|
36592
37116
|
function personStatusLineCommand(configFolder) {
|
|
36593
37117
|
try {
|
|
36594
|
-
const v = JSON.parse(
|
|
37118
|
+
const v = JSON.parse(readFileSync35(nodePath7.join(configFolder, PERSON_SETTINGS_FILENAME), "utf-8"));
|
|
36595
37119
|
const line2 = v["statusLine"];
|
|
36596
37120
|
if (typeof line2 !== "object" || line2 === null)
|
|
36597
37121
|
return null;
|