@stage5/lumine 0.2.55 → 0.2.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -229,7 +229,7 @@ claude "Read CLAUDE.md, then make the requested change."
229
229
  The login command uses a browser approval code and stores a scoped token and the
230
230
  selected project at `~/.twinkle/lumine-cli-auth.json`.
231
231
 
232
- ## Sponsoring Zero or Ciel Build Workshop duty
232
+ ## Sponsoring shared Zero and Ciel Build Workshop help
233
233
 
234
234
  Sponsorship is an approved contribution role, not an open switch and not a
235
235
  website-management role. Applications are submitted only through Lumine CLI;
@@ -243,12 +243,12 @@ lumine sponsor status
243
243
  ```
244
244
 
245
245
  After Mikey approves an application, configure conservative limits based on
246
- the subscription you are contributing, then start one foreground duty:
246
+ the subscription you are contributing, then start one shared foreground duty:
247
247
 
248
248
  ```bash
249
249
  lumine sponsor capacity --concurrency 1 --helpers 0 \
250
250
  --daily-limit 3 --weekly-limit 10
251
- lumine sponsor duty start zero --provider codex \
251
+ lumine sponsor duty start --provider codex \
252
252
  --model gpt-5.6-sol --effort max --service-tier priority
253
253
  ```
254
254
 
@@ -259,11 +259,14 @@ account may authenticate this way, but login never grants sponsor duty:
259
259
  `sponsor duty start` still requires that exact account to have a canonical,
260
260
  server-approved sponsor profile.
261
261
 
262
- While that foreground process has a fresh server lease, Zero or Ciel exposes a
263
- Build Workshop in chat and users may see the named sponsor and canonical queue.
262
+ While that foreground process has a fresh server lease, both Zero and Ciel can
263
+ delegate user-approved Build work to the shared worker pool. The user chooses
264
+ the assistant for each request, and may see the named sponsor and canonical
265
+ shared queue.
264
266
  With no live duty, the website stays in its ordinary chat state and shows none
265
267
  of the Workshop UI. Press Ctrl-C to stop accepting work and drain already
266
- claimed jobs before duty ends; `pause`, `resume`, and `stop` are also available.
268
+ claimed jobs before duty ends; `pause`, `resume`, and `stop` are also available
269
+ without a Zero/Ciel argument.
267
270
 
268
271
  Zero or Ciel remains the user-facing teammate. The local coding agent receives
269
272
  only the initial relay and active-job Build follow-ups covered by the user’s
@@ -273,8 +276,9 @@ cannot merge into Main, publish, or use website-management APIs. Lumine records
273
276
  the requested and provider-reported model, effort, service tier, runtime/usage
274
277
  evidence, coordinator/helper tree, saved artifact, and branch notice. Every
275
278
  completed handoff enters the daily integrity flow; probationary, hard-flagged,
276
- and sampled work requires review. Each unique cleared handoff earns a flat 50
277
- Karma Points, while retries and helper agents do not multiply the award.
279
+ and sampled work requires review. Each unique cleared contribution to another
280
+ user earns a flat 50 Karma Points, while self-sponsored testing, retries, and
281
+ helper agents do not earn or multiply the award.
278
282
 
279
283
  ## Privileged website administration
280
284
 
package/lib/commands.js CHANGED
@@ -2730,8 +2730,8 @@ export function printHelp() {
2730
2730
  lumine agent --provider <codex|claude-code> "<build request>"
2731
2731
  lumine sponsor agreement|apply|status|withdraw
2732
2732
  lumine sponsor capacity [--concurrency <n>] [--helpers <n>] [--daily-limit <n>] [--weekly-limit <n>]
2733
- lumine sponsor duty start <zero|ciel> --provider <codex|claude-code> [--model <name>] [--effort <level>] [--service-tier <tier>]
2734
- lumine sponsor duty pause|resume|stop <zero|ciel>
2733
+ lumine sponsor duty start --provider <codex|claude-code> [--model <name>] [--effort <level>] [--service-tier <tier>]
2734
+ lumine sponsor duty pause|resume|stop
2735
2735
  lumine sponsor jobs
2736
2736
  lumine app-mcp <published-app-url-or-id> [--no-open]
2737
2737
  lumine new [title]
package/lib/sponsor.js CHANGED
@@ -212,24 +212,41 @@ async function sponsorDutyCommand(options, args, commandServices) {
212
212
  .trim()
213
213
  .toLowerCase();
214
214
  if (action === "status") {
215
+ if (args.length > 1) throw new Error(sponsorUsage());
215
216
  await printSponsorStatus(options);
216
217
  return;
217
218
  }
218
- const persona = normalizePersona(args[1] || options.sponsorPersona);
219
+ if (args.length > 1 || options.sponsorPersona) {
220
+ throw new Error(
221
+ "Sponsor duty is shared by Zero and Ciel. Remove the persona argument.",
222
+ );
223
+ }
219
224
  if (["pause", "resume", "stop"].includes(action)) {
220
225
  const auth = await ensureAuth(options);
226
+ const status = await sponsorRequest({ options, auth, path: "/status" });
227
+ const currentDuties = (status.duties || []).filter((duty) =>
228
+ ["active", "paused"].includes(String(duty.state || "")),
229
+ );
230
+ if (currentDuties.length === 0) {
231
+ throw new Error("No active sponsor duty session was found.");
232
+ }
233
+ if (currentDuties.length > 1) {
234
+ throw new Error(
235
+ `Multiple legacy duty sessions are still open (${currentDuties.map((duty) => `#${duty.id}`).join(", ")}). Stop them with the CLI version that started them before using shared duty.`,
236
+ );
237
+ }
238
+ const dutyId = Number(currentDuties[0].id || 0);
239
+ if (!dutyId) throw new Error("Twinkle returned an invalid duty session.");
221
240
  const state =
222
241
  action === "resume" ? "active" : action === "stop" ? "stopped" : "paused";
223
242
  const result = await sponsorRequest({
224
243
  options,
225
244
  auth,
226
245
  method: "POST",
227
- path: `/duty/${persona}/state`,
228
- body: { state },
246
+ path: "/duty/state",
247
+ body: { dutySessionId: dutyId, state },
229
248
  });
230
- printJsonOrLines(options, result, [
231
- `${displayPersona(persona)} duty is now ${state}.`,
232
- ]);
249
+ printJsonOrLines(options, result, [`Sponsor duty is now ${state}.`]);
233
250
  return;
234
251
  }
235
252
  if (action !== "start") throw new Error(sponsorUsage());
@@ -249,7 +266,7 @@ async function sponsorDutyCommand(options, args, commandServices) {
249
266
  method: "POST",
250
267
  path: "/duty/start",
251
268
  body: {
252
- persona,
269
+ scope: "shared",
253
270
  provider,
254
271
  requestedModel: options.model || null,
255
272
  requestedEffort: options.sponsorEffort || null,
@@ -260,7 +277,6 @@ async function sponsorDutyCommand(options, args, commandServices) {
260
277
  await runSponsorDuty({
261
278
  options,
262
279
  auth,
263
- persona,
264
280
  provider,
265
281
  started,
266
282
  commandServices,
@@ -270,7 +286,6 @@ async function sponsorDutyCommand(options, args, commandServices) {
270
286
  async function runSponsorDuty({
271
287
  options,
272
288
  auth,
273
- persona,
274
289
  provider,
275
290
  started,
276
291
  commandServices,
@@ -280,6 +295,9 @@ async function runSponsorDuty({
280
295
  if (!dutyId || !leaseToken) {
281
296
  throw new Error("Twinkle did not return a valid sponsor duty lease.");
282
297
  }
298
+ if (started.duty?.scope !== "shared") {
299
+ throw new Error("Twinkle did not return a shared sponsor duty lease.");
300
+ }
283
301
  let canonicalDuty = started.duty;
284
302
  let stopRequested = false;
285
303
  let dutyLeaseError = null;
@@ -333,9 +351,7 @@ async function runSponsorDuty({
333
351
  Math.max(10, Number(started.heartbeatEverySeconds || 30)) * 1_000,
334
352
  );
335
353
 
336
- console.log(
337
- `${displayPersona(persona)} sponsor duty started with ${provider}.`,
338
- );
354
+ console.log(`Shared Zero/Ciel sponsor duty started with ${provider}.`);
339
355
  printDutyRuntime(canonicalDuty);
340
356
  console.log(
341
357
  "The Workshop is now discoverable to users. Press Ctrl-C for a graceful stop.",
@@ -365,7 +381,6 @@ async function runSponsorDuty({
365
381
  sponsorAuth: auth,
366
382
  dutyId,
367
383
  dutyLeaseToken: leaseToken,
368
- persona,
369
384
  provider,
370
385
  claim,
371
386
  commandServices,
@@ -385,8 +400,8 @@ async function runSponsorDuty({
385
400
  options,
386
401
  auth,
387
402
  method: "POST",
388
- path: `/duty/${persona}/state`,
389
- body: { state: "paused" },
403
+ path: "/duty/state",
404
+ body: { dutySessionId: dutyId, state: "paused" },
390
405
  });
391
406
  canonicalDuty = paused.duty || canonicalDuty;
392
407
  }
@@ -401,8 +416,8 @@ async function runSponsorDuty({
401
416
  options,
402
417
  auth,
403
418
  method: "POST",
404
- path: `/duty/${persona}/state`,
405
- body: { state: "stopped" },
419
+ path: "/duty/state",
420
+ body: { dutySessionId: dutyId, state: "stopped" },
406
421
  }).catch((error) => {
407
422
  if (!dutyLeaseError) {
408
423
  console.error(
@@ -412,7 +427,7 @@ async function runSponsorDuty({
412
427
  });
413
428
  }
414
429
  }
415
- console.log(`${displayPersona(persona)} sponsor duty stopped.`);
430
+ console.log("Shared Zero/Ciel sponsor duty stopped.");
416
431
  }
417
432
 
418
433
  async function processSponsorJob({
@@ -420,12 +435,12 @@ async function processSponsorJob({
420
435
  sponsorAuth,
421
436
  dutyId,
422
437
  dutyLeaseToken,
423
- persona,
424
438
  provider,
425
439
  claim,
426
440
  commandServices,
427
441
  }) {
428
442
  const job = claim.job;
443
+ const persona = normalizeJobPersona(job?.persona);
429
444
  const jobId = Number(job.id);
430
445
  const attemptToken = String(claim.attempt?.token || "");
431
446
  const workspaceToken = String(claim.workspaceToken?.accessToken || "");
@@ -1153,8 +1168,12 @@ async function printSponsorStatus(options) {
1153
1168
  );
1154
1169
  }
1155
1170
  for (const duty of status.duties || []) {
1171
+ const scope =
1172
+ duty.scope === "shared"
1173
+ ? "shared Zero/Ciel"
1174
+ : `legacy assistant user ${duty.personaUserId}`;
1156
1175
  console.log(
1157
- `Duty #${duty.id}: user ${duty.personaUserId} ${duty.state} · ${duty.provider} · model=${duty.requestedModel || "provider default"} · effort=${duty.requestedEffort || "provider default"}`,
1176
+ `Duty #${duty.id}: ${scope} · ${duty.state} · ${duty.provider} · model=${duty.requestedModel || "provider default"} · effort=${duty.requestedEffort || "provider default"}`,
1158
1177
  );
1159
1178
  }
1160
1179
  }
@@ -1253,12 +1272,12 @@ function normalizeProvider(value) {
1253
1272
  return provider;
1254
1273
  }
1255
1274
 
1256
- function normalizePersona(value) {
1275
+ function normalizeJobPersona(value) {
1257
1276
  const persona = String(value || "")
1258
1277
  .trim()
1259
1278
  .toLowerCase();
1260
1279
  if (!PERSONAS.has(persona)) {
1261
- throw new Error("Choose a duty persona: zero or ciel.");
1280
+ throw new Error("Twinkle returned an invalid Workshop job assistant.");
1262
1281
  }
1263
1282
  return persona;
1264
1283
  }
@@ -1285,8 +1304,8 @@ function sponsorUsage() {
1285
1304
  " lumine sponsor status",
1286
1305
  " lumine sponsor withdraw [--yes]",
1287
1306
  " lumine sponsor capacity [--concurrency <n>] [--helpers <n>] [--daily-limit <n>] [--weekly-limit <n>]",
1288
- " lumine sponsor duty start <zero|ciel> --provider <codex|claude-code> [--model <name>] [--effort <level>] [--service-tier <tier>]",
1289
- " lumine sponsor duty pause|resume|stop <zero|ciel>",
1307
+ " lumine sponsor duty start --provider <codex|claude-code> [--model <name>] [--effort <level>] [--service-tier <tier>]",
1308
+ " lumine sponsor duty pause|resume|stop",
1290
1309
  " lumine sponsor jobs [--limit <n>]",
1291
1310
  ].join("\n");
1292
1311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stage5/lumine",
3
- "version": "0.2.55",
3
+ "version": "0.2.56",
4
4
  "description": "Command line tools for launching Lumine builds on Twinkle.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -663,7 +663,9 @@ artifact snapshot, branch-notice evidence, and requested/resolved provider,
663
663
  model, effort, service-tier, runtime, usage, and agent-tree records. It never
664
664
  includes raw Zero/Ciel chat.
665
665
 
666
- `clear` qualifies that unique handoff for its flat 50 KP award;
666
+ `clear` qualifies a contribution to another user for its flat 50 KP award;
667
+ self-sponsored testing remains ineligible even when its integrity evidence is
668
+ cleared.
667
669
  `disqualify` makes it ineligible. `hold` and `flag` require an evidence note and
668
670
  remain open. The scan itself never changes sponsor status or applies a sanction.
669
671
  Use the separate, audited `sponsor status set` command for an explicit human