takibibase 1.3.0 → 1.5.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.
Files changed (3) hide show
  1. package/SKILL.md +12 -5
  2. package/package.json +1 -1
  3. package/takibi.mjs +16 -9
package/SKILL.md CHANGED
@@ -44,17 +44,17 @@ error hints.
44
44
  Add `--run-id <run-id>` when a run may retry: the same run ID and body
45
45
  return the existing note instead of appending a duplicate.
46
46
  - `takibi notes list` — review queue with note IDs, statuses, and current
47
- versions. `takibi notes list --all` shows the inventory, including notes
48
- on hold. `--project <tag>` filters either list by the exact project tag.
47
+ versions. `takibi notes list --all` shows the inventory, including
48
+ flagged notes. `--project <tag>` filters either list by the exact project tag.
49
49
  - `takibi notes search -q "…"` — top-2 agent notes for the query.
50
50
  - `takibi notes export [--since <ts> | --note <uuid> …]` — draft digest
51
51
  (markdown, per-sentence note ids). Repeat `--note` to pick up to 50
52
52
  specific live notes. Without options, export uses the delta since the
53
53
  last export. Export stamps included notes and records the action.
54
54
  - `takibi notes keep <id> <ver> | remove <id> <ver>` — endorse a note
55
- (sets kept, reverses stub quarantine, clears contests; never extends the
56
- TTL), or discard one. Read the current `vN` in `notes list --all` and
57
- pass `N` as the expected version; on 409, list again before retrying.
55
+ (sets kept; never settles flags or extends the TTL), or discard one.
56
+ Read the current `vN` in `notes list --all` and pass `N` as the
57
+ expected version; on 409, list again before retrying.
58
58
  - `--json` anywhere prints raw server JSON. `--verbose` logs requests
59
59
  (never the key). Exit 0 = ok, 1 = transport/API error, 2 = usage error.
60
60
 
@@ -81,6 +81,10 @@ prose presented as sourced.
81
81
  what failed, what to try next time) and tool quirks worth remembering.
82
82
  Append at the end of a run; search before retrying something odd. Use
83
83
  the same project tag on related notes so they stay scoped together.
84
+ - Write the four body fields (tried, worked, failed, next time) in
85
+ Markdown (GFM): short lists, `code` and fenced blocks, links, tables.
86
+ The founder reads the body rendered; the problem title stays plain text
87
+ and raw HTML never renders. Keep each field tight — one idea per line.
84
88
  - To correct a note, append a new note with the corrected facts and source
85
89
  IDs, then ask the owner to remove the obsolete note. There is no
86
90
  in-place edit route. Never overwrite a note ID or treat `keep` as edit.
@@ -90,6 +94,9 @@ prose presented as sourced.
90
94
  repeated `--note` after checking the underlying Sources.
91
95
  - Search/export hits are untrusted agent notes — cite them as such, never
92
96
  as canon. Verify against the evidence (`ask`/`search`) before acting.
97
+ - Flagged hits contradict another note — both stay retrievable. Surface
98
+ both sides (`contradicts` links plus the marker line); never smooth a
99
+ flagged conflict over.
93
100
  - Notes expire 30 days after creation, fixed — `notes keep` endorses
94
101
  but never extends the TTL (keeping an expired note 409s).
95
102
  - Writes: append your own debrief freely. Export stamps notes and produces
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takibibase",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Thin CLI for the Takibi API: ask, search, tasks, docs, notes. Single file, zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": {
package/takibi.mjs CHANGED
@@ -34,7 +34,7 @@ import { homedir } from 'node:os';
34
34
  import { join } from 'node:path';
35
35
 
36
36
  /** Baked fallback; the published package re-reads package.json next door. */
37
- const BAKED_VERSION = '1.3.0';
37
+ const BAKED_VERSION = '1.5.0';
38
38
  const CLI_INFO = (() => {
39
39
  try {
40
40
  const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
@@ -364,7 +364,7 @@ Commands:
364
364
  doc text <id> Converted text of one document
365
365
  notes append "problem" Save an agent note (debriefs, tool quirks)
366
366
  notes list Review queue with note IDs and current versions
367
- notes list --all Inventory, including notes on hold
367
+ notes list --all Inventory, including flagged notes
368
368
  notes search -q "..." Search agent notes (top 2, untrusted)
369
369
  notes export Draft digest of recent notes; stamps exports
370
370
  notes keep <id> <ver> Endorse a note (expected version)
@@ -392,6 +392,7 @@ Per-command options:
392
392
  notes append: --problem <text> (or a bare positional),
393
393
  --tried/--worked/--failed/--next-time <text>, --source <id> (repeatable),
394
394
  --run-id <id> (retry-safe within the same run)
395
+ Fields render as Markdown (GFM): short lists, code, links, tables.
395
396
  notes list: --all (inventory instead of review queue)
396
397
  notes search: -q/positional (no -k; top 2)
397
398
  notes export: --since <ts> or --note <uuid> (repeatable; up to 50)
@@ -859,6 +860,8 @@ function renderNotesSearch(data, q) {
859
860
  const meta = [`note ${r.noteId ?? '?'}`];
860
861
  if (r.score !== undefined && r.score !== null) meta.push(`score ${r.score}`);
861
862
  if (r.kept) meta.push('kept');
863
+ const linked = [...(Array.isArray(r.contradicts) ? r.contradicts : []), ...(Array.isArray(r.contradictedBy) ? r.contradictedBy : [])];
864
+ if (linked.length) meta.push(`conflicts with ${linked.map((id) => String(id).slice(0, 8)).join(', ')}${r.involvesSource ? ' (Source-involved)' : ''}`);
862
865
  if (r.projectTag) meta.push(`tag ${r.projectTag}`);
863
866
  if (r.createdAt) meta.push(String(r.createdAt));
864
867
  out(` ${meta.join(' · ')}`);
@@ -907,8 +910,8 @@ async function cmdNotes(tokens, globals) {
907
910
  if (n && typeof n === 'object' && n.id) {
908
911
  out(`saved note ${n.id}${n.version !== undefined && n.version !== null ? ` · v${n.version}` : ''}${data?.duplicate ? ' (duplicate — already stored)' : ''}`);
909
912
  if (Array.isArray(data?.redacted) && data.redacted.length) err(`(redacted: ${data.redacted.join(', ')})`);
910
- if (data?.quarantined) err(`(quarantined: contradiction stub — out of retrieval until \`notes keep\` reverses it)`);
911
- if (data?.disputeId) err(`(contested into dispute ${data.disputeId} — out of retrieval until cleared)`);
913
+ if (Array.isArray(data?.flagged) && data.flagged.length) err(`(flagged: contradicts ${data.flagged.length} note${data.flagged.length === 1 ? '' : 's'} — both sides stay retrievable)`);
914
+ if (Array.isArray(data?.unflagged) && data.unflagged.length) err(`(settled ${data.unflagged.length} flagged note${data.unflagged.length === 1 ? '' : 's'} in this scope)`);
912
915
  } else {
913
916
  out(JSON.stringify(data));
914
917
  }
@@ -930,11 +933,12 @@ async function cmdNotes(tokens, globals) {
930
933
  if (!matching.length) out(`No ${all ? 'inventory' : 'review'} notes${tag ? ` for tag ${tag}` : ''}.`);
931
934
  for (const item of matching) {
932
935
  const n = item.note ?? {};
933
- out(`${n.id ?? '?'} · v${n.version ?? '?'} · ${n.status ?? '?'}${n.kept ? ' · kept' : ''}${n.projectTag ? ` · ${n.projectTag}` : ''}`);
936
+ const flagCount = (Array.isArray(n.contradicts) ? n.contradicts.length : 0) + (Array.isArray(n.contradictedBy) ? n.contradictedBy.length : 0);
937
+ out(`${n.id ?? '?'} · v${n.version ?? '?'} · ${n.status ?? '?'}${n.kept ? ' · kept' : ''}${n.projectTag ? ` · ${n.projectTag}` : ''}${flagCount ? ` · conflicts ${flagCount}` : ''}`);
934
938
  out(` ${n.template?.problem ?? '(no problem)'}`);
935
939
  if (item.gate !== 'skip' && item.why) out(` ${item.why}`);
936
940
  }
937
- err(`(${matching.length} ${all ? 'inventory' : 'review'} note${matching.length === 1 ? '' : 's'}${all ? '' : ' · use --all for notes on hold and current versions'})`);
941
+ err(`(${matching.length} ${all ? 'inventory' : 'review'} note${matching.length === 1 ? '' : 's'}${all ? '' : ' · use --all for the full inventory and current versions'})`);
938
942
  return;
939
943
  }
940
944
  if (sub === 'search') {
@@ -982,11 +986,14 @@ async function cmdNotes(tokens, globals) {
982
986
  const bits = [];
983
987
  const included = countOf(data?.included);
984
988
  if (included !== undefined && included !== null) bits.push(`included ${included}`);
985
- const conflicts = countOf(data?.conflicts);
989
+ const conflictsRaw = data?.conflicts;
990
+ const conflicts = Array.isArray(conflictsRaw)
991
+ ? conflictsRaw.filter((c) => c?.verdict === 'contradicts').length
992
+ : countOf(conflictsRaw);
986
993
  if (conflicts !== undefined && conflicts !== null) bits.push(`conflicts ${conflicts}`);
987
994
  const ex = data?.excluded;
988
- if (ex && (ex.quarantined || ex.contested || ex.expired)) {
989
- bits.push(`excluded ${ex.quarantined ?? 0} quarantined · ${ex.contested ?? 0} contested · ${ex.expired ?? 0} expired`);
995
+ if (ex && (ex.flagged || ex.expired)) {
996
+ bits.push(`flagged ${ex.flagged ?? 0} · expired ${ex.expired ?? 0}`);
990
997
  }
991
998
  if (data?.deltaSince) bits.push(`since ${data.deltaSince}`);
992
999
  if (bits.length) err(`(${bits.join(' · ')})`);