@josfox/jos 4.1.0 → 5.0.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.
- package/LICENSE +208 -21
- package/PROMISES.md +52 -0
- package/README.md +334 -138
- package/SECURITY-MCP.md +117 -0
- package/SECURITY-SECRETS.md +108 -0
- package/STYLE.md +23 -0
- package/bin/jos +170 -160
- package/examples/01-hello.jos +44 -0
- package/examples/02-criteria.jos +54 -0
- package/examples/03-flow-gate.jos +83 -0
- package/examples/04-use-template/README.md +22 -0
- package/examples/04-use-template/lib/greeting.jos +56 -0
- package/examples/04-use-template/use.jos +64 -0
- package/examples/05-sealed/.jos/manifest.jos +53 -0
- package/examples/05-sealed/README.md +25 -0
- package/examples/06-requires.jos +42 -0
- package/examples/07-sandbox.jos +39 -0
- package/examples/08-ids-ledger-meter.md +26 -0
- package/examples/10-ollama.jos +47 -0
- package/examples/11-openai.jos +47 -0
- package/examples/12-gemini.jos +47 -0
- package/examples/13-anthropic.jos +47 -0
- package/examples/14-serve.jos +88 -0
- package/examples/README.md +105 -0
- package/examples/hello.jos +47 -0
- package/package.json +57 -40
- package/promises.json +894 -0
- package/src/args.js +47 -0
- package/src/commands/_frozen/add.README.md +1 -0
- package/src/commands/_frozen/get.README.md +1 -0
- package/src/commands/_frozen/llm.README.md +1 -0
- package/src/commands/_frozen/prompts.README.md +1 -0
- package/src/commands/_frozen/repo.README.md +1 -0
- package/src/commands/_frozen/serve-explorer.README.md +1 -0
- package/src/commands/ids.js +101 -0
- package/src/commands/init.js +128 -162
- package/src/commands/ledger.js +94 -0
- package/src/commands/meter.js +96 -0
- package/src/commands/migrate.js +214 -0
- package/src/commands/overview.js +118 -0
- package/src/commands/run.js +194 -244
- package/src/commands/runs.js +102 -0
- package/src/commands/secrets.js +717 -137
- package/src/commands/start.js +210 -0
- package/src/commands/validate.js +178 -194
- package/src/commands/verify.js +56 -98
- package/src/commands/version.js +23 -0
- package/src/intention.js +114 -0
- package/src/kernel.js +69 -0
- package/src/ledgers.js +57 -0
- package/src/mcp-guide.js +138 -0
- package/src/mcp.js +734 -0
- package/src/serve.js +48 -781
- package/src/ui.js +98 -0
- package/src/adapters/index.js +0 -16
- package/src/adapters/native.js +0 -41
- package/src/adapters/ollama.js +0 -140
- package/src/commands/add.js +0 -145
- package/src/commands/get.js +0 -245
- package/src/commands/llm.js +0 -159
- package/src/commands/prompts.js +0 -229
- package/src/commands/repo.js +0 -139
- package/src/utils/crypto.js +0 -41
- package/src/utils/request.js +0 -41
package/src/commands/llm.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JOS LLM Command - Execute artifacts via LLM
|
|
3
|
-
*/
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const AdapterFactory = require('../adapters');
|
|
7
|
-
const { calculateChecksum, verifyIntegrity } = require('../utils/crypto');
|
|
8
|
-
|
|
9
|
-
// AURORA colors
|
|
10
|
-
const C = {
|
|
11
|
-
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
12
|
-
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
13
|
-
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
14
|
-
yellow: '\x1b[38;5;220m', white: '\x1b[38;5;255m',
|
|
15
|
-
gray: '\x1b[38;5;245m', blue: '\x1b[38;5;39m'
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const DEFAULT_PROVIDER = 'https://api.josfox.cloud/prompts';
|
|
19
|
-
|
|
20
|
-
function getProviderConfig(home) {
|
|
21
|
-
const configPath = path.join(home, 'prompts', 'providers.json');
|
|
22
|
-
if (fs.existsSync(configPath)) {
|
|
23
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
providers: {
|
|
27
|
-
'josfox-cloud': { url: DEFAULT_PROVIDER, type: 'native', description: 'Official JOSFOX Cloud provider' }
|
|
28
|
-
},
|
|
29
|
-
default: 'josfox-cloud'
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getApiKey(home) {
|
|
34
|
-
const secretsPath = path.join(home, 'secrets', 'vault.json');
|
|
35
|
-
if (fs.existsSync(secretsPath)) {
|
|
36
|
-
try {
|
|
37
|
-
const secrets = JSON.parse(fs.readFileSync(secretsPath, 'utf8'));
|
|
38
|
-
return secrets.JOSFOX_API_KEY || secrets.OPENAI_API_KEY || null;
|
|
39
|
-
} catch { return null; }
|
|
40
|
-
}
|
|
41
|
-
return process.env.JOSFOX_API_KEY || process.env.OPENAI_API_KEY || null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
exports.execute = async (args, home) => {
|
|
45
|
-
if (args.includes('--help') || args.length === 0) {
|
|
46
|
-
console.log(`
|
|
47
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
48
|
-
${C.bold}JOS LLM EXECUTION${C.reset} // Execute artifacts via LLM
|
|
49
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
50
|
-
|
|
51
|
-
${C.bold}Usage:${C.reset}
|
|
52
|
-
jos llm <artifact.jos|.fox> [options]
|
|
53
|
-
|
|
54
|
-
${C.bold}Options:${C.reset}
|
|
55
|
-
--model <name> Target model
|
|
56
|
-
--provider <url> API endpoint or Ollama URL
|
|
57
|
-
--type <native|ollama> Provider type
|
|
58
|
-
--production Enforce strict SHA integrity for .jos
|
|
59
|
-
|
|
60
|
-
${C.bold}Notes:${C.reset}
|
|
61
|
-
• .fox artifacts ALWAYS require valid SHA checksums.
|
|
62
|
-
• .jos artifacts require SHA only in --production mode.
|
|
63
|
-
`);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const target = args[0];
|
|
68
|
-
const absPath = path.resolve(target);
|
|
69
|
-
|
|
70
|
-
if (!fs.existsSync(absPath)) {
|
|
71
|
-
console.log(`${C.red}✖ File not found: ${target}${C.reset}`);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const ext = path.extname(absPath);
|
|
76
|
-
if (ext !== '.jos' && ext !== '.fox') {
|
|
77
|
-
console.log(`${C.red}✖ Invalid file type. Must be .jos or .fox${C.reset}`);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
console.log(`\n${C.cyan}${C.bold}JOS LLM EXECUTION${C.reset}`);
|
|
82
|
-
console.log(`${C.dim}Artifact: ${path.basename(absPath)}${C.reset}`);
|
|
83
|
-
|
|
84
|
-
// READ & PARSE
|
|
85
|
-
const rawContent = fs.readFileSync(absPath, 'utf8');
|
|
86
|
-
let artifact;
|
|
87
|
-
try {
|
|
88
|
-
artifact = JSON.parse(rawContent);
|
|
89
|
-
} catch (e) {
|
|
90
|
-
console.log(`${C.red}✖ Invalid JSON: ${e.message}${C.reset}`);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// INTEGRITY CHECK
|
|
95
|
-
const isProduction = args.includes('--production') || process.env.NODE_ENV === 'production';
|
|
96
|
-
const enforceSha = ext === '.fox' || isProduction;
|
|
97
|
-
|
|
98
|
-
if (enforceSha) {
|
|
99
|
-
// TODO: Strict canonical verification. For now, we check if meta.checksum exists.
|
|
100
|
-
if (!artifact.meta || !artifact.meta.checksum) {
|
|
101
|
-
console.log(`${C.red}✖ Integrity Check Failed: Missing checksum in ${ext} file${C.reset}`);
|
|
102
|
-
console.log(`${C.gray} (.fox files and production .jos require signed checksums)${C.reset}`);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
// const isValid = verifyIntegrity(artifact, rawContent); // Placeholder for strict check
|
|
106
|
-
// if (!isValid) { ... }
|
|
107
|
-
console.log(`${C.green}✓ Integrity Validated (Signature present)${C.reset}`);
|
|
108
|
-
} else {
|
|
109
|
-
console.log(`${C.yellow}⚠ Integrity Check Skipped (Dev Mode)${C.reset}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// RESOLVE PROVIDER
|
|
113
|
-
const config = getProviderConfig(home);
|
|
114
|
-
const providerKey = config.default;
|
|
115
|
-
const providerCfg = config.providers[providerKey] || config.providers['josfox-cloud'];
|
|
116
|
-
|
|
117
|
-
let providerUrl = providerCfg.url;
|
|
118
|
-
let providerType = providerCfg.type || 'native';
|
|
119
|
-
|
|
120
|
-
if (args.includes('--provider')) {
|
|
121
|
-
const pName = args[args.indexOf('--provider') + 1];
|
|
122
|
-
if (config.providers[pName]) {
|
|
123
|
-
providerUrl = config.providers[pName].url;
|
|
124
|
-
providerType = config.providers[pName].type || 'native';
|
|
125
|
-
} else {
|
|
126
|
-
providerUrl = pName;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (args.includes('--type')) {
|
|
130
|
-
providerType = args[args.indexOf('--type') + 1];
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const model = args.includes('--model') ? args[args.indexOf('--model') + 1] : null;
|
|
134
|
-
const apiKey = getApiKey(home);
|
|
135
|
-
|
|
136
|
-
console.log(`${C.dim}Provider: ${providerUrl} (${providerType})${C.reset}`);
|
|
137
|
-
console.log(`${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`);
|
|
138
|
-
|
|
139
|
-
// EXECUTE
|
|
140
|
-
const Adapter = AdapterFactory.getAdapter(providerType);
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
console.log(`${C.yellow}⏳ Executing via LLM...${C.reset}`);
|
|
144
|
-
|
|
145
|
-
const result = await Adapter.execute(artifact, providerUrl, model, apiKey);
|
|
146
|
-
|
|
147
|
-
console.log(`\n${C.green}✓ Execution Complete${C.reset}`);
|
|
148
|
-
console.log(`${C.cyan}Status:${C.reset} ${result.status}`);
|
|
149
|
-
console.log(`\n${C.bold}Output:${C.reset}\n`);
|
|
150
|
-
console.log(result.output);
|
|
151
|
-
console.log('');
|
|
152
|
-
|
|
153
|
-
} catch (e) {
|
|
154
|
-
console.log(`${C.red}✖ Execution Failed: ${e.message}${C.reset}`);
|
|
155
|
-
if (e.message && e.message.includes('ECONNREFUSED')) {
|
|
156
|
-
console.log(`${C.gray} Is the provider running?${C.reset}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
};
|
package/src/commands/prompts.js
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JOS PROMPTS Command - Prompt optimization via open API or Local LLM
|
|
3
|
-
* Complies with JOS Prompts API Specification
|
|
4
|
-
* Format version v0.0.8 — Specification maturity v0.1.0 (Alpha)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const AdapterFactory = require('../adapters');
|
|
10
|
-
|
|
11
|
-
// AURORA colors
|
|
12
|
-
const C = {
|
|
13
|
-
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
14
|
-
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
15
|
-
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
16
|
-
yellow: '\x1b[38;5;220m', white: '\x1b[38;5;255m',
|
|
17
|
-
gray: '\x1b[38;5;245m', blue: '\x1b[38;5;39m'
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const DEFAULT_PROVIDER = 'https://api.josfox.cloud/prompts';
|
|
21
|
-
|
|
22
|
-
function getProviderConfig(home) {
|
|
23
|
-
const configPath = path.join(home, 'prompts', 'providers.json');
|
|
24
|
-
if (fs.existsSync(configPath)) {
|
|
25
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
providers: {
|
|
29
|
-
'josfox-cloud': { url: DEFAULT_PROVIDER, type: 'native', description: 'Official JOSFOX Cloud provider' }
|
|
30
|
-
},
|
|
31
|
-
default: 'josfox-cloud'
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function saveProviderConfig(home, config) {
|
|
36
|
-
const configDir = path.join(home, 'prompts');
|
|
37
|
-
if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
|
|
38
|
-
fs.writeFileSync(path.join(configDir, 'providers.json'), JSON.stringify(config, null, 2));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getApiKey(home) {
|
|
42
|
-
const secretsPath = path.join(home, 'secrets', 'vault.json');
|
|
43
|
-
if (fs.existsSync(secretsPath)) {
|
|
44
|
-
try {
|
|
45
|
-
const secrets = JSON.parse(fs.readFileSync(secretsPath, 'utf8'));
|
|
46
|
-
return secrets.JOSFOX_API_KEY || secrets.OPENAI_API_KEY || null;
|
|
47
|
-
} catch { return null; }
|
|
48
|
-
}
|
|
49
|
-
return process.env.JOSFOX_API_KEY || process.env.OPENAI_API_KEY || null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
exports.execute = async (args, home) => {
|
|
53
|
-
const subcommand = args[0];
|
|
54
|
-
|
|
55
|
-
if (args.includes('--help') || !subcommand) {
|
|
56
|
-
console.log(`
|
|
57
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
58
|
-
${C.bold}JOS PROMPTS${C.reset} // Prompt optimization via API or Local LLM
|
|
59
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
60
|
-
|
|
61
|
-
${C.bold}Usage:${C.reset}
|
|
62
|
-
jos prompts <subcommand> [options]
|
|
63
|
-
|
|
64
|
-
${C.bold}Subcommands:${C.reset}
|
|
65
|
-
optimize <file.jos> Optimize prompts in artifact
|
|
66
|
-
validate <file.jos> Check prompt quality
|
|
67
|
-
generate "<intention>" Create new .jos from text
|
|
68
|
-
provider Manage API providers
|
|
69
|
-
|
|
70
|
-
${C.bold}Options:${C.reset}
|
|
71
|
-
--model <name> Target model (e.g., gpt-4o, llama3)
|
|
72
|
-
--provider <url> API endpoint or Ollama URL
|
|
73
|
-
--type <native|ollama> Provider type (default: native)
|
|
74
|
-
--dry-run Show changes without writing
|
|
75
|
-
--output <file> Output file path
|
|
76
|
-
|
|
77
|
-
${C.bold}Experimental:${C.reset}
|
|
78
|
-
Ollama Adapter supported via --type ollama
|
|
79
|
-
|
|
80
|
-
${C.bold}Examples:${C.reset}
|
|
81
|
-
jos prompts optimize flow.jos --model llama3 --provider local
|
|
82
|
-
jos prompts provider add local http://localhost:11434 ollama
|
|
83
|
-
jos prompts generate "Deploy app"
|
|
84
|
-
`);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Provider management
|
|
89
|
-
if (subcommand === 'provider') {
|
|
90
|
-
const action = args[1];
|
|
91
|
-
const config = getProviderConfig(home);
|
|
92
|
-
|
|
93
|
-
if (action === 'list' || !action) {
|
|
94
|
-
console.log(`\n${C.cyan}${C.bold}Configured Providers${C.reset}\n`);
|
|
95
|
-
for (const [name, info] of Object.entries(config.providers)) {
|
|
96
|
-
const isDefault = config.default === name;
|
|
97
|
-
const marker = isDefault ? `${C.green}★${C.reset}` : ' ';
|
|
98
|
-
const typeLabel = info.type === 'ollama' ? `${C.yellow}[Ollama]${C.reset}` : `${C.blue}[Native]${C.reset}`;
|
|
99
|
-
console.log(` ${marker} ${C.bold}${name}${C.reset} ${typeLabel}`);
|
|
100
|
-
console.log(` ${C.gray}${info.url}${C.reset}`);
|
|
101
|
-
}
|
|
102
|
-
console.log('');
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (action === 'add') {
|
|
107
|
-
const name = args[2];
|
|
108
|
-
const url = args[3];
|
|
109
|
-
const type = args[4] || 'native'; // 'native' or 'ollama'
|
|
110
|
-
if (!name || !url) {
|
|
111
|
-
console.log(`${C.red}✖ Usage: jos prompts provider add <name> <url> [type]${C.reset}`);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
config.providers[name] = { url, type };
|
|
115
|
-
saveProviderConfig(home, config);
|
|
116
|
-
console.log(`${C.green}✓ Added provider: ${name} (${type})${C.reset}`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (action === 'remove') {
|
|
121
|
-
const name = args[2];
|
|
122
|
-
if (!config.providers[name]) return console.log(`${C.red}✖ Not found${C.reset}`);
|
|
123
|
-
delete config.providers[name];
|
|
124
|
-
if (config.default === name) config.default = 'josfox-cloud';
|
|
125
|
-
saveProviderConfig(home, config);
|
|
126
|
-
console.log(`${C.green}✓ Removed${C.reset}`);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (action === 'default') {
|
|
130
|
-
const name = args[2];
|
|
131
|
-
if (!config.providers[name]) return console.log(`${C.red}✖ Not found${C.reset}`);
|
|
132
|
-
config.default = name;
|
|
133
|
-
saveProviderConfig(home, config);
|
|
134
|
-
console.log(`${C.green}✓ Default: ${name}${C.reset}`);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Resolve Provider
|
|
141
|
-
const config = getProviderConfig(home);
|
|
142
|
-
const providerKey = config.default;
|
|
143
|
-
const providerCfg = config.providers[providerKey] || config.providers['josfox-cloud'];
|
|
144
|
-
|
|
145
|
-
// Allow overrides
|
|
146
|
-
let providerUrl = providerCfg.url;
|
|
147
|
-
let providerType = providerCfg.type || 'native';
|
|
148
|
-
|
|
149
|
-
if (args.includes('--provider')) {
|
|
150
|
-
const pName = args[args.indexOf('--provider') + 1];
|
|
151
|
-
if (config.providers[pName]) {
|
|
152
|
-
providerUrl = config.providers[pName].url;
|
|
153
|
-
providerType = config.providers[pName].type || 'native';
|
|
154
|
-
} else {
|
|
155
|
-
// Assume direct URL, default to native unless --type specified
|
|
156
|
-
providerUrl = pName;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (args.includes('--type')) {
|
|
160
|
-
providerType = args[args.indexOf('--type') + 1];
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const apiKey = getApiKey(home);
|
|
164
|
-
const model = args.includes('--model') ? args[args.indexOf('--model') + 1] : null;
|
|
165
|
-
|
|
166
|
-
// Use Factory
|
|
167
|
-
const Adapter = AdapterFactory.getAdapter(providerType);
|
|
168
|
-
|
|
169
|
-
console.log(`\n${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
170
|
-
console.log(`${C.cyan}${C.bold}JOS PROMPTS${C.reset} [${subcommand.toUpperCase()}]`);
|
|
171
|
-
console.log(`${C.dim}Provider: ${providerUrl} (${providerType})${C.reset}`);
|
|
172
|
-
if (model) console.log(`${C.dim}Model: ${model}${C.reset}`);
|
|
173
|
-
console.log(`${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`);
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
if (subcommand === 'optimize') {
|
|
177
|
-
const target = args[1];
|
|
178
|
-
if (!target) return console.log(`${C.red}✖ Target file required${C.reset}`);
|
|
179
|
-
|
|
180
|
-
const artifactPath = path.resolve(target.endsWith('.jos') ? target : target + '.jos');
|
|
181
|
-
const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8'));
|
|
182
|
-
|
|
183
|
-
console.log(`${C.yellow}⏳ Optimizing...${C.reset}`);
|
|
184
|
-
const result = await Adapter.optimize(artifact, { optimization_goals: ['clarity'] }, providerUrl, model, apiKey);
|
|
185
|
-
|
|
186
|
-
if (args.includes('--dry-run')) {
|
|
187
|
-
console.log(JSON.stringify(result.optimized_artifact, null, 2));
|
|
188
|
-
} else {
|
|
189
|
-
fs.writeFileSync(artifactPath, JSON.stringify(result.optimized_artifact, null, 2));
|
|
190
|
-
console.log(`${C.green}✓ Optimized artifact saved to ${path.basename(artifactPath)}${C.reset}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
else if (subcommand === 'validate') {
|
|
194
|
-
const target = args[1];
|
|
195
|
-
if (!target) return console.log(`${C.red}✖ Target file required${C.reset}`);
|
|
196
|
-
const artifactPath = path.resolve(target.endsWith('.jos') ? target : target + '.jos');
|
|
197
|
-
const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8'));
|
|
198
|
-
|
|
199
|
-
console.log(`${C.yellow}⏳ Validating...${C.reset}`);
|
|
200
|
-
const result = await Adapter.validate(artifact, providerUrl, model, apiKey);
|
|
201
|
-
|
|
202
|
-
console.log(`${C.cyan}Quality Score:${C.reset} ${result.quality_score}`);
|
|
203
|
-
console.log(`${C.cyan}Valid:${C.reset} ${result.valid}`);
|
|
204
|
-
if (result.issues) result.issues.forEach(i => console.log(` ${C.red}✖ ${i.message}${C.reset}`));
|
|
205
|
-
}
|
|
206
|
-
else if (subcommand === 'generate') {
|
|
207
|
-
const intention = args[1];
|
|
208
|
-
if (!intention) return console.log(`${C.red}✖ Intention required${C.reset}`);
|
|
209
|
-
|
|
210
|
-
console.log(`${C.yellow}⏳ Generating...${C.reset}`);
|
|
211
|
-
const result = await Adapter.generate(intention, { type: 'task' }, providerUrl, model, apiKey);
|
|
212
|
-
|
|
213
|
-
const outputPath = args.includes('--output') ? args[args.indexOf('--output') + 1] : null;
|
|
214
|
-
if (outputPath) {
|
|
215
|
-
fs.writeFileSync(path.resolve(outputPath), JSON.stringify(result.artifact, null, 2));
|
|
216
|
-
console.log(`${C.green}✓ Saved to ${outputPath}${C.reset}`);
|
|
217
|
-
} else {
|
|
218
|
-
console.log(JSON.stringify(result.artifact, null, 2));
|
|
219
|
-
}
|
|
220
|
-
} else {
|
|
221
|
-
console.log(`${C.red}✖ Unknown subcommand${C.reset}`);
|
|
222
|
-
}
|
|
223
|
-
} catch (e) {
|
|
224
|
-
console.error(`${C.red}✖ Error: ${e.message}${C.reset}`);
|
|
225
|
-
if (e.message && e.message.includes('ECONNREFUSED')) {
|
|
226
|
-
console.log(`${C.gray} Is Ollama running? (Try 'ollama serve')${C.reset}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
};
|
package/src/commands/repo.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JOS REPO Command - Manage package repositories
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
|
|
8
|
-
// AURORA colors
|
|
9
|
-
const C = {
|
|
10
|
-
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
11
|
-
purple: '\x1b[38;5;135m', magenta: '\x1b[38;5;198m', cyan: '\x1b[38;5;51m',
|
|
12
|
-
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m', gray: '\x1b[38;5;245m',
|
|
13
|
-
white: '\x1b[38;5;255m', yellow: '\x1b[38;5;220m'
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const DEFAULT_REPOS = {
|
|
17
|
-
default: 'https://registry.josfox.ai',
|
|
18
|
-
local: '~/.jos/artifacts'
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function getReposPath(home) {
|
|
22
|
-
return path.join(home, 'repos.json');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function loadRepos(home) {
|
|
26
|
-
const reposPath = getReposPath(home);
|
|
27
|
-
if (fs.existsSync(reposPath)) {
|
|
28
|
-
return { ...DEFAULT_REPOS, ...JSON.parse(fs.readFileSync(reposPath, 'utf8')) };
|
|
29
|
-
}
|
|
30
|
-
return { ...DEFAULT_REPOS };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function saveRepos(home, repos) {
|
|
34
|
-
const reposPath = getReposPath(home);
|
|
35
|
-
fs.writeFileSync(reposPath, JSON.stringify(repos, null, 2));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
exports.execute = async (args, home) => {
|
|
39
|
-
const action = args[0];
|
|
40
|
-
const name = args[1];
|
|
41
|
-
const url = args[2];
|
|
42
|
-
const showHelp = args.includes('--help') || args.includes('-h');
|
|
43
|
-
|
|
44
|
-
if (showHelp || !action) {
|
|
45
|
-
console.log(`
|
|
46
|
-
${C.cyan}${C.bold}JOS REPO${C.reset} - Manage package repositories
|
|
47
|
-
|
|
48
|
-
${C.white}Usage:${C.reset} jos repo <action> [name] [url]
|
|
49
|
-
|
|
50
|
-
${C.white}Actions:${C.reset}
|
|
51
|
-
list Show all configured repos
|
|
52
|
-
add <name> <url> Add a new repository
|
|
53
|
-
remove <name> Remove a repository
|
|
54
|
-
default <name> Set default repository
|
|
55
|
-
|
|
56
|
-
${C.white}Examples:${C.reset}
|
|
57
|
-
jos repo list
|
|
58
|
-
jos repo add myserver http://192.168.1.10:1111
|
|
59
|
-
jos repo add company https://artifacts.company.com
|
|
60
|
-
jos repo default myserver
|
|
61
|
-
jos repo remove myserver
|
|
62
|
-
|
|
63
|
-
${C.white}Using repos:${C.reset}
|
|
64
|
-
jos get myserver:package-name
|
|
65
|
-
jos get package --from 192.168.1.10
|
|
66
|
-
`);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const repos = loadRepos(home);
|
|
71
|
-
|
|
72
|
-
switch (action) {
|
|
73
|
-
case 'list':
|
|
74
|
-
console.log(`\n${C.cyan}${C.bold}📦 Configured Repositories${C.reset}\n`);
|
|
75
|
-
Object.entries(repos).forEach(([name, url]) => {
|
|
76
|
-
const isDefault = name === 'default';
|
|
77
|
-
const isLocal = name === 'local';
|
|
78
|
-
console.log(` ${C.white}${name}${C.reset}`);
|
|
79
|
-
console.log(` ${C.gray}${url}${C.reset}`);
|
|
80
|
-
if (isDefault) console.log(` ${C.green}★ Default registry${C.reset}`);
|
|
81
|
-
if (isLocal) console.log(` ${C.cyan}📁 Local artifacts${C.reset}`);
|
|
82
|
-
console.log();
|
|
83
|
-
});
|
|
84
|
-
console.log(`${C.dim}Config: ~/.jos/repos.json${C.reset}\n`);
|
|
85
|
-
break;
|
|
86
|
-
|
|
87
|
-
case 'add':
|
|
88
|
-
if (!name || !url) {
|
|
89
|
-
console.log(`${C.red}✖ Usage: jos repo add <name> <url>${C.reset}`);
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
if (repos[name] && name !== 'default' && name !== 'local') {
|
|
93
|
-
console.log(`${C.yellow}⚠ Repository '${name}' already exists. Updating...${C.reset}`);
|
|
94
|
-
}
|
|
95
|
-
repos[name] = url;
|
|
96
|
-
saveRepos(home, repos);
|
|
97
|
-
console.log(`${C.green}✓ Repository '${name}' added: ${url}${C.reset}`);
|
|
98
|
-
console.log(`${C.dim} Use: jos get ${name}:package-name${C.reset}`);
|
|
99
|
-
break;
|
|
100
|
-
|
|
101
|
-
case 'remove':
|
|
102
|
-
case 'rm':
|
|
103
|
-
if (!name) {
|
|
104
|
-
console.log(`${C.red}✖ Usage: jos repo remove <name>${C.reset}`);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|
|
107
|
-
if (name === 'default' || name === 'local') {
|
|
108
|
-
console.log(`${C.red}✖ Cannot remove built-in repository '${name}'${C.reset}`);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
111
|
-
if (!repos[name]) {
|
|
112
|
-
console.log(`${C.yellow}⚠ Repository '${name}' not found${C.reset}`);
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
delete repos[name];
|
|
116
|
-
saveRepos(home, repos);
|
|
117
|
-
console.log(`${C.green}✓ Repository '${name}' removed${C.reset}`);
|
|
118
|
-
break;
|
|
119
|
-
|
|
120
|
-
case 'default':
|
|
121
|
-
if (!name) {
|
|
122
|
-
console.log(`${C.white}Current default: ${repos.default}${C.reset}`);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
if (!repos[name] && !name.startsWith('http')) {
|
|
126
|
-
console.log(`${C.red}✖ Repository '${name}' not found${C.reset}`);
|
|
127
|
-
process.exit(1);
|
|
128
|
-
}
|
|
129
|
-
repos.default = repos[name] || name;
|
|
130
|
-
saveRepos(home, repos);
|
|
131
|
-
console.log(`${C.green}✓ Default repository set to: ${repos.default}${C.reset}`);
|
|
132
|
-
break;
|
|
133
|
-
|
|
134
|
-
default:
|
|
135
|
-
console.log(`${C.red}✖ Unknown action: ${action}${C.reset}`);
|
|
136
|
-
console.log(`${C.dim}Run 'jos repo --help' for usage${C.reset}`);
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
};
|
package/src/utils/crypto.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const crypto = require('crypto');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Calculate SHA-256 checksum of detailed content
|
|
6
|
-
* @param {string} content
|
|
7
|
-
* @returns {string} Hex digest
|
|
8
|
-
*/
|
|
9
|
-
exports.calculateChecksum = (content) => {
|
|
10
|
-
return crypto.createHash('sha256').update(content).digest('hex');
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Verify artifact integrity
|
|
15
|
-
* @param {object} artifact Parsed JSON artifact
|
|
16
|
-
* @param {string} rawContent Raw file content string
|
|
17
|
-
* @returns {boolean} True if valid
|
|
18
|
-
*/
|
|
19
|
-
exports.verifyIntegrity = (artifact, rawContent) => {
|
|
20
|
-
const expected = artifact.meta?.checksum;
|
|
21
|
-
if (!expected) return false;
|
|
22
|
-
|
|
23
|
-
// To verify, we need to reproduce how the checksum was calculated.
|
|
24
|
-
// Standard JOS: Checksum is of the minified JSON structure *excluding* the checksum field itself.
|
|
25
|
-
// For simplicity in this v0.0.7 alpha, we'll assume it's a file-hash if provided externally,
|
|
26
|
-
// OR we just trust the meta if we aren't doing strict reproduction yet.
|
|
27
|
-
|
|
28
|
-
// STRICT MODE:
|
|
29
|
-
// 1. Remove meta.checksum from object
|
|
30
|
-
// 2. Canonicalize JSON
|
|
31
|
-
// 3. Hash
|
|
32
|
-
|
|
33
|
-
const clone = JSON.parse(JSON.stringify(artifact));
|
|
34
|
-
if (clone.meta) delete clone.meta.checksum;
|
|
35
|
-
|
|
36
|
-
// Canonical stringify (basic)
|
|
37
|
-
const canonical = JSON.stringify(clone);
|
|
38
|
-
const calculated = exports.calculateChecksum(canonical);
|
|
39
|
-
|
|
40
|
-
return calculated === expected;
|
|
41
|
-
};
|
package/src/utils/request.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const https = require('https');
|
|
2
|
-
const http = require('http');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Shared HTTP Request Helper
|
|
6
|
-
*/
|
|
7
|
-
exports.apiRequest = async (url, method, body, apiKey) => {
|
|
8
|
-
return new Promise((resolve, reject) => {
|
|
9
|
-
const urlObj = new URL(url);
|
|
10
|
-
const client = urlObj.protocol === 'https:' ? https : http;
|
|
11
|
-
|
|
12
|
-
const options = {
|
|
13
|
-
hostname: urlObj.hostname,
|
|
14
|
-
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
|
15
|
-
path: urlObj.pathname,
|
|
16
|
-
method: method,
|
|
17
|
-
headers: {
|
|
18
|
-
'Content-Type': 'application/json',
|
|
19
|
-
'User-Agent': 'jos-cli/1.0'
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
if (apiKey) options.headers['Authorization'] = `Bearer ${apiKey}`;
|
|
24
|
-
|
|
25
|
-
const req = client.request(options, (res) => {
|
|
26
|
-
let data = '';
|
|
27
|
-
res.on('data', chunk => data += chunk);
|
|
28
|
-
res.on('end', () => {
|
|
29
|
-
try {
|
|
30
|
-
resolve({ status: res.statusCode, data: JSON.parse(data) });
|
|
31
|
-
} catch {
|
|
32
|
-
resolve({ status: res.statusCode, data: data });
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
req.on('error', reject);
|
|
38
|
-
if (body) req.write(JSON.stringify(body));
|
|
39
|
-
req.end();
|
|
40
|
-
});
|
|
41
|
-
};
|