@jkwd/inbase 0.1.21 → 0.1.23

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 (58) hide show
  1. package/README.md +13 -7
  2. package/apps/explorer/package.json +1 -0
  3. package/apps/explorer/scripts/explain-store.d.ts +135 -0
  4. package/apps/explorer/scripts/explain-store.mjs +666 -0
  5. package/apps/explorer/scripts/patch-lib.mjs +4 -0
  6. package/apps/explorer/scripts/scan-target.mjs +22 -5
  7. package/apps/explorer/scripts/session-store.d.ts +86 -11
  8. package/apps/explorer/scripts/session-store.mjs +371 -58
  9. package/apps/explorer/scripts/target-config.d.ts +38 -3
  10. package/apps/explorer/scripts/target-config.mjs +147 -3
  11. package/apps/explorer/src/App.tsx +1073 -158
  12. package/apps/explorer/src/agentIntent.ts +61 -7
  13. package/apps/explorer/src/codebase.ts +1 -1
  14. package/apps/explorer/src/devTargets.ts +66 -0
  15. package/apps/explorer/src/explain.ts +312 -0
  16. package/apps/explorer/src/index.css +874 -222
  17. package/apps/explorer/src/layout.ts +55 -0
  18. package/apps/explorer/src/scene/DistantFileBlocks.tsx +4 -2
  19. package/apps/explorer/src/scene/FileBlock.tsx +95 -72
  20. package/apps/explorer/src/scene/FolderArea.tsx +55 -32
  21. package/apps/explorer/src/scene/MapView.tsx +506 -33
  22. package/apps/explorer/src/scene/RelationLines.tsx +7 -0
  23. package/apps/explorer/src/scene/World.tsx +146 -32
  24. package/apps/explorer/src/speech.ts +228 -0
  25. package/apps/explorer/src/theme.ts +29 -0
  26. package/apps/explorer/src/types.ts +98 -8
  27. package/apps/explorer/src/ui/CanvasErrorBoundary.tsx +1 -1
  28. package/apps/explorer/src/ui/ExplainAskCard.tsx +142 -0
  29. package/apps/explorer/src/ui/ExplainHud.tsx +524 -0
  30. package/apps/explorer/src/ui/ExplainInfoPanel.tsx +135 -0
  31. package/apps/explorer/src/ui/ExplainPointer.tsx +73 -0
  32. package/apps/explorer/src/ui/EyeIcon.tsx +38 -1
  33. package/apps/explorer/src/ui/HUD.tsx +1067 -795
  34. package/apps/explorer/src/ui/NameInput.tsx +114 -5
  35. package/apps/explorer/src/userContext.ts +0 -11
  36. package/apps/explorer/src/userCreated.ts +54 -1
  37. package/apps/explorer/vite.config.ts +173 -26
  38. package/bin/inbase.mjs +11 -2
  39. package/bin/project.mjs +6 -4
  40. package/bin/session.mjs +287 -38
  41. package/package.json +4 -1
  42. package/skill/commands/amber.md +23 -0
  43. package/skill/commands/blue.md +13 -0
  44. package/skill/commands/coral.md +23 -0
  45. package/skill/commands/explain.md +77 -0
  46. package/skill/commands/green.md +23 -0
  47. package/skill/commands/inbase.md +7 -5
  48. package/skill/commands/lime.md +23 -0
  49. package/skill/commands/orange.md +23 -0
  50. package/skill/commands/purple.md +23 -0
  51. package/skill/commands/red.md +23 -0
  52. package/skill/commands/skipinbase.md +1 -1
  53. package/skill/commands/violet.md +23 -0
  54. package/skill/commands/yellow.md +23 -0
  55. package/skill/inbase/SKILL.md +124 -76
  56. package/apps/explorer/src/scene/BlockPlacer.tsx +0 -78
  57. package/apps/explorer/src/scene/IslandPlacer.tsx +0 -31
  58. package/apps/explorer/src/scene/SelectionThumbnail.tsx +0 -1069
@@ -1,11 +1,16 @@
1
+ import fs from 'node:fs'
1
2
  import path from 'node:path'
2
3
  import { fileURLToPath } from 'node:url'
3
4
 
4
5
  const here = path.dirname(fileURLToPath(import.meta.url))
5
6
  const explorerRoot = path.resolve(here, '..')
6
7
  const repoRoot = path.resolve(explorerRoot, '../..')
8
+ const appsDir = path.resolve(explorerRoot, '..')
7
9
  const defaultTargetRoot = path.resolve(explorerRoot, '../example-target')
8
10
  const defaultDataDir = path.resolve(explorerRoot, 'src/data')
11
+ const DEV_TARGET_FILE = 'dev-target.json'
12
+ const EXPLORER_APP_NAME = 'explorer'
13
+ const REPO_TARGET_ID = 'repo'
9
14
 
10
15
  export function resolvePathValue(value, fallback) {
11
16
  const raw = value?.trim()
@@ -21,9 +26,122 @@ export function resolveDataDir(value = process.env.INBASE_DATA_DIR) {
21
26
  return resolvePathValue(value, defaultDataDir)
22
27
  }
23
28
 
24
- export const targetRoot = resolveTargetRoot()
25
29
  export const dataDir = resolveDataDir()
26
- export const targetName = path.basename(targetRoot)
30
+
31
+ function samePath(left, right) {
32
+ return path.resolve(left) === path.resolve(right)
33
+ }
34
+
35
+ function labelFromFolderName(name) {
36
+ if (name === 'example-target') return 'Example target'
37
+ return name
38
+ .split(/[-_]/)
39
+ .filter(Boolean)
40
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
41
+ .join(' ')
42
+ }
43
+
44
+ export function persistedTargetFile(dir = dataDir) {
45
+ return path.join(dir, DEV_TARGET_FILE)
46
+ }
47
+
48
+ export function readPersistedTargetId(dir = dataDir) {
49
+ try {
50
+ const parsed = JSON.parse(fs.readFileSync(persistedTargetFile(dir), 'utf8'))
51
+ return typeof parsed?.id === 'string' && parsed.id.trim() ? parsed.id.trim() : null
52
+ } catch {
53
+ return null
54
+ }
55
+ }
56
+
57
+ export function writePersistedTargetId(id, dir = dataDir) {
58
+ fs.mkdirSync(dir, { recursive: true })
59
+ fs.writeFileSync(persistedTargetFile(dir), `${JSON.stringify({ id }, null, 2)}\n`)
60
+ }
61
+
62
+ /**
63
+ * True when this checkout still has the bundled demo app and the explorer is
64
+ * using its own src/data dir — i.e. `npm run dev`, not `inbase run`.
65
+ */
66
+ export function isWorkspaceDevSwitcherEnabled({
67
+ exampleTarget = defaultTargetRoot,
68
+ resolvedDataDir = dataDir,
69
+ explorerDataDir = defaultDataDir,
70
+ } = {}) {
71
+ return fs.existsSync(exampleTarget) && samePath(resolvedDataDir, explorerDataDir)
72
+ }
73
+
74
+ export function listWorkspaceTargets({
75
+ appsRoot = appsDir,
76
+ repositoryRoot = repoRoot,
77
+ } = {}) {
78
+ const apps = []
79
+ try {
80
+ for (const entry of fs.readdirSync(appsRoot, { withFileTypes: true })) {
81
+ if (!entry.isDirectory()) continue
82
+ if (entry.name === EXPLORER_APP_NAME || entry.name.startsWith('.')) continue
83
+ apps.push({
84
+ id: entry.name,
85
+ label: labelFromFolderName(entry.name),
86
+ root: path.resolve(appsRoot, entry.name),
87
+ })
88
+ }
89
+ } catch {
90
+ // No apps directory in published layouts.
91
+ }
92
+ apps.sort((left, right) => {
93
+ if (left.id === 'example-target') return -1
94
+ if (right.id === 'example-target') return 1
95
+ return left.id.localeCompare(right.id)
96
+ })
97
+ return [
98
+ ...apps,
99
+ {
100
+ id: REPO_TARGET_ID,
101
+ label: 'Complete repo',
102
+ root: path.resolve(repositoryRoot),
103
+ },
104
+ ]
105
+ }
106
+
107
+ export function matchWorkspaceTargetId(root, targets = listWorkspaceTargets()) {
108
+ const resolved = path.resolve(root)
109
+ return targets.find((target) => samePath(target.root, resolved))?.id ?? null
110
+ }
111
+
112
+ export function resolveInitialTargetRoot({
113
+ envTarget = process.env.VISUAL_CODER_TARGET,
114
+ persistedId = null,
115
+ switcherEnabled = false,
116
+ targets = [],
117
+ fallback = defaultTargetRoot,
118
+ } = {}) {
119
+ const fromEnv = envTarget?.trim()
120
+ if (fromEnv) return resolveTargetRoot(fromEnv)
121
+ if (switcherEnabled && persistedId) {
122
+ const match = targets.find((target) => target.id === persistedId)
123
+ if (match) return match.root
124
+ }
125
+ return fallback
126
+ }
127
+
128
+ function applyTargetRoot(root) {
129
+ targetRoot = path.resolve(root)
130
+ targetName = path.basename(targetRoot)
131
+ targetPathPrefix = resolveTargetPathPrefix(targetRoot)
132
+ process.env.VISUAL_CODER_TARGET = targetRoot
133
+ }
134
+
135
+ const switcherEnabledAtBoot = isWorkspaceDevSwitcherEnabled()
136
+ const bootTargets = switcherEnabledAtBoot ? listWorkspaceTargets() : []
137
+
138
+ export let targetRoot = resolveInitialTargetRoot({
139
+ persistedId: switcherEnabledAtBoot ? readPersistedTargetId() : null,
140
+ switcherEnabled: switcherEnabledAtBoot,
141
+ targets: bootTargets,
142
+ })
143
+ export let targetName = path.basename(targetRoot)
144
+ export let targetPathPrefix = null
27
145
 
28
146
  /**
29
147
  * Agents write diffs against repo-relative paths, so a target that lives inside
@@ -39,4 +157,30 @@ export function resolveTargetPathPrefix(root = targetRoot) {
39
157
  return `${relative.split(path.sep).join('/')}/`
40
158
  }
41
159
 
42
- export const targetPathPrefix = resolveTargetPathPrefix()
160
+ targetPathPrefix = resolveTargetPathPrefix(targetRoot)
161
+
162
+ export function currentWorkspaceTargetId() {
163
+ return matchWorkspaceTargetId(targetRoot)
164
+ }
165
+
166
+ export function workspaceDevTargetsState() {
167
+ if (!isWorkspaceDevSwitcherEnabled()) {
168
+ return { enabled: false, currentId: null, targets: [] }
169
+ }
170
+ const targets = listWorkspaceTargets()
171
+ const currentId = matchWorkspaceTargetId(targetRoot, targets) ?? 'custom'
172
+ const publicTargets = targets.map(({ id, label }) => ({ id, label }))
173
+ if (currentId === 'custom') {
174
+ publicTargets.push({ id: 'custom', label: targetName })
175
+ }
176
+ return { enabled: true, currentId, targets: publicTargets }
177
+ }
178
+
179
+ export function setWorkspaceTarget(id) {
180
+ const targets = listWorkspaceTargets()
181
+ const match = targets.find((target) => target.id === id)
182
+ if (!match) throw new Error(`Unknown workspace target: ${id}`)
183
+ applyTargetRoot(match.root)
184
+ writePersistedTargetId(match.id)
185
+ return match
186
+ }