@matthewfl/pi-jtodo 0.0.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/LICENSE +19 -0
- package/README.md +83 -0
- package/package.json +48 -0
- package/src/config.ts +71 -0
- package/src/constants.ts +78 -0
- package/src/gates.ts +771 -0
- package/src/index.ts +873 -0
- package/src/model.ts +155 -0
- package/src/normalize.ts +122 -0
- package/src/schema.ts +101 -0
- package/src/viewer.ts +136 -0
- package/src/watchdog.ts +71 -0
- package/src/widget.ts +378 -0
- package/tests/test-todo.cjs +1040 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @matthewfl/pi-jtodo
|
|
2
|
+
|
|
3
|
+
A quality-gated `todo` tool for the [pi](https://github.com/earendil-works/pi-coding-agent) coding agent.
|
|
4
|
+
|
|
5
|
+
Most harness todo tools are checklists: the agent writes items, ticks them off, and nothing checks that "completed" meant *verified*. pi-jtodo ports the todo quality machinery from the **jcode** harness — confidence scores with tool-owned histories, plan and per-goal assessments, write-time ownership rejection, and turn-end validation gates — and adds pi-native reliability, recovery, and display features on top.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pi install npm:@matthewfl/pi-jtodo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> Registers the `todo` tool. If you use another todo extension (e.g. `@juicesharp/rpiv-todo`), remove it first — two extensions registering `todo` collide.
|
|
12
|
+
|
|
13
|
+
## Inspiration and lineage
|
|
14
|
+
|
|
15
|
+
The todo-tool family tree, as verified from each implementation's source:
|
|
16
|
+
|
|
17
|
+
| | Claude Code `TodoWrite` | opencode `todowrite` | jcode `todo` | typical pi todo extensions | **pi-jtodo** |
|
|
18
|
+
|---|---|---|---|---|---|
|
|
19
|
+
| **Lineage** | invented the concept + usage prose (2025) | copied Claude's prose verbatim, added `priority` + `cancelled` | opencode's schema/semantics, none of the prose — plus the whole quality layer | lightweight list trackers | **jcode's quality layer, ported to pi** |
|
|
20
|
+
| **Item schema** | `content`, `status` (3 states), `activeForm` | + `priority`, `cancelled` | + required `id`, `group`, `confidence`, `completion_confidence` | `content`/`status`/`priority` | = jcode (plus field-merge updates) |
|
|
21
|
+
| **What enforces "done"?** | nothing — prose only | nothing — prose only | ownership gate rejects the write; turn-end completion/spike gates; deferred quality digest | nothing | **full port** + early-stop + watchdog |
|
|
22
|
+
| **Pokes the agent when it stops early?** | no | no | auto-poke cycle, `/poke` re-arm | no | **port** + re-arm on new work + starvation watchdog |
|
|
23
|
+
| **Survives reload / tree jumps / compaction?** | n/a (single turn) | yes (SQLite) | app state, lost across restarts | session state | **replayed from the branch log**, including gate flags |
|
|
24
|
+
| **Tells the agent what its write actually changed?** | no | no | plan/goal assessment diffs only | no | **item-level `Changes:` digest** (names removed ids, cleared groups) |
|
|
25
|
+
|
|
26
|
+
What each layer contributed, concretely:
|
|
27
|
+
|
|
28
|
+
- **Claude Code** — the TodoWrite concept and the "when to use / when not to use" prose manual (opencode's 2025 description was a word-for-word copy of it).
|
|
29
|
+
- **opencode** — `content`/`status`/`priority`, full-replace write semantics, and the full-list JSON echo.
|
|
30
|
+
- **jcode** — everything that makes the list *load-bearing*: model-supplied ids, groups, the two confidence scores with tool-owned append-only histories, the `plan`/`goals` assessment objects, the whole-write ownership rejection, the deferred quality digest, and the auto-poke cycle. jcode deliberately carries no system-prompt guidance and keeps its calibration thresholds out of model-visible text; pi-jtodo keeps both disciplines.
|
|
31
|
+
- **@juicesharp/rpiv-todo** — the compact above-editor list display this extension's widget is modeled on.
|
|
32
|
+
|
|
33
|
+
pi-specific additions (not in any of the above): branch-log recovery of todo state *and* gate cycle flags across `/reload`, `/tree` jumps, and compaction; re-arm on new work (pi has no poke hotkey); a starvation watchdog that re-pokes when a follow-up was lost; the unchanged-signature early stop that halts a gate loop when the agent's scores aren't moving; update-style field inheritance with a `Changes:` digest; and the enriched widget strip (per-item confidence tails, per-goal table, poke-target fingers).
|
|
34
|
+
|
|
35
|
+
Deliberately **not** ported from jcode: the `/overnight` mission mode (presumes a supervisor/manifest apparatus), the guardrail and credential circuit breakers (pi and pi-robust-provider own that territory), and jcode's `/poke` hotkey (replaced by `/todos poke`).
|
|
36
|
+
|
|
37
|
+
## How it behaves
|
|
38
|
+
|
|
39
|
+
- **Writes are replace-on-membership, merge-on-fields**: `todos` present = the new list (omitted ids are deleted); omit the array to read. On an existing id, omitted optional fields (`group`, `completion_confidence`) are inherited; `group: ""` clears. Accepted writes append `Changes: 2 updated; 1 new; removed #x; group cleared on #y`.
|
|
40
|
+
- **Plan and goals are field-merged**: `plan` carries `user_intention` + `understands_user_intent`; each goal (one per group) carries `closed_feedback_loop` + `feedback_loop` + `end_to_end_ownership`. Omitted groups/fields are retained. All four histories are tool-owned — model-supplied history values are discarded.
|
|
41
|
+
- **Write-time gate**: a write that closes a group (or the implicit ungrouped list) without an honest `end_to_end_ownership` claim is **rejected whole** — stored state is returned unchanged with an actionable message naming the failing groups. A first plan write with severely low intent gets an immediate in-band continuation.
|
|
42
|
+
- **Turn-end gates** (when the agent settles): incomplete todos → auto-poke ("You have N incomplete todos. Continue working, or update the todo tool."). Fully settled → the deferred quality digest (intent/feedback-loop weak points), then the completion-confidence and confidence-spike gates — each naming the flagged `#id`s — with an attempt budget, an unchanged-signature early stop, and a done notice when validation passes.
|
|
43
|
+
- **Follow-ups are attributed**: pokes, digests, and gate challenges travel as custom messages (LLM-visible as user-role text, transcript-visible as `pi-jtodo/followup`), so reload/resume never re-renders them as user prompts.
|
|
44
|
+
|
|
45
|
+
## Display
|
|
46
|
+
|
|
47
|
+
- **Above-editor strip**: intention header, value-ranked item lines (in_progress → pending → completed → cancelled) with status icons and `· conf N` tails, and a per-goal table (`Todo Goal | Settled | Conf | Own | Feedback`) with threshold-colored scores; `👉` marks the items that caused the most recent poke.
|
|
48
|
+
- **`/todos`** overlay: full list with plan, goals, and feedback-loop texts. `**/todos export**`, `**/todos clear**`, `**/todos poke on|off|status|trigger**`.
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
`~/.pi/agent/state/pi-jtodo/config.json` (all keys optional):
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"enabled": true,
|
|
57
|
+
"autoPoke": true,
|
|
58
|
+
"completionGateMaxAttempts": 5,
|
|
59
|
+
"maxGateObservations": 256,
|
|
60
|
+
"maxConsecutivePokesWithoutProgress": 0,
|
|
61
|
+
"idleNudge": true,
|
|
62
|
+
"idleNudgeAfterAssistantTurns": 50,
|
|
63
|
+
"watchdog": true,
|
|
64
|
+
"watchdogIdleMs": 90000,
|
|
65
|
+
"watchdogTickMs": 30000,
|
|
66
|
+
"watchdogMaxRePokes": 3,
|
|
67
|
+
"widgetMaxLines": 6
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Gate calibration (the 96/60/15 thresholds and the 5-attempt budget) is intentionally **not** configurable — jcode keeps its calibration private from the model, and a knob the agent can turn is a knob the agent will turn.
|
|
72
|
+
|
|
73
|
+
## Development
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
npm test # 34 tests: write-time gates (Suite A) + turn-end e2e via a scripted mock provider (Suite B)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Layout: `src/` (extension modules — `index.ts` is the entry), `tests/test-todo.cjs`.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT — see [LICENSE](./LICENSE).
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@matthewfl/pi-jtodo",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Quality-gated todo tool for Pi: confidence scores with tool-owned histories, plan and per-goal assessments, write-time ownership rejection, turn-end completion/spike gates, deferred quality digests, auto-poke continuation, starvation watchdog, and a live todo strip.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node tests/test-todo.cjs"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "matthewfl",
|
|
11
|
+
"homepage": "https://github.com/matthewfl/pi-plugins/tree/master/extensions/pi-jtodo",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/matthewfl/pi-plugins.git",
|
|
15
|
+
"directory": "extensions/pi-jtodo"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/matthewfl/pi-plugins/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"pi-package",
|
|
22
|
+
"pi-extension",
|
|
23
|
+
"todo",
|
|
24
|
+
"quality-gates",
|
|
25
|
+
"agent",
|
|
26
|
+
"planning"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"src",
|
|
30
|
+
"tests",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@earendil-works/pi-ai": "*",
|
|
39
|
+
"@earendil-works/pi-tui": "*",
|
|
40
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
41
|
+
"@sinclair/typebox": "*"
|
|
42
|
+
},
|
|
43
|
+
"pi": {
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./src/index.ts"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional per-user configuration: ~/.pi/agent/state/pi-jtodo/config.json
|
|
3
|
+
* Missing or unreadable config falls back to defaults. Gate thresholds are
|
|
4
|
+
* calibration constants (see constants.ts) and deliberately NOT configurable.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { MAX_GATE_OBSERVATIONS, TODO_COMPLETION_GATE_MAX_ATTEMPTS } from "./constants.js";
|
|
11
|
+
|
|
12
|
+
export interface TodoConfig {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
/** Arm the auto-poke cycle when each session starts (TUI/RPC only). */
|
|
15
|
+
autoPoke: boolean;
|
|
16
|
+
/** Turn-end re-validation budget before the gate stalls and disarms. */
|
|
17
|
+
completionGateMaxAttempts: number;
|
|
18
|
+
/** Cap on the turn-scoped observation log; oldest dropped first. */
|
|
19
|
+
maxGateObservations: number;
|
|
20
|
+
/**
|
|
21
|
+
* 0 = disabled (pure jcode: poke until the list settles). >0 disarms after
|
|
22
|
+
* N consecutive settles with no todo-state change (token-burn safety).
|
|
23
|
+
*/
|
|
24
|
+
maxConsecutivePokesWithoutProgress: number;
|
|
25
|
+
idleNudge: boolean;
|
|
26
|
+
idleNudgeAfterAssistantTurns: number;
|
|
27
|
+
/** Line budget for the above-editor todo widget (header included). */
|
|
28
|
+
widgetMaxLines: number;
|
|
29
|
+
/** Idle starvation watchdog: re-fire the poke when the agent sits idle
|
|
30
|
+
* with open todos (armed) longer than watchdogIdleMs. */
|
|
31
|
+
watchdog: boolean;
|
|
32
|
+
watchdogIdleMs: number;
|
|
33
|
+
watchdogTickMs: number;
|
|
34
|
+
/** Dead re-pokes without any activity before the cycle disarms. */
|
|
35
|
+
watchdogMaxRePokes: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_CONFIG: TodoConfig = {
|
|
39
|
+
enabled: true,
|
|
40
|
+
autoPoke: true,
|
|
41
|
+
completionGateMaxAttempts: TODO_COMPLETION_GATE_MAX_ATTEMPTS,
|
|
42
|
+
maxGateObservations: MAX_GATE_OBSERVATIONS,
|
|
43
|
+
maxConsecutivePokesWithoutProgress: 0,
|
|
44
|
+
idleNudge: true,
|
|
45
|
+
idleNudgeAfterAssistantTurns: 50,
|
|
46
|
+
widgetMaxLines: 6,
|
|
47
|
+
watchdog: true,
|
|
48
|
+
watchdogIdleMs: 90_000,
|
|
49
|
+
watchdogTickMs: 30_000,
|
|
50
|
+
watchdogMaxRePokes: 3,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export function loadConfig(): TodoConfig {
|
|
54
|
+
try {
|
|
55
|
+
const p = path.join(
|
|
56
|
+
os.homedir(),
|
|
57
|
+
".pi",
|
|
58
|
+
"agent",
|
|
59
|
+
"state",
|
|
60
|
+
"pi-jtodo",
|
|
61
|
+
"config.json",
|
|
62
|
+
);
|
|
63
|
+
const parsed = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
64
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
65
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// missing or unreadable config -> defaults
|
|
69
|
+
}
|
|
70
|
+
return { ...DEFAULT_CONFIG };
|
|
71
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants — thresholds and model-visible texts, verbatim from
|
|
3
|
+
* jcode-base/src/todo.rs. These are private calibration: never interpolate
|
|
4
|
+
* them into schema descriptions, continuations, digests, or notices, so the
|
|
5
|
+
* model cannot learn to target the evaluator instead of reporting honestly.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const TODO_TOOL_NAME = "todo";
|
|
9
|
+
|
|
10
|
+
/** Minimum passing score for 0-100 quality assessments. */
|
|
11
|
+
export const QUALITY_GATE_THRESHOLD = 96;
|
|
12
|
+
/** Goals scoring below this are considered open-loop. */
|
|
13
|
+
export const LOW_CLOSED_FEEDBACK_LOOP = QUALITY_GATE_THRESHOLD;
|
|
14
|
+
/** Below this the agent does not yet understand the user's intent. */
|
|
15
|
+
export const LOW_INTENT_UNDERSTANDING = QUALITY_GATE_THRESHOLD;
|
|
16
|
+
/**
|
|
17
|
+
* Below this score on the very first plan write the agent is admitting it
|
|
18
|
+
* does not know the task; worth one immediate nudge. Every other write-time
|
|
19
|
+
* check is deferred to the turn-end digest.
|
|
20
|
+
*/
|
|
21
|
+
export const SEVERE_INTENT_MISUNDERSTANDING = 60;
|
|
22
|
+
/** A completed todo whose final recorded confidence jump is at least this. */
|
|
23
|
+
export const TODO_CONFIDENCE_SPIKE = 15;
|
|
24
|
+
/** Turn-end re-validation budget before the gate gives up and disarms. */
|
|
25
|
+
export const TODO_COMPLETION_GATE_MAX_ATTEMPTS = 5;
|
|
26
|
+
/** Upper bound on retained turn-scoped observations; oldest dropped first. */
|
|
27
|
+
export const MAX_GATE_OBSERVATIONS = 256;
|
|
28
|
+
|
|
29
|
+
/** customType for all synthetic gate follow-ups (custom session messages). */
|
|
30
|
+
export const FOLLOWUP_CUSTOM_TYPE = "pi-jtodo/followup";
|
|
31
|
+
|
|
32
|
+
// Display-hidden session entries marking auto-poke arm/disarm transitions.
|
|
33
|
+
// The branch walker replays these so reload / tree navigation reset the
|
|
34
|
+
// gate cycle exactly where the live machine reset it — without them,
|
|
35
|
+
// transcript flags are monotone and a post-rearm reload would inherit the
|
|
36
|
+
// previous cycle's digestDelivered/spikeChallenged.
|
|
37
|
+
export const CYCLE_CUSTOM_TYPE = "pi-jtodo/cycle";
|
|
38
|
+
|
|
39
|
+
// ----------------------------------------------------------------------------
|
|
40
|
+
// Model-visible continuations — verbatim from jcode-base/src/todo.rs
|
|
41
|
+
// ----------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
/** Immediate nudge for a severely low first intent assessment (in-band). */
|
|
44
|
+
export const TODO_INTENT_UNDERSTANDING_CONTINUATION_MESSAGE =
|
|
45
|
+
"Your understanding of the user's intent is not high enough. Re-read the request and think harder about what the user actually wants and left implicit, using the conversation and codebase as evidence. Do not ask the user; resolve the ambiguity yourself, then update the plan's user intention and understands_user_intent.";
|
|
46
|
+
|
|
47
|
+
/** Ownership gate rejection. Names the field to raise and discloses the rejection. */
|
|
48
|
+
export const TODO_OWNERSHIP_CONTINUATION_MESSAGE =
|
|
49
|
+
"Your end-to-end ownership is not high enough to complete this goal. Take ownership of the full user outcome, not just the immediate implementation. Follow the work through every relevant integration and runtime path, resolve consequential gaps, validate the complete workflow, and finish the necessary follow-through. Then call the todo tool again, setting a higher `end_to_end_ownership` on the goal for this group; until that field is raised the write is rejected and the stored todo list is left unchanged.";
|
|
50
|
+
|
|
51
|
+
/** Turn-end completion-confidence gate. */
|
|
52
|
+
export const TODO_COMPLETION_CONTINUATION_MESSAGE =
|
|
53
|
+
"[automated todo completion gate - not a user message] Your completion confidence is missing or not high enough. Do not reply conversationally or wait for the user. Instead: Validate the completed result more thoroughly with concrete evidence, address any remaining issues, then call the todo tool again with updated completion_confidence values that reflect the validation you performed.";
|
|
54
|
+
|
|
55
|
+
/** Turn-end confidence-spike gate. */
|
|
56
|
+
export const TODO_CONFIDENCE_SPIKE_CONTINUATION_MESSAGE =
|
|
57
|
+
"[automated todo completion gate - not a user message] Your completion confidence rose too sharply to count as independently validated. Do not reply conversationally or wait for the user. Instead: recheck the completed result using concrete evidence, address any issues you find, then call the todo tool again with completion_confidence values that reflect the validation you performed.";
|
|
58
|
+
|
|
59
|
+
/** Turn-end digest header. Framed as "double-check", never a refusal. */
|
|
60
|
+
export const TODO_GATE_DIGEST_PREFIX =
|
|
61
|
+
"[automated todo quality review - not a user message] Before you treat this turn as finished, double-check the weak points it surfaced. Do not reply conversationally or wait for the user.";
|
|
62
|
+
|
|
63
|
+
// ----------------------------------------------------------------------------
|
|
64
|
+
// Display-only notices (jcode DisplayMessage::system strings; /poke adapted
|
|
65
|
+
// to /todos poke). Shown via ctx.ui.notify, never sent to the model.
|
|
66
|
+
// ----------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
export const NOTICE_POKE_OFF_HINT = "/todos poke off to stop.";
|
|
69
|
+
export const NOTICE_DIGEST_QUEUED =
|
|
70
|
+
"🔎 We asked the agent to double-check this turn's weak points.";
|
|
71
|
+
export const NOTICE_COMPLETION_CHALLENGED =
|
|
72
|
+
"🛑 The agent marked its work done without strong enough validation. We asked it to double-check.";
|
|
73
|
+
export const NOTICE_SPIKE_CHALLENGED =
|
|
74
|
+
"🛑 The agent's confidence jumped suddenly. We asked it to verify that independently.";
|
|
75
|
+
export const NOTICE_GATE_STALLED =
|
|
76
|
+
"⚠️ We nudged the agent several times but its validation still isn't holding up. We stopped poking; review the remaining todos yourself.";
|
|
77
|
+
export const NOTICE_GATE_UNCHANGED =
|
|
78
|
+
"⚠️ The agent re-validated but its completion confidence did not move, so further nudges would only repeat themselves. We stopped poking; review the completed todos yourself. /todos poke on to resume.";
|