compound-agent 1.1.0 → 1.2.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/CHANGELOG.md +17 -1
- package/README.md +12 -0
- package/dist/cli.js +277 -3
- package/dist/cli.js.map +1 -1
- package/package.json +21 -12
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.2.0] - 2026-02-15
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`ca loop` command**: Generate autonomous infinity loop scripts that process beads epics end-to-end via chained Claude Code sessions
|
|
17
|
+
- **HUMAN_REQUIRED marker**: Loop detects human-blocking issues, logs reason to beads, skips epic without stopping the loop
|
|
18
|
+
- **Review+compound blocking tasks**: Plan phase now creates review and compound beads issues with dependencies, ensuring these phases survive context compaction and surface via `bd ready`
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **Loop script `set -u` crash**: `LOOP_DRY_RUN` now uses safe expansion (`${VAR:-}`) for `set -u` compatibility
|
|
23
|
+
- **Infinite reprocessing**: Loop tracks processed epics to prevent re-selecting the same epic in dry-run or human-required paths
|
|
24
|
+
- **Input validation**: `--max-retries` rejects non-integer values; epic IDs validated against safe pattern to prevent shell injection
|
|
25
|
+
- **Exit codes**: `ca loop` now returns non-zero on errors (overwrite refusal, invalid options)
|
|
26
|
+
|
|
12
27
|
## [1.1.0] - 2026-02-15
|
|
13
28
|
|
|
14
29
|
### Added
|
|
@@ -423,7 +438,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
423
438
|
- Vitest test suite
|
|
424
439
|
- tsup build configuration
|
|
425
440
|
|
|
426
|
-
[Unreleased]: https://github.com/Nathandela/learning_agent/compare/v1.
|
|
441
|
+
[Unreleased]: https://github.com/Nathandela/learning_agent/compare/v1.2.0...HEAD
|
|
442
|
+
[1.2.0]: https://github.com/Nathandela/learning_agent/compare/v1.1.0...v1.2.0
|
|
427
443
|
[1.1.0]: https://github.com/Nathandela/learning_agent/compare/v1.0.0...v1.1.0
|
|
428
444
|
[1.0.0]: https://github.com/Nathandela/learning_agent/compare/v0.2.9...v1.0.0
|
|
429
445
|
[0.2.9]: https://github.com/Nathandela/learning_agent/compare/v0.2.8...v0.2.9
|
package/README.md
CHANGED
|
@@ -170,6 +170,18 @@ The CLI binary is `ca` (alias: `compound-agent`).
|
|
|
170
170
|
| `ca rules check` | Run repository-defined rule checks |
|
|
171
171
|
| `ca test-summary` | Run tests and output a compact summary |
|
|
172
172
|
|
|
173
|
+
### Automation
|
|
174
|
+
|
|
175
|
+
| Command | Description |
|
|
176
|
+
|---------|-------------|
|
|
177
|
+
| `ca loop` | Generate infinity loop script for autonomous epic processing |
|
|
178
|
+
| `ca loop --epics <ids...>` | Target specific epic IDs |
|
|
179
|
+
| `ca loop -o <path>` | Custom output path (default: `./infinity-loop.sh`) |
|
|
180
|
+
| `ca loop --max-retries <n>` | Max retries per epic on failure (default: 1) |
|
|
181
|
+
| `ca loop --force` | Overwrite existing script |
|
|
182
|
+
|
|
183
|
+
Generated scripts detect three markers: `EPIC_COMPLETE` (success), `EPIC_FAILED` (retry then stop), `HUMAN_REQUIRED: <reason>` (skip and continue). Run with `LOOP_DRY_RUN=1` to preview.
|
|
184
|
+
|
|
173
185
|
### Setup
|
|
174
186
|
|
|
175
187
|
| Command | Description |
|
package/dist/cli.js
CHANGED
|
@@ -3,9 +3,9 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { getLlama, resolveModelFile } from 'node-llama-cpp';
|
|
4
4
|
import { mkdirSync, writeFileSync, statSync, existsSync, readFileSync, unlinkSync, chmodSync, readdirSync } from 'fs';
|
|
5
5
|
import { homedir } from 'os';
|
|
6
|
-
import { join, dirname, relative } from 'path';
|
|
6
|
+
import { join, dirname, resolve, relative } from 'path';
|
|
7
7
|
import * as fs from 'fs/promises';
|
|
8
|
-
import { readFile, mkdir, appendFile,
|
|
8
|
+
import { readFile, mkdir, appendFile, writeFile, chmod, rm, rename } from 'fs/promises';
|
|
9
9
|
import { createHash } from 'crypto';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { createRequire } from 'module';
|
|
@@ -2971,7 +2971,15 @@ Create a structured implementation plan enriched by semantic memory and existing
|
|
|
2971
2971
|
bd create --title="<task>" --type=task --priority=<1-4>
|
|
2972
2972
|
bd dep add <dependent-task> <blocking-task>
|
|
2973
2973
|
\`\`\`
|
|
2974
|
-
9.
|
|
2974
|
+
9. **Create review and compound blocking tasks** so they survive compaction:
|
|
2975
|
+
\`\`\`bash
|
|
2976
|
+
bd create --title="Review: /compound:review" --type=task --priority=1
|
|
2977
|
+
bd create --title="Compound: /compound:compound" --type=task --priority=1
|
|
2978
|
+
bd dep add <review-id> <last-work-task> # review depends on work
|
|
2979
|
+
bd dep add <compound-id> <review-id> # compound depends on review
|
|
2980
|
+
\`\`\`
|
|
2981
|
+
These tasks surface via \`bd ready\` after work completes, ensuring review and compound phases are never skipped \u2014 even after context compaction.
|
|
2982
|
+
10. Output the plan as a structured list with task IDs and dependency graph.
|
|
2975
2983
|
|
|
2976
2984
|
## Memory Integration
|
|
2977
2985
|
- Call \`memory_search\` before planning to learn from past approaches.
|
|
@@ -3168,6 +3176,7 @@ Chain all phases: brainstorm, plan, work, review, compound. End-to-end delivery.
|
|
|
3168
3176
|
- \`TeamCreate\` team "plan-<slug>", spawn docs-analyst + repo-analyst + memory-analyst as parallel teammates.
|
|
3169
3177
|
- Break into tasks with dependencies and acceptance criteria.
|
|
3170
3178
|
- Create beads issues with \`bd create\` and map dependencies with \`bd dep add\`.
|
|
3179
|
+
- Create review and compound blocking tasks (\`bd create\` + \`bd dep add\`) so they survive compaction and surface via \`bd ready\` after work completes.
|
|
3171
3180
|
- Shut down plan team before next phase.
|
|
3172
3181
|
|
|
3173
3182
|
3. **Work phase**: Implement with adaptive TDD.
|
|
@@ -3348,6 +3357,7 @@ Create a concrete implementation plan by decomposing work into small, testable t
|
|
|
3348
3357
|
7. Define acceptance criteria for each task
|
|
3349
3358
|
8. Map dependencies between tasks
|
|
3350
3359
|
9. Create beads issues: \`bd create --title="..." --type=task\`
|
|
3360
|
+
10. Create review and compound blocking tasks (\`bd create\` + \`bd dep add\`) that depend on work tasks \u2014 these survive compaction and surface via \`bd ready\` after work completes
|
|
3351
3361
|
|
|
3352
3362
|
## Memory Integration
|
|
3353
3363
|
- Call \`memory_search\` for patterns related to the feature area
|
|
@@ -5612,6 +5622,269 @@ function registerCaptureCommands(program2) {
|
|
|
5612
5622
|
await handleCapture(this, options);
|
|
5613
5623
|
});
|
|
5614
5624
|
}
|
|
5625
|
+
var EPIC_ID_PATTERN = /^[a-zA-Z0-9_.-]+$/;
|
|
5626
|
+
function buildScriptHeader(timestamp, maxRetries, model, epicIds) {
|
|
5627
|
+
return `#!/usr/bin/env bash
|
|
5628
|
+
# Infinity Loop - Generated by: ca loop
|
|
5629
|
+
# Date: ${timestamp}
|
|
5630
|
+
# Autonomously processes beads epics via Claude Code sessions.
|
|
5631
|
+
#
|
|
5632
|
+
# Usage:
|
|
5633
|
+
# ./infinity-loop.sh
|
|
5634
|
+
# LOOP_DRY_RUN=1 ./infinity-loop.sh # Preview without executing
|
|
5635
|
+
|
|
5636
|
+
set -euo pipefail
|
|
5637
|
+
|
|
5638
|
+
# Config
|
|
5639
|
+
MAX_RETRIES=${maxRetries}
|
|
5640
|
+
MODEL="${model}"
|
|
5641
|
+
EPIC_IDS="${epicIds}"
|
|
5642
|
+
LOG_DIR="agent_logs"
|
|
5643
|
+
|
|
5644
|
+
# Helpers
|
|
5645
|
+
timestamp() { date '+%Y-%m-%d_%H-%M-%S'; }
|
|
5646
|
+
log() { echo "[$(timestamp)] $*"; }
|
|
5647
|
+
die() { log "FATAL: $*"; exit 1; }
|
|
5648
|
+
|
|
5649
|
+
command -v python3 >/dev/null || die "python3 required for JSON parsing"
|
|
5650
|
+
command -v claude >/dev/null || die "claude CLI required"
|
|
5651
|
+
command -v bd >/dev/null || die "bd (beads) CLI required"
|
|
5652
|
+
|
|
5653
|
+
mkdir -p "$LOG_DIR"
|
|
5654
|
+
` + buildEpicSelector() + buildPromptFunction();
|
|
5655
|
+
}
|
|
5656
|
+
function buildEpicSelector() {
|
|
5657
|
+
return `
|
|
5658
|
+
get_next_epic() {
|
|
5659
|
+
if [ -n "$EPIC_IDS" ]; then
|
|
5660
|
+
# From explicit list, find first still-open epic not yet processed
|
|
5661
|
+
for epic_id in $EPIC_IDS; do
|
|
5662
|
+
case " $PROCESSED " in *" $epic_id "*) continue ;; esac
|
|
5663
|
+
local status
|
|
5664
|
+
status=$(bd show "$epic_id" --json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status',''))" 2>/dev/null || echo "")
|
|
5665
|
+
if [ "$status" = "open" ]; then
|
|
5666
|
+
echo "$epic_id"
|
|
5667
|
+
return 0
|
|
5668
|
+
fi
|
|
5669
|
+
done
|
|
5670
|
+
return 1
|
|
5671
|
+
else
|
|
5672
|
+
# Dynamic: get next ready epic from dependency graph, filtering processed
|
|
5673
|
+
local epic_id
|
|
5674
|
+
epic_id=$(bd list --type=epic --ready --json --limit=10 2>/dev/null | python3 -c "
|
|
5675
|
+
import sys,json
|
|
5676
|
+
processed = set('$PROCESSED'.split())
|
|
5677
|
+
items = json.load(sys.stdin)
|
|
5678
|
+
for item in items:
|
|
5679
|
+
if item['id'] not in processed:
|
|
5680
|
+
print(item['id'])
|
|
5681
|
+
break" 2>/dev/null || echo "")
|
|
5682
|
+
if [ -z "$epic_id" ]; then
|
|
5683
|
+
return 1
|
|
5684
|
+
fi
|
|
5685
|
+
echo "$epic_id"
|
|
5686
|
+
return 0
|
|
5687
|
+
fi
|
|
5688
|
+
}
|
|
5689
|
+
`;
|
|
5690
|
+
}
|
|
5691
|
+
function buildPromptFunction() {
|
|
5692
|
+
return `
|
|
5693
|
+
build_prompt() {
|
|
5694
|
+
local epic_id="$1"
|
|
5695
|
+
cat <<'PROMPT_HEADER'
|
|
5696
|
+
You are running in an autonomous infinity loop. Your task is to fully implement a beads epic.
|
|
5697
|
+
|
|
5698
|
+
## Step 1: Load context
|
|
5699
|
+
Run these commands to prime your session:
|
|
5700
|
+
PROMPT_HEADER
|
|
5701
|
+
cat <<PROMPT_BODY
|
|
5702
|
+
\\\`\\\`\\\`bash
|
|
5703
|
+
npx ca load-session
|
|
5704
|
+
bd show $epic_id
|
|
5705
|
+
\\\`\\\`\\\`
|
|
5706
|
+
|
|
5707
|
+
Read the epic details carefully. Understand scope, acceptance criteria, and sub-tasks.
|
|
5708
|
+
|
|
5709
|
+
## Step 2: Execute the workflow
|
|
5710
|
+
Run the full compound workflow for this epic, starting from the plan phase
|
|
5711
|
+
(brainstorm is already done -- the epic exists):
|
|
5712
|
+
|
|
5713
|
+
/compound:lfg from plan -- Epic: $epic_id
|
|
5714
|
+
|
|
5715
|
+
Work through all phases: plan, work, review, compound.
|
|
5716
|
+
|
|
5717
|
+
## Step 3: On completion
|
|
5718
|
+
When all work is done and tests pass:
|
|
5719
|
+
1. Close the epic: \`bd close $epic_id\`
|
|
5720
|
+
2. Sync beads: \`bd sync\`
|
|
5721
|
+
3. Commit and push all changes
|
|
5722
|
+
4. Output this exact marker on its own line:
|
|
5723
|
+
|
|
5724
|
+
EPIC_COMPLETE
|
|
5725
|
+
|
|
5726
|
+
## Step 4: On failure
|
|
5727
|
+
If you cannot complete the epic after reasonable effort:
|
|
5728
|
+
1. Add a note: \`bd update $epic_id --notes "Loop failed: <reason>"\`
|
|
5729
|
+
2. Output this exact marker on its own line:
|
|
5730
|
+
|
|
5731
|
+
EPIC_FAILED
|
|
5732
|
+
|
|
5733
|
+
## Step 5: On human required
|
|
5734
|
+
If you hit a blocker that REQUIRES human action (account creation, API keys,
|
|
5735
|
+
external service setup, design decisions you cannot make, etc.):
|
|
5736
|
+
1. Add a note: \`bd update $epic_id --notes "Human required: <reason>"\`
|
|
5737
|
+
2. Output this exact marker followed by a short reason on the SAME line:
|
|
5738
|
+
|
|
5739
|
+
HUMAN_REQUIRED: <reason>
|
|
5740
|
+
|
|
5741
|
+
Example: HUMAN_REQUIRED: Need AWS credentials configured in .env
|
|
5742
|
+
|
|
5743
|
+
## Rules
|
|
5744
|
+
- Do NOT ask questions -- there is no human. Make reasonable decisions.
|
|
5745
|
+
- Do NOT stop early -- complete the full workflow.
|
|
5746
|
+
- If tests fail, fix them. Retry up to 3 times before declaring failure.
|
|
5747
|
+
- Use HUMAN_REQUIRED only for true blockers that no amount of retrying can solve.
|
|
5748
|
+
- Commit incrementally as you make progress.
|
|
5749
|
+
PROMPT_BODY
|
|
5750
|
+
}`;
|
|
5751
|
+
}
|
|
5752
|
+
function buildMainLoop() {
|
|
5753
|
+
return `
|
|
5754
|
+
# Main loop
|
|
5755
|
+
COMPLETED=0
|
|
5756
|
+
FAILED=0
|
|
5757
|
+
SKIPPED=0
|
|
5758
|
+
PROCESSED=""
|
|
5759
|
+
|
|
5760
|
+
log "Infinity loop starting"
|
|
5761
|
+
log "Config: max_retries=$MAX_RETRIES model=$MODEL"
|
|
5762
|
+
[ -n "$EPIC_IDS" ] && log "Targeting epics: $EPIC_IDS" || log "Targeting: all ready epics"
|
|
5763
|
+
|
|
5764
|
+
while true; do
|
|
5765
|
+
EPIC_ID=$(get_next_epic) || break
|
|
5766
|
+
|
|
5767
|
+
log "Processing epic: $EPIC_ID"
|
|
5768
|
+
|
|
5769
|
+
ATTEMPT=0
|
|
5770
|
+
SUCCESS=false
|
|
5771
|
+
|
|
5772
|
+
while [ $ATTEMPT -le $MAX_RETRIES ]; do
|
|
5773
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
5774
|
+
LOGFILE="$LOG_DIR/loop_$EPIC_ID-$(timestamp).log"
|
|
5775
|
+
|
|
5776
|
+
log "Attempt $ATTEMPT/$((MAX_RETRIES + 1)) for $EPIC_ID (log: $LOGFILE)"
|
|
5777
|
+
|
|
5778
|
+
if [ -n "\${LOOP_DRY_RUN:-}" ]; then
|
|
5779
|
+
log "[DRY RUN] Would run claude session for $EPIC_ID"
|
|
5780
|
+
SUCCESS=true
|
|
5781
|
+
break
|
|
5782
|
+
fi
|
|
5783
|
+
|
|
5784
|
+
PROMPT=$(build_prompt "$EPIC_ID")
|
|
5785
|
+
|
|
5786
|
+
claude --dangerously-skip-permissions \\
|
|
5787
|
+
--model "$MODEL" \\
|
|
5788
|
+
-p "$PROMPT" \\
|
|
5789
|
+
&> "$LOGFILE" || true
|
|
5790
|
+
|
|
5791
|
+
if grep -q "EPIC_COMPLETE" "$LOGFILE"; then
|
|
5792
|
+
log "Epic $EPIC_ID completed successfully"
|
|
5793
|
+
SUCCESS=true
|
|
5794
|
+
break
|
|
5795
|
+
elif grep -q "HUMAN_REQUIRED" "$LOGFILE"; then
|
|
5796
|
+
REASON=$(grep "HUMAN_REQUIRED:" "$LOGFILE" | head -1 | sed 's/.*HUMAN_REQUIRED: *//')
|
|
5797
|
+
log "Epic $EPIC_ID needs human action: $REASON"
|
|
5798
|
+
bd update "$EPIC_ID" --notes "Human required: $REASON" 2>/dev/null || true
|
|
5799
|
+
SKIPPED=$((SKIPPED + 1))
|
|
5800
|
+
SUCCESS=skip
|
|
5801
|
+
break
|
|
5802
|
+
elif grep -q "EPIC_FAILED" "$LOGFILE"; then
|
|
5803
|
+
log "Epic $EPIC_ID reported failure (attempt $ATTEMPT)"
|
|
5804
|
+
else
|
|
5805
|
+
log "Epic $EPIC_ID session ended without marker (attempt $ATTEMPT)"
|
|
5806
|
+
fi
|
|
5807
|
+
|
|
5808
|
+
if [ $ATTEMPT -le $MAX_RETRIES ]; then
|
|
5809
|
+
log "Retrying $EPIC_ID..."
|
|
5810
|
+
sleep 5
|
|
5811
|
+
fi
|
|
5812
|
+
done
|
|
5813
|
+
|
|
5814
|
+
if [ "$SUCCESS" = true ]; then
|
|
5815
|
+
COMPLETED=$((COMPLETED + 1))
|
|
5816
|
+
log "Epic $EPIC_ID done. Completed so far: $COMPLETED"
|
|
5817
|
+
elif [ "$SUCCESS" = skip ]; then
|
|
5818
|
+
log "Epic $EPIC_ID skipped (human required). Continuing."
|
|
5819
|
+
else
|
|
5820
|
+
FAILED=$((FAILED + 1))
|
|
5821
|
+
log "Epic $EPIC_ID failed after $((MAX_RETRIES + 1)) attempts. Stopping loop."
|
|
5822
|
+
PROCESSED="$PROCESSED $EPIC_ID"
|
|
5823
|
+
break
|
|
5824
|
+
fi
|
|
5825
|
+
|
|
5826
|
+
PROCESSED="$PROCESSED $EPIC_ID"
|
|
5827
|
+
done
|
|
5828
|
+
|
|
5829
|
+
log "Loop finished. Completed: $COMPLETED, Failed: $FAILED, Skipped: $SKIPPED"
|
|
5830
|
+
[ $FAILED -eq 0 ] && exit 0 || exit 1`;
|
|
5831
|
+
}
|
|
5832
|
+
function validateOptions(options) {
|
|
5833
|
+
if (!Number.isInteger(options.maxRetries) || options.maxRetries < 0) {
|
|
5834
|
+
throw new Error(`Invalid maxRetries: must be a non-negative integer, got ${options.maxRetries}`);
|
|
5835
|
+
}
|
|
5836
|
+
if (options.epics) {
|
|
5837
|
+
for (const id of options.epics) {
|
|
5838
|
+
if (!EPIC_ID_PATTERN.test(id)) {
|
|
5839
|
+
throw new Error(`Invalid epic ID "${id}": must match ${EPIC_ID_PATTERN}`);
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
function generateLoopScript(options) {
|
|
5845
|
+
validateOptions(options);
|
|
5846
|
+
const epicIds = options.epics?.join(" ") ?? "";
|
|
5847
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
5848
|
+
return buildScriptHeader(timestamp, options.maxRetries, options.model, epicIds) + buildMainLoop();
|
|
5849
|
+
}
|
|
5850
|
+
async function handleLoop(cmd, options) {
|
|
5851
|
+
const outputPath = resolve(options.output ?? "./infinity-loop.sh");
|
|
5852
|
+
if (existsSync(outputPath) && !options.force) {
|
|
5853
|
+
out.error(`File already exists: ${outputPath}`);
|
|
5854
|
+
out.info("Use --force to overwrite");
|
|
5855
|
+
process.exitCode = 1;
|
|
5856
|
+
return;
|
|
5857
|
+
}
|
|
5858
|
+
const maxRetries = Number(options.maxRetries ?? 1);
|
|
5859
|
+
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
|
|
5860
|
+
out.error(`Invalid --max-retries: must be a non-negative integer, got "${options.maxRetries}"`);
|
|
5861
|
+
process.exitCode = 1;
|
|
5862
|
+
return;
|
|
5863
|
+
}
|
|
5864
|
+
let script;
|
|
5865
|
+
try {
|
|
5866
|
+
script = generateLoopScript({
|
|
5867
|
+
epics: options.epics,
|
|
5868
|
+
maxRetries,
|
|
5869
|
+
model: options.model ?? "claude-opus-4-6"
|
|
5870
|
+
});
|
|
5871
|
+
} catch (err) {
|
|
5872
|
+
out.error(err.message);
|
|
5873
|
+
process.exitCode = 1;
|
|
5874
|
+
return;
|
|
5875
|
+
}
|
|
5876
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
5877
|
+
await writeFile(outputPath, script, "utf-8");
|
|
5878
|
+
await chmod(outputPath, 493);
|
|
5879
|
+
out.success(`Generated infinity loop script: ${outputPath}`);
|
|
5880
|
+
out.info("Run it with: " + outputPath);
|
|
5881
|
+
out.info("Preview with: LOOP_DRY_RUN=1 " + outputPath);
|
|
5882
|
+
}
|
|
5883
|
+
function registerLoopCommands(program2) {
|
|
5884
|
+
program2.command("loop").description("Generate infinity loop script for epic tasks").option("--epics <ids...>", "Specific epic IDs to process").option("-o, --output <path>", "Output script path", "./infinity-loop.sh").option("--max-retries <n>", "Max retries per epic on failure", "1").option("--model <model>", "Claude model to use", "claude-opus-4-6").option("--force", "Overwrite existing script").action(async function(options) {
|
|
5885
|
+
await handleLoop(this, options);
|
|
5886
|
+
});
|
|
5887
|
+
}
|
|
5615
5888
|
function parseLimitOrExit(rawLimit, optionName, commandName) {
|
|
5616
5889
|
try {
|
|
5617
5890
|
return parseLimit(rawLimit, optionName);
|
|
@@ -5897,6 +6170,7 @@ registerRetrievalCommands(program);
|
|
|
5897
6170
|
registerManagementCommands(program);
|
|
5898
6171
|
registerSetupCommands(program);
|
|
5899
6172
|
registerCompoundCommands(program);
|
|
6173
|
+
registerLoopCommands(program);
|
|
5900
6174
|
program.parse();
|
|
5901
6175
|
//# sourceMappingURL=cli.js.map
|
|
5902
6176
|
//# sourceMappingURL=cli.js.map
|