autark-cli 0.5.5 → 0.5.7

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 (2) hide show
  1. package/autark.mjs +49 -6
  2. package/package.json +1 -1
package/autark.mjs CHANGED
@@ -517,7 +517,9 @@ async function refreshRuntimeFiles() {
517
517
  }
518
518
 
519
519
  async function refreshSkills() {
520
- const res = await spawnSync('pnpm', ['dlx', '--silent', 'skills', 'add', 'kiluazen/kstack', '-s', SKILL_NAMES.join(','), '-y', '-g'])
520
+ // skills CLI switched from `-s name,name` to positional `name name`.
521
+ // The old comma-separated form silently matches nothing.
522
+ const res = await spawnSync('pnpm', ['dlx', '--silent', 'skills', 'add', 'kiluazen/kstack', ...SKILL_NAMES, '-y', '-g'])
521
523
  if (res.status !== 0) throw new Error(`kstack skills install failed`)
522
524
  }
523
525
 
@@ -774,15 +776,31 @@ async function hypothesisPause(rest, status) {
774
776
  async function feedbackRecord(rest) {
775
777
  const opts = parseArgs(rest)
776
778
  const ref = opts.hypothesis || opts._[0]
779
+ const text = readValue(required(opts.text || opts.message || opts.body, '--text "<feedback>"'))
780
+
781
+ // --product-id (or a bare product slug with no /Hxx) → product-level feedback.
782
+ const productId = opts['product-id'] || opts.product_id
783
+ const isProductSlug = ref && !opts['hypothesis-id'] && !opts.hypothesis_id && !/\/H\d{2}$/.test(ref)
784
+ if (productId || isProductSlug) {
785
+ let pid = productId
786
+ if (!pid) {
787
+ const ctx = await api('GET', `/v1/context/${encodeURIComponent(ref)}`)
788
+ pid = ctx.product?.id
789
+ }
790
+ if (!pid) throw new Error('product not found')
791
+ const result = await api('POST', `/v1/products/${encodeURIComponent(pid)}/feedback`, { text })
792
+ console.log(result.id)
793
+ return
794
+ }
795
+
777
796
  let hypId = opts['hypothesis-id'] || opts.hypothesis_id
778
797
  if (!hypId) {
779
- if (!ref) throw new Error('pass product/Hxx or --hypothesis-id')
798
+ if (!ref) throw new Error('pass product, product/Hxx, --product-id, or --hypothesis-id')
780
799
  const [productSlug, code] = splitHypothesisRef(ref)
781
800
  const ctx = await api('GET', `/v1/context/${encodeURIComponent(productSlug)}/${encodeURIComponent(code)}`)
782
801
  hypId = ctx.hypothesis?.id
783
802
  }
784
803
  if (!hypId) throw new Error('hypothesis not found')
785
- const text = readValue(required(opts.text || opts.message || opts.body, '--text "<feedback>"'))
786
804
  const body = { text }
787
805
  if (opts['action-id'] || opts.action_id) body.action_id = opts['action-id'] || opts.action_id
788
806
  const result = await api('POST', `/v1/hypotheses/${encodeURIComponent(hypId)}/feedback`, body)
@@ -797,7 +815,8 @@ async function feedbackDelete(rest) {
797
815
  }
798
816
 
799
817
  function feedbackUsage() {
800
- console.log(`autark feedback record <product/Hxx> --text "<nudge>" [--action-id <id>]
818
+ console.log(`autark feedback record <product/Hxx> --text "<nudge>" [--action-id <id>] per-hypothesis nudge
819
+ autark feedback record <product> --text "<nudge>" product-level note (any hypothesis)
801
820
  autark feedback delete <feedback-id>`)
802
821
  }
803
822
 
@@ -884,7 +903,16 @@ async function mailLint(rest) {
884
903
  const compoundQ = /\b(are|is|do|does|did|will|would|can|could|should|have|has)\b[^?]{0,200}\bor\b[^?]{0,200}\?/i
885
904
  if (compoundQ.test(body)) violations.push({ rule: 'compound-question', detail: 'a/b question with "or"', why: WHY['compound-question'] })
886
905
  const sigSplit = body.split(/\n\s*\n(?:best|thanks|cheers|—|-)[\s,]*\n/i)[0] || body
887
- const len = sigSplit.trim().length
906
+ // Measure VISIBLE prose length, not raw markup. An <a href>/[text](url) signature
907
+ // anchor or any HTML wrapper must not eat into the 400-char content budget — only
908
+ // what the recipient actually reads counts.
909
+ const visibleText = sigSplit
910
+ .replace(/<a\b[^>]*>(.*?)<\/a>/gis, '$1') // <a ...>Kushal</a> -> Kushal
911
+ .replace(/\[([^\]]+)\]\(\s*https?:\/\/[^)]+\)/g, '$1') // [Kushal](url) -> Kushal
912
+ .replace(/<[^>]+>/g, '') // drop remaining html tags
913
+ .replace(/\s+/g, ' ') // collapse whitespace
914
+ .trim()
915
+ const len = visibleText.length
888
916
  if (len > 400) violations.push({ rule: 'too-long', detail: `${len} chars`, why: WHY['too-long'] })
889
917
  const hasMdAnchor = /\[[^\]]+\]\(https?:\/\/[^)]+\)/.test(body)
890
918
  const hasHtmlAnchor = /<a\b[^>]*href\s*=\s*["']https?:\/\/[^"']+["'][^>]*>[^<]+<\/a>/i.test(body)
@@ -1186,6 +1214,14 @@ function printProductContext(r) {
1186
1214
  kv('product.url', r.product.url)
1187
1215
  kv('product.visibility', r.product.visibility)
1188
1216
  kv('product.hypothesis_count', (r.hypotheses || []).length)
1217
+ // Product-level operator feedback (newest first). Append-only + timestamped,
1218
+ // so each entry is a distinct nudge — re-read these every run.
1219
+ kv('product.feedback_count', (r.feedback || []).length)
1220
+ for (const f of (r.feedback || [])) {
1221
+ const shortF = String(f.id || '').slice(0, 8)
1222
+ kv(`product.feedback.${shortF}.created_at`, f.created_at)
1223
+ kv(`product.feedback.${shortF}.text`, f.text)
1224
+ }
1189
1225
  for (const h of (r.hypotheses || [])) {
1190
1226
  kv(`hypothesis.${h.code}.id`, h.id)
1191
1227
  kv(`hypothesis.${h.code}.title`, h.title)
@@ -1207,6 +1243,13 @@ function printProductContext(r) {
1207
1243
  if (r.product.tagline) console.log(`> ${r.product.tagline}\n`)
1208
1244
  console.log(`## Brief\n`)
1209
1245
  console.log(r.product.brief?.trim() || '(no brief set — owner can add one at https://autark.sh)')
1246
+ if ((r.feedback || []).length > 0) {
1247
+ console.log(`\n## Operator feedback (${r.feedback.length}) — product-level, newest first\n`)
1248
+ console.log(`These are general operator nudges, not tied to one hypothesis. Treat the most recent as the freshest signal and let them re-shape your next move.\n`)
1249
+ for (const f of r.feedback) {
1250
+ console.log(`- (${f.created_at}) ${f.text}`)
1251
+ }
1252
+ }
1210
1253
  if (!r.hypotheses?.length) {
1211
1254
  console.log(`\n## Hypotheses\n\n(none yet — create one with: autark hypothesis create --product-id <product_id> --md @hyp.md)`)
1212
1255
  } else {
@@ -1469,7 +1512,7 @@ function usage() {
1469
1512
  run start|finish start / finish a run
1470
1513
  log action record one outreach touch
1471
1514
  action escalate flag an action for human attention
1472
- feedback record|delete leave a free-text nudge on a hypothesis
1515
+ feedback record|delete leave a free-text nudge on a hypothesis or product
1473
1516
  context [<slug>|...] pull product or hypothesis context
1474
1517
 
1475
1518
  mail setup|send|reply|... send/read mail via your AgentMail inbox
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autark-cli",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "CLI for autark \u2014 hypothesis-driven product runbooks. Track products, hypotheses, runs, and actions from the terminal.",
5
5
  "type": "module",
6
6
  "license": "MIT",