opencode-auto-loop 0.1.0 → 0.1.2

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.
@@ -4,27 +4,12 @@ description: Start Auto Loop - auto-continues until task completion
4
4
 
5
5
  # Auto Loop
6
6
 
7
- Start an iterative development loop that automatically continues until the task is complete.
7
+ Invoke the `auto-loop` tool with the following arguments:
8
8
 
9
- ## Setup
9
+ - **task**: $ARGUMENTS
10
+ - **maxIterations**: 100
10
11
 
11
- Create the state file in the project directory:
12
-
13
- ```bash
14
- mkdir -p .opencode && cat > .opencode/auto-loop.local.md << 'EOF'
15
- ---
16
- active: true
17
- iteration: 0
18
- maxIterations: 100
19
- ---
20
-
21
- $ARGUMENTS
22
- EOF
23
- ```
24
-
25
- ## Task
26
-
27
- Now begin working on the task: **$ARGUMENTS**
12
+ After the tool confirms the loop is active, **immediately begin working on the task**. Do not just acknowledge — start doing the work right away.
28
13
 
29
14
  ## Progress Tracking
30
15
 
@@ -38,15 +23,11 @@ Before going idle, you MUST output structured progress so the plugin knows where
38
23
  - [ ] What needs to be done next (in priority order)
39
24
  ```
40
25
 
41
- The plugin extracts these into the state file for the next iteration's continuation prompt.
42
-
43
26
  ## Completion
44
27
 
45
- When the task is FULLY completed, signal completion by outputting:
28
+ When the task is FULLY completed, signal completion by outputting the promise-DONE XML tag on its own line:
46
29
 
47
- ```
48
30
  <promise>DONE</promise>
49
- ```
50
31
 
51
32
  **IMPORTANT:** ONLY output this when the task is COMPLETELY and VERIFIABLY finished. Do NOT output false promises to escape the loop.
52
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-auto-loop",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Auto-continue for OpenCode",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -11,30 +11,19 @@ Start an iterative development loop that automatically continues until the task
11
11
 
12
12
  The Auto Loop creates a continuous feedback cycle for completing complex tasks:
13
13
 
14
- 1. You work on the task until you go idle
15
- 2. The plugin detects the idle state and checks for completion
16
- 3. If not complete, it extracts your progress and prompts you to continue
17
- 4. This repeats until you output the completion promise or max iterations reached
14
+ 1. You invoke the `auto-loop` tool, which creates the state file and starts the loop
15
+ 2. You work on the task until you go idle
16
+ 3. The plugin detects the idle state and checks for completion
17
+ 4. If not complete, it extracts your progress and prompts you to continue
18
+ 5. This repeats until you output the completion signal or max iterations reached
18
19
 
19
20
  Your previous work remains accessible through files, git history, and the state file's progress sections.
20
21
 
21
22
  ## Starting the Loop
22
23
 
23
- When you invoke this skill, create the state file in the project directory:
24
+ **Always use the `auto-loop` tool** to start the loop. Do NOT create the state file manually. The tool handles state file creation, session tracking, and initialization.
24
25
 
25
- ```bash
26
- mkdir -p .opencode && cat > .opencode/auto-loop.local.md << 'EOF'
27
- ---
28
- active: true
29
- iteration: 0
30
- maxIterations: 100
31
- ---
32
-
33
- [The user's task prompt goes here]
34
- EOF
35
- ```
36
-
37
- Then inform the user and begin working on the task.
26
+ After the tool confirms the loop is active, **immediately begin working on the task**. Do not just acknowledge — start doing the work.
38
27
 
39
28
  ## Progress Tracking - CRITICAL
40
29
 
@@ -61,9 +50,9 @@ Use this format in your final message of each iteration:
61
50
  - Order ## Next Steps by priority — the continuation will tell you to start from the top
62
51
  - The plugin extracts these sections and writes them into `auto-loop.local.md` for the next iteration
63
52
 
64
- ## Completion Promise - CRITICAL RULES
53
+ ## Completion Signal - CRITICAL RULES
65
54
 
66
- When you have FULLY completed the task, signal completion by outputting:
55
+ When you have FULLY completed the task, signal completion by outputting the promise-DONE XML tag on its own line:
67
56
 
68
57
  ```
69
58
  <promise>DONE</promise>
@@ -71,14 +60,14 @@ When you have FULLY completed the task, signal completion by outputting:
71
60
 
72
61
  **IMPORTANT CONSTRAINTS:**
73
62
 
74
- - ONLY output `<promise>DONE</promise>` when the task is COMPLETELY and VERIFIABLY finished
75
- - The statement MUST be completely and unequivocally TRUE
76
- - Do NOT output false promises to escape the loop, even if you think you're stuck
77
- - Do NOT lie even if you think you should exit for other reasons
63
+ - ONLY output the completion signal when the task is COMPLETELY and VERIFIABLY finished
64
+ - The completion tag MUST be on its own line (not inline with other text)
65
+ - Do NOT mention or echo the completion tag in explanatory text only output it as the actual signal
66
+ - Do NOT output false completion signals to escape the loop, even if you think you're stuck
78
67
  - If you're blocked, explain the blocker and request help instead of falsely completing
79
68
 
80
69
  The loop can only be stopped by:
81
- 1. Truthful completion promise
70
+ 1. Truthful completion signal
82
71
  2. Max iterations reached
83
72
  3. User running `/cancel-auto-loop`
84
73
 
package/src/index.ts CHANGED
@@ -30,7 +30,7 @@ type OpencodeClient = PluginInput["client"];
30
30
  const SERVICE_NAME = "auto-loop";
31
31
  const STATE_FILENAME = "auto-loop.local.md";
32
32
  const OPENCODE_CONFIG_DIR = join(homedir(), ".config/opencode");
33
- const COMPLETION_TAG = /<promise>\s*DONE\s*<\/promise>/is;
33
+ const COMPLETION_TAG = /^\s*<promise>\s*DONE\s*<\/promise>\s*$/im;
34
34
  const DEBOUNCE_MS = 2000;
35
35
 
36
36
  // Get plugin root directory (ESM only — package is "type": "module")
@@ -52,11 +52,13 @@ function copyIfChanged(src: string, dest: string): void {
52
52
  cpSync(src, dest, { recursive: true });
53
53
  }
54
54
 
55
- // Auto-copy skills and commands to opencode config, updating if content changed
56
- function setupSkillsAndCommands(log: LogFn): void {
55
+ // Auto-copy skills and commands to opencode config, updating if content changed.
56
+ // Returns true if any new files were copied (first install), false otherwise.
57
+ function setupSkillsAndCommands(log: LogFn): boolean {
57
58
  const pluginRoot = getPluginRoot();
58
59
  const skillsDir = join(OPENCODE_CONFIG_DIR, "skill");
59
60
  const commandsDir = join(OPENCODE_CONFIG_DIR, "command");
61
+ let newFilesCopied = false;
60
62
 
61
63
  // Copy skills
62
64
  const pluginSkillsDir = join(pluginRoot, "skills");
@@ -65,8 +67,10 @@ function setupSkillsAndCommands(log: LogFn): void {
65
67
  for (const skill of skills) {
66
68
  const srcFile = join(pluginSkillsDir, skill, "SKILL.md");
67
69
  const destFile = join(skillsDir, skill, "SKILL.md");
70
+ const isNew = !existsSync(destFile);
68
71
  try {
69
72
  copyIfChanged(srcFile, destFile);
73
+ if (isNew && existsSync(destFile)) newFilesCopied = true;
70
74
  } catch (err) {
71
75
  log("warn", `Failed to copy skill '${skill}': ${err}`);
72
76
  }
@@ -78,13 +82,18 @@ function setupSkillsAndCommands(log: LogFn): void {
78
82
  if (existsSync(pluginCommandsDir)) {
79
83
  const commands = ["auto-loop.md", "cancel-auto-loop.md", "auto-loop-help.md"];
80
84
  for (const cmd of commands) {
85
+ const destCmd = join(commandsDir, cmd);
86
+ const isNew = !existsSync(destCmd);
81
87
  try {
82
- copyIfChanged(join(pluginCommandsDir, cmd), join(commandsDir, cmd));
88
+ copyIfChanged(join(pluginCommandsDir, cmd), destCmd);
89
+ if (isNew && existsSync(destCmd)) newFilesCopied = true;
83
90
  } catch (err) {
84
91
  log("warn", `Failed to copy command '${cmd}': ${err}`);
85
92
  }
86
93
  }
87
94
  }
95
+
96
+ return newFilesCopied;
88
97
  }
89
98
 
90
99
  // Get state file path (project-relative)
@@ -182,9 +191,11 @@ function clearState(directory: string, log: LogFn): void {
182
191
  }
183
192
  }
184
193
 
185
- // Strip markdown code fences before checking for completion tag
194
+ // Strip markdown code fences and inline code before checking for completion tag
186
195
  function stripCodeFences(text: string): string {
187
- return text.replace(/```[\s\S]*?```/g, "");
196
+ return text
197
+ .replace(/```[\s\S]*?```/g, "") // triple-backtick blocks
198
+ .replace(/`[^`]+`/g, ""); // inline backtick code
188
199
  }
189
200
 
190
201
  // Extract text from the last assistant message in a session
@@ -366,8 +377,12 @@ export const AutoLoopPlugin: Plugin = async (ctx) => {
366
377
  }
367
378
  };
368
379
 
369
- // Auto-setup skills and commands
370
- setupSkillsAndCommands(log);
380
+ // Auto-setup skills and commands — notify on first install
381
+ const isFirstInstall = setupSkillsAndCommands(log);
382
+ if (isFirstInstall) {
383
+ toast("Auto Loop installed — restart opencode to enable /auto-loop commands", "warning");
384
+ log("info", "First install detected — commands copied, restart needed for slash commands");
385
+ }
371
386
 
372
387
  // Debounce tracking for idle events
373
388
  let lastContinuation = 0;
@@ -403,7 +418,9 @@ export const AutoLoopPlugin: Plugin = async (ctx) => {
403
418
 
404
419
  Task: ${task}
405
420
 
406
- I will auto-continue until the task is complete. Before going idle each iteration, I will output structured progress:
421
+ **Begin working on the task now.** The loop will auto-continue until you signal completion.
422
+
423
+ Before going idle each iteration, output structured progress:
407
424
 
408
425
  \`\`\`
409
426
  ## Completed
@@ -413,7 +430,7 @@ I will auto-continue until the task is complete. Before going idle each iteratio
413
430
  - [ ] What remains (in priority order)
414
431
  \`\`\`
415
432
 
416
- When fully done, I will output \`<promise>DONE</promise>\` to signal completion.
433
+ When the task is FULLY and VERIFIABLY complete, output the completion signal on its own line (the promise-DONE XML tag). Do NOT mention or echo the completion tag until you are truly done.
417
434
 
418
435
  Use /cancel-auto-loop to stop early.`;
419
436
  },
@@ -480,7 +497,9 @@ Located at: .opencode/auto-loop.local.md`;
480
497
  // Fetch last assistant message (used for completion check + progress extraction)
481
498
  const lastText = await getLastAssistantText(client, sessionId, directory, log);
482
499
 
483
- if (lastText && checkCompletion(lastText)) {
500
+ // Skip completion check on iteration 0 (first idle after loop start)
501
+ // to avoid false positives from the tool's initial response text
502
+ if (state.iteration > 0 && lastText && checkCompletion(lastText)) {
484
503
  clearState(directory, log);
485
504
  log("info", `Loop completed at iteration ${state.iteration}`);
486
505
  toast(`Auto Loop completed after ${state.iteration} iteration(s)`, "success");