{"id":13495321,"url":"https://github.com/replit/clui","last_synced_at":"2025-03-28T16:32:15.932Z","repository":{"id":42290327,"uuid":"228441470","full_name":"replit/clui","owner":"replit","description":"CLUI is a collection of JavaScript libraries for building command-driven interfaces with context-aware autocomplete.","archived":true,"fork":false,"pushed_at":"2024-04-30T15:24:46.000Z","size":2108,"stargazers_count":1236,"open_issues_count":20,"forks_count":36,"subscribers_count":55,"default_branch":"master","last_synced_at":"2024-10-29T00:51:52.017Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/replit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-16T17:40:15.000Z","updated_at":"2024-10-20T16:18:13.000Z","dependencies_parsed_at":"2024-01-08T08:01:29.717Z","dependency_job_id":"b4a44403-f8aa-4daf-9764-c2bcb3768592","html_url":"https://github.com/replit/clui","commit_stats":{"total_commits":123,"total_committers":6,"mean_commits":20.5,"dds":0.08943089430894313,"last_synced_commit":"357bef4192528046fb50aa6cdbdd7a1702e2e4c3"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Fclui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Fclui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Fclui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Fclui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/replit","download_url":"https://codeload.github.com/replit/clui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222395813,"owners_count":16977627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:33.521Z","updated_at":"2024-10-31T10:30:56.761Z","avatar_url":"https://github.com/replit.png","language":"TypeScript","readme":"# CLUI\n\n**This repository is no longer maintained** \n\nCLUI is a collection of JavaScript libraries for building command-line interfaces with context-aware autocomplete.\n\n[See Demo](https://repl.it/@clui/demo)\n\n## Packages\n\n### `@replit/clui-input`\n\n`@replit/clui-input` implements the logic for mapping text input to suggestions and a potential `run` function.\n\n```jsx\nimport input from '@replit/clui-input';\n\nconst rootCommand = {\n  commands: {\n    open: {\n      commands: {\n        sesame: {\n          run: (args) =\u003e {\n            /* do something */\n          },\n        },\n      },\n    },\n  },\n};\n\nconst update = input({\n  command: rootCommand,\n  onUpdate: (updates) =\u003e {\n    /* Update #1: `updates.options` will be\n     * [\n     *   {\n     *     \"value\": \"open\",\n     *     \"inputValue\": \"open\",\n     *     \"searchValue\": \"o\",\n     *     \"cursorTarget\": 4\n     *   }\n     * ]\n     */\n\n    /* Update #2: `updates.options` will be\n     * [\n     *   {\n     *     \"value\": \"sesame\",\n     *     \"inputValue\": \"open sesame\",\n     *     \"searchValue\": \"s\",\n     *     \"cursorTarget\": 12\n     *   }\n     * ]\n     */\n  },\n});\n\n/* Update #1 */\nupdate({ value: 'o', index: 1 });\n\n/* Update #2 */\nupdate({ value: 'open s', index: 6 });\n```\n\nWhen the input matches a command with a `run` function, the `onUpdate` callback will include a reference to it.\n\n```jsx\nconst update = input({\n  command: rootCommand,\n  onUpdate: (updates) =\u003e {\n    // call or store reference to `updates.run` based on user interaction\n  },\n});\n\nupdate({ value: 'open sesame', index: 6 });\n```\n\n`@replit/clui-input` a framework agnostic primitive that can be wrapped by more specific framework or application code (like a react hook). If using react you will most likey want to keep the result of `onUpdate` in a state object. For managing dropdown selection UX I highly recommend [downshift](https://github.com/downshift-js/downshift).\n\n### `@replit/clui-session`\n\n`@replit/clui-session` implements the logic for rendering a list of react children. For building a CLI-style interfaces this can be useful for adding and removing lines when the prompt is submitted.\n\n```jsx\nimport React from 'react'\nimport { render } from 'react-dom'\nimport Session, { Do } from '@replit/clui-session';\n\n/* `Do` is a helper that exposes the `item` prop\n * You will most likey render your own component\n * which will get `item` injected as a prop so \n * that component can call `item.next` based\n * on specific application logic\n */\nrender(\n  \u003cSession\u003e\n    \u003cDo\u003e\n      {item =\u003e \u003cbutton onClick={item.next}\u003enext 1\u003c/button\u003e}\n    \u003c/Do\u003e\n    \u003cDo\u003e\n      {item =\u003e \u003cbutton onClick={item.next}\u003enext 2\u003c/button\u003e}\n    \u003c/Do\u003e\n    \u003cDo\u003e\n      {item =\u003e \u003cbutton onClick={item.next}\u003enext 3\u003c/button\u003e}\n    \u003c/Do\u003e\n  \u003c/Session\u003e,\n  document.getElementById('root'),\n);\n```\n\n### `@replit/clui-gql`\n\n`@replit/clui-gql` is a utility library for building [CLUI](https://github.com/replit/clui) commands from [GraphQL introspection](https://graphql.org/learn/introspection) data.\n\n## Install\n\n```sh\nnpm install @replit/clui-gql\n```\n\n## Usage\n\nTo create a tree of CLUI commands call `toCommand` and then `visit` each command to define a run function.\n\n```jsx\nimport { toCommand, visit } from '@replit/clui-gql';\nimport { introspectionFromSchema } from 'graphql';\nimport schema from './your-graphql-schema';\n\n// on server\nconst introspection = introspectionFromSchema(schema);\n\n// on client\nconst introspection = makeNetworkRequestForData();\n\n// Create a command tree from graphql introspection data. This could be done on\n// the server or the client.\nconst root = toCommand({\n  // 'query' or 'mutation'\n  operation: 'query',\n\n  // The name of the graphql type that has the fields that act as top level commands\n  rootTypeName: 'CluiCommands'\n\n  // the path at which the above type appears in the graph\n  mountPath: ['cli', 'admin'],\n\n  // GraphQL introspection data\n  introspectionSchema: introspection.__schema,\n\n  // Configure fields and fragments for the output of the GraphQL operation string\n  output: () =\u003e ({\n    fields: '...Output',\n    fragments: `\n      fragment Output on YourOutputTypes {\n        ...on SuccessOutput {\n          message\n        }\n        ...on ErrorOutput {\n          error\n        }\n      }`,\n  }),\n});\n\n// Define some application specific behavior for when a command is `run`\nvisit(root, (command) =\u003e {\n  if (command.outputType !== 'YourOutputTypes') {\n    // If command does not match an output type you may want do something different.\n    By omitting the run function the command acts as a namespace for sub-commands.\n    return;\n  }\n\n  command.run = (options) =\u003e {\n    return \u003cOutputView command={command} options={options} /\u003e\n  }\n}\n```\n\n'parseArgs' is a helper for working with args\n\n```jsx\nimport { parse } from 'graphql';\nimport { parseArgs } from '@replit/clui-gql';\n\nconst OutputView = (props) =\u003e {\n  // CLIU command generated from graphql\n  const { command } = props;\n\n  // CLUI args\n  const { args } = props.options;\n\n  const parsed = parseArgs({ command, args });\n\n  // Handle state for submitting command based on parsed args\n\n  if (parsed.missing.required) {\n    return \u003cHandleMissingArgs /\u003e;\n  }\n\n  if (parsed.missing.optional) {\n    return \u003cPotentiallyShowOptinalInputs /\u003e;\n  }\n\n  if (command.query) {\n    graphQLClient.query(parse(command.query), { variables: parsed.variables })\n  } else if (command.mutation) {\n    graphQLClient.mutate(parse(command.mutation), { variables: parsed.variables })\n  }\n\n  // ...some component to communicate above state\n}\n\n```\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freplit%2Fclui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freplit%2Fclui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freplit%2Fclui/lists"}