@stoneforge/quarry 0.1.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 +13 -0
- package/README.md +160 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/quarry-api.d.ts +268 -0
- package/dist/api/quarry-api.d.ts.map +1 -0
- package/dist/api/quarry-api.js +3905 -0
- package/dist/api/quarry-api.js.map +1 -0
- package/dist/api/types.d.ts +1359 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +204 -0
- package/dist/api/types.js.map +1 -0
- package/dist/bin/sf.d.ts +3 -0
- package/dist/bin/sf.d.ts.map +1 -0
- package/dist/bin/sf.js +9 -0
- package/dist/bin/sf.js.map +1 -0
- package/dist/cli/commands/admin.d.ts +11 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +465 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/commands/alias.d.ts +8 -0
- package/dist/cli/commands/alias.d.ts.map +1 -0
- package/dist/cli/commands/alias.js +70 -0
- package/dist/cli/commands/alias.js.map +1 -0
- package/dist/cli/commands/channel.d.ts +13 -0
- package/dist/cli/commands/channel.d.ts.map +1 -0
- package/dist/cli/commands/channel.js +680 -0
- package/dist/cli/commands/channel.js.map +1 -0
- package/dist/cli/commands/completion.d.ts +8 -0
- package/dist/cli/commands/completion.d.ts.map +1 -0
- package/dist/cli/commands/completion.js +87 -0
- package/dist/cli/commands/completion.js.map +1 -0
- package/dist/cli/commands/config.d.ts +12 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +242 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/crud.d.ts +64 -0
- package/dist/cli/commands/crud.d.ts.map +1 -0
- package/dist/cli/commands/crud.js +805 -0
- package/dist/cli/commands/crud.js.map +1 -0
- package/dist/cli/commands/dep.d.ts +16 -0
- package/dist/cli/commands/dep.d.ts.map +1 -0
- package/dist/cli/commands/dep.js +499 -0
- package/dist/cli/commands/dep.js.map +1 -0
- package/dist/cli/commands/document.d.ts +12 -0
- package/dist/cli/commands/document.d.ts.map +1 -0
- package/dist/cli/commands/document.js +1039 -0
- package/dist/cli/commands/document.js.map +1 -0
- package/dist/cli/commands/embeddings.d.ts +12 -0
- package/dist/cli/commands/embeddings.d.ts.map +1 -0
- package/dist/cli/commands/embeddings.js +273 -0
- package/dist/cli/commands/embeddings.js.map +1 -0
- package/dist/cli/commands/entity.d.ts +16 -0
- package/dist/cli/commands/entity.d.ts.map +1 -0
- package/dist/cli/commands/entity.js +522 -0
- package/dist/cli/commands/entity.js.map +1 -0
- package/dist/cli/commands/gc.d.ts +10 -0
- package/dist/cli/commands/gc.d.ts.map +1 -0
- package/dist/cli/commands/gc.js +257 -0
- package/dist/cli/commands/gc.js.map +1 -0
- package/dist/cli/commands/help.d.ts +11 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +169 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/history.d.ts +9 -0
- package/dist/cli/commands/history.d.ts.map +1 -0
- package/dist/cli/commands/history.js +160 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/identity.d.ts +18 -0
- package/dist/cli/commands/identity.d.ts.map +1 -0
- package/dist/cli/commands/identity.js +698 -0
- package/dist/cli/commands/identity.js.map +1 -0
- package/dist/cli/commands/inbox.d.ts +20 -0
- package/dist/cli/commands/inbox.d.ts.map +1 -0
- package/dist/cli/commands/inbox.js +493 -0
- package/dist/cli/commands/inbox.js.map +1 -0
- package/dist/cli/commands/init.d.ts +20 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +144 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install.d.ts +9 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +200 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/library.d.ts +12 -0
- package/dist/cli/commands/library.d.ts.map +1 -0
- package/dist/cli/commands/library.js +665 -0
- package/dist/cli/commands/library.js.map +1 -0
- package/dist/cli/commands/message.d.ts +11 -0
- package/dist/cli/commands/message.d.ts.map +1 -0
- package/dist/cli/commands/message.js +608 -0
- package/dist/cli/commands/message.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +17 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +698 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/playbook.d.ts +12 -0
- package/dist/cli/commands/playbook.d.ts.map +1 -0
- package/dist/cli/commands/playbook.js +730 -0
- package/dist/cli/commands/playbook.js.map +1 -0
- package/dist/cli/commands/reset.d.ts +12 -0
- package/dist/cli/commands/reset.d.ts.map +1 -0
- package/dist/cli/commands/reset.js +306 -0
- package/dist/cli/commands/reset.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +11 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +106 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +8 -0
- package/dist/cli/commands/stats.d.ts.map +1 -0
- package/dist/cli/commands/stats.js +82 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +14 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +370 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/task.d.ts +25 -0
- package/dist/cli/commands/task.d.ts.map +1 -0
- package/dist/cli/commands/task.js +1153 -0
- package/dist/cli/commands/task.js.map +1 -0
- package/dist/cli/commands/team.d.ts +13 -0
- package/dist/cli/commands/team.d.ts.map +1 -0
- package/dist/cli/commands/team.js +471 -0
- package/dist/cli/commands/team.js.map +1 -0
- package/dist/cli/commands/workflow.d.ts +16 -0
- package/dist/cli/commands/workflow.d.ts.map +1 -0
- package/dist/cli/commands/workflow.js +753 -0
- package/dist/cli/commands/workflow.js.map +1 -0
- package/dist/cli/completion.d.ts +28 -0
- package/dist/cli/completion.d.ts.map +1 -0
- package/dist/cli/completion.js +295 -0
- package/dist/cli/completion.js.map +1 -0
- package/dist/cli/db.d.ts +38 -0
- package/dist/cli/db.d.ts.map +1 -0
- package/dist/cli/db.js +90 -0
- package/dist/cli/db.js.map +1 -0
- package/dist/cli/formatter.d.ts +87 -0
- package/dist/cli/formatter.d.ts.map +1 -0
- package/dist/cli/formatter.js +464 -0
- package/dist/cli/formatter.js.map +1 -0
- package/dist/cli/index.d.ts +33 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +38 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parser.d.ts +45 -0
- package/dist/cli/parser.d.ts.map +1 -0
- package/dist/cli/parser.js +256 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/cli/plugin-loader.d.ts +39 -0
- package/dist/cli/plugin-loader.d.ts.map +1 -0
- package/dist/cli/plugin-loader.js +165 -0
- package/dist/cli/plugin-loader.js.map +1 -0
- package/dist/cli/plugin-registry.d.ts +50 -0
- package/dist/cli/plugin-registry.d.ts.map +1 -0
- package/dist/cli/plugin-registry.js +206 -0
- package/dist/cli/plugin-registry.js.map +1 -0
- package/dist/cli/plugin-types.d.ts +106 -0
- package/dist/cli/plugin-types.d.ts.map +1 -0
- package/dist/cli/plugin-types.js +103 -0
- package/dist/cli/plugin-types.js.map +1 -0
- package/dist/cli/runner.d.ts +35 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +340 -0
- package/dist/cli/runner.js.map +1 -0
- package/dist/cli/suggest.d.ts +15 -0
- package/dist/cli/suggest.d.ts.map +1 -0
- package/dist/cli/suggest.js +49 -0
- package/dist/cli/suggest.js.map +1 -0
- package/dist/cli/types.d.ts +138 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +63 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/config/config.d.ts +86 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +348 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/defaults.d.ts +66 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +114 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/duration.d.ts +75 -0
- package/dist/config/duration.d.ts.map +1 -0
- package/dist/config/duration.js +190 -0
- package/dist/config/duration.js.map +1 -0
- package/dist/config/env.d.ts +67 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +207 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/file.d.ts +97 -0
- package/dist/config/file.d.ts.map +1 -0
- package/dist/config/file.js +365 -0
- package/dist/config/file.js.map +1 -0
- package/dist/config/index.d.ts +35 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +41 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/merge.d.ts +53 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +226 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/types.d.ts +257 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +72 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validation.d.ts +55 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +251 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/http/index.d.ts +8 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +12 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/sync-handlers.d.ts +162 -0
- package/dist/http/sync-handlers.d.ts.map +1 -0
- package/dist/http/sync-handlers.js +271 -0
- package/dist/http/sync-handlers.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/server/index.d.ts +34 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3329 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/static.d.ts +18 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +71 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/ws/broadcaster.d.ts +8 -0
- package/dist/server/ws/broadcaster.d.ts.map +1 -0
- package/dist/server/ws/broadcaster.js +7 -0
- package/dist/server/ws/broadcaster.js.map +1 -0
- package/dist/server/ws/handler.d.ts +55 -0
- package/dist/server/ws/handler.d.ts.map +1 -0
- package/dist/server/ws/handler.js +160 -0
- package/dist/server/ws/handler.js.map +1 -0
- package/dist/services/blocked-cache.d.ts +297 -0
- package/dist/services/blocked-cache.d.ts.map +1 -0
- package/dist/services/blocked-cache.js +755 -0
- package/dist/services/blocked-cache.js.map +1 -0
- package/dist/services/dependency.d.ts +205 -0
- package/dist/services/dependency.d.ts.map +1 -0
- package/dist/services/dependency.js +566 -0
- package/dist/services/dependency.js.map +1 -0
- package/dist/services/embeddings/fusion.d.ts +33 -0
- package/dist/services/embeddings/fusion.d.ts.map +1 -0
- package/dist/services/embeddings/fusion.js +34 -0
- package/dist/services/embeddings/fusion.js.map +1 -0
- package/dist/services/embeddings/index.d.ts +12 -0
- package/dist/services/embeddings/index.d.ts.map +1 -0
- package/dist/services/embeddings/index.js +10 -0
- package/dist/services/embeddings/index.js.map +1 -0
- package/dist/services/embeddings/local-provider.d.ts +31 -0
- package/dist/services/embeddings/local-provider.d.ts.map +1 -0
- package/dist/services/embeddings/local-provider.js +80 -0
- package/dist/services/embeddings/local-provider.js.map +1 -0
- package/dist/services/embeddings/service.d.ts +76 -0
- package/dist/services/embeddings/service.d.ts.map +1 -0
- package/dist/services/embeddings/service.js +153 -0
- package/dist/services/embeddings/service.js.map +1 -0
- package/dist/services/embeddings/types.d.ts +70 -0
- package/dist/services/embeddings/types.d.ts.map +1 -0
- package/dist/services/embeddings/types.js +8 -0
- package/dist/services/embeddings/types.js.map +1 -0
- package/dist/services/id-length-cache.d.ts +156 -0
- package/dist/services/id-length-cache.d.ts.map +1 -0
- package/dist/services/id-length-cache.js +197 -0
- package/dist/services/id-length-cache.js.map +1 -0
- package/dist/services/inbox.d.ts +147 -0
- package/dist/services/inbox.d.ts.map +1 -0
- package/dist/services/inbox.js +428 -0
- package/dist/services/inbox.js.map +1 -0
- package/dist/services/index.d.ts +10 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +10 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/priority-service.d.ts +145 -0
- package/dist/services/priority-service.d.ts.map +1 -0
- package/dist/services/priority-service.js +272 -0
- package/dist/services/priority-service.js.map +1 -0
- package/dist/services/search-utils.d.ts +47 -0
- package/dist/services/search-utils.d.ts.map +1 -0
- package/dist/services/search-utils.js +83 -0
- package/dist/services/search-utils.js.map +1 -0
- package/dist/sync/hash.d.ts +48 -0
- package/dist/sync/hash.d.ts.map +1 -0
- package/dist/sync/hash.js +136 -0
- package/dist/sync/hash.js.map +1 -0
- package/dist/sync/index.d.ts +11 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +16 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/merge.d.ts +80 -0
- package/dist/sync/merge.d.ts.map +1 -0
- package/dist/sync/merge.js +310 -0
- package/dist/sync/merge.js.map +1 -0
- package/dist/sync/serialization.d.ts +132 -0
- package/dist/sync/serialization.d.ts.map +1 -0
- package/dist/sync/serialization.js +306 -0
- package/dist/sync/serialization.js.map +1 -0
- package/dist/sync/service.d.ts +102 -0
- package/dist/sync/service.d.ts.map +1 -0
- package/dist/sync/service.js +493 -0
- package/dist/sync/service.js.map +1 -0
- package/dist/sync/types.d.ts +275 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +76 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/systems/identity.d.ts +479 -0
- package/dist/systems/identity.d.ts.map +1 -0
- package/dist/systems/identity.js +817 -0
- package/dist/systems/identity.js.map +1 -0
- package/dist/systems/index.d.ts +8 -0
- package/dist/systems/index.d.ts.map +1 -0
- package/dist/systems/index.js +29 -0
- package/dist/systems/index.js.map +1 -0
- package/package.json +121 -0
- package/web/assets/charts-vendor-D1YcbGux.js +55 -0
- package/web/assets/dnd-vendor-DmxE-_ZH.js +5 -0
- package/web/assets/editor-vendor-BxraAWts.js +279 -0
- package/web/assets/index-B77vv208.js +341 -0
- package/web/assets/index-CF_XnVLh.css +1 -0
- package/web/assets/router-vendor-BCKpRBrB.js +41 -0
- package/web/assets/ui-vendor-DUahGnbT.js +45 -0
- package/web/assets/utils-vendor-CfYKiENT.js +813 -0
- package/web/favicon.ico +0 -0
- package/web/index.html +23 -0
- package/web/logo.png +0 -0
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Commands - Identity management and whoami
|
|
3
|
+
*
|
|
4
|
+
* Provides CLI commands for identity operations:
|
|
5
|
+
* - whoami: Show current actor context
|
|
6
|
+
* - identity: Parent command for identity operations
|
|
7
|
+
* - sign: Sign data using a private key
|
|
8
|
+
* - verify: Verify a signature against data
|
|
9
|
+
* - keygen: Generate a new Ed25519 keypair
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
import { success, failure, ExitCode } from '../types.js';
|
|
13
|
+
import { getOutputMode } from '../formatter.js';
|
|
14
|
+
import { getValue, getValueSource, loadConfig } from '../../config/index.js';
|
|
15
|
+
import { IdentityMode, ActorSource, signEd25519, verifyEd25519Signature, generateEd25519Keypair, constructSignedData, hashRequestBody, isValidPublicKey, isValidSignature, isValidRequestHash, } from '../../systems/identity.js';
|
|
16
|
+
/**
|
|
17
|
+
* Resolves the current actor from various sources
|
|
18
|
+
*
|
|
19
|
+
* Priority order (highest to lowest):
|
|
20
|
+
* 1. CLI --actor flag
|
|
21
|
+
* 2. STONEFORGE_ACTOR environment variable
|
|
22
|
+
* 3. Config file actor setting
|
|
23
|
+
* 4. Default fallback
|
|
24
|
+
*/
|
|
25
|
+
function resolveCurrentActor(options) {
|
|
26
|
+
// Load config with CLI overrides
|
|
27
|
+
const cliOverrides = options.actor ? { actor: options.actor } : undefined;
|
|
28
|
+
loadConfig({ cliOverrides });
|
|
29
|
+
// Get identity mode
|
|
30
|
+
const mode = getValue('identity.mode');
|
|
31
|
+
// Check CLI flag first
|
|
32
|
+
if (options.actor) {
|
|
33
|
+
return {
|
|
34
|
+
actor: options.actor,
|
|
35
|
+
source: ActorSource.CLI_FLAG,
|
|
36
|
+
verified: false,
|
|
37
|
+
mode,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Check configured actor
|
|
41
|
+
const configuredActor = getValue('actor');
|
|
42
|
+
if (configuredActor) {
|
|
43
|
+
const source = getValueSource('actor');
|
|
44
|
+
return {
|
|
45
|
+
actor: configuredActor,
|
|
46
|
+
source,
|
|
47
|
+
verified: false,
|
|
48
|
+
mode,
|
|
49
|
+
details: source === 'environment' ? { envVar: 'STONEFORGE_ACTOR' } : undefined,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// No actor configured - return indication
|
|
53
|
+
return {
|
|
54
|
+
actor: '',
|
|
55
|
+
source: ActorSource.SYSTEM,
|
|
56
|
+
verified: false,
|
|
57
|
+
mode,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// ============================================================================
|
|
61
|
+
// Whoami Command
|
|
62
|
+
// ============================================================================
|
|
63
|
+
async function whoamiHandler(_args, options) {
|
|
64
|
+
const resolution = resolveCurrentActor(options);
|
|
65
|
+
const mode = getOutputMode(options);
|
|
66
|
+
// Build data object for JSON output
|
|
67
|
+
const data = {
|
|
68
|
+
actor: resolution.actor || null,
|
|
69
|
+
source: resolution.source,
|
|
70
|
+
verified: resolution.verified,
|
|
71
|
+
identityMode: resolution.mode,
|
|
72
|
+
...(resolution.details && { details: resolution.details }),
|
|
73
|
+
};
|
|
74
|
+
if (mode === 'json') {
|
|
75
|
+
return success(data);
|
|
76
|
+
}
|
|
77
|
+
if (mode === 'quiet') {
|
|
78
|
+
if (!resolution.actor) {
|
|
79
|
+
return failure('No actor configured', ExitCode.NOT_FOUND);
|
|
80
|
+
}
|
|
81
|
+
return success(resolution.actor);
|
|
82
|
+
}
|
|
83
|
+
// Human-readable output
|
|
84
|
+
if (!resolution.actor) {
|
|
85
|
+
const lines = [
|
|
86
|
+
'No actor configured.',
|
|
87
|
+
'',
|
|
88
|
+
'Set an actor using one of:',
|
|
89
|
+
' --actor <name> CLI flag (highest priority)',
|
|
90
|
+
' STONEFORGE_ACTOR=<name> Environment variable',
|
|
91
|
+
' sf config set actor <name> Configuration file',
|
|
92
|
+
];
|
|
93
|
+
return success(data, lines.join('\n'));
|
|
94
|
+
}
|
|
95
|
+
// Build formatted output
|
|
96
|
+
const lines = [];
|
|
97
|
+
lines.push(`Actor: ${resolution.actor}`);
|
|
98
|
+
lines.push(`Source: ${formatSource(resolution.source)}`);
|
|
99
|
+
lines.push(`Identity Mode: ${resolution.mode}`);
|
|
100
|
+
lines.push(`Verified: ${resolution.verified ? 'yes' : 'no'}`);
|
|
101
|
+
if (resolution.details?.envVar) {
|
|
102
|
+
lines.push(`Environment Variable: ${resolution.details.envVar}`);
|
|
103
|
+
}
|
|
104
|
+
return success(data, lines.join('\n'));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Formats a source value for human display
|
|
108
|
+
*/
|
|
109
|
+
function formatSource(source) {
|
|
110
|
+
switch (source) {
|
|
111
|
+
case ActorSource.CLI_FLAG:
|
|
112
|
+
case 'cli':
|
|
113
|
+
return 'CLI --actor flag';
|
|
114
|
+
case ActorSource.CONFIG:
|
|
115
|
+
case 'file':
|
|
116
|
+
return 'configuration file';
|
|
117
|
+
case 'environment':
|
|
118
|
+
return 'environment variable';
|
|
119
|
+
case ActorSource.EXPLICIT:
|
|
120
|
+
return 'explicit';
|
|
121
|
+
case ActorSource.ELEMENT:
|
|
122
|
+
return 'element';
|
|
123
|
+
case ActorSource.SYSTEM:
|
|
124
|
+
return 'system';
|
|
125
|
+
case 'default':
|
|
126
|
+
return 'default';
|
|
127
|
+
default:
|
|
128
|
+
return String(source);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export const whoamiCommand = {
|
|
132
|
+
name: 'whoami',
|
|
133
|
+
description: 'Show current actor identity',
|
|
134
|
+
usage: 'sf whoami',
|
|
135
|
+
help: `Display the current actor identity and how it was determined.
|
|
136
|
+
|
|
137
|
+
The actor is resolved from multiple sources in priority order:
|
|
138
|
+
1. CLI --actor flag (highest priority)
|
|
139
|
+
2. STONEFORGE_ACTOR environment variable
|
|
140
|
+
3. Configuration file (actor setting)
|
|
141
|
+
4. No actor (operations will require explicit actor)
|
|
142
|
+
|
|
143
|
+
Output includes:
|
|
144
|
+
- Actor name
|
|
145
|
+
- Source of the actor identity
|
|
146
|
+
- Identity mode (soft, cryptographic, hybrid)
|
|
147
|
+
- Verification status
|
|
148
|
+
|
|
149
|
+
Examples:
|
|
150
|
+
sf whoami
|
|
151
|
+
sf whoami --json
|
|
152
|
+
sf --actor myagent whoami`,
|
|
153
|
+
options: [],
|
|
154
|
+
handler: whoamiHandler,
|
|
155
|
+
};
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// Identity Parent Command
|
|
158
|
+
// ============================================================================
|
|
159
|
+
async function identityHandler(args, options) {
|
|
160
|
+
// If no subcommand, show current identity (same as whoami)
|
|
161
|
+
return whoamiHandler(args, options);
|
|
162
|
+
}
|
|
163
|
+
// ============================================================================
|
|
164
|
+
// Private Key Resolution Helper
|
|
165
|
+
// ============================================================================
|
|
166
|
+
/**
|
|
167
|
+
* Resolves the private key from CLI options or environment
|
|
168
|
+
*
|
|
169
|
+
* Priority order:
|
|
170
|
+
* 1. --sign-key flag (direct key)
|
|
171
|
+
* 2. --sign-key-file flag (path to key file)
|
|
172
|
+
* 3. STONEFORGE_SIGN_KEY environment variable
|
|
173
|
+
* 4. STONEFORGE_SIGN_KEY_FILE environment variable
|
|
174
|
+
*/
|
|
175
|
+
function resolvePrivateKey(options) {
|
|
176
|
+
// Check direct key from CLI
|
|
177
|
+
if (options.signKey) {
|
|
178
|
+
return { key: options.signKey, source: 'cli_flag' };
|
|
179
|
+
}
|
|
180
|
+
// Check key file from CLI
|
|
181
|
+
if (options.signKeyFile) {
|
|
182
|
+
try {
|
|
183
|
+
const key = readFileSync(options.signKeyFile, 'utf8').trim();
|
|
184
|
+
return { key, source: 'cli_file' };
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
188
|
+
throw new Error(`Failed to read key file: ${message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Check environment variable for direct key
|
|
192
|
+
const envKey = process.env.STONEFORGE_SIGN_KEY;
|
|
193
|
+
if (envKey) {
|
|
194
|
+
return { key: envKey, source: 'environment' };
|
|
195
|
+
}
|
|
196
|
+
// Check environment variable for key file
|
|
197
|
+
const envKeyFile = process.env.STONEFORGE_SIGN_KEY_FILE;
|
|
198
|
+
if (envKeyFile) {
|
|
199
|
+
try {
|
|
200
|
+
const key = readFileSync(envKeyFile, 'utf8').trim();
|
|
201
|
+
return { key, source: 'environment_file' };
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
205
|
+
throw new Error(`Failed to read key file from STONEFORGE_SIGN_KEY_FILE: ${message}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return { key: null, source: 'none' };
|
|
209
|
+
}
|
|
210
|
+
const signOptions = [
|
|
211
|
+
{
|
|
212
|
+
name: 'data',
|
|
213
|
+
short: 'd',
|
|
214
|
+
description: 'Data to sign (string)',
|
|
215
|
+
hasValue: true,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'file',
|
|
219
|
+
short: 'f',
|
|
220
|
+
description: 'Path to file containing data to sign',
|
|
221
|
+
hasValue: true,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'hash',
|
|
225
|
+
description: 'Pre-computed hash to sign (for request signing)',
|
|
226
|
+
hasValue: true,
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
async function signHandler(_args, options) {
|
|
230
|
+
const mode = getOutputMode(options);
|
|
231
|
+
// Resolve actor
|
|
232
|
+
const resolution = resolveCurrentActor(options);
|
|
233
|
+
if (!resolution.actor) {
|
|
234
|
+
return failure('Actor is required for signing. Use --actor <name>', ExitCode.VALIDATION);
|
|
235
|
+
}
|
|
236
|
+
// Resolve private key
|
|
237
|
+
let keyInfo;
|
|
238
|
+
try {
|
|
239
|
+
keyInfo = resolvePrivateKey(options);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
243
|
+
return failure(message, ExitCode.GENERAL_ERROR);
|
|
244
|
+
}
|
|
245
|
+
if (!keyInfo.key) {
|
|
246
|
+
return failure('Private key is required for signing. Use --sign-key <key>, --sign-key-file <path>, or set STONEFORGE_SIGN_KEY', ExitCode.VALIDATION);
|
|
247
|
+
}
|
|
248
|
+
// Get data to sign
|
|
249
|
+
let dataToSign;
|
|
250
|
+
let requestHash;
|
|
251
|
+
if (options.hash) {
|
|
252
|
+
// Validate pre-computed hash format
|
|
253
|
+
if (!isValidRequestHash(options.hash)) {
|
|
254
|
+
return failure('Invalid hash format. Expected 64-character hex-encoded SHA256 hash', ExitCode.VALIDATION);
|
|
255
|
+
}
|
|
256
|
+
requestHash = options.hash;
|
|
257
|
+
}
|
|
258
|
+
else if (options.data) {
|
|
259
|
+
// Hash the provided data
|
|
260
|
+
requestHash = await hashRequestBody(options.data);
|
|
261
|
+
}
|
|
262
|
+
else if (options.file) {
|
|
263
|
+
// Read and hash file contents
|
|
264
|
+
try {
|
|
265
|
+
const fileData = readFileSync(options.file, 'utf8');
|
|
266
|
+
requestHash = await hashRequestBody(fileData);
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
270
|
+
return failure(`Failed to read file: ${message}`, ExitCode.GENERAL_ERROR);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
return failure('No data to sign. Use --data <string>, --file <path>, or --hash <hash>', ExitCode.VALIDATION);
|
|
275
|
+
}
|
|
276
|
+
// Create signed data string
|
|
277
|
+
const signedAt = new Date().toISOString();
|
|
278
|
+
dataToSign = constructSignedData({
|
|
279
|
+
actor: resolution.actor,
|
|
280
|
+
signedAt,
|
|
281
|
+
requestHash,
|
|
282
|
+
});
|
|
283
|
+
// Sign the data
|
|
284
|
+
try {
|
|
285
|
+
const signature = await signEd25519(keyInfo.key, dataToSign);
|
|
286
|
+
const data = {
|
|
287
|
+
signature,
|
|
288
|
+
signedAt,
|
|
289
|
+
actor: resolution.actor,
|
|
290
|
+
requestHash,
|
|
291
|
+
keySource: keyInfo.source,
|
|
292
|
+
};
|
|
293
|
+
if (mode === 'json') {
|
|
294
|
+
return success(data);
|
|
295
|
+
}
|
|
296
|
+
if (mode === 'quiet') {
|
|
297
|
+
return success(signature);
|
|
298
|
+
}
|
|
299
|
+
const lines = [];
|
|
300
|
+
lines.push(`Signature: ${signature}`);
|
|
301
|
+
lines.push(`Signed At: ${signedAt}`);
|
|
302
|
+
lines.push(`Actor: ${resolution.actor}`);
|
|
303
|
+
lines.push(`Request Hash: ${requestHash}`);
|
|
304
|
+
lines.push(`Key Source: ${keyInfo.source}`);
|
|
305
|
+
return success(data, lines.join('\n'));
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
309
|
+
return failure(`Failed to sign data: ${message}`, ExitCode.GENERAL_ERROR);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
export const signCommand = {
|
|
313
|
+
name: 'sign',
|
|
314
|
+
description: 'Sign data using a private key',
|
|
315
|
+
usage: 'sf identity sign [options]',
|
|
316
|
+
help: `Sign data using an Ed25519 private key.
|
|
317
|
+
|
|
318
|
+
The signature is computed over: actor|signedAt|requestHash
|
|
319
|
+
|
|
320
|
+
Options:
|
|
321
|
+
-d, --data <string> Data to sign (will be hashed)
|
|
322
|
+
-f, --file <path> File containing data to sign
|
|
323
|
+
--hash <hash> Pre-computed SHA256 hash (hex)
|
|
324
|
+
--sign-key <key> Private key (base64 PKCS8)
|
|
325
|
+
--sign-key-file <path> Path to private key file
|
|
326
|
+
|
|
327
|
+
The private key can also be set via environment variables:
|
|
328
|
+
STONEFORGE_SIGN_KEY Direct base64-encoded private key
|
|
329
|
+
STONEFORGE_SIGN_KEY_FILE Path to file containing private key
|
|
330
|
+
|
|
331
|
+
Examples:
|
|
332
|
+
sf identity sign --data "hello world" --sign-key <key> --actor alice
|
|
333
|
+
sf identity sign --file request.json --sign-key-file ~/.stoneforge/private.key
|
|
334
|
+
sf identity sign --hash abc123... --actor alice`,
|
|
335
|
+
options: signOptions,
|
|
336
|
+
handler: signHandler,
|
|
337
|
+
};
|
|
338
|
+
const verifyOptions = [
|
|
339
|
+
{
|
|
340
|
+
name: 'signature',
|
|
341
|
+
short: 's',
|
|
342
|
+
description: 'Signature to verify (base64)',
|
|
343
|
+
hasValue: true,
|
|
344
|
+
required: true,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: 'data',
|
|
348
|
+
short: 'd',
|
|
349
|
+
description: 'Original data that was signed',
|
|
350
|
+
hasValue: true,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: 'file',
|
|
354
|
+
short: 'f',
|
|
355
|
+
description: 'Path to file containing original data',
|
|
356
|
+
hasValue: true,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: 'hash',
|
|
360
|
+
description: 'Request hash that was signed',
|
|
361
|
+
hasValue: true,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: 'public-key',
|
|
365
|
+
short: 'k',
|
|
366
|
+
description: 'Public key to verify against (base64)',
|
|
367
|
+
hasValue: true,
|
|
368
|
+
required: true,
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: 'signed-at',
|
|
372
|
+
description: 'Timestamp when signature was created (ISO 8601)',
|
|
373
|
+
hasValue: true,
|
|
374
|
+
required: true,
|
|
375
|
+
},
|
|
376
|
+
];
|
|
377
|
+
async function verifyHandler(_args, options) {
|
|
378
|
+
const mode = getOutputMode(options);
|
|
379
|
+
// Validate required options
|
|
380
|
+
if (!options.signature) {
|
|
381
|
+
return failure('--signature is required', ExitCode.VALIDATION);
|
|
382
|
+
}
|
|
383
|
+
if (!options['public-key']) {
|
|
384
|
+
return failure('--public-key is required', ExitCode.VALIDATION);
|
|
385
|
+
}
|
|
386
|
+
if (!options['signed-at']) {
|
|
387
|
+
return failure('--signed-at is required', ExitCode.VALIDATION);
|
|
388
|
+
}
|
|
389
|
+
// Resolve actor
|
|
390
|
+
const resolution = resolveCurrentActor(options);
|
|
391
|
+
if (!resolution.actor) {
|
|
392
|
+
return failure('Actor is required for verification. Use --actor <name>', ExitCode.VALIDATION);
|
|
393
|
+
}
|
|
394
|
+
// Validate signature format
|
|
395
|
+
if (!isValidSignature(options.signature)) {
|
|
396
|
+
return failure('Invalid signature format. Expected 88-character base64 string', ExitCode.VALIDATION);
|
|
397
|
+
}
|
|
398
|
+
// Validate public key format
|
|
399
|
+
if (!isValidPublicKey(options['public-key'])) {
|
|
400
|
+
return failure('Invalid public key format. Expected 44-character base64 string', ExitCode.VALIDATION);
|
|
401
|
+
}
|
|
402
|
+
// Get request hash
|
|
403
|
+
let requestHash;
|
|
404
|
+
if (options.hash) {
|
|
405
|
+
// Validate pre-computed hash format
|
|
406
|
+
if (!isValidRequestHash(options.hash)) {
|
|
407
|
+
return failure('Invalid hash format. Expected 64-character hex-encoded SHA256 hash', ExitCode.VALIDATION);
|
|
408
|
+
}
|
|
409
|
+
requestHash = options.hash;
|
|
410
|
+
}
|
|
411
|
+
else if (options.data) {
|
|
412
|
+
requestHash = await hashRequestBody(options.data);
|
|
413
|
+
}
|
|
414
|
+
else if (options.file) {
|
|
415
|
+
try {
|
|
416
|
+
const fileData = readFileSync(options.file, 'utf8');
|
|
417
|
+
requestHash = await hashRequestBody(fileData);
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
421
|
+
return failure(`Failed to read file: ${message}`, ExitCode.GENERAL_ERROR);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
return failure('Must provide --data, --file, or --hash', ExitCode.VALIDATION);
|
|
426
|
+
}
|
|
427
|
+
// Construct signed data
|
|
428
|
+
const signedData = constructSignedData({
|
|
429
|
+
actor: resolution.actor,
|
|
430
|
+
signedAt: options['signed-at'],
|
|
431
|
+
requestHash,
|
|
432
|
+
});
|
|
433
|
+
// Verify the signature
|
|
434
|
+
try {
|
|
435
|
+
const valid = await verifyEd25519Signature(options['public-key'], options.signature, signedData);
|
|
436
|
+
const data = {
|
|
437
|
+
valid,
|
|
438
|
+
actor: resolution.actor,
|
|
439
|
+
signedAt: options['signed-at'],
|
|
440
|
+
requestHash,
|
|
441
|
+
};
|
|
442
|
+
if (mode === 'json') {
|
|
443
|
+
return success(data);
|
|
444
|
+
}
|
|
445
|
+
if (mode === 'quiet') {
|
|
446
|
+
return success(valid ? 'valid' : 'invalid');
|
|
447
|
+
}
|
|
448
|
+
if (valid) {
|
|
449
|
+
return success(data, 'Signature is VALID');
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
return success(data, 'Signature is INVALID');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
catch (err) {
|
|
456
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
457
|
+
return failure(`Failed to verify signature: ${message}`, ExitCode.GENERAL_ERROR);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
export const verifyCommand = {
|
|
461
|
+
name: 'verify',
|
|
462
|
+
description: 'Verify a signature against data',
|
|
463
|
+
usage: 'sf identity verify [options]',
|
|
464
|
+
help: `Verify an Ed25519 signature against data.
|
|
465
|
+
|
|
466
|
+
The signature must have been computed over: actor|signedAt|requestHash
|
|
467
|
+
|
|
468
|
+
Required options:
|
|
469
|
+
-s, --signature <sig> Signature to verify (base64)
|
|
470
|
+
-k, --public-key <key> Public key (base64)
|
|
471
|
+
--signed-at <time> Timestamp when signed (ISO 8601)
|
|
472
|
+
|
|
473
|
+
Data options (one required):
|
|
474
|
+
-d, --data <string> Original data that was signed
|
|
475
|
+
-f, --file <path> File containing original data
|
|
476
|
+
--hash <hash> Request hash that was signed
|
|
477
|
+
|
|
478
|
+
Examples:
|
|
479
|
+
sf identity verify --signature <sig> --public-key <key> --signed-at 2024-01-01T00:00:00Z --data "hello" --actor alice
|
|
480
|
+
sf identity verify -s <sig> -k <key> --signed-at <time> --hash abc123... --actor alice`,
|
|
481
|
+
options: verifyOptions,
|
|
482
|
+
handler: verifyHandler,
|
|
483
|
+
};
|
|
484
|
+
// ============================================================================
|
|
485
|
+
// Keygen Command
|
|
486
|
+
// ============================================================================
|
|
487
|
+
async function keygenHandler(_args, options) {
|
|
488
|
+
const mode = getOutputMode(options);
|
|
489
|
+
try {
|
|
490
|
+
const keypair = await generateEd25519Keypair();
|
|
491
|
+
const data = {
|
|
492
|
+
publicKey: keypair.publicKey,
|
|
493
|
+
privateKey: keypair.privateKey,
|
|
494
|
+
};
|
|
495
|
+
if (mode === 'json') {
|
|
496
|
+
return success(data);
|
|
497
|
+
}
|
|
498
|
+
if (mode === 'quiet') {
|
|
499
|
+
// In quiet mode, return just the public key (safest for scripts)
|
|
500
|
+
return success(keypair.publicKey);
|
|
501
|
+
}
|
|
502
|
+
const lines = [];
|
|
503
|
+
lines.push('Generated Ed25519 keypair:');
|
|
504
|
+
lines.push('');
|
|
505
|
+
lines.push(`Public Key: ${keypair.publicKey}`);
|
|
506
|
+
lines.push(`Private Key: ${keypair.privateKey}`);
|
|
507
|
+
lines.push('');
|
|
508
|
+
lines.push('IMPORTANT: Store the private key securely. It cannot be recovered.');
|
|
509
|
+
lines.push('');
|
|
510
|
+
lines.push('Register this entity with:');
|
|
511
|
+
lines.push(` sf entity register <name> --public-key ${keypair.publicKey}`);
|
|
512
|
+
lines.push('');
|
|
513
|
+
lines.push('Sign requests with:');
|
|
514
|
+
lines.push(' sf --sign-key <private-key> --actor <name> <command>');
|
|
515
|
+
return success(data, lines.join('\n'));
|
|
516
|
+
}
|
|
517
|
+
catch (err) {
|
|
518
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
519
|
+
return failure(`Failed to generate keypair: ${message}`, ExitCode.GENERAL_ERROR);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
export const keygenCommand = {
|
|
523
|
+
name: 'keygen',
|
|
524
|
+
description: 'Generate a new Ed25519 keypair',
|
|
525
|
+
usage: 'sf identity keygen',
|
|
526
|
+
help: `Generate a new Ed25519 keypair for cryptographic identity.
|
|
527
|
+
|
|
528
|
+
The keypair can be used for:
|
|
529
|
+
- Registering an entity with a public key
|
|
530
|
+
- Signing requests in cryptographic mode
|
|
531
|
+
|
|
532
|
+
Output:
|
|
533
|
+
- Public Key: Register with 'sf entity register --public-key <key>'
|
|
534
|
+
- Private Key: Use with --sign-key to sign requests
|
|
535
|
+
|
|
536
|
+
SECURITY: The private key should be stored securely and never shared.
|
|
537
|
+
|
|
538
|
+
Examples:
|
|
539
|
+
sf identity keygen
|
|
540
|
+
sf identity keygen --json
|
|
541
|
+
sf identity keygen --quiet # Returns just the public key`,
|
|
542
|
+
options: [],
|
|
543
|
+
handler: keygenHandler,
|
|
544
|
+
};
|
|
545
|
+
const hashOptions = [
|
|
546
|
+
{
|
|
547
|
+
name: 'data',
|
|
548
|
+
short: 'd',
|
|
549
|
+
description: 'Data to hash',
|
|
550
|
+
hasValue: true,
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: 'file',
|
|
554
|
+
short: 'f',
|
|
555
|
+
description: 'Path to file to hash',
|
|
556
|
+
hasValue: true,
|
|
557
|
+
},
|
|
558
|
+
];
|
|
559
|
+
async function hashHandler(_args, options) {
|
|
560
|
+
const mode = getOutputMode(options);
|
|
561
|
+
let dataToHash;
|
|
562
|
+
if (options.data) {
|
|
563
|
+
dataToHash = options.data;
|
|
564
|
+
}
|
|
565
|
+
else if (options.file) {
|
|
566
|
+
try {
|
|
567
|
+
dataToHash = readFileSync(options.file, 'utf8');
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
571
|
+
return failure(`Failed to read file: ${message}`, ExitCode.GENERAL_ERROR);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
return failure('Must provide --data or --file', ExitCode.VALIDATION);
|
|
576
|
+
}
|
|
577
|
+
try {
|
|
578
|
+
const hash = await hashRequestBody(dataToHash);
|
|
579
|
+
const data = { hash, length: dataToHash.length };
|
|
580
|
+
if (mode === 'json') {
|
|
581
|
+
return success(data);
|
|
582
|
+
}
|
|
583
|
+
if (mode === 'quiet') {
|
|
584
|
+
return success(hash);
|
|
585
|
+
}
|
|
586
|
+
return success(data, `SHA256: ${hash}`);
|
|
587
|
+
}
|
|
588
|
+
catch (err) {
|
|
589
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
590
|
+
return failure(`Failed to hash data: ${message}`, ExitCode.GENERAL_ERROR);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
export const hashCommand = {
|
|
594
|
+
name: 'hash',
|
|
595
|
+
description: 'Compute SHA256 hash of data',
|
|
596
|
+
usage: 'sf identity hash [options]',
|
|
597
|
+
help: `Compute the SHA256 hash of data for use in signing.
|
|
598
|
+
|
|
599
|
+
Options:
|
|
600
|
+
-d, --data <string> Data to hash
|
|
601
|
+
-f, --file <path> File to hash
|
|
602
|
+
|
|
603
|
+
Examples:
|
|
604
|
+
sf identity hash --data "hello world"
|
|
605
|
+
sf identity hash --file request.json`,
|
|
606
|
+
options: hashOptions,
|
|
607
|
+
handler: hashHandler,
|
|
608
|
+
};
|
|
609
|
+
export const identityCommand = {
|
|
610
|
+
name: 'identity',
|
|
611
|
+
description: 'Manage identity settings',
|
|
612
|
+
usage: 'sf identity [subcommand]',
|
|
613
|
+
help: `Manage identity settings and view current actor.
|
|
614
|
+
|
|
615
|
+
Without a subcommand, shows the current actor identity (same as 'sf whoami').
|
|
616
|
+
|
|
617
|
+
Subcommands:
|
|
618
|
+
whoami Show current actor identity
|
|
619
|
+
mode Show or set identity mode
|
|
620
|
+
sign Sign data using a private key
|
|
621
|
+
verify Verify a signature against data
|
|
622
|
+
keygen Generate a new Ed25519 keypair
|
|
623
|
+
hash Compute SHA256 hash of data
|
|
624
|
+
|
|
625
|
+
Examples:
|
|
626
|
+
sf identity Show current identity
|
|
627
|
+
sf identity whoami Same as above
|
|
628
|
+
sf identity mode Show current identity mode
|
|
629
|
+
sf identity mode soft Set identity mode to soft
|
|
630
|
+
sf identity keygen Generate a new keypair
|
|
631
|
+
sf identity sign --data "hello" --sign-key <key>
|
|
632
|
+
sf identity verify --signature <sig> --public-key <key> --data "hello"`,
|
|
633
|
+
handler: identityHandler,
|
|
634
|
+
subcommands: {
|
|
635
|
+
whoami: whoamiCommand,
|
|
636
|
+
sign: signCommand,
|
|
637
|
+
verify: verifyCommand,
|
|
638
|
+
keygen: keygenCommand,
|
|
639
|
+
hash: hashCommand,
|
|
640
|
+
mode: {
|
|
641
|
+
name: 'mode',
|
|
642
|
+
description: 'Show or set identity mode',
|
|
643
|
+
usage: 'sf identity mode [mode]',
|
|
644
|
+
help: `Show or set the identity verification mode.
|
|
645
|
+
|
|
646
|
+
Available modes:
|
|
647
|
+
soft Name-based identity without verification (default)
|
|
648
|
+
cryptographic Key-based identity with signature verification
|
|
649
|
+
hybrid Accepts both verified and unverified actors
|
|
650
|
+
|
|
651
|
+
Examples:
|
|
652
|
+
sf identity mode Show current mode
|
|
653
|
+
sf identity mode soft Set to soft mode
|
|
654
|
+
sf identity mode cryptographic Set to cryptographic mode`,
|
|
655
|
+
options: [],
|
|
656
|
+
handler: async (args, options) => {
|
|
657
|
+
const mode = getOutputMode(options);
|
|
658
|
+
if (args.length === 0) {
|
|
659
|
+
// Show current mode
|
|
660
|
+
loadConfig();
|
|
661
|
+
const currentMode = getValue('identity.mode');
|
|
662
|
+
const source = getValueSource('identity.mode');
|
|
663
|
+
const data = { mode: currentMode, source };
|
|
664
|
+
if (mode === 'json') {
|
|
665
|
+
return success(data);
|
|
666
|
+
}
|
|
667
|
+
if (mode === 'quiet') {
|
|
668
|
+
return success(currentMode);
|
|
669
|
+
}
|
|
670
|
+
return success(data, `Identity mode: ${currentMode} (from ${source})`);
|
|
671
|
+
}
|
|
672
|
+
// Set mode
|
|
673
|
+
const newMode = args[0].toLowerCase();
|
|
674
|
+
const validModes = Object.values(IdentityMode);
|
|
675
|
+
if (!validModes.includes(newMode)) {
|
|
676
|
+
return failure(`Invalid identity mode: ${newMode}. Must be one of: ${validModes.join(', ')}`, ExitCode.VALIDATION);
|
|
677
|
+
}
|
|
678
|
+
try {
|
|
679
|
+
const { setValue } = await import('../../config/index.js');
|
|
680
|
+
setValue('identity.mode', newMode);
|
|
681
|
+
const data = { mode: newMode, previous: getValue('identity.mode') };
|
|
682
|
+
if (mode === 'json') {
|
|
683
|
+
return success(data);
|
|
684
|
+
}
|
|
685
|
+
if (mode === 'quiet') {
|
|
686
|
+
return success(newMode);
|
|
687
|
+
}
|
|
688
|
+
return success(data, `Identity mode set to: ${newMode}`);
|
|
689
|
+
}
|
|
690
|
+
catch (err) {
|
|
691
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
692
|
+
return failure(`Failed to set identity mode: ${message}`, ExitCode.GENERAL_ERROR);
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
//# sourceMappingURL=identity.js.map
|