@nseng-ai/ns 0.1.0 → 0.1.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.
@@ -0,0 +1,120 @@
1
+ import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
+
3
+ // ../../infra/foundation/src/primitives/primitives.ts
4
+ function formatErrorMessage(error) {
5
+ return error instanceof Error ? error.message : String(error);
6
+ }
7
+
8
+ // ../../kernel/src/runtime/pi-text-generation.ts
9
+ var DEFAULT_MAX_TOKENS = 512;
10
+ var DEFAULT_REASONING = "low";
11
+ var DEFAULT_TIMEOUT_MS = 12e4;
12
+ var PiTextGenerator = class {
13
+ modelRegistry;
14
+ completeSimple;
15
+ loadDefaultModelRegistry;
16
+ constructor(options = {}) {
17
+ this.modelRegistry = options.modelRegistry;
18
+ this.completeSimple = options.completeSimple;
19
+ this.loadDefaultModelRegistry = options.loadDefaultModelRegistry ?? loadDefaultModelRegistry;
20
+ }
21
+ async generateText(request) {
22
+ const parsed = parsePiModelRef(request.modelRef);
23
+ if (!parsed.ok) {
24
+ return { ok: false, error: parsed.error };
25
+ }
26
+ const modelRegistry = this.modelRegistry ?? await this.loadDefaultModelRegistry();
27
+ const model = modelRegistry.find(parsed.provider, parsed.modelId);
28
+ if (model === void 0) {
29
+ return { ok: false, error: `Could not find Pi model ${request.modelRef}.` };
30
+ }
31
+ const auth = await modelRegistry.getApiKeyAndHeaders(model);
32
+ if (!auth.ok) {
33
+ return { ok: false, error: `Pi auth failed for ${request.modelRef}: ${auth.error}` };
34
+ }
35
+ if (!auth.apiKey) {
36
+ return {
37
+ ok: false,
38
+ error: `No Pi auth found for ${parsed.provider}. Run /login or configure Pi auth.`
39
+ };
40
+ }
41
+ try {
42
+ const completeSimple = this.completeSimple ?? await loadCompleteSimple();
43
+ const response = await completeSimple(
44
+ model,
45
+ {
46
+ systemPrompt: request.system,
47
+ messages: [
48
+ {
49
+ role: "user",
50
+ content: [{ type: "text", text: request.prompt }],
51
+ timestamp: Date.now()
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ ...auth.headers === void 0 ? {} : { headers: auth.headers },
57
+ apiKey: auth.apiKey,
58
+ maxTokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
59
+ reasoning: request.reasoning ?? DEFAULT_REASONING,
60
+ timeoutMs: DEFAULT_TIMEOUT_MS
61
+ }
62
+ );
63
+ if (response.stopReason === "error" || response.stopReason === "aborted") {
64
+ return {
65
+ ok: false,
66
+ error: `Pi model ${request.modelRef} failed to generate text: ${response.errorMessage ?? response.stopReason}`
67
+ };
68
+ }
69
+ const text = response.content.filter(
70
+ (content) => content.type === "text" && typeof content.text === "string"
71
+ ).map((content) => content.text).join("\n");
72
+ if (text.trim().length === 0) {
73
+ return { ok: false, error: `Pi model ${request.modelRef} returned empty text.` };
74
+ }
75
+ const usage = textGenerationUsageFromResponse(response.usage);
76
+ return {
77
+ ok: true,
78
+ text,
79
+ ...usage === void 0 ? {} : { usage }
80
+ };
81
+ } catch (error) {
82
+ return {
83
+ ok: false,
84
+ error: `Pi model ${request.modelRef} failed to generate text: ${formatErrorMessage(error)}`
85
+ };
86
+ }
87
+ }
88
+ };
89
+ function textGenerationUsageFromResponse(usage) {
90
+ if (!Number.isFinite(usage.input) || !Number.isFinite(usage.output)) return void 0;
91
+ return {
92
+ inputTokens: usage.input,
93
+ outputTokens: usage.output
94
+ };
95
+ }
96
+ function parsePiModelRef(modelRef) {
97
+ const separator = modelRef.indexOf("/");
98
+ if (separator <= 0 || separator === modelRef.length - 1) {
99
+ return {
100
+ ok: false,
101
+ error: `Invalid Pi model reference ${JSON.stringify(modelRef)}. Expected provider/model-id.`
102
+ };
103
+ }
104
+ return {
105
+ ok: true,
106
+ provider: modelRef.slice(0, separator),
107
+ modelId: modelRef.slice(separator + 1)
108
+ };
109
+ }
110
+ async function loadCompleteSimple() {
111
+ const piAi = await import("@earendil-works/pi-ai");
112
+ return piAi.completeSimple;
113
+ }
114
+ async function loadDefaultModelRegistry() {
115
+ const { AuthStorage, ModelRegistry } = await import("@earendil-works/pi-coding-agent");
116
+ return ModelRegistry.create(AuthStorage.create());
117
+ }
118
+ export {
119
+ PiTextGenerator
120
+ };
package/kernel/sdk.js ADDED
@@ -0,0 +1,157 @@
1
+ import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
+
3
+ // ../../kernel/src/sdk/command.ts
4
+ function defineExtension(extension) {
5
+ return extension;
6
+ }
7
+
8
+ // ../../kernel/src/sdk/repo-local-ns-extension.ts
9
+ function repoLocalNsCommandDescriptor(options) {
10
+ const manifestName = options.manifestName ?? options.command.name;
11
+ return {
12
+ command: options.command,
13
+ ...options.manifestName === void 0 ? {} : { manifestName },
14
+ ...options.manifestPath === void 0 ? {} : { manifestPath: options.manifestPath },
15
+ manifestEntry: `./src/commands/${manifestName}.ts`,
16
+ packageExport: `${options.packageExportPrefix}/${manifestName}`
17
+ };
18
+ }
19
+ function defineRepoLocalNsExtensionDescriptor(descriptor) {
20
+ return descriptor;
21
+ }
22
+
23
+ // ../../kernel/src/sdk/schema.ts
24
+ import { z } from "zod";
25
+
26
+ // ../../kernel/src/sdk/extension-manifest.ts
27
+ var nsExtensionManifestCommandSchema = z.looseObject({
28
+ name: z.string().optional(),
29
+ path: z.array(z.string()).optional(),
30
+ group: z.string().optional(),
31
+ description: z.string().optional(),
32
+ fullDescription: z.string().optional(),
33
+ entry: z.string().optional()
34
+ });
35
+ var nsExtensionManifestSchema = z.looseObject({
36
+ description: z.string().optional(),
37
+ group: z.string().optional(),
38
+ commands: z.array(z.unknown()).optional()
39
+ });
40
+ var nsExtensionPackageManifestSchema = z.looseObject({
41
+ description: z.string().optional(),
42
+ ns: nsExtensionManifestSchema.optional()
43
+ });
44
+
45
+ // ../../infra/foundation/src/terminal/text-normalization.ts
46
+ function normalizeTextOutput(output) {
47
+ return stripOuterCodeFence(trimOuterBlankLines(output.replace(/\r\n?/g, "\n")));
48
+ }
49
+ function trimOuterBlankLines(text) {
50
+ const lines = text.split("\n");
51
+ let start = 0;
52
+ let end = lines.length;
53
+ while (start < end && lines[start]?.trim() === "") {
54
+ start += 1;
55
+ }
56
+ while (end > start && lines[end - 1]?.trim() === "") {
57
+ end -= 1;
58
+ }
59
+ return lines.slice(start, end).join("\n");
60
+ }
61
+ function stripOuterCodeFence(text) {
62
+ const trimmed = trimOuterBlankLines(text);
63
+ const lines = trimmed.split("\n");
64
+ const firstLine = lines[0]?.trim() ?? "";
65
+ const lastLine = lines[lines.length - 1]?.trim() ?? "";
66
+ if (lines.length >= 2 && /^```[a-zA-Z0-9_-]*$/.test(firstLine) && lastLine === "```") {
67
+ return trimOuterBlankLines(lines.slice(1, -1).join("\n"));
68
+ }
69
+ return trimmed;
70
+ }
71
+
72
+ // ../../infra/foundation/src/terminal/text-truncation.ts
73
+ function truncateTextHeadTail(input) {
74
+ if (input.value.length <= input.maxChars) return input.value;
75
+ const marker = input.buildMarker(input.markerOmittedChars ?? input.value.length - input.maxChars);
76
+ const remainingChars = Math.max(0, input.maxChars - marker.length);
77
+ const headChars = splitHeadChars(remainingChars, input.headRatio, input.headRounding ?? "floor");
78
+ const tailChars = remainingChars - headChars;
79
+ const head = maybeTrimEnd(input.value.slice(0, headChars), input.shouldTrimHead === true);
80
+ const tail = maybeTrimStart(
81
+ tailChars === 0 ? "" : input.value.slice(input.value.length - tailChars),
82
+ input.shouldTrimTail === true
83
+ );
84
+ return `${head}${marker}${tail}`;
85
+ }
86
+ function truncateTextHead(input) {
87
+ const value = input.shouldTrimInput === true ? input.value.trim() : input.value;
88
+ if (value.length <= input.maxChars) return value;
89
+ let markerState = headMarkerState(input, 0);
90
+ markerState = refineHeadMarkerState(input, value.length, markerState);
91
+ markerState = refineHeadMarkerState(input, value.length, markerState);
92
+ const head = maybeTrimEnd(
93
+ value.slice(0, markerState.preservedChars),
94
+ input.shouldTrimHead !== false
95
+ );
96
+ return `${head}${markerState.marker}`;
97
+ }
98
+ function headMarkerState(input, omittedChars) {
99
+ const marker = input.buildMarker(omittedChars);
100
+ return { marker, preservedChars: Math.max(0, input.maxChars - marker.length) };
101
+ }
102
+ function refineHeadMarkerState(input, valueLength, state) {
103
+ return headMarkerState(input, valueLength - state.preservedChars);
104
+ }
105
+ function splitHeadChars(remainingChars, headRatio, headRounding) {
106
+ const rawHeadChars = remainingChars * headRatio;
107
+ const roundedHeadChars = headRounding === "ceil" ? Math.ceil(rawHeadChars) : Math.floor(rawHeadChars);
108
+ return Math.max(0, Math.min(remainingChars, roundedHeadChars));
109
+ }
110
+ function maybeTrimEnd(value, shouldTrim) {
111
+ return shouldTrim ? value.trimEnd() : value;
112
+ }
113
+ function maybeTrimStart(value, shouldTrim) {
114
+ return shouldTrim ? value.trimStart() : value;
115
+ }
116
+
117
+ // ../../kernel/src/sdk/result.ts
118
+ function ok(message) {
119
+ return { ok: true, message };
120
+ }
121
+ function failed(message, exitCode = 1) {
122
+ return { ok: false, exitCode, message };
123
+ }
124
+
125
+ // ../../kernel/src/sdk/services.ts
126
+ var noopNsCommandIo = {
127
+ phase: () => {
128
+ },
129
+ notify: () => {
130
+ },
131
+ message: () => {
132
+ },
133
+ clearPhase: () => {
134
+ }
135
+ };
136
+ var noopNsProgress = {
137
+ phase: () => {
138
+ }
139
+ };
140
+ export {
141
+ defineExtension,
142
+ defineRepoLocalNsExtensionDescriptor,
143
+ failed,
144
+ noopNsCommandIo,
145
+ noopNsProgress,
146
+ normalizeTextOutput,
147
+ nsExtensionManifestCommandSchema,
148
+ nsExtensionManifestSchema,
149
+ nsExtensionPackageManifestSchema,
150
+ ok,
151
+ repoLocalNsCommandDescriptor,
152
+ stripOuterCodeFence,
153
+ trimOuterBlankLines,
154
+ truncateTextHead,
155
+ truncateTextHeadTail,
156
+ z
157
+ };
package/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "name": "@nseng-ai/ns",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Checkout-free ns CLI package.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "ns": "bin/ns.js"
8
8
  },
9
+ "exports": {
10
+ "./kernel/cli": "./kernel/cli.js",
11
+ "./kernel/command-io": "./kernel/command-io.js",
12
+ "./kernel/context": "./kernel/context.js",
13
+ "./kernel/pi-text-generation": "./kernel/pi-text-generation.js",
14
+ "./kernel/sdk": "./kernel/sdk.js"
15
+ },
9
16
  "files": [
10
17
  "bin",
18
+ "kernel",
11
19
  "README.md"
12
20
  ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
13
24
  "engines": {
14
25
  "node": ">=24.12.0"
15
26
  },