@loops-adk/core 0.1.0 → 0.1.1
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 +16 -1
- package/bin/loops.mjs +5 -5
- package/dist/api.d.ts +70 -1
- package/dist/api.js +2 -2
- package/dist/api.js.map +1 -1
- package/dist/{chunk-3BPU34DE.js → chunk-6BDWTFOS.js} +200 -14
- package/dist/chunk-6BDWTFOS.js.map +1 -0
- package/dist/index.js +111 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/author-loop/SKILL.md +12 -10
- package/dist/chunk-3BPU34DE.js.map +0 -1
package/README.md
CHANGED
|
@@ -447,6 +447,19 @@ The error taxonomy backs this: an engine classifies a throttle into a `RATE_LIMI
|
|
|
447
447
|
|
|
448
448
|
Every mode ends with a summary: result, per-loop iterations, review tallies, token usage by model, and any errors.
|
|
449
449
|
|
|
450
|
+
## Supervise a running loop
|
|
451
|
+
|
|
452
|
+
Run with `--supervise` and the loop registers itself under `~/.loops/runs/`, writing its live state there as it goes. Another process reads it with no daemon and no socket, because the filesystem is the channel (the same bet the rest of the library makes).
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
loops run build.loop.ts --supervise # in one terminal
|
|
456
|
+
loops list # in another: every supervised run, with state and iteration
|
|
457
|
+
loops status <runId> # its shape plus where it is now: iteration, last gate verdict, tokens
|
|
458
|
+
loops tail <runId> # stream its events live
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
`list` marks a run dead if its process is gone. The read side is also on the public surface (`listRuns`, `readRunStatus`, `runEventsPath`), so an agent supervising a fleet of loops, killing the ones that drift and kicking work back into the ones that hit a problem, reads the same files. Out-of-process control (pause, abort, and kickback from outside) is the next step.
|
|
462
|
+
|
|
450
463
|
## What `loops` is (and isn't)
|
|
451
464
|
|
|
452
465
|
`loops` is a **fresh-context loop primitive**, not a durable workflow engine. The design bet is that **the workspace is the state**: progress _and its reasoning_ live in git (the Ledger), so each iteration can start clean and still know what came before. If the process dies mid-run, you re-run against the same workspace (the worktree holds the files, the scratch files hold the why, the log holds the milestones) and continue. You lose the bookkeeping, not the work.
|
|
@@ -464,7 +477,9 @@ It deliberately does **not** do durable mid-run replay (re-running a half-finish
|
|
|
464
477
|
- [x] **Ledger**, git-memory core: the scratch files (working memory + handoff), grounding, milestone commits
|
|
465
478
|
- [x] Worktree isolation (branches-as-teams) with `--no-ff` land-back
|
|
466
479
|
- [x] Environment axis: provider interface + offline mock
|
|
467
|
-
- [
|
|
480
|
+
- [x] Publish to npm (`@loops-adk/core`, built `dist` + types, CI release)
|
|
481
|
+
- [x] Supervision: a file-based run registry with `loops list` / `status` / `tail`
|
|
482
|
+
- [ ] Out-of-process control: `pause` / `abort` / `kickback` a running loop from outside
|
|
468
483
|
- [ ] Optional `wip:` autosave tier (per-iteration recovery, squashed on convergence)
|
|
469
484
|
- [ ] No-progress / stall detection: the third hard stop, alongside `max` and `budget`
|
|
470
485
|
- [ ] `cost per accepted change` as a first-class reported metric
|
package/bin/loops.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Thin launcher. Registers tsx's ESM loader globally so the CLI can transform a
|
|
3
3
|
// user's `.loop.ts` recipe from any repo (the run-from-anywhere contract), then
|
|
4
|
-
// hands off to the CLI.
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// hands off to the CLI. From a checkout the TypeScript source is the entry (the
|
|
5
|
+
// no-build-step dev path); a published install ships no `src`, so it falls back
|
|
6
|
+
// to the built `dist`. Source wins so a stale `dist` never shadows live code.
|
|
7
7
|
import { existsSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
9
9
|
import { dirname, join } from 'node:path';
|
|
@@ -11,6 +11,6 @@ import { register } from 'tsx/esm/api';
|
|
|
11
11
|
|
|
12
12
|
register();
|
|
13
13
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
const
|
|
15
|
-
const entry = existsSync(
|
|
14
|
+
const src = join(here, '..', 'src', 'index.ts');
|
|
15
|
+
const entry = existsSync(src) ? src : join(here, '..', 'dist', 'index.js');
|
|
16
16
|
await import(pathToFileURL(entry).href);
|
package/dist/api.d.ts
CHANGED
|
@@ -903,6 +903,12 @@ interface RunOptions {
|
|
|
903
903
|
recordTo?: string;
|
|
904
904
|
/** Snapshot the shared run state here at each loop/dag/job boundary. */
|
|
905
905
|
checkpoint?: string;
|
|
906
|
+
/**
|
|
907
|
+
* Register this run in the global registry (`~/.loops/runs/<runId>`) and write
|
|
908
|
+
* its live state there, so another process can `loops list` / `status` / `tail`
|
|
909
|
+
* it. Off by default — opt in to make a run observable from outside.
|
|
910
|
+
*/
|
|
911
|
+
supervise?: boolean;
|
|
906
912
|
/** Restore shared run state written by a prior `checkpoint` before starting. */
|
|
907
913
|
resumeFrom?: string;
|
|
908
914
|
/**
|
|
@@ -930,11 +936,74 @@ interface RunResult {
|
|
|
930
936
|
spent: number;
|
|
931
937
|
remaining: number;
|
|
932
938
|
};
|
|
939
|
+
/** The registry id, when the run was supervised. */
|
|
940
|
+
runId?: string;
|
|
933
941
|
}
|
|
934
942
|
declare function run(job: Job, options?: RunOptions): Promise<RunResult>;
|
|
935
943
|
/** Process exit code mapped from a terminal outcome. */
|
|
936
944
|
declare function exitCodeFor(outcome: Outcome): number;
|
|
937
945
|
|
|
946
|
+
/**
|
|
947
|
+
* Out-of-process supervision. A supervised run registers itself under a global
|
|
948
|
+
* registry (`~/.loops/runs/<runId>/`) and writes its live state there as it goes:
|
|
949
|
+
*
|
|
950
|
+
* - `status.json`: a snapshot rewritten at each boundary: the run's shape (the
|
|
951
|
+
* static `JobMeta`) plus where it is right now (path, iteration, last gate
|
|
952
|
+
* verdict and confidence, last outcome, token usage, terminal status at end).
|
|
953
|
+
* - `events.jsonl`: the event stream appended live (the same record `recordTo`
|
|
954
|
+
* writes, here automatically and in the registry).
|
|
955
|
+
*
|
|
956
|
+
* A separate process (a human `loops list/status/tail`, or an agent over MCP)
|
|
957
|
+
* reads those files. No daemon, no socket: the filesystem is the channel, which
|
|
958
|
+
* is the same "the workspace is the state" bet the rest of the library makes.
|
|
959
|
+
* Liveness is a pid check, so a crashed run is distinguishable from a live one.
|
|
960
|
+
*/
|
|
961
|
+
|
|
962
|
+
/** The registry root. `LOOPS_HOME` overrides `~/.loops` (used to isolate tests). */
|
|
963
|
+
declare function runsHome(): string;
|
|
964
|
+
interface RunLive {
|
|
965
|
+
path: string[];
|
|
966
|
+
iteration: number;
|
|
967
|
+
lastGate?: {
|
|
968
|
+
which: string;
|
|
969
|
+
met: boolean;
|
|
970
|
+
confidence?: number;
|
|
971
|
+
reason: string;
|
|
972
|
+
};
|
|
973
|
+
lastOutcome?: {
|
|
974
|
+
status: string;
|
|
975
|
+
summary?: string;
|
|
976
|
+
};
|
|
977
|
+
usage: {
|
|
978
|
+
inputTokens: number;
|
|
979
|
+
outputTokens: number;
|
|
980
|
+
calls: number;
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
interface RunStatus {
|
|
984
|
+
runId: string;
|
|
985
|
+
pid: number;
|
|
986
|
+
cwd: string;
|
|
987
|
+
title: string;
|
|
988
|
+
startedAt: number;
|
|
989
|
+
updatedAt: number;
|
|
990
|
+
endedAt?: number;
|
|
991
|
+
/** Stored disposition: `running` until the run ends, then the terminal status. */
|
|
992
|
+
status: 'running' | Outcome['status'];
|
|
993
|
+
/** Whether the owning process is still alive: computed on read, not stored. */
|
|
994
|
+
alive?: boolean;
|
|
995
|
+
shape?: JobMeta;
|
|
996
|
+
live: RunLive;
|
|
997
|
+
}
|
|
998
|
+
/** Read one run's status, with `alive` computed from its pid. */
|
|
999
|
+
declare function readRunStatus(runId: string): RunStatus | undefined;
|
|
1000
|
+
/** All known runs, newest first. */
|
|
1001
|
+
declare function listRuns(): RunStatus[];
|
|
1002
|
+
/** Path to a run's appended event stream (for tailing). */
|
|
1003
|
+
declare function runEventsPath(runId: string): string;
|
|
1004
|
+
/** A compact one-line rendering of an event, for `loops tail`. */
|
|
1005
|
+
declare function formatEvent(event: LoopEvent): string;
|
|
1006
|
+
|
|
938
1007
|
/**
|
|
939
1008
|
* Public API. A loop-definition file imports from here and `export default`s a
|
|
940
1009
|
* `Job` (usually a `loop(...)` or `dag(...)`). The CLI runs that default export.
|
|
@@ -946,4 +1015,4 @@ declare function exitCodeFor(outcome: Outcome): number;
|
|
|
946
1015
|
/** Identity helper that pins the type of a default export to `Job`. */
|
|
947
1016
|
declare function defineJob(job: Job): Job;
|
|
948
1017
|
|
|
949
|
-
export { type AgentCheckConfig, AgentDef, AgentRequest, AgentResult, BudgetConfig, type CommitInput, type CommitRecord, type CompactOptions, Condition, ConditionInput, type ConsolidateJobConfig, type ConsolidateOptions, DagConfig, EXIT_PAUSED, Engine, type EngineFactory, EngineName, EngineOptions, EngineRef, EngineRegistry, EnvHandle, Environment, Forge, type GroundOptions, type IsolatedOptions, Job, JobContext, JobMeta, type LedgerEntry, LimitPolicy, type LogQuery, LoopConfig, LoopEvent, type MergeJobConfig, type MergeResult, type MergeSynthesisConfig, type MergeSynthesisResult, MockEngine, type MockEnvOptions, MockEnvironment, type MockResponder, Outcome, type PromptNote, type PullRequestJobConfig, type PushJobConfig, type PushOptions, type PushResult, type RetrieveOptions, type RunOptions, type RunResult, Stats, type StatsSnapshot, type TournamentConfig, Usage, Workspace, type WorktreeHandle, addWorktree, agentCheck, all, always, any, appendLedger, appendPrompt, bodyPassed, commandSucceeds, commit, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, dag, defineJob, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, forgeChecks, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isRepo, isolated, jobMeta, ledgerPath, log, loop, mergeAbort, mergeBranch, mergeJob, mergeNoCommit, mergeSynthesis, minConfidence, mockVerdict, never, not, parallel, predicate, promptPath, pullRequestJob, push, pushJob, quorum, readLedger, readPrompt, removeWorktree, renderPlan, resetLedger, resetPrompt, retrieveLedger, run, sequence, stageAll, toCondition, tournament };
|
|
1018
|
+
export { type AgentCheckConfig, AgentDef, AgentRequest, AgentResult, BudgetConfig, type CommitInput, type CommitRecord, type CompactOptions, Condition, ConditionInput, type ConsolidateJobConfig, type ConsolidateOptions, DagConfig, EXIT_PAUSED, Engine, type EngineFactory, EngineName, EngineOptions, EngineRef, EngineRegistry, EnvHandle, Environment, Forge, type GroundOptions, type IsolatedOptions, Job, JobContext, JobMeta, type LedgerEntry, LimitPolicy, type LogQuery, LoopConfig, LoopEvent, type MergeJobConfig, type MergeResult, type MergeSynthesisConfig, type MergeSynthesisResult, MockEngine, type MockEnvOptions, MockEnvironment, type MockResponder, Outcome, type PromptNote, type PullRequestJobConfig, type PushJobConfig, type PushOptions, type PushResult, type RetrieveOptions, type RunLive, type RunOptions, type RunResult, type RunStatus, Stats, type StatsSnapshot, type TournamentConfig, Usage, Workspace, type WorktreeHandle, addWorktree, agentCheck, all, always, any, appendLedger, appendPrompt, bodyPassed, commandSucceeds, commit, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, dag, defineJob, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, forgeChecks, formatEvent, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isRepo, isolated, jobMeta, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeJob, mergeNoCommit, mergeSynthesis, minConfidence, mockVerdict, never, not, parallel, predicate, promptPath, pullRequestJob, push, pushJob, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, retrieveLedger, run, runEventsPath, runsHome, sequence, stageAll, toCondition, tournament };
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { mergeNoCommit, stageAll, commit, mergeAbort, log, setMeta, jobMeta, isRepo, addWorktree, childContext, composeCommitBody, mergeBranch, removeWorktree, deleteBranch, push, consolidate, toCondition, GhForge } from './chunk-
|
|
2
|
-
export { Budget, EXIT_PAUSED, EngineRegistry, GhForge, MockForge, Stats, addWorktree, agentCheck, agentJob, all, always, any, appendLedger, appendPrompt, bodyPassed, buildChecksArgs, buildCreateArgs, buildEditArgs, buildMergeArgs, buildViewArgs, commandSucceeds, commit, commitJob, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, defineAgent, defineSkill, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, fnJob, forgeChecks, fromFile, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isForge, isRepo, jobMeta, kickback, ledgerPath, log, loop, mergeAbort, mergeBranch, mergeNoCommit, minConfidence, never, not, predicate, promptPath, push, quorum, readLedger, readPrompt, removeWorktree, renderPlan, resetLedger, resetPrompt, resolveSystem, retrieveLedger, run, stageAll, toCondition } from './chunk-
|
|
1
|
+
import { mergeNoCommit, stageAll, commit, mergeAbort, log, setMeta, jobMeta, isRepo, addWorktree, childContext, composeCommitBody, mergeBranch, removeWorktree, deleteBranch, push, consolidate, toCondition, GhForge } from './chunk-6BDWTFOS.js';
|
|
2
|
+
export { Budget, EXIT_PAUSED, EngineRegistry, GhForge, MockForge, Stats, addWorktree, agentCheck, agentJob, all, always, any, appendLedger, appendPrompt, bodyPassed, buildChecksArgs, buildCreateArgs, buildEditArgs, buildMergeArgs, buildViewArgs, commandSucceeds, commit, commitJob, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, defineAgent, defineSkill, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, fnJob, forgeChecks, formatEvent, fromFile, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isForge, isRepo, jobMeta, kickback, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeNoCommit, minConfidence, never, not, predicate, promptPath, push, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, resolveSystem, retrieveLedger, run, runEventsPath, runsHome, stageAll, toCondition } from './chunk-6BDWTFOS.js';
|
|
3
3
|
import './chunk-JFTXJ7I2.js';
|
|
4
4
|
export { SUBAGENT_TOOLS, isEngine } from './chunk-XC46B4FD.js';
|
|
5
5
|
import './chunk-Y2SD7GBL.js';
|