@n8r/surface 0.0.0-stage → 0.1.0-experimental.5
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/LICENSE +202 -0
- package/LICENSE-DOCS +395 -0
- package/LICENSING.md +36 -0
- package/README.md +207 -2
- package/dist/activity.d.ts +16 -0
- package/dist/activity.js +44 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +412 -0
- package/dist/codec.d.ts +6 -0
- package/dist/codec.js +56 -0
- package/dist/codex.d.ts +72 -0
- package/dist/codex.js +526 -0
- package/dist/contracts.d.ts +235 -0
- package/dist/contracts.js +1 -0
- package/dist/cyclonedx-schemas/bom-1.7.schema.json +6700 -0
- package/dist/cyclonedx-schemas/cryptography-defs.schema.json +576 -0
- package/dist/cyclonedx-schemas/jsf-0.82.schema.json +240 -0
- package/dist/cyclonedx-schemas/spdx.schema.json +786 -0
- package/dist/cyclonedx-validation.d.ts +1 -0
- package/dist/cyclonedx-validation.js +45 -0
- package/dist/html.d.ts +5 -0
- package/dist/html.js +74 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +5 -0
- package/dist/notes.d.ts +52 -0
- package/dist/notes.js +184 -0
- package/dist/portable.d.ts +10 -0
- package/dist/portable.js +71 -0
- package/dist/recent.d.ts +9 -0
- package/dist/recent.js +71 -0
- package/dist/revisions.d.ts +2 -0
- package/dist/revisions.js +60 -0
- package/dist/settings.d.ts +23 -0
- package/dist/settings.js +100 -0
- package/dist/setup.d.ts +9 -0
- package/dist/setup.js +161 -0
- package/dist/skill-artifacts-cli.d.ts +1 -0
- package/dist/skill-artifacts-cli.js +13 -0
- package/dist/skill-artifacts.d.ts +15 -0
- package/dist/skill-artifacts.js +184 -0
- package/dist/skill-cyclonedx.d.ts +26 -0
- package/dist/skill-cyclonedx.js +214 -0
- package/dist/skill-presentation.d.ts +10 -0
- package/dist/skill-presentation.js +108 -0
- package/dist/skill-surface-cli.d.ts +1 -0
- package/dist/skill-surface-cli.js +37 -0
- package/dist/skill-surface-store.d.ts +7 -0
- package/dist/skill-surface-store.js +126 -0
- package/dist/source-tools.d.ts +102 -0
- package/dist/source-tools.js +201 -0
- package/dist/startup.d.ts +7 -0
- package/dist/startup.js +74 -0
- package/dist/surface-bom.d.ts +73 -0
- package/dist/surface-bom.js +139 -0
- package/dist/surface-draft.d.ts +22 -0
- package/dist/surface-draft.js +112 -0
- package/dist/surface-instructions.d.ts +3 -0
- package/dist/surface-instructions.js +32 -0
- package/dist/surface-overview.d.ts +15 -0
- package/dist/surface-overview.js +86 -0
- package/dist/surface-store.d.ts +34 -0
- package/dist/surface-store.js +213 -0
- package/dist/surface-view.d.ts +3 -0
- package/dist/surface-view.js +50 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +482 -0
- package/docs/n8r-surface/README.md +133 -0
- package/docs/n8r-surface/cli-bundles.md +72 -0
- package/docs/n8r-surface/codex-research-transcript.md +51 -0
- package/docs/n8r-surface/codex-research-verification.md +176 -0
- package/docs/n8r-surface/command-outcomes.md +711 -0
- package/docs/n8r-surface/contracts.md +220 -0
- package/docs/n8r-surface/critical-path.md +184 -0
- package/docs/n8r-surface/design.md +289 -0
- package/docs/n8r-surface/first-use-access.md +143 -0
- package/docs/n8r-surface/first-use-overview.md +262 -0
- package/docs/n8r-surface/getting-started.md +74 -0
- package/docs/n8r-surface/guided-journey-verification.md +137 -0
- package/docs/n8r-surface/host-contract.md +176 -0
- package/docs/n8r-surface/implementation-decisions.md +96 -0
- package/docs/n8r-surface/instance-first-research.md +209 -0
- package/docs/n8r-surface/npm-distribution.md +107 -0
- package/docs/n8r-surface/npm-release.md +315 -0
- package/docs/n8r-surface/product-direction.md +327 -0
- package/docs/n8r-surface/recreation-handoff.md +117 -0
- package/docs/n8r-surface/researcher-discovery.md +157 -0
- package/docs/n8r-surface/researcher-prepared-check.md +117 -0
- package/docs/n8r-surface/researcher-reconciliation-trial.md +149 -0
- package/docs/n8r-surface/researcher-repository-check.md +95 -0
- package/docs/n8r-surface/researcher-skeleton-check.md +84 -0
- package/docs/n8r-surface/researcher-skill-verification.md +725 -0
- package/docs/n8r-surface/researcher-skill.md +309 -0
- package/docs/n8r-surface/researcher-vault.md +134 -0
- package/docs/n8r-surface/save-reopen-transcript.md +211 -0
- package/docs/n8r-surface/save-reopen-verification.md +152 -0
- package/docs/n8r-surface/security-assurance-strategy.md +267 -0
- package/docs/n8r-surface/skill-bom-verification.md +142 -0
- package/docs/n8r-surface/skill-cyclonedx-verification.md +144 -0
- package/docs/n8r-surface/skill-cyclonedx.md +85 -0
- package/docs/n8r-surface/skill-manual.md +129 -0
- package/docs/n8r-surface/skill-surface-artifacts.md +234 -0
- package/docs/n8r-surface/skill-usefulness-verification.md +135 -0
- package/docs/n8r-surface/skill-workspace-automation.md +359 -0
- package/docs/n8r-surface/startup-human-check.md +172 -0
- package/docs/n8r-surface/startup-verification.md +161 -0
- package/docs/n8r-surface/startup.md +151 -0
- package/docs/n8r-surface/surface-description-contract.md +224 -0
- package/docs/n8r-surface/surface-descriptions.md +173 -0
- package/docs/n8r-surface/surface-relationships.md +231 -0
- package/docs/n8r-surface/surface-revisions-transcript.md +552 -0
- package/docs/n8r-surface/surface-revisions-verification.md +161 -0
- package/docs/n8r-surface/tester-candidate.md +158 -0
- package/docs/n8r-surface/vault-setup-verification.md +210 -0
- package/docs/n8r-surface/verification.md +117 -0
- package/docs/n8r-surface/versioning.md +172 -0
- package/docs/n8r-surface/workspace-human-check.md +101 -0
- package/docs/n8r-surface/workspace-installation.md +68 -0
- package/docs/n8r-surface/workspace-verification.md +350 -0
- package/docs/n8r-surface/workspace.md +83 -0
- package/examples/researcher/README.md +100 -0
- package/examples/researcher/composed.surface.json +430 -0
- package/examples/researcher/composed.surface.yaml +283 -0
- package/examples/researcher/cyclonedx/configured/README.md +7 -0
- package/examples/researcher/cyclonedx/configured/manifest.json +10 -0
- package/examples/researcher/cyclonedx/configured/mapping.json +323 -0
- package/examples/researcher/cyclonedx/configured/surface-records.json +1275 -0
- package/examples/researcher/cyclonedx/configured/surface.cdx.json +79 -0
- package/examples/researcher/descriptions/README.md +29 -0
- package/examples/researcher/descriptions/bound-r1.json +141 -0
- package/examples/researcher/descriptions/bound-r2.json +153 -0
- package/examples/researcher/descriptions/capability.json +167 -0
- package/examples/researcher/descriptions/research-r1.json +153 -0
- package/examples/researcher/descriptions/research-r2.json +157 -0
- package/examples/researcher/descriptions/sources.md +24 -0
- package/examples/researcher/harbor-r1.research.html +193 -0
- package/examples/researcher/harbor-r2.research.html +226 -0
- package/examples/researcher/lumen-manual-edit.pending.html +271 -0
- package/examples/researcher/lumen-r1.research.html +271 -0
- package/examples/researcher/lumen-r2.research.html +280 -0
- package/examples/researcher/relationships/README.md +34 -0
- package/examples/researcher/relationships/bound-r1.json +346 -0
- package/examples/researcher/relationships/bound-r2.json +358 -0
- package/examples/researcher/relationships/capability.json +325 -0
- package/examples/researcher/relationships/config/assistant.env.example +4 -0
- package/examples/researcher/relationships/research-r1.json +300 -0
- package/examples/researcher/relationships/research-r2.json +304 -0
- package/examples/researcher/relationships/sources.md +38 -0
- package/examples/researcher/sources/harbor-api.md +16 -0
- package/examples/researcher/sources/harbor-auth.md +8 -0
- package/examples/researcher/sources/lumen-guide.md +28 -0
- package/examples/researcher/sources/lumen-settings.md +9 -0
- package/examples/researcher/surface-bom/README.md +17 -0
- package/examples/researcher/surface-bom/initial.cdx.json +188 -0
- package/package.json +45 -4
- package/plugins/n8r-surface/.codex-plugin/plugin.json +31 -0
- package/plugins/n8r-surface/LICENSE +202 -0
- package/plugins/n8r-surface/LICENSE-DOCS +395 -0
- package/plugins/n8r-surface/LICENSING.md +39 -0
- package/plugins/n8r-surface/assets/icon.svg +5 -0
- package/plugins/n8r-surface/plugin.json +27 -0
- package/plugins/n8r-surface/skills/research/SKILL.md +163 -0
- package/plugins/n8r-surface/skills/research/agents/openai.yaml +4 -0
- package/plugins/n8r-surface/skills/research/references/artifacts.md +152 -0
- package/plugins/n8r-surface/skills/research/references/cyclonedx.md +207 -0
- package/plugins/n8r-surface/skills/research/references/discovery-map.md +178 -0
- package/plugins/n8r-surface/skills/research/references/examples/bound-r1.json +346 -0
- package/plugins/n8r-surface/skills/research/references/examples/capability.json +325 -0
- package/plugins/n8r-surface/skills/research/references/examples/research-r1.json +300 -0
- package/plugins/n8r-surface/skills/research/references/examples/surface.cdx.json +188 -0
- package/plugins/n8r-surface/skills/research/references/first-use-access.md +97 -0
- package/plugins/n8r-surface/skills/research/references/first-use-overview.md +101 -0
- package/plugins/n8r-surface/skills/research/references/instance-first.md +125 -0
- package/plugins/n8r-surface/skills/research/references/model-meanings.md +55 -0
- package/plugins/n8r-surface/skills/research/references/skeleton-surface.md +105 -0
- package/plugins/n8r-surface/skills/research/references/working-notes.md +121 -0
- package/plugins/n8r-surface/skills/research/references/workspace.md +89 -0
- package/plugins/n8r-surface/skills/research/scripts/THIRD-PARTY-NOTICES.txt +273 -0
- package/plugins/n8r-surface/skills/research/scripts/artifacts.mjs +8348 -0
- package/plugins/n8r-surface/skills/research/scripts/cyclonedx.mjs +28113 -0
- package/plugins/n8r-surface/skills/research/scripts/surface.mjs +27800 -0
- package/plugins/n8r-surface/skills/research/scripts/workspace.mjs +120 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Shared workspace boundary. No network, global settings or host attachment.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
7
|
+
|
|
8
|
+
export const WORKSPACE_FORMAT = 'n8r.workspace/1';
|
|
9
|
+
const uuid4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
10
|
+
const nonempty = value => typeof value === 'string' && value.trim().length > 0;
|
|
11
|
+
const result = (status, message, extra = {}) => ({ status, message, ...extra });
|
|
12
|
+
|
|
13
|
+
export function validateWorkspace(record) {
|
|
14
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)
|
|
15
|
+
|| !nonempty(record.format)) {
|
|
16
|
+
return result('malformed', 'Workspace metadata must be an object with a nonempty format token.');
|
|
17
|
+
}
|
|
18
|
+
// An unknown format has its own contract: do not apply this version's fields.
|
|
19
|
+
if (record.format !== WORKSPACE_FORMAT) {
|
|
20
|
+
return result('unsupported', 'Unsupported workspace format; use a compatible reader or another destination.');
|
|
21
|
+
}
|
|
22
|
+
if (typeof record.id !== 'string' || !uuid4.test(record.id) || !nonempty(record.name)
|
|
23
|
+
|| (Object.hasOwn(record, 'purpose') && typeof record.purpose !== 'string')) {
|
|
24
|
+
return result('malformed', 'Workspace metadata requires a UUID v4 id, nonempty name and optional text purpose.');
|
|
25
|
+
}
|
|
26
|
+
return result('recognized', 'Recognized supported workspace; existing bytes are unchanged.', { record });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function statIfPresent(file) {
|
|
30
|
+
try { return fs.lstatSync(file); }
|
|
31
|
+
catch (error) { if (error.code === 'ENOENT') return undefined; throw error; }
|
|
32
|
+
}
|
|
33
|
+
function failure(error, directory) {
|
|
34
|
+
return result('io-error', `Filesystem operation failed (${error.code ?? 'unknown'}); inspect the destination before retrying. No repair was attempted.`, { directory });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function inspectWorkspace(directory) {
|
|
38
|
+
if (!nonempty(directory) || directory.includes('\0')) return result('invalid-input', 'Select a nonempty local directory path.');
|
|
39
|
+
directory = path.resolve(directory);
|
|
40
|
+
const at = (status, message, extra) => result(status, message, { directory, ...extra });
|
|
41
|
+
try {
|
|
42
|
+
const root = statIfPresent(directory);
|
|
43
|
+
if (!root) return at('missing', 'Destination does not exist; explicit setup may create it.');
|
|
44
|
+
if (!root.isDirectory() || root.isSymbolicLink()) return at('conflict', 'Destination must be a real directory, not a file or symbolic link. Choose another folder.');
|
|
45
|
+
const metaPath = path.join(directory, '.n8r'), meta = statIfPresent(metaPath);
|
|
46
|
+
if (!meta) return fs.readdirSync(directory).length === 0
|
|
47
|
+
? at('empty', 'Empty destination; explicit setup may initialize it.')
|
|
48
|
+
: at('needs-choice', 'Existing files are present. Initialize here or choose another folder?');
|
|
49
|
+
if (!meta.isDirectory() || meta.isSymbolicLink()) return at('conflict', '.n8r conflicts with workspace metadata. Choose another folder; repair is separate.');
|
|
50
|
+
const file = path.join(metaPath, 'workspace.json'), stat = statIfPresent(file);
|
|
51
|
+
if (!stat || !stat.isFile() || stat.isSymbolicLink()) return at('conflict', '.n8r has no regular workspace.json identity record. Choose another folder; repair is separate.');
|
|
52
|
+
let record;
|
|
53
|
+
try { record = JSON.parse(fs.readFileSync(file, 'utf8')); }
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof SyntaxError) return at('malformed', 'workspace.json is not valid JSON. Preserve it; choose another folder or arrange separate repair.');
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
return { ...validateWorkspace(record), directory };
|
|
59
|
+
} catch (error) { return failure(error, directory); }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function setupWorkspace(directory, options = {}) {
|
|
63
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)
|
|
64
|
+
|| Object.keys(options).some(key => !['name', 'purpose', 'adopt'].includes(key))
|
|
65
|
+
|| (options.name !== undefined && !nonempty(options.name))
|
|
66
|
+
|| (options.purpose !== undefined && typeof options.purpose !== 'string')
|
|
67
|
+
|| (options.adopt !== undefined && typeof options.adopt !== 'boolean')) {
|
|
68
|
+
return result('invalid-input', 'Use an optional nonempty name, text purpose and boolean adopt choice.');
|
|
69
|
+
}
|
|
70
|
+
const state = inspectWorkspace(directory);
|
|
71
|
+
if (!['missing', 'empty', 'needs-choice'].includes(state.status)) return state;
|
|
72
|
+
if (state.status === 'needs-choice' && options.adopt !== true) return state;
|
|
73
|
+
directory = state.directory;
|
|
74
|
+
const record = { format: WORKSPACE_FORMAT, id: randomUUID(), name: options.name ?? path.basename(directory) };
|
|
75
|
+
if (options.purpose !== undefined) record.purpose = options.purpose;
|
|
76
|
+
const validation = validateWorkspace(record);
|
|
77
|
+
if (validation.status !== 'recognized') return result('invalid-input', validation.message, { directory });
|
|
78
|
+
const meta = path.join(directory, '.n8r');
|
|
79
|
+
const temporary = path.join(meta, `.workspace-${randomUUID()}.tmp`);
|
|
80
|
+
try {
|
|
81
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
82
|
+
// Exclusive directory creation refuses an intervening metadata writer.
|
|
83
|
+
fs.mkdirSync(meta);
|
|
84
|
+
fs.writeFileSync(temporary, `${JSON.stringify(record, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
85
|
+
const descriptor = fs.openSync(temporary, 'r');
|
|
86
|
+
try { fs.fsyncSync(descriptor); } finally { fs.closeSync(descriptor); }
|
|
87
|
+
// Hard-link publication is atomic and refuses an existing target. No partial
|
|
88
|
+
// JSON is ever published at the identity path. No rename-overwrite fallback.
|
|
89
|
+
fs.linkSync(temporary, path.join(meta, 'workspace.json'));
|
|
90
|
+
fs.unlinkSync(temporary);
|
|
91
|
+
const readback = inspectWorkspace(directory);
|
|
92
|
+
if (readback.status !== 'recognized' || readback.record.id !== record.id) {
|
|
93
|
+
return result('io-error', 'Created metadata could not be independently read back. Inspect the destination; setup is not confirmed.', { directory });
|
|
94
|
+
}
|
|
95
|
+
return { ...readback, status: 'created', message: 'Workspace created and read back. Research has not started; app attachment is separate.' };
|
|
96
|
+
} catch (error) {
|
|
97
|
+
// Keep evidence of interrupted initialization. Never remove or repair data
|
|
98
|
+
// here; a later setup refuses incomplete .n8r rather than guessing ownership.
|
|
99
|
+
return failure(error, directory);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function main(args) {
|
|
104
|
+
const [operation, directory, ...rest] = args;
|
|
105
|
+
const options = {};
|
|
106
|
+
let valid = ['inspect', 'setup'].includes(operation) && nonempty(directory);
|
|
107
|
+
for (let i = 0; i < rest.length && valid; i++) {
|
|
108
|
+
const flag = rest[i], key = flag.slice(2);
|
|
109
|
+
if (operation !== 'setup' || !['--adopt', '--name', '--purpose'].includes(flag) || Object.hasOwn(options, key)) { valid = false; break; }
|
|
110
|
+
if (flag === '--adopt') options.adopt = true;
|
|
111
|
+
else if (rest[i + 1] === undefined || rest[i + 1].startsWith('--')) valid = false;
|
|
112
|
+
else options[key] = rest[++i];
|
|
113
|
+
}
|
|
114
|
+
const output = !valid ? result('invalid-input', 'Usage: node workspace.mjs inspect PATH | setup PATH [--name NAME] [--purpose TEXT] [--adopt]')
|
|
115
|
+
: operation === 'inspect' ? inspectWorkspace(directory) : setupWorkspace(directory, options);
|
|
116
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
117
|
+
process.exitCode = ['created', 'recognized'].includes(output.status) ? 0
|
|
118
|
+
: ['missing', 'empty', 'needs-choice'].includes(output.status) ? 3 : 2;
|
|
119
|
+
}
|
|
120
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(fs.realpathSync(process.argv[1])).href) main(process.argv.slice(2));
|