create-cordisx-plugin 0.1.0-beta.0 → 0.1.0-beta.1

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.
package/README.md CHANGED
@@ -11,10 +11,20 @@ npx create-cordisx-plugin@beta my-plugin
11
11
  The `@beta` qualifier is required while npm `latest` remains the non-functional
12
12
  `0.0.0` package-name reservation.
13
13
 
14
- The generated project includes a version-1 manifest exported from its entry,
15
- structured UI contribution, TypeScript build, manifest test, and
16
- `cordisx dev --dry-run` script. It does not install to a marketplace, sign the
17
- plugin, provide a permission sandbox, or promise hot reload.
14
+ The generated project includes a version-1 manifest, a structured toolbar
15
+ route, a React page body, TypeScript build, manifest test, and
16
+ `cordisx dev --dry-run` script. The plugin installs only `cordisx`: React,
17
+ React DOM, their types, JSX runtimes, and the initial CordisX component set are
18
+ provided by the Host through `cordisx/react` and `cordisx/ui`. Plugin artifacts
19
+ that bundle a private React copy are rejected.
20
+
21
+ The generated route and page use closed route-v2/page-v3 documents with real
22
+ localized title and description dictionaries. Canonical ids, path, outlet,
23
+ params, and chrome remain untranslated machine fields. CordisX owns route and
24
+ page chrome, the React root, theme, error boundary, and lifecycle cleanup; the
25
+ plugin owns only the controlled body component. The generator does not install
26
+ to a marketplace, sign the plugin, provide a permission sandbox, or promise
27
+ hot reload.
18
28
 
19
29
  The `create-cordisx-plugin` tool itself is licensed under
20
30
  `AGPL-3.0-or-later`. Files under its marked `template` directory and projects
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-cordisx-plugin",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.1",
4
4
  "description": "Create a minimal CordisX plugin project",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,7 +1,7 @@
1
1
  # {{packageName}}
2
2
 
3
- A minimal trusted-local CordisX plugin. Its manifest is exported from
4
- `src/{{pluginId}}.ts`, which is also the runtime entry used by CordisX.
3
+ A minimal trusted-local CordisX React plugin. Its manifest is exported from
4
+ `src/{{pluginId}}.tsx`, which is also the runtime entry used by CordisX.
5
5
 
6
6
  ```bash
7
7
  npm install
@@ -13,9 +13,17 @@ npm run dev
13
13
  `npm run dev:dry-run` bundles the plugin without launching Codex Desktop.
14
14
  `npm run dev` launches the separate CordisX development host.
15
15
 
16
- The template intentionally requests no platform capabilities. It contributes
17
- structured data to a host-owned toolbar surface and does not depend on a
18
- marketplace, signing, a permission sandbox, or hot module replacement.
16
+ The template intentionally requests no platform capabilities. It contributes a
17
+ structured toolbar route and a React page body. Import React from
18
+ `cordisx/react` and components from `cordisx/ui`; do not install `react`,
19
+ `react-dom`, React type packages, or a component library. CordisX supplies one
20
+ Host React singleton and rejects a plugin artifact that bundles another copy.
21
+
22
+ The route and page use closed route-v2/page-v3 documents with separate retained
23
+ localized `title` and `description` messages. Path, outlet, page id, route id,
24
+ params, and chrome remain untranslated. CordisX owns the route, page header,
25
+ theme, error boundary, and React root cleanup; the plugin owns only the page
26
+ body component. Plugins remain trusted local code, not sandboxed code.
19
27
 
20
28
  This generated project is Marked Template Material under the
21
29
  [CordisX Independent Plugin Exception](https://github.com/cordisx/cordisx/blob/main/CORDISX-INDEPENDENT-PLUGIN-EXCEPTION.md).
@@ -10,8 +10,8 @@
10
10
  "scripts": {
11
11
  "build": "tsc -p tsconfig.json",
12
12
  "check": "npm run typecheck && npm run build && npm test",
13
- "dev": "cordisx dev ./src/{{pluginId}}.ts",
14
- "dev:dry-run": "cordisx dev ./src/{{pluginId}}.ts --dry-run",
13
+ "dev": "cordisx dev ./src/{{pluginId}}.tsx",
14
+ "dev:dry-run": "cordisx dev ./src/{{pluginId}}.tsx --dry-run",
15
15
  "test": "node --test test/manifest.mjs",
16
16
  "typecheck": "tsc -p tsconfig.json --noEmit"
17
17
  },
@@ -0,0 +1,107 @@
1
+ import type { Context } from '@deepseek-ai/cordis'
2
+ import { defineReactPage, useState } from 'cordisx/react'
3
+ import { Button, Card, Heading, Stack, Text } from 'cordisx/ui'
4
+ import {
5
+ CORDISX_PAGE_SCHEMA_V3,
6
+ CORDISX_PLUGIN_MANIFEST_SCHEMA_V1,
7
+ CORDISX_ROUTE_SCHEMA_V2,
8
+ type CordisXPluginManifestV1,
9
+ } from 'cordisx/contracts'
10
+ import type {} from 'cordisx/contracts'
11
+
12
+ type Messages = {
13
+ 'command.open': undefined
14
+ 'page.title': undefined
15
+ 'page.description': undefined
16
+ 'route.title': undefined
17
+ 'route.description': undefined
18
+ 'counter.label': { count: number }
19
+ }
20
+
21
+ export const manifest = {
22
+ $schema: CORDISX_PLUGIN_MANIFEST_SCHEMA_V1,
23
+ schemaVersion: 1,
24
+ id: '{{pluginId}}',
25
+ name: '{{packageName}}',
26
+ capabilities: [],
27
+ } as const satisfies CordisXPluginManifestV1
28
+
29
+ export const inject = ['i18n', 'pages', 'routes', 'slots']
30
+
31
+ const page = {
32
+ $schema: CORDISX_PAGE_SCHEMA_V3,
33
+ schemaVersion: 3,
34
+ id: 'overview',
35
+ title: { key: 'page.title', fallback: '{{packageName}}' },
36
+ description: { key: 'page.description', fallback: 'A React page rendered by the shared CordisX Host runtime.' },
37
+ icon: 'host:info',
38
+ } as const
39
+
40
+ const route = {
41
+ $schema: CORDISX_ROUTE_SCHEMA_V2,
42
+ schemaVersion: 2,
43
+ id: 'overview',
44
+ path: '/app/{{pluginId}}',
45
+ outlet: 'app',
46
+ page: 'overview',
47
+ title: { key: 'route.title', fallback: '{{packageName}}' },
48
+ description: { key: 'route.description', fallback: 'Open the plugin React example.' },
49
+ } as const
50
+
51
+ const mountOverview = defineReactPage<Messages>(({ t }) => {
52
+ const [count, setCount] = useState(0)
53
+ return (
54
+ <Stack gap="large">
55
+ <Heading>{t('page.title')}</Heading>
56
+ <Card>
57
+ <Stack gap="medium" align="flex-start">
58
+ <Text tone="muted">{t('page.description')}</Text>
59
+ <Button variant="primary" onClick={() => setCount(value => value + 1)}>
60
+ {t('counter.label', { count })}
61
+ </Button>
62
+ </Stack>
63
+ </Card>
64
+ </Stack>
65
+ )
66
+ })
67
+
68
+ export function apply(ctx: Context): void {
69
+ ctx.i18n.define<Messages>({
70
+ namespace: '{{pluginId}}',
71
+ locale: 'en',
72
+ default: true,
73
+ messages: {
74
+ 'command.open': 'Open {{packageName}}',
75
+ 'page.title': '{{packageName}}',
76
+ 'page.description': 'This page uses the React singleton and components provided by CordisX.',
77
+ 'route.title': '{{packageName}}',
78
+ 'route.description': 'Open the plugin React example.',
79
+ 'counter.label': 'Clicked {count, number} times',
80
+ },
81
+ })
82
+ ctx.i18n.define<Messages>({
83
+ namespace: '{{pluginId}}',
84
+ locale: 'zh-CN',
85
+ messages: {
86
+ 'command.open': '打开 {{packageName}}',
87
+ 'page.title': '{{packageName}}',
88
+ 'page.description': '此页面复用 CordisX 提供的 React 单例与组件。',
89
+ 'route.title': '{{packageName}}',
90
+ 'route.description': '打开插件的 React 示例。',
91
+ 'counter.label': '已点击 {count, number} 次',
92
+ },
93
+ })
94
+ ctx.pages.register<Messages>(page, mountOverview)
95
+ ctx.routes.register(route)
96
+ ctx.slots.register({
97
+ name: 'workspace.toolbar.items',
98
+ id: 'open',
99
+ order: 10,
100
+ }, {
101
+ anchor: 'workspace.primary',
102
+ placement: 'after',
103
+ label: { key: 'command.open', fallback: 'Open {{packageName}}' },
104
+ icon: 'host:open',
105
+ route: { id: 'overview' },
106
+ })
107
+ }
@@ -6,6 +6,6 @@ test('exports a minimal CordisX plugin module', () => {
6
6
  assert.equal(manifest.schemaVersion, 1)
7
7
  assert.equal(manifest.id, '{{pluginId}}')
8
8
  assert.deepEqual(manifest.capabilities, [])
9
- assert.deepEqual(inject, ['i18n', 'commands', 'slots'])
9
+ assert.deepEqual(inject, ['i18n', 'pages', 'routes', 'slots'])
10
10
  assert.equal(typeof apply, 'function')
11
11
  })
@@ -3,6 +3,8 @@
3
3
  "target": "ES2022",
4
4
  "module": "NodeNext",
5
5
  "moduleResolution": "NodeNext",
6
+ "jsx": "react-jsx",
7
+ "jsxImportSource": "cordisx/react",
6
8
  "lib": ["ES2023", "DOM"],
7
9
  "rootDir": "src",
8
10
  "outDir": "dist",
@@ -11,6 +13,6 @@
11
13
  "forceConsistentCasingInFileNames": true,
12
14
  "skipLibCheck": true
13
15
  },
14
- "include": ["src/**/*.ts"],
16
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
15
17
  "exclude": ["dist", "node_modules"]
16
18
  }
@@ -1,48 +0,0 @@
1
- import type { Context } from '@deepseek-ai/cordis'
2
- import {
3
- CORDISX_PLUGIN_MANIFEST_SCHEMA_V1,
4
- type CordisXPluginManifestV1,
5
- } from 'cordisx/contracts'
6
- import type {} from 'cordisx/contracts'
7
-
8
- export const manifest = {
9
- $schema: CORDISX_PLUGIN_MANIFEST_SCHEMA_V1,
10
- schemaVersion: 1,
11
- id: '{{pluginId}}',
12
- name: '{{packageName}}',
13
- capabilities: [],
14
- } as const satisfies CordisXPluginManifestV1
15
-
16
- export const inject = ['i18n', 'commands', 'slots']
17
-
18
- export function apply(ctx: Context): void {
19
- ctx.i18n.define({
20
- namespace: '{{pluginId}}',
21
- locale: 'en',
22
- default: true,
23
- messages: { 'command.hello': 'Say hello from {{packageName}}' },
24
- })
25
- ctx.commands.register({
26
- id: 'hello',
27
- title: {
28
- namespace: '{{pluginId}}',
29
- key: 'command.hello',
30
- fallback: 'Say hello from {{packageName}}',
31
- },
32
- }, () => console.info('[{{pluginId}}] hello'))
33
- ctx.slots.register({
34
- name: 'workspace.toolbar.items',
35
- id: 'hello',
36
- order: 10,
37
- }, {
38
- anchor: 'workspace.primary',
39
- placement: 'after',
40
- label: {
41
- namespace: '{{pluginId}}',
42
- key: 'command.hello',
43
- fallback: 'Say hello from {{packageName}}',
44
- },
45
- icon: 'host:open',
46
- command: { id: 'hello' },
47
- })
48
- }