ticlawk 0.1.17-dev.2 → 0.1.17-dev.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticlawk",
3
- "version": "0.1.17-dev.2",
3
+ "version": "0.1.17-dev.4",
4
4
  "description": "Local connector that links agent harnesses (Claude Code, Codex, OpenClaw, opencode, Pi) to the Ticlawk mobile app.",
5
5
  "type": "module",
6
6
  "main": "ticlawk.mjs",
@@ -15,9 +15,9 @@ import { buildEnvelopeTarget, buildCharterBlock } from './wake-prompt.mjs';
15
15
  const STEP_GUIDES = {
16
16
  gap_analysis: {
17
17
  title: 'GAP ANALYSIS',
18
- body: `Compare the current state of the work against the goal and success criteria. Read whatever you need (charter, dashboard, task board, repo, prior messages) to judge where things actually stand.
18
+ body: `Compare the current state of the work against the goal and success criteria. Read whatever you need (charter, dashboard, task board, repo, prior messages) to judge where things actually stand. The dashboard is the owner's at-a-glance visualization of how far this goal has progressed — this step owns keeping it true to reality: if a durable goal has no dashboard yet, create it (\`ticlawk dashboard set\`); if overall progress has moved materially, refresh its content/data. See SURFACES.md.
19
19
  - If there is concrete executable work toward the goal, first make sure the next unit exists as a task (create/assign it with \`ticlawk task ...\` when a task fits), then report outcome=gap.
20
- - If the goal/milestone is fully met with no meaningful gap, report outcome=no_gap.
20
+ - If the goal/milestone is fully met with no meaningful gap, make sure the dashboard reflects the completed state, publish a final-result briefing for the owner (\`ticlawk briefing publish --mode info\`), then report outcome=no_gap.
21
21
  - If closing the gap depends on a future or external state that nobody can act on right now, schedule a reminder for the resume condition, then report outcome=wait.`,
22
22
  outcomes: ['gap', 'no_gap', 'wait'],
23
23
  },
@@ -25,7 +25,7 @@ const STEP_GUIDES = {
25
25
  title: 'EXECUTE',
26
26
  body: `Do the next concrete unit of work toward the goal (or drive the current task to completion). Send interim updates with \`ticlawk message send --phase progress\` as you go.
27
27
  - When the unit of work is finished and ready to be checked, report outcome=task_completed.
28
- - If you cannot proceed without an owner approval, decision, or permission, park ONE canonical approval with \`ticlawk approval request --title "<what you need approved>" [--detail "<context>"]\`, tell the owner what you need and why with \`ticlawk message send\`, then report outcome=needs_approval. The owner's approval (button or a natural-language reply) resumes you automatically.
28
+ - If you cannot proceed without an owner approval, decision, or permission, park ONE canonical approval with \`ticlawk approval request --title "<what you need approved>" [--detail "<context>"]\`, surface the decision to the owner with a briefing (\`ticlawk briefing publish --mode approval\`) saying what you need and why, then report outcome=needs_approval. The owner's approval (button or a natural-language reply) resumes you automatically.
29
29
  - If you are blocked by something else (missing input, external failure, a needed resource), explain it to the owner, then report outcome=blocked.`,
30
30
  outcomes: ['task_completed', 'needs_approval', 'blocked'],
31
31
  },
@@ -77,7 +77,7 @@ export function buildGoalStepPrompt(msg) {
77
77
  `When the step is done, advance the state machine by running EXACTLY ONE report:`,
78
78
  ` ${reportCmd}`,
79
79
  ``,
80
- `Reporting the outcome is what continues the loop: a running next state arrives as a fresh step, and the loop parks itself when there is no gap or it must wait. Send owner-facing updates with \`ticlawk message send --target ${target} --phase progress\` (use --phase final only when the loop reaches no_gap/wait/blocked-on-owner). Report exactly once; do not loop inside this single turn.`,
80
+ `Reporting the outcome is what continues the loop: a running next state arrives as a fresh step, and the loop parks itself when there is no gap or it must wait. Reach the owner only through the surface this step names (\`ticlawk message send --target ${target}\` for chat, plus \`briefing publish\`/\`dashboard set\` where the step calls for them; see \`SURFACES.md\`). Any owner-facing text — chat, briefing, or dashboard — is for the owner in their language: say what changed, why it matters, and what (if anything) they must do; never expose internal task titles, file paths, step numbers, or harness tokens. Report exactly once; do not loop inside this single turn.`,
81
81
  `[/goal_step]`,
82
82
  ].join('\n'));
83
83
  } else {
@@ -31,7 +31,7 @@ Read other local files only when the current work clearly needs them.`;
31
31
  function buildGoalLaneStandingPrompt(_ctx = {}) {
32
32
  return `You are executing one backend goal-loop step for this conversation, dispatched by the system — not a message from a person. Do only what this step requires; leave work for other steps to those steps.
33
33
 
34
- Your normal output is private and reaches no one. When the step calls for an owner-facing update, send it with \`ticlawk message send --target <target> --phase progress|final\`. Read \`MEMORY.md\` only if the step needs durable context.`;
34
+ Your normal output is private and reaches no one. The owner is reached only through Ticlawk surfaces: \`ticlawk message send\` (chat update), \`ticlawk briefing publish\` (active notification/decision), \`ticlawk dashboard set\` (goal-level report). The step tells you which one to use; \`SURFACES.md\` holds the rules for each. Read \`SURFACES.md\` or \`MEMORY.md\` only if the step needs them.`;
35
35
  }
36
36
 
37
37
  function isGoalLane(ctx = {}) {
@@ -84,8 +84,23 @@ export function buildGroupContextBlock(msg) {
84
84
 
85
85
  export function buildCharterBlock(msg) {
86
86
  const charter = (msg.conversation_charter || '').trim();
87
- if (!charter) return '';
88
87
  const conversationId = msg.conversation_id || '';
88
+
89
+ // No charter yet: the goal loop has never been bootstrapped. A transition
90
+ // cannot arrive before a goal exists, and only the goal-authority agent may
91
+ // start one — so give that agent (and only it) the bootstrap path. Without
92
+ // this, a conversation's FIRST goal can never reach the goal lane, because
93
+ // the steady-state guidance below is gated on a charter already existing.
94
+ if (!charter) {
95
+ if (msg.reason === 'transition' || !hasGoalAuthority(msg)) return '';
96
+ return promptBlock(`
97
+ [conversation_goal]
98
+ This conversation has no goal charter yet, so the backend goal loop is not running.
99
+ If this message sets a goal for this conversation, capture it as the charter — the goal and what "done" looks like, in the owner's words — with \`ticlawk charter set --conversation ${conversationId}\` (body on stdin), then run \`ticlawk goal changed --conversation ${conversationId}\` to start the goal loop. Otherwise handle the message normally. See GOAL_AUTHORITY.md.
100
+ [/conversation_goal]
101
+ `);
102
+ }
103
+
89
104
  // The goal lane (transition deliveries) executes against the charter; its
90
105
  // per-step instructions come from the goal-step prompt, so here the charter
91
106
  // is just the goal/success spec. The chat lane must NOT run the loop — it