@jkwd/inbase 0.1.13 → 0.1.16

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.
@@ -390,7 +390,6 @@ export function listAttachQueue(dataDir) {
390
390
  missing.push(sessionId)
391
391
  }
392
392
  }
393
- missing.reverse()
394
393
  const next = [...queued, ...missing]
395
394
  const unchanged =
396
395
  next.length === recorded.length &&
@@ -406,15 +405,11 @@ export function nextAttachSessionId(dataDir) {
406
405
  function enqueueAttachSession(dataDir, sessionId) {
407
406
  const safeId = assertSessionId(sessionId)
408
407
  const rest = listAttachQueue(dataDir).filter((id) => id !== safeId)
409
- writeAttachQueue(dataDir, [safeId, ...rest])
408
+ writeAttachQueue(dataDir, [...rest, safeId])
410
409
  }
411
410
 
412
- function sessionAllowsPlacement(manifest) {
413
- return (
414
- manifest.phase !== 'blueprint_ask' &&
415
- manifest.phase !== 'finished' &&
416
- manifest.phase !== 'stopped'
417
- )
411
+ function blueprintFile(dataDir) {
412
+ return path.join(dataDir, 'blueprint.json')
418
413
  }
419
414
 
420
415
  function blueprintHasContent(blueprint) {
@@ -423,7 +418,8 @@ function blueprintHasContent(blueprint) {
423
418
  (blueprint.userCreatedIslands?.length ?? 0) > 0 ||
424
419
  (blueprint.addedFunctions?.length ?? 0) > 0 ||
425
420
  (blueprint.addedVariables?.length ?? 0) > 0 ||
426
- (blueprint.addedImports?.length ?? 0) > 0
421
+ (blueprint.addedImports?.length ?? 0) > 0 ||
422
+ (blueprint.notes?.length ?? 0) > 0
427
423
  )
428
424
  }
429
425
 
@@ -660,8 +656,10 @@ export function sessionIntent(
660
656
  !isSessionConnected(dataDir, sessionId, waiterIds),
661
657
  listening: waiterIds.has(sessionId),
662
658
  lastAck: readSessionAck(dataDir, sessionId),
663
- creationMode: sessionAllowsPlacement(manifest),
659
+ creationMode: true,
664
660
  canEnterBlueprint,
661
+ blueprintHidden: Boolean(blueprint.hidden),
662
+ blueprintRevision: blueprint.revision,
665
663
  blueprintSessionId: null,
666
664
  userCreatedBlocks: blueprint.userCreatedBlocks,
667
665
  userCreatedIslands: blueprint.userCreatedIslands,
@@ -669,6 +667,7 @@ export function sessionIntent(
669
667
  blueprintFunctions: blueprint.addedFunctions,
670
668
  blueprintVariables: blueprint.addedVariables,
671
669
  blueprintImports: blueprint.addedImports,
670
+ blueprintNotes: blueprint.notes,
672
671
  }
673
672
  }
674
673
 
@@ -935,7 +934,6 @@ export function startSession(dataDir, input) {
935
934
  diffs: [],
936
935
  }
937
936
  writeManifest(dataDir, manifest)
938
- writeBlueprint(dataDir, sessionId, emptyBlueprint())
939
937
  focusSession(dataDir, sessionId)
940
938
  return manifest
941
939
  }
@@ -974,11 +972,6 @@ export function setupSession(dataDir, input = {}) {
974
972
  diffs: [],
975
973
  }
976
974
  writeManifest(dataDir, manifest)
977
- writeBlueprint(dataDir, sessionId, {
978
- ...emptyBlueprint(),
979
- enabled: true,
980
- sent: false,
981
- })
982
975
  focusSession(dataDir, sessionId)
983
976
  enqueueAttachSession(dataDir, sessionId)
984
977
  return manifest
@@ -1047,25 +1040,14 @@ export function answerBlueprint(dataDir, sessionId, enabled) {
1047
1040
  if (manifest.phase !== 'blueprint_ask') {
1048
1041
  throw new Error(`Session ${sessionId} is not asking for a blueprint`)
1049
1042
  }
1050
- const blueprint = {
1051
- ...emptyBlueprint(),
1052
- enabled: Boolean(enabled),
1053
- sent: !enabled,
1054
- }
1055
- writeBlueprint(dataDir, sessionId, blueprint)
1056
1043
  manifest.phase = enabled ? 'blueprint' : 'preparing'
1057
1044
  if (!enabled) manifest.workStartedAt = new Date().toISOString()
1058
1045
  writeManifest(dataDir, manifest)
1059
1046
  return manifest
1060
1047
  }
1061
1048
 
1062
- export function updateBlueprint(dataDir, sessionId, input = {}) {
1063
- const safeId = assertSessionId(sessionId)
1064
- const manifest = requireManifest(dataDir, safeId)
1065
- if (!sessionAllowsPlacement(manifest)) {
1066
- throw new Error(`Session ${safeId} is not accepting blueprint edits`)
1067
- }
1068
- const current = readBlueprint(dataDir, safeId)
1049
+ export function updateBlueprint(dataDir, _sessionId, input = {}) {
1050
+ const current = readBlueprint(dataDir)
1069
1051
  const next = {
1070
1052
  ...current,
1071
1053
  userCreatedBlocks: input.userCreatedBlocks ?? current.userCreatedBlocks,
@@ -1073,13 +1055,9 @@ export function updateBlueprint(dataDir, sessionId, input = {}) {
1073
1055
  addedFunctions: input.addedFunctions ?? current.addedFunctions,
1074
1056
  addedVariables: input.addedVariables ?? current.addedVariables,
1075
1057
  addedImports: input.addedImports ?? current.addedImports,
1058
+ notes: input.notes ?? current.notes,
1076
1059
  }
1077
- writeBlueprint(dataDir, safeId, {
1078
- ...next,
1079
- enabled: current.enabled || blueprintHasContent(next),
1080
- sent: manifest.phase === 'blueprint' ? false : current.sent,
1081
- })
1082
- return readBlueprint(dataDir, safeId)
1060
+ return writeBlueprint(dataDir, next)
1083
1061
  }
1084
1062
 
1085
1063
  export function sendBlueprint(dataDir, sessionId, input = {}) {
@@ -1088,19 +1066,16 @@ export function sendBlueprint(dataDir, sessionId, input = {}) {
1088
1066
  if (manifest.phase !== 'blueprint') {
1089
1067
  throw new Error(`Session ${safeId} is not in blueprint mode`)
1090
1068
  }
1091
- const current = readBlueprint(dataDir, safeId)
1092
- const next = {
1093
- userCreatedBlocks: input.userCreatedBlocks ?? current.userCreatedBlocks,
1094
- userCreatedIslands: input.userCreatedIslands ?? current.userCreatedIslands,
1095
- addedFunctions: input.addedFunctions ?? current.addedFunctions,
1096
- addedVariables: input.addedVariables ?? current.addedVariables,
1097
- addedImports: input.addedImports ?? current.addedImports,
1069
+ if (
1070
+ input.userCreatedBlocks ||
1071
+ input.userCreatedIslands ||
1072
+ input.addedFunctions ||
1073
+ input.addedVariables ||
1074
+ input.addedImports ||
1075
+ input.notes
1076
+ ) {
1077
+ updateBlueprint(dataDir, safeId, input)
1098
1078
  }
1099
- writeBlueprint(dataDir, safeId, {
1100
- ...next,
1101
- enabled: blueprintHasContent(next),
1102
- sent: true,
1103
- })
1104
1079
  manifest.phase = 'preparing'
1105
1080
  manifest.workStartedAt = new Date().toISOString()
1106
1081
  writeManifest(dataDir, manifest)
@@ -1114,12 +1089,6 @@ export function maybeStartVisualizerHandshake(dataDir, sessionId) {
1114
1089
  if (manifest.phase !== 'blueprint_ask' && manifest.phase !== 'blueprint') {
1115
1090
  return manifest
1116
1091
  }
1117
- const current = readBlueprint(dataDir, safeId)
1118
- writeBlueprint(dataDir, safeId, {
1119
- ...current,
1120
- enabled: blueprintHasContent(current),
1121
- sent: true,
1122
- })
1123
1092
  manifest.phase = 'preparing'
1124
1093
  manifest.workStartedAt = new Date().toISOString()
1125
1094
  writeManifest(dataDir, manifest)
@@ -1552,13 +1521,16 @@ export function finalizeFinishedSession(dataDir, sessionId) {
1552
1521
 
1553
1522
  export function emptyBlueprint() {
1554
1523
  return {
1524
+ hidden: false,
1525
+ revision: 0,
1555
1526
  enabled: false,
1556
- sent: false,
1527
+ sent: true,
1557
1528
  userCreatedBlocks: [],
1558
1529
  userCreatedIslands: [],
1559
1530
  addedFunctions: [],
1560
1531
  addedVariables: [],
1561
1532
  addedImports: [],
1533
+ notes: [],
1562
1534
  }
1563
1535
  }
1564
1536
 
@@ -1622,36 +1594,170 @@ function namedBlueprintImportAdditions(value) {
1622
1594
  })
1623
1595
  }
1624
1596
 
1625
- export function readBlueprint(dataDir, sessionId) {
1626
- const { blueprint } = sessionPaths(dataDir, sessionId)
1627
- const value = readJson(blueprint, emptyBlueprint())
1597
+ function namedBlueprintNotes(value) {
1598
+ if (!Array.isArray(value)) return []
1599
+ const seen = new Set()
1600
+ const notes = []
1601
+ for (const item of value) {
1602
+ if (!item || typeof item !== 'object') continue
1603
+ const file = typeof item.file === 'string' ? item.file.trim() : ''
1604
+ const note = typeof item.note === 'string' ? item.note : ''
1605
+ if (!file || !note.trim()) continue
1606
+ let stored = null
1607
+ if (item.kind === 'file') {
1608
+ stored = { file, kind: 'file', note }
1609
+ } else if (
1610
+ (item.kind === 'function' || item.kind === 'variable') &&
1611
+ typeof item.name === 'string' &&
1612
+ item.name.trim() !== ''
1613
+ ) {
1614
+ stored = { file, kind: item.kind, name: item.name.trim(), note }
1615
+ }
1616
+ if (!stored) continue
1617
+ const key =
1618
+ stored.kind === 'file'
1619
+ ? `file:${stored.file}`
1620
+ : `${stored.kind}:${stored.file}:${stored.name}`
1621
+ if (seen.has(key)) continue
1622
+ seen.add(key)
1623
+ notes.push(stored)
1624
+ }
1625
+ return notes
1626
+ }
1627
+
1628
+ function blueprintContentEqual(left, right) {
1629
+ return (
1630
+ JSON.stringify({
1631
+ userCreatedBlocks: left.userCreatedBlocks,
1632
+ userCreatedIslands: left.userCreatedIslands,
1633
+ addedFunctions: left.addedFunctions,
1634
+ addedVariables: left.addedVariables,
1635
+ addedImports: left.addedImports,
1636
+ notes: left.notes,
1637
+ }) ===
1638
+ JSON.stringify({
1639
+ userCreatedBlocks: right.userCreatedBlocks,
1640
+ userCreatedIslands: right.userCreatedIslands,
1641
+ addedFunctions: right.addedFunctions,
1642
+ addedVariables: right.addedVariables,
1643
+ addedImports: right.addedImports,
1644
+ notes: right.notes,
1645
+ })
1646
+ )
1647
+ }
1648
+
1649
+ function normalizeBlueprint(value) {
1650
+ const userCreatedBlocks = namedBlueprintBlocks(value?.userCreatedBlocks)
1651
+ const userCreatedIslands = namedBlueprintIslands(value?.userCreatedIslands)
1652
+ const addedFunctions = namedBlueprintSymbols(value?.addedFunctions)
1653
+ const addedVariables = namedBlueprintSymbols(value?.addedVariables)
1654
+ const addedImports = namedBlueprintImportAdditions(value?.addedImports)
1655
+ const notes = namedBlueprintNotes(value?.notes)
1656
+ const revision =
1657
+ Number.isInteger(value?.revision) && value.revision >= 0 ? value.revision : 0
1628
1658
  return {
1629
- enabled: Boolean(value?.enabled),
1630
- sent: Boolean(value?.sent),
1631
- userCreatedBlocks: namedBlueprintBlocks(value?.userCreatedBlocks),
1632
- userCreatedIslands: namedBlueprintIslands(value?.userCreatedIslands),
1633
- addedFunctions: namedBlueprintSymbols(value?.addedFunctions),
1634
- addedVariables: namedBlueprintSymbols(value?.addedVariables),
1635
- addedImports: namedBlueprintImportAdditions(value?.addedImports),
1659
+ hidden: Boolean(value?.hidden),
1660
+ revision,
1661
+ enabled: blueprintHasContent({
1662
+ userCreatedBlocks,
1663
+ userCreatedIslands,
1664
+ addedFunctions,
1665
+ addedVariables,
1666
+ addedImports,
1667
+ notes,
1668
+ }),
1669
+ sent: true,
1670
+ userCreatedBlocks,
1671
+ userCreatedIslands,
1672
+ addedFunctions,
1673
+ addedVariables,
1674
+ addedImports,
1675
+ notes,
1636
1676
  }
1637
1677
  }
1638
1678
 
1639
- export function writeBlueprint(dataDir, sessionId, blueprint) {
1640
- const paths = sessionPaths(dataDir, sessionId)
1679
+ export function readBlueprint(dataDir, _sessionId) {
1680
+ return normalizeBlueprint(readJson(blueprintFile(dataDir), emptyBlueprint()))
1681
+ }
1682
+
1683
+ export function writeBlueprint(dataDir, sessionIdOrBlueprint, maybeBlueprint) {
1684
+ const current = readBlueprint(dataDir)
1685
+ const incoming =
1686
+ maybeBlueprint === undefined ? sessionIdOrBlueprint : maybeBlueprint
1687
+ const next = normalizeBlueprint({
1688
+ ...current,
1689
+ ...incoming,
1690
+ hidden:
1691
+ incoming?.hidden !== undefined ? incoming.hidden : current.hidden,
1692
+ })
1693
+ if (!blueprintContentEqual(current, next)) {
1694
+ next.revision = current.revision + 1
1695
+ } else {
1696
+ next.revision = current.revision
1697
+ }
1698
+ next.enabled = blueprintHasContent(next)
1699
+ next.sent = true
1641
1700
  atomicWrite(
1642
- paths.blueprint,
1701
+ blueprintFile(dataDir),
1643
1702
  `${JSON.stringify(
1644
1703
  {
1645
- enabled: Boolean(blueprint.enabled),
1646
- sent: Boolean(blueprint.sent),
1647
- userCreatedBlocks: namedBlueprintBlocks(blueprint.userCreatedBlocks),
1648
- userCreatedIslands: namedBlueprintIslands(blueprint.userCreatedIslands),
1649
- addedFunctions: namedBlueprintSymbols(blueprint.addedFunctions),
1650
- addedVariables: namedBlueprintSymbols(blueprint.addedVariables),
1651
- addedImports: namedBlueprintImportAdditions(blueprint.addedImports),
1704
+ hidden: Boolean(next.hidden),
1705
+ revision: next.revision,
1706
+ enabled: next.enabled,
1707
+ sent: true,
1708
+ userCreatedBlocks: namedBlueprintBlocks(next.userCreatedBlocks),
1709
+ userCreatedIslands: namedBlueprintIslands(next.userCreatedIslands),
1710
+ addedFunctions: namedBlueprintSymbols(next.addedFunctions),
1711
+ addedVariables: namedBlueprintSymbols(next.addedVariables),
1712
+ addedImports: namedBlueprintImportAdditions(next.addedImports),
1713
+ notes: namedBlueprintNotes(next.notes),
1652
1714
  },
1653
1715
  null,
1654
1716
  2,
1655
1717
  )}\n`,
1656
1718
  )
1719
+ return readBlueprint(dataDir)
1720
+ }
1721
+
1722
+ export function setBlueprintHidden(dataDir, hidden) {
1723
+ return writeBlueprint(dataDir, { ...readBlueprint(dataDir), hidden: Boolean(hidden) })
1724
+ }
1725
+
1726
+ export function clearBlueprint(dataDir) {
1727
+ const current = readBlueprint(dataDir)
1728
+ return writeBlueprint(dataDir, {
1729
+ ...emptyBlueprint(),
1730
+ hidden: current.hidden,
1731
+ revision: current.revision,
1732
+ })
1733
+ }
1734
+
1735
+ export function cleanupBlueprint(dataDir, knownFileIds = [], knownFolderPaths = []) {
1736
+ const current = readBlueprint(dataDir)
1737
+ const files = new Set(knownFileIds)
1738
+ const folders = new Set(knownFolderPaths)
1739
+ const removedFiles = new Set(
1740
+ current.userCreatedBlocks.filter((block) => files.has(block.id)).map((block) => block.id),
1741
+ )
1742
+ const next = {
1743
+ ...current,
1744
+ userCreatedBlocks: current.userCreatedBlocks.filter((block) => !files.has(block.id)),
1745
+ userCreatedIslands: current.userCreatedIslands.filter(
1746
+ (island) => !folders.has(island.path),
1747
+ ),
1748
+ addedFunctions: current.addedFunctions.filter((item) => !removedFiles.has(item.file)),
1749
+ addedVariables: current.addedVariables.filter((item) => !removedFiles.has(item.file)),
1750
+ addedImports: current.addedImports.filter((item) => !removedFiles.has(item.file)),
1751
+ notes: current.notes.filter((item) => !removedFiles.has(item.file)),
1752
+ }
1753
+ return writeBlueprint(dataDir, next)
1754
+ }
1755
+
1756
+ export function markBlueprintSeen(dataDir, sessionId, revision) {
1757
+ const manifest = readManifest(dataDir, sessionId)
1758
+ if (!manifest) return null
1759
+ if (manifest.blueprintRevision === revision) return manifest
1760
+ manifest.blueprintRevision = revision
1761
+ writeManifest(dataDir, manifest)
1762
+ return manifest
1657
1763
  }