halfcycle 0.4.9 → 0.4.10
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 +148 -136
- package/dist/bin.js +0 -0
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/cli.js +237 -112
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +10 -2
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/draw/index.d.ts +4 -1
- package/dist/draw/index.d.ts.map +1 -1
- package/dist/index.js +85 -52
- package/dist/index.js.map +2 -2
- package/dist/plan.d.ts +21 -10
- package/dist/plan.d.ts.map +1 -1
- package/dist/review.d.ts +6 -3
- package/dist/review.d.ts.map +1 -1
- package/package.json +11 -11
package/dist/cli.js
CHANGED
|
@@ -420,18 +420,6 @@ function hasDuplicates(items) {
|
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
// ../core/dist/phase-reference.js
|
|
423
|
-
var TYPED_NUMBER = /^(?:0|[1-9][0-9]*)$/;
|
|
424
|
-
function resolvePhaseReference(typed, phases) {
|
|
425
|
-
if (typeof typed !== "string" || typed === "")
|
|
426
|
-
return null;
|
|
427
|
-
const byIdentity = phases.filter((entry) => entry.phase === typed);
|
|
428
|
-
if (byIdentity.length > 0)
|
|
429
|
-
return byIdentity.length === 1 ? byIdentity[0] : null;
|
|
430
|
-
if (!TYPED_NUMBER.test(typed))
|
|
431
|
-
return null;
|
|
432
|
-
const byNumber = phases.filter((entry) => Number.isInteger(entry.number) && String(entry.number) === typed);
|
|
433
|
-
return byNumber.length === 1 ? byNumber[0] : null;
|
|
434
|
-
}
|
|
435
423
|
function typedPhaseReference(phase, number) {
|
|
436
424
|
return phase.includes(":") && number !== null ? String(number) : phase;
|
|
437
425
|
}
|
|
@@ -1162,10 +1150,10 @@ var openPhaseResponseSchema = z6.object({
|
|
|
1162
1150
|
|
|
1163
1151
|
// ../events/dist/crew.js
|
|
1164
1152
|
import { z as z7 } from "zod";
|
|
1165
|
-
var crewGroupSchema = z7.enum(["builder", "reviewer", "
|
|
1153
|
+
var crewGroupSchema = z7.enum(["analyst-architect", "builder", "reviewer", "lead"]);
|
|
1166
1154
|
var crewTierSchema = z7.enum(["deep", "standard", "fast"]);
|
|
1167
1155
|
var CREW_DISCIPLINE_MAX = 64;
|
|
1168
|
-
var crewFaceHeadSchema = z7.enum(["sq", "sqr", "rnd", "dome", "hex"]);
|
|
1156
|
+
var crewFaceHeadSchema = z7.enum(["sq", "sqr", "rnd", "dome", "hex", "gable"]);
|
|
1169
1157
|
var crewFaceAntennaSchema = z7.enum(["none", "stalk", "twin", "dish"]);
|
|
1170
1158
|
var crewFaceEyesSchema = z7.enum(["dots", "bars", "visor", "cyclops"]);
|
|
1171
1159
|
var crewFaceMouthSchema = z7.enum(["line", "grid", "dots", "wave"]);
|
|
@@ -1182,12 +1170,25 @@ var crewFaceSchema = z7.object({
|
|
|
1182
1170
|
// Whether this member is drawn with ears.
|
|
1183
1171
|
ears: z7.boolean()
|
|
1184
1172
|
}).strict();
|
|
1173
|
+
var crewRoleSchema = z7.enum([
|
|
1174
|
+
"business-analyst",
|
|
1175
|
+
"architect",
|
|
1176
|
+
"spec-writer",
|
|
1177
|
+
"builder",
|
|
1178
|
+
"context-docs",
|
|
1179
|
+
"spec-reviewer",
|
|
1180
|
+
"code-test-reviewer",
|
|
1181
|
+
"delivery-lead",
|
|
1182
|
+
"quality-lead"
|
|
1183
|
+
]);
|
|
1185
1184
|
var crewMemberSchema = z7.object({
|
|
1186
|
-
// The agent's name. The same
|
|
1185
|
+
// The agent's name. The same names on every project, so a name is a
|
|
1187
1186
|
// vocabulary a returning client already knows.
|
|
1188
1187
|
callsign: z7.string().min(1).max(32),
|
|
1189
|
-
// Which of the
|
|
1188
|
+
// Which of the four teams this member belongs to.
|
|
1190
1189
|
group: crewGroupSchema,
|
|
1190
|
+
// The part this member plays, which decides the stages it leads and helps with.
|
|
1191
|
+
role: crewRoleSchema,
|
|
1191
1192
|
// The kind of work this member takes. A task names a discipline, and only
|
|
1192
1193
|
// agents holding it can be dispatched to it.
|
|
1193
1194
|
discipline: z7.string().min(1).max(CREW_DISCIPLINE_MAX),
|
|
@@ -1199,10 +1200,44 @@ var crewMemberSchema = z7.object({
|
|
|
1199
1200
|
face: crewFaceSchema
|
|
1200
1201
|
}).strict();
|
|
1201
1202
|
var CREW_ROSTER = [
|
|
1203
|
+
// ── analysts and architects ─────────────────────────────────────────────────
|
|
1204
|
+
{
|
|
1205
|
+
callsign: "SOFIA",
|
|
1206
|
+
group: "analyst-architect",
|
|
1207
|
+
role: "business-analyst",
|
|
1208
|
+
discipline: "business analyst",
|
|
1209
|
+
tier: "deep",
|
|
1210
|
+
face: { head: "gable", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
callsign: "BEA",
|
|
1214
|
+
group: "analyst-architect",
|
|
1215
|
+
role: "business-analyst",
|
|
1216
|
+
discipline: "business analyst",
|
|
1217
|
+
tier: "standard",
|
|
1218
|
+
face: { head: "gable", antenna: "none", eyes: "visor", mouth: "line", ears: false }
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
callsign: "WREN",
|
|
1222
|
+
group: "analyst-architect",
|
|
1223
|
+
role: "architect",
|
|
1224
|
+
discipline: "solution architect",
|
|
1225
|
+
tier: "deep",
|
|
1226
|
+
face: { head: "gable", antenna: "dish", eyes: "bars", mouth: "line", ears: true }
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
callsign: "PEI",
|
|
1230
|
+
group: "analyst-architect",
|
|
1231
|
+
role: "architect",
|
|
1232
|
+
discipline: "technical architect",
|
|
1233
|
+
tier: "standard",
|
|
1234
|
+
face: { head: "gable", antenna: "twin", eyes: "cyclops", mouth: "dots", ears: false }
|
|
1235
|
+
},
|
|
1202
1236
|
// ── builders: code ──────────────────────────────────────────────────────────
|
|
1203
1237
|
{
|
|
1204
1238
|
callsign: "ADA",
|
|
1205
1239
|
group: "builder",
|
|
1240
|
+
role: "builder",
|
|
1206
1241
|
discipline: "implementation",
|
|
1207
1242
|
tier: "deep",
|
|
1208
1243
|
face: { head: "sq", antenna: "stalk", eyes: "dots", mouth: "line", ears: false }
|
|
@@ -1210,6 +1245,7 @@ var CREW_ROSTER = [
|
|
|
1210
1245
|
{
|
|
1211
1246
|
callsign: "OTTO",
|
|
1212
1247
|
group: "builder",
|
|
1248
|
+
role: "builder",
|
|
1213
1249
|
discipline: "implementation",
|
|
1214
1250
|
tier: "deep",
|
|
1215
1251
|
face: { head: "sq", antenna: "twin", eyes: "bars", mouth: "grid", ears: true }
|
|
@@ -1217,6 +1253,7 @@ var CREW_ROSTER = [
|
|
|
1217
1253
|
{
|
|
1218
1254
|
callsign: "MILO",
|
|
1219
1255
|
group: "builder",
|
|
1256
|
+
role: "builder",
|
|
1220
1257
|
discipline: "implementation",
|
|
1221
1258
|
tier: "standard",
|
|
1222
1259
|
face: { head: "sqr", antenna: "stalk", eyes: "dots", mouth: "dots", ears: false }
|
|
@@ -1224,42 +1261,24 @@ var CREW_ROSTER = [
|
|
|
1224
1261
|
{
|
|
1225
1262
|
callsign: "NOVA",
|
|
1226
1263
|
group: "builder",
|
|
1264
|
+
role: "builder",
|
|
1227
1265
|
discipline: "implementation",
|
|
1228
1266
|
tier: "standard",
|
|
1229
1267
|
face: { head: "sq", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
1230
1268
|
},
|
|
1231
|
-
{
|
|
1232
|
-
callsign: "KAI",
|
|
1233
|
-
group: "builder",
|
|
1234
|
-
discipline: "implementation",
|
|
1235
|
-
tier: "standard",
|
|
1236
|
-
face: { head: "sqr", antenna: "none", eyes: "bars", mouth: "line", ears: true }
|
|
1237
|
-
},
|
|
1238
1269
|
{
|
|
1239
1270
|
callsign: "HUGO",
|
|
1240
1271
|
group: "builder",
|
|
1272
|
+
role: "builder",
|
|
1241
1273
|
discipline: "infrastructure",
|
|
1242
1274
|
tier: "standard",
|
|
1243
1275
|
face: { head: "sq", antenna: "twin", eyes: "dots", mouth: "grid", ears: true }
|
|
1244
1276
|
},
|
|
1245
|
-
{
|
|
1246
|
-
callsign: "WREN",
|
|
1247
|
-
group: "builder",
|
|
1248
|
-
discipline: "refactor",
|
|
1249
|
-
tier: "fast",
|
|
1250
|
-
face: { head: "sqr", antenna: "stalk", eyes: "bars", mouth: "wave", ears: false }
|
|
1251
|
-
},
|
|
1252
|
-
{
|
|
1253
|
-
callsign: "PIP",
|
|
1254
|
-
group: "builder",
|
|
1255
|
-
discipline: "refactor",
|
|
1256
|
-
tier: "fast",
|
|
1257
|
-
face: { head: "sqr", antenna: "none", eyes: "dots", mouth: "dots", ears: false }
|
|
1258
|
-
},
|
|
1259
1277
|
// ── builders: specs and docs ────────────────────────────────────────────────
|
|
1260
1278
|
{
|
|
1261
1279
|
callsign: "IRIS",
|
|
1262
1280
|
group: "builder",
|
|
1281
|
+
role: "spec-writer",
|
|
1263
1282
|
discipline: "feature spec",
|
|
1264
1283
|
tier: "deep",
|
|
1265
1284
|
face: { head: "dome", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
@@ -1267,6 +1286,7 @@ var CREW_ROSTER = [
|
|
|
1267
1286
|
{
|
|
1268
1287
|
callsign: "JUNO",
|
|
1269
1288
|
group: "builder",
|
|
1289
|
+
role: "spec-writer",
|
|
1270
1290
|
discipline: "feature spec",
|
|
1271
1291
|
tier: "standard",
|
|
1272
1292
|
face: { head: "dome", antenna: "none", eyes: "dots", mouth: "wave", ears: false }
|
|
@@ -1274,6 +1294,7 @@ var CREW_ROSTER = [
|
|
|
1274
1294
|
{
|
|
1275
1295
|
callsign: "LEX",
|
|
1276
1296
|
group: "builder",
|
|
1297
|
+
role: "context-docs",
|
|
1277
1298
|
discipline: "context & docs",
|
|
1278
1299
|
tier: "fast",
|
|
1279
1300
|
face: { head: "dome", antenna: "twin", eyes: "bars", mouth: "dots", ears: false }
|
|
@@ -1282,6 +1303,7 @@ var CREW_ROSTER = [
|
|
|
1282
1303
|
{
|
|
1283
1304
|
callsign: "VERA",
|
|
1284
1305
|
group: "reviewer",
|
|
1306
|
+
role: "spec-reviewer",
|
|
1285
1307
|
discipline: "spec consistency",
|
|
1286
1308
|
tier: "deep",
|
|
1287
1309
|
face: { head: "rnd", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
|
|
@@ -1289,6 +1311,7 @@ var CREW_ROSTER = [
|
|
|
1289
1311
|
{
|
|
1290
1312
|
callsign: "ODIN",
|
|
1291
1313
|
group: "reviewer",
|
|
1314
|
+
role: "spec-reviewer",
|
|
1292
1315
|
discipline: "cross-spec audit",
|
|
1293
1316
|
tier: "deep",
|
|
1294
1317
|
face: { head: "rnd", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
|
|
@@ -1296,6 +1319,7 @@ var CREW_ROSTER = [
|
|
|
1296
1319
|
{
|
|
1297
1320
|
callsign: "CASS",
|
|
1298
1321
|
group: "reviewer",
|
|
1322
|
+
role: "code-test-reviewer",
|
|
1299
1323
|
discipline: "code review",
|
|
1300
1324
|
tier: "deep",
|
|
1301
1325
|
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "grid", ears: true }
|
|
@@ -1303,13 +1327,23 @@ var CREW_ROSTER = [
|
|
|
1303
1327
|
{
|
|
1304
1328
|
callsign: "THEO",
|
|
1305
1329
|
group: "reviewer",
|
|
1330
|
+
role: "code-test-reviewer",
|
|
1306
1331
|
discipline: "code review",
|
|
1307
1332
|
tier: "standard",
|
|
1308
1333
|
face: { head: "rnd", antenna: "twin", eyes: "bars", mouth: "line", ears: false }
|
|
1309
1334
|
},
|
|
1335
|
+
{
|
|
1336
|
+
callsign: "KAI",
|
|
1337
|
+
group: "reviewer",
|
|
1338
|
+
role: "code-test-reviewer",
|
|
1339
|
+
discipline: "code review",
|
|
1340
|
+
tier: "standard",
|
|
1341
|
+
face: { head: "rnd", antenna: "none", eyes: "bars", mouth: "line", ears: true }
|
|
1342
|
+
},
|
|
1310
1343
|
{
|
|
1311
1344
|
callsign: "ECHO",
|
|
1312
1345
|
group: "reviewer",
|
|
1346
|
+
role: "code-test-reviewer",
|
|
1313
1347
|
discipline: "test quality",
|
|
1314
1348
|
tier: "standard",
|
|
1315
1349
|
face: { head: "rnd", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
|
|
@@ -1317,6 +1351,7 @@ var CREW_ROSTER = [
|
|
|
1317
1351
|
{
|
|
1318
1352
|
callsign: "MAVIS",
|
|
1319
1353
|
group: "reviewer",
|
|
1354
|
+
role: "code-test-reviewer",
|
|
1320
1355
|
discipline: "suites & coverage",
|
|
1321
1356
|
tier: "standard",
|
|
1322
1357
|
face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "dots", ears: false }
|
|
@@ -1324,6 +1359,7 @@ var CREW_ROSTER = [
|
|
|
1324
1359
|
{
|
|
1325
1360
|
callsign: "ZARA",
|
|
1326
1361
|
group: "reviewer",
|
|
1362
|
+
role: "code-test-reviewer",
|
|
1327
1363
|
discipline: "smoke & walk aid",
|
|
1328
1364
|
tier: "standard",
|
|
1329
1365
|
face: { head: "rnd", antenna: "dish", eyes: "bars", mouth: "wave", ears: false }
|
|
@@ -1331,39 +1367,31 @@ var CREW_ROSTER = [
|
|
|
1331
1367
|
{
|
|
1332
1368
|
callsign: "NORA",
|
|
1333
1369
|
group: "reviewer",
|
|
1370
|
+
role: "code-test-reviewer",
|
|
1334
1371
|
discipline: "evidence & provenance",
|
|
1335
1372
|
tier: "fast",
|
|
1336
1373
|
face: { head: "rnd", antenna: "twin", eyes: "dots", mouth: "line", ears: false }
|
|
1337
1374
|
},
|
|
1338
|
-
// ──
|
|
1375
|
+
// ── leads ───────────────────────────────────────────────────────────────────
|
|
1339
1376
|
{
|
|
1340
1377
|
callsign: "ARGUS",
|
|
1341
|
-
group: "
|
|
1342
|
-
|
|
1378
|
+
group: "lead",
|
|
1379
|
+
role: "quality-lead",
|
|
1380
|
+
discipline: "quality lead \xB7 every diff",
|
|
1343
1381
|
tier: "standard",
|
|
1344
1382
|
face: { head: "hex", antenna: "dish", eyes: "visor", mouth: "grid", ears: true }
|
|
1345
1383
|
},
|
|
1346
1384
|
{
|
|
1347
1385
|
callsign: "ATLAS",
|
|
1348
|
-
group: "
|
|
1349
|
-
|
|
1386
|
+
group: "lead",
|
|
1387
|
+
role: "delivery-lead",
|
|
1388
|
+
discipline: "delivery lead",
|
|
1350
1389
|
tier: "deep",
|
|
1351
1390
|
face: { head: "hex", antenna: "twin", eyes: "cyclops", mouth: "line", ears: true }
|
|
1352
1391
|
}
|
|
1353
1392
|
];
|
|
1354
1393
|
var CREW_ROSTER_SIZE = CREW_ROSTER.length;
|
|
1355
1394
|
var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
|
|
1356
|
-
var crewRoleSchema = z7.enum([
|
|
1357
|
-
"business-analyst",
|
|
1358
|
-
"architect",
|
|
1359
|
-
"spec-writer",
|
|
1360
|
-
"builder",
|
|
1361
|
-
"context-docs",
|
|
1362
|
-
"spec-reviewer",
|
|
1363
|
-
"code-test-reviewer",
|
|
1364
|
-
"delivery-lead",
|
|
1365
|
-
"quality-lead"
|
|
1366
|
-
]);
|
|
1367
1395
|
var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
|
|
1368
1396
|
var crewRoleLayersSchema = z7.object({
|
|
1369
1397
|
leads: z7.array(crewLayerSchema),
|
|
@@ -1722,7 +1750,8 @@ var systemDrawDrawnSchema = /* @__PURE__ */ z8.object({
|
|
|
1722
1750
|
mermaid: z8.string().min(1).refine((v) => utf8ByteLength2(v) <= SYSTEM_DRAW_MERMAID_MAX_BYTES, {
|
|
1723
1751
|
message: "the diagram text is larger than 256 KB"
|
|
1724
1752
|
}),
|
|
1725
|
-
pictures: systemPicturesSchema
|
|
1753
|
+
pictures: systemPicturesSchema,
|
|
1754
|
+
closedAt: utcIso8601.optional()
|
|
1726
1755
|
}).strict();
|
|
1727
1756
|
var systemDrawRefusedSchema = z8.object({
|
|
1728
1757
|
outcome: z8.literal("refused"),
|
|
@@ -1967,14 +1996,13 @@ var SCOPE_STATE_NAMES = [
|
|
|
1967
1996
|
"waiting",
|
|
1968
1997
|
"sent-back",
|
|
1969
1998
|
"approved",
|
|
1970
|
-
"partly-stale"
|
|
1971
|
-
"withdrawn"
|
|
1999
|
+
"partly-stale"
|
|
1972
2000
|
];
|
|
1973
2001
|
var scopeStateNameSchema = z10.enum(SCOPE_STATE_NAMES);
|
|
1974
2002
|
var plannedScopeStateSchema = scopeStateNameSchema.exclude(["not-planned"]);
|
|
1975
2003
|
var SCOPE_PART_STATUSES = ["approved", "waiting"];
|
|
1976
2004
|
var scopePartStatusSchema = z10.enum(SCOPE_PART_STATUSES);
|
|
1977
|
-
var SCOPE_ACTS = ["approve", "send-back"
|
|
2005
|
+
var SCOPE_ACTS = ["approve", "send-back"];
|
|
1978
2006
|
var scopeActSchema = z10.enum(SCOPE_ACTS);
|
|
1979
2007
|
var SCOPE_GIVEN_IN = ["console", "chat"];
|
|
1980
2008
|
var scopeGivenInSchema = z10.enum(SCOPE_GIVEN_IN);
|
|
@@ -2045,14 +2073,9 @@ var scopeSendBackRequestSchema = z10.object({
|
|
|
2045
2073
|
parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
|
|
2046
2074
|
note: scopeNoteWireSchema.optional()
|
|
2047
2075
|
}).strict();
|
|
2048
|
-
var scopeWithdrawRequestSchema = z10.object({
|
|
2049
|
-
act: z10.literal("withdraw"),
|
|
2050
|
-
planVersion: planVersionSchema
|
|
2051
|
-
}).strict();
|
|
2052
2076
|
var scopeDecisionRequestSchema = z10.discriminatedUnion("act", [
|
|
2053
2077
|
scopeApproveRequestSchema,
|
|
2054
|
-
scopeSendBackRequestSchema
|
|
2055
|
-
scopeWithdrawRequestSchema
|
|
2078
|
+
scopeSendBackRequestSchema
|
|
2056
2079
|
]);
|
|
2057
2080
|
var scopeDecisionRecordedSchema = z10.object({
|
|
2058
2081
|
outcome: z10.literal("recorded"),
|
|
@@ -2085,7 +2108,6 @@ var scopeDecisionResultSchema = z10.discriminatedUnion("outcome", [
|
|
|
2085
2108
|
reasonOutcome("not-owner"),
|
|
2086
2109
|
reasonOutcome("no-owner"),
|
|
2087
2110
|
reasonOutcome("plan-changed"),
|
|
2088
|
-
reasonOutcome("nothing-to-withdraw"),
|
|
2089
2111
|
reasonOutcome("build-started")
|
|
2090
2112
|
]);
|
|
2091
2113
|
var scopeReadPartSchema = z10.object({
|
|
@@ -2387,6 +2409,15 @@ var observedChangesSchema = z13.object({
|
|
|
2387
2409
|
ctx.addIssue({ code: "custom", path: ["descriptionVersion"], message: "must name the version the counts used" });
|
|
2388
2410
|
}
|
|
2389
2411
|
});
|
|
2412
|
+
function partChangedUnderPaths(observed, partId, description) {
|
|
2413
|
+
if (observed === null || observed.counting.state !== "counted")
|
|
2414
|
+
return "unknown";
|
|
2415
|
+
const part = description.parts.find((candidate) => candidate.id === partId);
|
|
2416
|
+
if (part === void 0 || part.outside)
|
|
2417
|
+
return "unknown";
|
|
2418
|
+
const entry = observed.parts.find((candidate) => candidate.part === partId);
|
|
2419
|
+
return entry !== void 0 && entry.files !== null && filesChanged(entry.files) >= 1 ? "changed" : "unchanged";
|
|
2420
|
+
}
|
|
2390
2421
|
var partOutsideThePlanSchema = z13.object({
|
|
2391
2422
|
part: systemPartIdSchema,
|
|
2392
2423
|
name: systemPartSchema.shape.name,
|
|
@@ -2404,14 +2435,78 @@ function agentSaid(task) {
|
|
|
2404
2435
|
return `The agent on "${title}" said: "${whyOutsidePlan}"`;
|
|
2405
2436
|
return `${agent} said, on "${title}": "${whyOutsidePlan}"`;
|
|
2406
2437
|
}
|
|
2438
|
+
var NOTHING_COUNTED_DESPITE_FINISHED_LINE = "Halfcycle only counts committed changes. Work not yet committed, saved in a folder this project ignores, or committed outside this part's own folders, shows as nothing here even when every task that builds this part has finished.";
|
|
2439
|
+
function hasWildcard(segment) {
|
|
2440
|
+
return segment.includes("*");
|
|
2441
|
+
}
|
|
2442
|
+
function leadingLiteralPrefix(segments) {
|
|
2443
|
+
const firstWildcard = segments.findIndex(hasWildcard);
|
|
2444
|
+
return segments.slice(0, firstWildcard === -1 ? segments.length : firstWildcard).join("/");
|
|
2445
|
+
}
|
|
2446
|
+
function isWholeWildcard(segment) {
|
|
2447
|
+
return segment === "*" || segment === "**";
|
|
2448
|
+
}
|
|
2449
|
+
function ownsEverythingUnderPrefix(segments) {
|
|
2450
|
+
const firstWildcard = segments.findIndex(hasWildcard);
|
|
2451
|
+
if (firstWildcard === -1)
|
|
2452
|
+
return false;
|
|
2453
|
+
const tail = segments.slice(firstWildcard);
|
|
2454
|
+
if (!tail.every(isWholeWildcard))
|
|
2455
|
+
return false;
|
|
2456
|
+
return tail.filter((segment) => segment === "*").length <= 1;
|
|
2457
|
+
}
|
|
2458
|
+
var EXTENSION_GLOB_SEGMENT = /^\*\.([^*]+)$/;
|
|
2459
|
+
var EXTENSIONLESS_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
2460
|
+
"Makefile",
|
|
2461
|
+
"Dockerfile",
|
|
2462
|
+
"Gemfile",
|
|
2463
|
+
"Rakefile",
|
|
2464
|
+
"Procfile",
|
|
2465
|
+
"Vagrantfile",
|
|
2466
|
+
"LICENSE",
|
|
2467
|
+
"CHANGELOG",
|
|
2468
|
+
"README",
|
|
2469
|
+
"NOTICE",
|
|
2470
|
+
"Jenkinsfile",
|
|
2471
|
+
"Justfile",
|
|
2472
|
+
"CODEOWNERS"
|
|
2473
|
+
]);
|
|
2474
|
+
var DOT_PREFIXED_FOLDER_NAMES = /* @__PURE__ */ new Set([".github", ".vscode", ".circleci", ".husky", ".changeset", ".devcontainer", ".idea", ".claude", ".config"]);
|
|
2475
|
+
function isBareFileName(name) {
|
|
2476
|
+
if (EXTENSIONLESS_FILE_NAMES.has(name))
|
|
2477
|
+
return true;
|
|
2478
|
+
if (DOT_PREFIXED_FOLDER_NAMES.has(name))
|
|
2479
|
+
return false;
|
|
2480
|
+
return name.includes(".");
|
|
2481
|
+
}
|
|
2407
2482
|
function whereOf(owns) {
|
|
2408
2483
|
if (owns.length !== 1)
|
|
2409
|
-
return "its paths";
|
|
2484
|
+
return "under its paths";
|
|
2410
2485
|
const pattern = owns[0];
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
const
|
|
2414
|
-
|
|
2486
|
+
const segments = pattern.split("/");
|
|
2487
|
+
const lastSegment = segments[segments.length - 1];
|
|
2488
|
+
const extensionGlob = EXTENSION_GLOB_SEGMENT.exec(lastSegment);
|
|
2489
|
+
if (extensionGlob !== null) {
|
|
2490
|
+
const ext = extensionGlob[1];
|
|
2491
|
+
const before = segments.slice(0, -1);
|
|
2492
|
+
if (before.length === 0 || before.some(hasWildcard)) {
|
|
2493
|
+
const prefix2 = leadingLiteralPrefix(before);
|
|
2494
|
+
return prefix2 === "" ? `in its .${ext} files` : `in .${ext} files under ${prefix2}`;
|
|
2495
|
+
}
|
|
2496
|
+
return `in the .${ext} files directly in ${before.join("/")}`;
|
|
2497
|
+
}
|
|
2498
|
+
if (!hasWildcard(pattern)) {
|
|
2499
|
+
return isBareFileName(lastSegment) ? `in ${pattern}` : `under ${pattern}/`;
|
|
2500
|
+
}
|
|
2501
|
+
if (lastSegment === "*") {
|
|
2502
|
+
const folder = segments.slice(0, -1).join("/");
|
|
2503
|
+
if (folder !== "" && !hasWildcard(folder))
|
|
2504
|
+
return `in the ${folder} folder`;
|
|
2505
|
+
}
|
|
2506
|
+
const prefix = leadingLiteralPrefix(segments);
|
|
2507
|
+
if (ownsEverythingUnderPrefix(segments))
|
|
2508
|
+
return prefix === "" ? "anywhere in the project" : `under ${prefix}/`;
|
|
2509
|
+
return prefix === "" ? "in some paths in the project" : `in some paths under ${prefix}/`;
|
|
2415
2510
|
}
|
|
2416
2511
|
function howMany(n, one, many) {
|
|
2417
2512
|
return `${n} ${n === 1 ? one : many}`;
|
|
@@ -2440,7 +2535,7 @@ function observedLines(observed, part, description) {
|
|
|
2440
2535
|
const t = files === null ? 0 : files.testFilesAdded;
|
|
2441
2536
|
const where = whereOf(held.owns);
|
|
2442
2537
|
return [
|
|
2443
|
-
n === 0 ? `Nothing changed
|
|
2538
|
+
n === 0 ? `Nothing changed ${where}` : `${howMany(n, "file", "files")} changed ${where}`,
|
|
2444
2539
|
t === 0 ? "No test files added" : `${howMany(t, "test file", "test files")} added`,
|
|
2445
2540
|
checks
|
|
2446
2541
|
];
|
|
@@ -3021,6 +3116,21 @@ function loopbackVerificationUrl(verificationUrl, target) {
|
|
|
3021
3116
|
return url.toString();
|
|
3022
3117
|
}
|
|
3023
3118
|
|
|
3119
|
+
// ../events/dist/project-page.js
|
|
3120
|
+
function projectPageUrl(engagementId) {
|
|
3121
|
+
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
3122
|
+
}
|
|
3123
|
+
function systemViewUrl(engagementId, phase) {
|
|
3124
|
+
const page = projectPageUrl(engagementId);
|
|
3125
|
+
if (page === void 0)
|
|
3126
|
+
return void 0;
|
|
3127
|
+
return `${page}/console/system-view?${new URLSearchParams({ phase }).toString()}`;
|
|
3128
|
+
}
|
|
3129
|
+
function requestAccessSentence(engagementId) {
|
|
3130
|
+
const page = projectPageUrl(engagementId) ?? "this project's page on Halfcycle";
|
|
3131
|
+
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.`;
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3024
3134
|
// ../events/dist/join-refusal.js
|
|
3025
3135
|
import { z as z17 } from "zod";
|
|
3026
3136
|
var NOT_THIS_ACCOUNT_REASON = "not-this-account";
|
|
@@ -3036,15 +3146,6 @@ function isNotThisAccountRefusal(body) {
|
|
|
3036
3146
|
return typeof body === "object" && body !== null && body.reason === NOT_THIS_ACCOUNT_REASON;
|
|
3037
3147
|
}
|
|
3038
3148
|
|
|
3039
|
-
// ../events/dist/project-page.js
|
|
3040
|
-
function projectPageUrl(engagementId) {
|
|
3041
|
-
return isEngagementId(engagementId) ? `${DASHBOARD_URL}/${encodeURIComponent(engagementId)}` : void 0;
|
|
3042
|
-
}
|
|
3043
|
-
function requestAccessSentence(engagementId) {
|
|
3044
|
-
const page = projectPageUrl(engagementId) ?? "this project's page on Halfcycle";
|
|
3045
|
-
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.`;
|
|
3046
|
-
}
|
|
3047
|
-
|
|
3048
3149
|
// ../events/dist/account-identity.js
|
|
3049
3150
|
import { z as z18 } from "zod";
|
|
3050
3151
|
var accountIdentitySchema = z18.object({
|
|
@@ -7110,7 +7211,7 @@ function decisionText(part, p) {
|
|
|
7110
7211
|
case "accepted":
|
|
7111
7212
|
return "Accepted";
|
|
7112
7213
|
case "carried":
|
|
7113
|
-
return part.carriedTo === null || part.carriedTo === void 0 ? `Carried to the next phase planned: ${p.text(part.reason ?? "")}` : `Carried to phase ${
|
|
7214
|
+
return part.carriedTo === null || part.carriedTo === void 0 ? `Carried to the next phase planned: ${p.text(part.reason ?? "")}` : `Carried to phase "${part.carriedTo.phase}": ${p.text(part.reason ?? "")}`;
|
|
7114
7215
|
case "dropped":
|
|
7115
7216
|
return `Dropped: ${p.text(part.reason ?? "")}`;
|
|
7116
7217
|
}
|
|
@@ -7516,6 +7617,12 @@ var COULD_NOT_COUNT_LINE = "[halfcycle] Halfcycle could not count what this phas
|
|
|
7516
7617
|
function typedReviewHintLine(offered) {
|
|
7517
7618
|
return offered ? '[halfcycle] The owner reviews each part in their own Claude Code session: they say "review what was built" to see the list, then type one decision per line.' : `[halfcycle] ${TYPED_REVIEW_OFF_SENTENCE}`;
|
|
7518
7619
|
}
|
|
7620
|
+
function systemViewReviewLine(offered, engagementId, phase) {
|
|
7621
|
+
const address = systemViewUrl(engagementId, phase);
|
|
7622
|
+
if (address === void 0)
|
|
7623
|
+
return void 0;
|
|
7624
|
+
return offered ? `[halfcycle] Or the owner reviews it in the System view: ${address}` : `[halfcycle] The owner reviews it in the System view: ${address}`;
|
|
7625
|
+
}
|
|
7519
7626
|
function tasksOpenLine(phase, open, more) {
|
|
7520
7627
|
const total = open.length + more;
|
|
7521
7628
|
const shown2 = open.slice(0, TASK_TITLES_SHOWN);
|
|
@@ -7540,7 +7647,7 @@ function unfinishedStepsLines(phase, steps) {
|
|
|
7540
7647
|
function cleanOverFindingsLine(phase, findings) {
|
|
7541
7648
|
return findings === 1 ? `${REFUSED} the walk's verdict is clean, but 1 defect is recorded against phase "${phase}". Run this again with --verdict defects and a --finding for it. Nothing was sent to the owner.` : `${REFUSED} the walk's verdict is clean, but ${String(findings)} defects are recorded against phase "${phase}". Run this again with --verdict defects and a --finding for each. Nothing was sent to the owner.`;
|
|
7542
7649
|
}
|
|
7543
|
-
function closeStepReport(phase, attempt) {
|
|
7650
|
+
function closeStepReport(phase, attempt, engagementId) {
|
|
7544
7651
|
const stdout = [];
|
|
7545
7652
|
const stderr = [];
|
|
7546
7653
|
let exitCode = 1;
|
|
@@ -7568,6 +7675,11 @@ function closeStepReport(phase, attempt) {
|
|
|
7568
7675
|
if (!answer.counted)
|
|
7569
7676
|
stdout.push(COULD_NOT_COUNT_LINE);
|
|
7570
7677
|
stdout.push(typedReviewHintLine(answer.typedReviewOffered));
|
|
7678
|
+
{
|
|
7679
|
+
const viewLine = systemViewReviewLine(answer.typedReviewOffered, engagementId, phase);
|
|
7680
|
+
if (viewLine !== void 0)
|
|
7681
|
+
stdout.push(viewLine);
|
|
7682
|
+
}
|
|
7571
7683
|
if (!attempt.closeCommit.read) {
|
|
7572
7684
|
stderr.push(`${REFUSED} the commit this review starts from could not be read (${attempt.closeCommit.reason}), so the phase's Build Record will show the commit as not stated.`);
|
|
7573
7685
|
}
|
|
@@ -8663,7 +8775,7 @@ function notAPhaseNameLine(verb, phase) {
|
|
|
8663
8775
|
`;
|
|
8664
8776
|
}
|
|
8665
8777
|
function removalOwedLines(verb, parts) {
|
|
8666
|
-
return parts.map((part) => `halfcycle ${verb}: docs/system.json still holds "${part.name}", which phase ${part.
|
|
8778
|
+
return parts.map((part) => `halfcycle ${verb}: docs/system.json still holds "${part.name}", which phase "${part.phase}"'s review ${part.act}. Take it out, run ${HALFCYCLE_COMMAND} system, then run this again.
|
|
8667
8779
|
`).join("");
|
|
8668
8780
|
}
|
|
8669
8781
|
function redrawLine(repoRoot, phase) {
|
|
@@ -8688,28 +8800,27 @@ function planStateSentence(state) {
|
|
|
8688
8800
|
return "The owner approved an earlier plan; the parts marked as changed wait for the owner's approval.";
|
|
8689
8801
|
case "sent-back":
|
|
8690
8802
|
return "The owner sent this plan back. Change it to answer the owner's notes, then run this again.";
|
|
8691
|
-
case "withdrawn":
|
|
8692
|
-
return "The owner withdrew their approval of this plan. It waits for the owner's approval again.";
|
|
8693
8803
|
}
|
|
8694
8804
|
}
|
|
8695
|
-
function approvalLine2(phase, number, typedApprovalOffered, pinnedVersion, shown2) {
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
if (!
|
|
8699
|
-
return
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8805
|
+
function approvalLine2(phase, number, typedApprovalOffered, pinnedVersion, shown2, engagementId) {
|
|
8806
|
+
const address = systemViewUrl(engagementId, phase);
|
|
8807
|
+
const then = (sentence, viewSentence) => address === void 0 ? sentence : `${sentence} ${viewSentence} ${address}`;
|
|
8808
|
+
if (!typedApprovalOffered) {
|
|
8809
|
+
return then(TYPED_APPROVAL_OFF_SENTENCE, "The project's owner approves it in the System view:");
|
|
8810
|
+
}
|
|
8811
|
+
if (!clientMeetsChatApprovalFloor(pinnedVersion)) {
|
|
8812
|
+
return then(CLIENT_UPDATE_SENTENCE, "Or the project's owner approves it in the System view now:");
|
|
8813
|
+
}
|
|
8814
|
+
return then(`To approve it, the project's owner types \`approve ${phase}\` in their own Claude Code session. Only the owner can.`, "They can also approve it in the System view:");
|
|
8704
8815
|
}
|
|
8705
8816
|
function changeLines(plan, description, changed, carriedFrom = []) {
|
|
8706
8817
|
const names = new Map(description.parts.map((part) => [part.id, part.name]));
|
|
8707
8818
|
const marked = new Set(changed);
|
|
8708
|
-
const carried = new Map(carriedFrom.map((entry) => [entry.part, entry.
|
|
8819
|
+
const carried = new Map(carriedFrom.map((entry) => [entry.part, entry.phase]));
|
|
8709
8820
|
return plan.changes.map((c) => {
|
|
8710
8821
|
const mark = marked.has(c.part) ? " (changed since the owner last decided)" : "";
|
|
8711
|
-
const
|
|
8712
|
-
const carriedMark =
|
|
8822
|
+
const carriedPhase = carried.get(c.part);
|
|
8823
|
+
const carriedMark = carriedPhase === void 0 ? "" : ` (carried over from phase "${carriedPhase}")`;
|
|
8713
8824
|
return ` - ${names.get(c.part) ?? c.part}${carriedMark} \xB7 ${PLAN_CHANGE_LABELS[c.change]} \xB7 ${c.summary}${mark}
|
|
8714
8825
|
`;
|
|
8715
8826
|
}).join("");
|
|
@@ -8756,7 +8867,7 @@ async function runPlan(repoRoot, phase, show, deps) {
|
|
|
8756
8867
|
break;
|
|
8757
8868
|
}
|
|
8758
8869
|
const shownPhase = String(plan.phase);
|
|
8759
|
-
const recorded = `[halfcycle] Plan for ${shownPhase} recorded: plan version ${outcome.version}
|
|
8870
|
+
const recorded = `[halfcycle] Plan for "${shownPhase}" recorded: plan version ${outcome.version}.`;
|
|
8760
8871
|
const stateSentence = planStateSentence(outcome.state);
|
|
8761
8872
|
const redraw = redrawLine(repoRoot, phase) ?? "";
|
|
8762
8873
|
if (!show)
|
|
@@ -8780,7 +8891,7 @@ ${redraw}`;
|
|
|
8780
8891
|
exitCode: 1
|
|
8781
8892
|
};
|
|
8782
8893
|
}
|
|
8783
|
-
const stdout = listed + `${approvalLine2(shownPhase, outcome.phaseNumber, outcome.typedApprovalOffered, deps.pinnedClientVersion(repoRoot), written.entries)}
|
|
8894
|
+
const stdout = listed + `${approvalLine2(shownPhase, outcome.phaseNumber, outcome.typedApprovalOffered, deps.pinnedClientVersion(repoRoot), written.entries, stage.credential.engagementId)}
|
|
8784
8895
|
`;
|
|
8785
8896
|
return { stdout, stderr: warnings, exitCode: 0 };
|
|
8786
8897
|
}
|
|
@@ -8888,9 +8999,16 @@ var CANNOT_DRAW_PHASE_YET = `${P} this Halfcycle service cannot draw phase pictu
|
|
|
8888
8999
|
function markdownAltText(text) {
|
|
8889
9000
|
return text.replace(/[[\]\\]/g, (ch) => `\\${ch}`);
|
|
8890
9001
|
}
|
|
9002
|
+
function closedAtWords(closedAt) {
|
|
9003
|
+
const m = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(?:\.\d+)?Z$/.exec(closedAt);
|
|
9004
|
+
return m === null ? closedAt : `${m[1]} ${m[2]} UTC`;
|
|
9005
|
+
}
|
|
9006
|
+
function closedPhraseFor(phase, closedAt) {
|
|
9007
|
+
return `phase "${phase}", as it closed on ${closedAtWords(closedAt)}`;
|
|
9008
|
+
}
|
|
8891
9009
|
var ARCHITECTURE_PASTE = { doc: "docs", alt: "Architecture", base: ARCHITECTURE_BASE };
|
|
8892
9010
|
function phasePaste(phase) {
|
|
8893
|
-
return { doc: "docs/phases", alt: `Phase ${phase}`, base: phaseDiagramBase(phase) };
|
|
9011
|
+
return { doc: "docs/phases", alt: `Phase "${phase}"`, base: phaseDiagramBase(phase) };
|
|
8894
9012
|
}
|
|
8895
9013
|
function pasteLines(mermaid, target) {
|
|
8896
9014
|
const block = mermaid.endsWith("\n") ? mermaid : `${mermaid}
|
|
@@ -8945,7 +9063,7 @@ async function runDraw(repoRoot, picture, deps) {
|
|
|
8945
9063
|
return { stdout: "", stderr: credentialRead.line, exitCode: 1 };
|
|
8946
9064
|
const closed = await deps.draw(credentialRead.credential, { picture: "closed-phase", phase });
|
|
8947
9065
|
if (closed.kind === "drawn" || closed.kind === "refused") {
|
|
8948
|
-
return writeDrawOutcome(repoRoot, deps, closed, phasePaste(phase), "", CANNOT_DRAW_PHASE_YET);
|
|
9066
|
+
return writeDrawOutcome(repoRoot, deps, closed, phasePaste(phase), "", CANNOT_DRAW_PHASE_YET, phase);
|
|
8949
9067
|
}
|
|
8950
9068
|
let checkedPlan = null;
|
|
8951
9069
|
const beforeSend = (description) => {
|
|
@@ -8983,14 +9101,14 @@ async function runDraw(repoRoot, picture, deps) {
|
|
|
8983
9101
|
case "recorded":
|
|
8984
9102
|
break;
|
|
8985
9103
|
}
|
|
8986
|
-
return drawAndWrite(repoRoot, deps, stage.credential, { picture: "phase", phase: plan.phase, planVersion: reported.version }, phasePaste(phase), warnings, CANNOT_DRAW_PHASE_YET);
|
|
9104
|
+
return drawAndWrite(repoRoot, deps, stage.credential, { picture: "phase", phase: plan.phase, planVersion: reported.version }, phasePaste(phase), warnings, CANNOT_DRAW_PHASE_YET, phase);
|
|
8987
9105
|
}
|
|
8988
|
-
async function drawAndWrite(repoRoot, deps, credential, request, target, warnings, cannotDrawYet) {
|
|
9106
|
+
async function drawAndWrite(repoRoot, deps, credential, request, target, warnings, cannotDrawYet, phaseName) {
|
|
8989
9107
|
const outcome = await deps.draw(credential, request);
|
|
8990
9108
|
const usable = outcome.kind === "not-closed" ? { kind: "unavailable", why: "Halfcycle sent an answer this command could not use. Nothing was written; try again later." } : outcome;
|
|
8991
|
-
return writeDrawOutcome(repoRoot, deps, usable, target, warnings, cannotDrawYet);
|
|
9109
|
+
return writeDrawOutcome(repoRoot, deps, usable, target, warnings, cannotDrawYet, phaseName);
|
|
8992
9110
|
}
|
|
8993
|
-
async function writeDrawOutcome(repoRoot, deps, outcome, target, warnings, cannotDrawYet) {
|
|
9111
|
+
async function writeDrawOutcome(repoRoot, deps, outcome, target, warnings, cannotDrawYet, phaseName) {
|
|
8994
9112
|
const base = target.base;
|
|
8995
9113
|
if (outcome.kind === "no-route")
|
|
8996
9114
|
return { stdout: "", stderr: warnings + cannotDrawYet, exitCode: 1 };
|
|
@@ -9014,20 +9132,25 @@ async function writeDrawOutcome(repoRoot, deps, outcome, target, warnings, canno
|
|
|
9014
9132
|
exitCode: 1
|
|
9015
9133
|
};
|
|
9016
9134
|
}
|
|
9135
|
+
const closedAt = outcome.drawn.closedAt;
|
|
9136
|
+
const closedLead = closedAt !== void 0 && phaseName !== void 0 ? `This is ${closedPhraseFor(phaseName, closedAt)}.
|
|
9137
|
+
|
|
9138
|
+
` : "";
|
|
9139
|
+
const pasteTarget = closedAt !== void 0 && phaseName !== void 0 ? { ...target, alt: closedPhraseFor(phaseName, closedAt) } : target;
|
|
9017
9140
|
const rel = (which) => diagramRel(base, which);
|
|
9018
9141
|
const result = deps.write(repoRoot, base, checked.set);
|
|
9019
9142
|
switch (result.kind) {
|
|
9020
9143
|
case "up-to-date":
|
|
9021
9144
|
return {
|
|
9022
|
-
stdout: `[halfcycle] The pictures in ${DIAGRAM_DIR_REL}/ are up to date.
|
|
9023
|
-
` + pasteLines(outcome.drawn.mermaid,
|
|
9145
|
+
stdout: closedLead + `[halfcycle] The pictures in ${DIAGRAM_DIR_REL}/ are up to date.
|
|
9146
|
+
` + pasteLines(outcome.drawn.mermaid, pasteTarget),
|
|
9024
9147
|
stderr: warnings,
|
|
9025
9148
|
exitCode: 0
|
|
9026
9149
|
};
|
|
9027
9150
|
case "written":
|
|
9028
9151
|
return {
|
|
9029
|
-
stdout: `[halfcycle] Wrote ${spokenList(DIAGRAM_FILES_AS_LISTED.map(rel))}.
|
|
9030
|
-
` + pasteLines(outcome.drawn.mermaid,
|
|
9152
|
+
stdout: closedLead + `[halfcycle] Wrote ${spokenList(DIAGRAM_FILES_AS_LISTED.map(rel))}.
|
|
9153
|
+
` + pasteLines(outcome.drawn.mermaid, pasteTarget),
|
|
9031
9154
|
stderr: warnings,
|
|
9032
9155
|
exitCode: 0
|
|
9033
9156
|
};
|
|
@@ -9094,8 +9217,7 @@ function parseReviewArgs(argv) {
|
|
|
9094
9217
|
}
|
|
9095
9218
|
function rv1Line(view) {
|
|
9096
9219
|
const waiting = view.parts.filter((p) => p.decidable).length;
|
|
9097
|
-
|
|
9098
|
-
return `${lead}, review round ${view.round}. Parts waiting for your decision: ${waiting} of ${view.parts.length}.`;
|
|
9220
|
+
return `Phase "${view.phase}", review round ${view.round}. Parts waiting for your decision: ${waiting} of ${view.parts.length}.`;
|
|
9099
9221
|
}
|
|
9100
9222
|
var RV1A_LINE = "Halfcycle could not count what this phase changed, so judge each part on what the agents reported alone.";
|
|
9101
9223
|
var CHANGE_WORDS = {
|
|
@@ -9115,7 +9237,7 @@ function partStatus(part, round) {
|
|
|
9115
9237
|
case "accepted":
|
|
9116
9238
|
return "Accepted";
|
|
9117
9239
|
case "carried":
|
|
9118
|
-
return part.carriedTo === void 0 || part.carriedTo === null ? "Carried to the next phase planned" : `Carried to phase ${part.carriedTo.
|
|
9240
|
+
return part.carriedTo === void 0 || part.carriedTo === null ? "Carried to the next phase planned" : `Carried to phase "${part.carriedTo.phase}"`;
|
|
9119
9241
|
case "dropped":
|
|
9120
9242
|
return "Dropped";
|
|
9121
9243
|
case void 0:
|
|
@@ -9162,6 +9284,9 @@ function partLines(part, view) {
|
|
|
9162
9284
|
}
|
|
9163
9285
|
const observed = view.observed ?? nothingCounted(view.phase);
|
|
9164
9286
|
lines.push(` What Halfcycle saw: ${observedLines(observed, part.part, view.description).join("; ")}`);
|
|
9287
|
+
if (!part.built && part.tasks.length > 0 && part.tasks.every((t) => t.state === "completed") && partChangedUnderPaths(observed, part.part, view.description) === "unchanged") {
|
|
9288
|
+
lines.push(` ${NOTHING_COUNTED_DESPITE_FINISHED_LINE}`);
|
|
9289
|
+
}
|
|
9165
9290
|
const code = codeLinkLine(part.codeLink);
|
|
9166
9291
|
if (code !== void 0)
|
|
9167
9292
|
lines.push(` ${code}`);
|
|
@@ -11102,7 +11227,7 @@ halfcycle open-phase: until ${opened.stampFailure.path} can be written, guard ev
|
|
|
11102
11227
|
acceptanceOutcome: { verdict, findings: findingsDetail.length, findingsDetail },
|
|
11103
11228
|
stated
|
|
11104
11229
|
}, () => runObserveChild(runner, credential, repoRoot), repoRoot);
|
|
11105
|
-
const report = closeStepReport(phaseArg, attempt);
|
|
11230
|
+
const report = closeStepReport(phaseArg, attempt, credential.engagementId);
|
|
11106
11231
|
for (const line of report.stdout)
|
|
11107
11232
|
process.stdout.write(`${line}
|
|
11108
11233
|
`);
|