@open-pencil/cli 0.7.0 → 0.8.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.
@@ -1,38 +1,29 @@
1
1
  import { defineCommand } from 'citty'
2
2
 
3
3
  import { loadDocument } from '../headless'
4
+ import { isAppMode, requireFile, rpc } from '../app-client'
4
5
  import { bold, fmtList, entity, formatType } from '../format'
5
6
 
7
+ import type { PageItem } from '@open-pencil/core'
8
+ import { executeRpcCommand } from '@open-pencil/core'
9
+
10
+ async function getData(file?: string): Promise<PageItem[]> {
11
+ if (isAppMode(file)) return rpc<PageItem[]>('pages')
12
+ const graph = await loadDocument(requireFile(file))
13
+ return executeRpcCommand(graph, 'pages', undefined) as PageItem[]
14
+ }
15
+
6
16
  export default defineCommand({
7
17
  meta: { description: 'List pages in a .fig file' },
8
18
  args: {
9
- file: { type: 'positional', description: '.fig file path', required: true },
19
+ file: { type: 'positional', description: '.fig file path (omit to connect to running app)', required: false },
10
20
  json: { type: 'boolean', description: 'Output as JSON' }
11
21
  },
12
22
  async run({ args }) {
13
- const graph = await loadDocument(args.file)
14
- const pages = graph.getPages()
15
-
16
- const countNodes = (pageId: string): number => {
17
- let count = 0
18
- const walk = (id: string) => {
19
- count++
20
- const n = graph.getNode(id)
21
- if (n) for (const cid of n.childIds) walk(cid)
22
- }
23
- const page = graph.getNode(pageId)
24
- if (page) for (const cid of page.childIds) walk(cid)
25
- return count
26
- }
23
+ const pages = await getData(args.file)
27
24
 
28
25
  if (args.json) {
29
- console.log(
30
- JSON.stringify(
31
- pages.map((p) => ({ id: p.id, name: p.name, nodes: countNodes(p.id) })),
32
- null,
33
- 2
34
- )
35
- )
26
+ console.log(JSON.stringify(pages, null, 2))
36
27
  return
37
28
  }
38
29
 
@@ -42,8 +33,8 @@ export default defineCommand({
42
33
  console.log(
43
34
  fmtList(
44
35
  pages.map((page) => ({
45
- header: entity(formatType(page.type), page.name, page.id),
46
- details: { nodes: countNodes(page.id) }
36
+ header: entity('page', page.name, page.id),
37
+ details: { nodes: page.nodes }
47
38
  })),
48
39
  { compact: true }
49
40
  )
@@ -1,59 +1,55 @@
1
1
  import { defineCommand } from 'citty'
2
2
 
3
3
  import { loadDocument } from '../headless'
4
- import { fmtTree, nodeToTreeNode, printError, entity, formatType } from '../format'
5
- import type { SceneNode } from '@open-pencil/core'
4
+ import { isAppMode, requireFile, rpc } from '../app-client'
5
+ import { fmtTree, printError, entity, formatType } from '../format'
6
+ import { executeRpcCommand } from '@open-pencil/core'
7
+
8
+ import type { TreeResult, TreeNodeResult } from '@open-pencil/core'
9
+ import type { TreeNode } from 'agentfmt'
10
+
11
+ function toAgentfmtTree(node: TreeNodeResult, maxDepth: number, depth = 0): TreeNode {
12
+ const treeNode: TreeNode = {
13
+ header: entity(formatType(node.type), node.name, node.id)
14
+ }
15
+ if (node.children && depth < maxDepth) {
16
+ treeNode.children = node.children.map((c) => toAgentfmtTree(c, maxDepth, depth + 1))
17
+ }
18
+ return treeNode
19
+ }
20
+
21
+ async function getData(file: string | undefined, args: { page?: string; depth?: string }): Promise<TreeResult | { error: string }> {
22
+ const rpcArgs = { page: args.page, depth: args.depth ? Number(args.depth) : undefined }
23
+ if (isAppMode(file)) return rpc<TreeResult>('tree', rpcArgs)
24
+ const graph = await loadDocument(requireFile(file))
25
+ return executeRpcCommand(graph, 'tree', rpcArgs) as TreeResult | { error: string }
26
+ }
6
27
 
7
28
  export default defineCommand({
8
29
  meta: { description: 'Print the node tree' },
9
30
  args: {
10
- file: { type: 'positional', description: '.fig file path', required: true },
31
+ file: { type: 'positional', description: '.fig file path (omit to connect to running app)', required: false },
11
32
  page: { type: 'string', description: 'Page name (default: first page)' },
12
33
  depth: { type: 'string', description: 'Max depth (default: unlimited)' },
13
34
  json: { type: 'boolean', description: 'Output as JSON' }
14
35
  },
15
36
  async run({ args }) {
16
- const graph = await loadDocument(args.file)
17
- const pages = graph.getPages()
37
+ const data = await getData(args.file, args)
18
38
  const maxDepth = args.depth ? Number(args.depth) : Infinity
19
39
 
20
- const page = args.page
21
- ? pages.find((p) => p.name === args.page)
22
- : pages[0]
23
-
24
- if (!page) {
25
- printError(`Page "${args.page}" not found. Available: ${pages.map((p) => p.name).join(', ')}`)
40
+ if ('error' in data) {
41
+ printError(data.error)
26
42
  process.exit(1)
27
43
  }
28
44
 
29
45
  if (args.json) {
30
- const buildJson = (id: string, depth: number): unknown => {
31
- const node = graph.getNode(id)
32
- if (!node) return null
33
- const result: Record<string, unknown> = {
34
- id: node.id,
35
- name: node.name,
36
- type: node.type,
37
- x: Math.round(node.x),
38
- y: Math.round(node.y),
39
- width: Math.round(node.width),
40
- height: Math.round(node.height)
41
- }
42
- if (node.childIds.length > 0 && depth < maxDepth) {
43
- result.children = node.childIds.map((cid) => buildJson(cid, depth + 1)).filter(Boolean)
44
- }
45
- return result
46
- }
47
- console.log(JSON.stringify(page.childIds.map((id) => buildJson(id, 0)), null, 2))
46
+ console.log(JSON.stringify(data.children, null, 2))
48
47
  return
49
48
  }
50
49
 
51
50
  const root = {
52
- header: entity(formatType(page.type), page.name, page.id),
53
- children: page.childIds
54
- .map((id) => graph.getNode(id))
55
- .filter((n): n is SceneNode => n !== undefined)
56
- .map((child) => nodeToTreeNode(graph, child, maxDepth))
51
+ header: entity(formatType(data.page.type), data.page.name, data.page.id),
52
+ children: data.children.map((c) => toAgentfmtTree(c, maxDepth))
57
53
  }
58
54
 
59
55
  console.log('')
@@ -1,82 +1,50 @@
1
1
  import { defineCommand } from 'citty'
2
2
 
3
3
  import { loadDocument } from '../headless'
4
+ import { isAppMode, requireFile, rpc } from '../app-client'
4
5
  import { bold, fmtList, fmtSummary } from '../format'
5
- import type { SceneGraph, Variable } from '@open-pencil/core'
6
+ import { executeRpcCommand } from '@open-pencil/core'
6
7
 
7
- function formatValue(variable: Variable, graph: SceneGraph): string {
8
- const modeId = graph.getActiveModeId(variable.collectionId)
9
- const raw = variable.valuesByMode[modeId]
10
- if (raw === undefined) return '–'
8
+ import type { VariablesResult } from '@open-pencil/core'
11
9
 
12
- if (typeof raw === 'object' && raw !== null && 'aliasId' in raw) {
13
- const alias = graph.variables.get(raw.aliasId)
14
- return alias ? `→ ${alias.name}` : `→ ${raw.aliasId}`
15
- }
16
-
17
- if (typeof raw === 'object' && 'r' in raw) {
18
- const { r, g, b } = raw as { r: number; g: number; b: number }
19
- return (
20
- '#' +
21
- [r, g, b]
22
- .map((c) =>
23
- Math.round(c * 255)
24
- .toString(16)
25
- .padStart(2, '0')
26
- )
27
- .join('')
28
- )
29
- }
30
-
31
- return String(raw)
10
+ async function getData(file: string | undefined, args: { collection?: string; type?: string }): Promise<VariablesResult> {
11
+ const rpcArgs = { collection: args.collection, type: args.type }
12
+ if (isAppMode(file)) return rpc<VariablesResult>('variables', rpcArgs)
13
+ const graph = await loadDocument(requireFile(file))
14
+ return executeRpcCommand(graph, 'variables', rpcArgs) as VariablesResult
32
15
  }
33
16
 
34
17
  export default defineCommand({
35
18
  meta: { description: 'List design variables and collections' },
36
19
  args: {
37
- file: { type: 'positional', description: '.fig file path', required: true },
20
+ file: { type: 'positional', description: '.fig file path (omit to connect to running app)', required: false },
38
21
  collection: { type: 'string', description: 'Filter by collection name' },
39
22
  type: { type: 'string', description: 'Filter by type: COLOR, FLOAT, STRING, BOOLEAN' },
40
23
  json: { type: 'boolean', description: 'Output as JSON' }
41
24
  },
42
25
  async run({ args }) {
43
- const graph = await loadDocument(args.file)
26
+ const data = await getData(args.file, args)
44
27
 
45
- const collections = [...graph.variableCollections.values()]
46
- const variables = [...graph.variables.values()]
47
-
48
- if (variables.length === 0) {
28
+ if (data.totalVariables === 0) {
49
29
  console.log('No variables found.')
50
30
  return
51
31
  }
52
32
 
53
33
  if (args.json) {
54
- console.log(JSON.stringify({ collections, variables }, null, 2))
34
+ console.log(JSON.stringify(data, null, 2))
55
35
  return
56
36
  }
57
37
 
58
- const typeFilter = args.type?.toUpperCase()
59
- const collFilter = args.collection?.toLowerCase()
60
-
61
38
  console.log('')
62
39
 
63
- for (const coll of collections) {
64
- if (collFilter && !coll.name.toLowerCase().includes(collFilter)) continue
65
-
66
- const collVars = graph
67
- .getVariablesForCollection(coll.id)
68
- .filter((v) => !typeFilter || v.type === typeFilter)
69
-
70
- if (collVars.length === 0) continue
71
-
72
- const modes = coll.modes.map((m) => m.name).join(', ')
73
- console.log(bold(` ${coll.name}`) + ` (${modes})`)
40
+ for (const coll of data.collections) {
41
+ console.log(bold(` ${coll.name}`) + ` (${coll.modes.join(', ')})`)
74
42
  console.log('')
75
43
  console.log(
76
44
  fmtList(
77
- collVars.map((v) => ({
45
+ coll.variables.map((v) => ({
78
46
  header: v.name,
79
- details: { value: formatValue(v, graph), type: v.type.toLowerCase() }
47
+ details: { value: v.value, type: v.type.toLowerCase() }
80
48
  })),
81
49
  { compact: true }
82
50
  )
@@ -86,8 +54,8 @@ export default defineCommand({
86
54
 
87
55
  console.log(
88
56
  fmtSummary({
89
- variables: variables.length,
90
- collections: collections.length
57
+ variables: data.totalVariables,
58
+ collections: data.totalCollections
91
59
  })
92
60
  )
93
61
  console.log('')