looply-cli 0.5.32 → 0.5.34

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.
Files changed (66) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/bin.d.ts.map +1 -1
  3. package/dist/bin.js +9 -0
  4. package/dist/bin.js.map +1 -1
  5. package/dist/checkout-deps.d.ts +75 -0
  6. package/dist/checkout-deps.d.ts.map +1 -0
  7. package/dist/checkout-deps.js +154 -0
  8. package/dist/checkout-deps.js.map +1 -0
  9. package/dist/daemon-cmd.d.ts.map +1 -1
  10. package/dist/daemon-cmd.js +11 -0
  11. package/dist/daemon-cmd.js.map +1 -1
  12. package/dist/gate-health.d.ts +1 -1
  13. package/dist/gate-health.d.ts.map +1 -1
  14. package/dist/gate-health.js +26 -0
  15. package/dist/gate-health.js.map +1 -1
  16. package/dist/grant-waiting-wiring.d.ts +5 -0
  17. package/dist/grant-waiting-wiring.d.ts.map +1 -1
  18. package/dist/grant-waiting-wiring.js +5 -0
  19. package/dist/grant-waiting-wiring.js.map +1 -1
  20. package/dist/run-cmd.d.ts.map +1 -1
  21. package/dist/run-cmd.js +60 -6
  22. package/dist/run-cmd.js.map +1 -1
  23. package/dist/tool-bridge.d.ts.map +1 -1
  24. package/dist/tool-bridge.js +7 -2
  25. package/dist/tool-bridge.js.map +1 -1
  26. package/dist/trusted-git.d.ts.map +1 -1
  27. package/dist/trusted-git.js +6 -1
  28. package/dist/trusted-git.js.map +1 -1
  29. package/dist/untrusted-exec.d.ts +37 -0
  30. package/dist/untrusted-exec.d.ts.map +1 -1
  31. package/dist/untrusted-exec.js +46 -2
  32. package/dist/untrusted-exec.js.map +1 -1
  33. package/dist/verifier.d.ts +2 -0
  34. package/dist/verifier.d.ts.map +1 -1
  35. package/dist/verifier.js +4 -1
  36. package/dist/verifier.js.map +1 -1
  37. package/dist/verify-cmd.d.ts +15 -1
  38. package/dist/verify-cmd.d.ts.map +1 -1
  39. package/dist/verify-cmd.js +21 -3
  40. package/dist/verify-cmd.js.map +1 -1
  41. package/dist/verify-pass.d.ts +6 -1
  42. package/dist/verify-pass.d.ts.map +1 -1
  43. package/dist/verify-pass.js +4 -1
  44. package/dist/verify-pass.js.map +1 -1
  45. package/dist/visual-proof-run.d.ts +6 -0
  46. package/dist/visual-proof-run.d.ts.map +1 -1
  47. package/dist/visual-proof-run.js +26 -1
  48. package/dist/visual-proof-run.js.map +1 -1
  49. package/dist/visual-proof-store.d.ts +8 -0
  50. package/dist/visual-proof-store.d.ts.map +1 -1
  51. package/dist/visual-proof-store.js +5 -0
  52. package/dist/visual-proof-store.js.map +1 -1
  53. package/dist/visual-proof.d.ts.map +1 -1
  54. package/dist/visual-proof.js +1 -0
  55. package/dist/visual-proof.js.map +1 -1
  56. package/dist/workspace-provisioner.d.ts +1 -0
  57. package/dist/workspace-provisioner.d.ts.map +1 -1
  58. package/dist/workspace-provisioner.js +2 -1
  59. package/dist/workspace-provisioner.js.map +1 -1
  60. package/dist/workspace.d.ts +21 -0
  61. package/dist/workspace.d.ts.map +1 -1
  62. package/dist/workspace.js +59 -0
  63. package/dist/workspace.js.map +1 -1
  64. package/package.json +2 -2
  65. package/win/acl-grant.ps1 +96 -0
  66. package/win/appcontainer.ps1 +27 -5
package/dist/run-cmd.js CHANGED
@@ -28,6 +28,7 @@ const evidence_cache_1 = require("./evidence-cache");
28
28
  const control_file_1 = require("./control-file");
29
29
  const git_driver_1 = require("./git-driver");
30
30
  const untrusted_gate_1 = require("./untrusted-gate");
31
+ const checkout_deps_1 = require("./checkout-deps");
31
32
  const model_transport_1 = require("./model-transport");
32
33
  const agent_envelope_1 = require("./agent-envelope");
33
34
  const provider_limit_1 = require("./provider-limit");
@@ -2862,6 +2863,10 @@ async function runLoop(opts) {
2862
2863
  const adaptiveTier = adaptiveBudget.compile;
2863
2864
  let compileTimedOut = false;
2864
2865
  let checkTimedOut = false;
2866
+ // RBB-B-218: the step check's own tier, and whether a pass this run checked nothing in time.
2867
+ const verifyKey = binding.kind === 'bound' ? (0, verify_cmd_2.verifyTimeoutKey)(binding.goal.id, binding.goal.version) : null;
2868
+ const verifyTier = (0, verify_cmd_2.verifierTierFor)(verifyKey === null ? 0 : (0, planner_timeouts_1.plannerTimeoutsFor)(projectStateDirPath, verifyKey));
2869
+ let verifyTimedOut = false;
2865
2870
  /**
2866
2871
  * A PLANNER THAT RAN OUT OF TIME IS THE MACHINE'S LIMIT, NOT THE GOAL'S FAULT: the run leaves
2867
2872
  * with `environment` / `planner_timeout`, so the controller voids this Start (it costs no try),
@@ -2873,6 +2878,16 @@ async function runLoop(opts) {
2873
2878
  * at the same eight minutes again — finished work that is never judged is never delivered.
2874
2879
  */
2875
2880
  const plannerTimedOut = (message) => {
2881
+ /**
2882
+ * A STEP CHECK THAT RAN OUT OF TIME, with nothing made ready (RBB-B-218): the machine's limit.
2883
+ * The goal is neither judged nor re-planned on it — four plans were spent that way on steps
2884
+ * never tried, and the goal ended "plan_limit_reached" with nothing delivered.
2885
+ */
2886
+ if (verifyTimedOut && verifyKey !== null) {
2887
+ const n = (0, planner_timeouts_1.notePlannerTimeout)(projectStateDirPath, verifyKey);
2888
+ return new RunRefused(`${message} — checking this plan's steps against the code took longer than its limit; the next Start checks each with ` +
2889
+ `${Math.round((0, verify_cmd_2.verifierTierFor)(n).timeoutMs / 60000)} minutes, and this Start does not count`, 'environment', undefined, undefined, 'planner_timeout');
2890
+ }
2876
2891
  if (checkTimedOut && binding.kind === 'bound') {
2877
2892
  const n = (0, planner_timeouts_1.notePlannerTimeout)(projectStateDirPath, (0, adaptive_budget_1.goalCheckTimeoutKey)(binding.goal.id, binding.goal.version));
2878
2893
  return new RunRefused(`${message} — the goal check took longer than its limit; the next Start checks with ${Math.round((0, goal_gap_1.goalCheckTimeoutFor)(n) / 60000)} minutes, ` +
@@ -2885,7 +2900,7 @@ async function runLoop(opts) {
2885
2900
  return new RunRefused(`${message} — planning took longer than its limit; the next Start plans with ${Math.round(next.timeoutMs / 60000)} minutes ` +
2886
2901
  `for at most ${next.maxSteps} steps, and this Start does not count`, 'environment', undefined, undefined, 'planner_timeout');
2887
2902
  };
2888
- let verifyBudget = Math.min(verify_cmd_2.VERIFY_MAX_PER_RUN, compileTier.maxSteps);
2903
+ let verifyBudget = Math.min(verify_cmd_2.VERIFY_MAX_PER_RUN, compileTier.maxSteps, verifyTier.maxPerRun);
2889
2904
  /**
2890
2905
  * EVERYTHING A START DOES BEFORE THE RUN, under one guard.
2891
2906
  *
@@ -3308,7 +3323,7 @@ async function runLoop(opts) {
3308
3323
  const pass = await (0, verify_pass_1.verifyDrafts)({
3309
3324
  queue: runQueue,
3310
3325
  ledger: ledgerForRun,
3311
- verify: (0, verify_cmd_1.makeItemVerifier)(verifyAgent, queue),
3326
+ verify: (0, verify_cmd_1.makeItemVerifier)(verifyAgent, queue, verifyTier.timeoutMs),
3312
3327
  cachePut: (id, head, ev) => evidence.put(id, head, ev),
3313
3328
  headSha: () => git.headSha(),
3314
3329
  projectId,
@@ -3329,6 +3344,8 @@ async function runLoop(opts) {
3329
3344
  verifyBudget -= pass.checked;
3330
3345
  log(`verify : ${pass.ready} of ${pass.checked} are ready to work on`);
3331
3346
  pickable = pass.ready;
3347
+ if (pass.ready === 0 && pass.timedOut > 0)
3348
+ verifyTimedOut = true;
3332
3349
  }
3333
3350
  }
3334
3351
  /**
@@ -3349,7 +3366,8 @@ async function runLoop(opts) {
3349
3366
  * work, and it is never reached again afterwards. `runner.run()` returns to a
3350
3367
  * `finally` that does nothing but clean up.
3351
3368
  */
3352
- if (!pickable && scope !== null && binding.kind === 'bound' && !compiledThisRun) {
3369
+ // A pass that checked nothing in time judges nothing: the goal check and a new plan wait for a Start that can (RBB-B-218).
3370
+ if (!pickable && scope !== null && binding.kind === 'bound' && !compiledThisRun && !verifyTimedOut) {
3353
3371
  const bound = binding.goal;
3354
3372
  // Captured, because `scope` moves when a new plan is materialised below and
3355
3373
  // the callbacks here must go on describing the goal they were built for.
@@ -3737,7 +3755,7 @@ async function runLoop(opts) {
3737
3755
  const pass = await (0, verify_pass_1.verifyDrafts)({
3738
3756
  queue: runQueue,
3739
3757
  ledger: ledgerForRun,
3740
- verify: (0, verify_cmd_1.makeItemVerifier)(verifyAgent, queue),
3758
+ verify: (0, verify_cmd_1.makeItemVerifier)(verifyAgent, queue, verifyTier.timeoutMs),
3741
3759
  cachePut: (id, head, ev) => evidence.put(id, head, ev),
3742
3760
  headSha: () => git.headSha(),
3743
3761
  projectId,
@@ -3750,6 +3768,8 @@ async function runLoop(opts) {
3750
3768
  verifyBudget -= pass.checked;
3751
3769
  log(`verify : ${pass.ready} of ${pass.checked} are ready to work on`);
3752
3770
  pickable = pass.ready;
3771
+ if (pass.ready === 0 && pass.timedOut > 0)
3772
+ verifyTimedOut = true;
3753
3773
  }
3754
3774
  }
3755
3775
  }
@@ -3771,6 +3791,8 @@ async function runLoop(opts) {
3771
3791
  return reproAsks;
3772
3792
  if (seamFailure !== null)
3773
3793
  return `could not check this goal — ${seamFailure}`;
3794
+ if (verifyTimedOut && adaptive === null)
3795
+ return `no step of this plan could be checked against the code in time — ${(0, queue_summary_1.describeNoReady)(runQueue.list())}`;
3774
3796
  const said = adaptive === null ? null : (0, goal_adaptive_1.describeAdaptive)(adaptive, attestedNow(), coverage);
3775
3797
  if (said !== null)
3776
3798
  return said.message;
@@ -3906,6 +3928,12 @@ async function runLoop(opts) {
3906
3928
  throw said.terminal ? new RunRefused(said.message, said.code, refusedOn, delivery) : (plannerTimedOut(said.message) ?? new Error(said.message));
3907
3929
  }
3908
3930
  }
3931
+ if (verifyTimedOut) {
3932
+ // Before the work-set exits: a step left `unclear` by a timeout is not a person's question.
3933
+ await releaseHold();
3934
+ const unchecked = `no step of this plan could be checked against the code in time — ${(0, queue_summary_1.describeNoReady)(runQueue.list())}`;
3935
+ throw plannerTimedOut(unchecked) ?? new Error(unchecked);
3936
+ }
3909
3937
  const left = scope === null ? null : (0, core_1.workLeft)(runQueue.list());
3910
3938
  if (left === 'finished') {
3911
3939
  // A WORK-SET fact, not a goal verdict: every row reached a terminal state.
@@ -4417,6 +4445,26 @@ async function runLoop(opts) {
4417
4445
  * not when AutoRyn or the file switched it off (`gates.baseCheck`, `run.base_check`).
4418
4446
  */
4419
4447
  const baseCheckWanted = binding.kind === 'bound' && effectiveGates.baseCheck && config.run.baseCheck !== false;
4448
+ /**
4449
+ * THE CHECKS' DEPENDENCIES, BEFORE ANYTHING IS JUDGED (AUT-B-62, `checkout-deps.ts`): a package folder the
4450
+ * gates run in, with a lockfile but no `node_modules`, is installed from its lockfile in the checkout's
4451
+ * sandbox — with internet access, which the gates themselves never get. A failed install is a machine
4452
+ * fault in the package manager's own words, never a red base.
4453
+ */
4454
+ const depsWanted = binding.kind === 'bound';
4455
+ let depsInstalled = false;
4456
+ const dependenciesBeforeFirstRound = async () => {
4457
+ const plan = (0, checkout_deps_1.dependencyInstallPlan)(config.gates, (0, checkout_deps_1.checkoutDepsFs)(cwd));
4458
+ if (plan.length === 0)
4459
+ return { ok: true };
4460
+ const out = await (0, checkout_deps_1.installDependencies)({ plan, runner: (0, untrusted_gate_1.makeUntrustedGateRunner)(cwd, { network: 'internet-client' }), log });
4461
+ if (out.kind === 'failed') {
4462
+ log(`deps : ${out.because}`);
4463
+ return { ok: false, because: out.because };
4464
+ }
4465
+ depsInstalled = out.kind === 'installed';
4466
+ return { ok: true };
4467
+ };
4420
4468
  const baseHealthBeforeFirstRound = async () => {
4421
4469
  const steps = config.gates;
4422
4470
  let record;
@@ -4424,7 +4472,8 @@ async function runLoop(opts) {
4424
4472
  const treeSha = await git.headTreeSha();
4425
4473
  const key = (0, gate_health_1.baseHealthKey)(treeSha, steps);
4426
4474
  record = (0, gate_health_1.readBaseHealth)(projectStateDirPath);
4427
- if ((0, gate_health_1.reusable)(record, key, Date.now())) {
4475
+ // Dependencies installed this run: what any earlier check of this base said was said without them.
4476
+ if (!depsInstalled && (0, gate_health_1.reusable)(record, key, Date.now())) {
4428
4477
  log(`base : the checks on this base were ${record.state} at ${record.checkedAt}`);
4429
4478
  }
4430
4479
  else {
@@ -4521,7 +4570,7 @@ async function runLoop(opts) {
4521
4570
  * The runner calls this after its own preconditions and after an item is
4522
4571
  * picked, which is the first moment a round is certain.
4523
4572
  */
4524
- ...((retryToSpend === null || safety === null) && !baseCheckWanted
4573
+ ...((retryToSpend === null || safety === null) && !baseCheckWanted && !depsWanted
4525
4574
  ? {}
4526
4575
  : {
4527
4576
  beforeFirstRound: async () => {
@@ -4529,6 +4578,11 @@ async function runLoop(opts) {
4529
4578
  * THE BASE FIRST: a check red on the unchanged code would throw away every round,
4530
4579
  * so it is found here, before the one retry below is spent on a round it would doom.
4531
4580
  */
4581
+ if (depsWanted) {
4582
+ const deps = await dependenciesBeforeFirstRound();
4583
+ if (!deps.ok)
4584
+ return deps;
4585
+ }
4532
4586
  if (baseCheckWanted) {
4533
4587
  const health = await baseHealthBeforeFirstRound();
4534
4588
  if (!health.ok)