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 +14 -4
- package/package.json +1 -1
- package/template/README.md +13 -5
- package/template/package.json +2 -2
- package/template/src/{{packageName}}.tsx +107 -0
- package/template/test/manifest.mjs +1 -1
- package/template/tsconfig.json +3 -1
- package/template/src/{{packageName}}.ts +0 -48
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
|
|
15
|
-
|
|
16
|
-
`cordisx dev --dry-run` script.
|
|
17
|
-
|
|
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
package/template/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# {{packageName}}
|
|
2
2
|
|
|
3
|
-
A minimal trusted-local CordisX plugin. Its manifest is exported from
|
|
4
|
-
`src/{{pluginId}}.
|
|
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
|
|
18
|
-
|
|
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).
|
package/template/package.json
CHANGED
|
@@ -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}}.
|
|
14
|
-
"dev:dry-run": "cordisx dev ./src/{{pluginId}}.
|
|
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', '
|
|
9
|
+
assert.deepEqual(inject, ['i18n', 'pages', 'routes', 'slots'])
|
|
10
10
|
assert.equal(typeof apply, 'function')
|
|
11
11
|
})
|
package/template/tsconfig.json
CHANGED
|
@@ -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
|
-
}
|